Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2bf11e80 authored by Rob Carr's avatar Rob Carr Committed by Android (Google) Code Review
Browse files

Merge "SurfaceFlinger: Use a lockless stack for binder->tracing thread" into tm-dev

parents cb1a77e5 a63d52ad
Loading
Loading
Loading
Loading
+72 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once
#include <atomic>

template <typename T>
// Single consumer multi producer stack. We can understand the two operations independently to see
// why they are without race condition.
//
// push is responsible for maintaining a linked list stored in mPush, and called from multiple
// threads without lock. We can see that if two threads never observe the same value from
// mPush.load, it just functions as a normal linked list. In the case where two threads observe the
// same value, one of them has to execute the compare_exchange first. The one that doesn't execute
// the compare exchange first, will receive false from compare_exchange. previousHead is updated (by
// compare_exchange) to the most recent value of mPush, and we try again. It's relatively clear to
// see that the process can repeat with an arbitrary number of threads.
//
// Pop is much simpler. If mPop is empty (as it begins) it atomically exchanges
// the entire push list with null. This is safe, since the only other reader (push)
// of mPush will retry if it changes in between it's read and atomic compare. We
// then store the list and pop one element.
//
// If we already had something in the pop list we just pop directly.
class LocklessStack {
public:
    class Entry {
    public:
        T* mValue;
        std::atomic<Entry*> mNext;
        Entry(T* value): mValue(value) {}
    };
    std::atomic<Entry*> mPush = nullptr;
    std::atomic<Entry*> mPop = nullptr;
    void push(T* value) {
        Entry* entry = new Entry(value);
        Entry* previousHead = mPush.load(/*std::memory_order_relaxed*/);
        do {
            entry->mNext = previousHead;
        } while (!mPush.compare_exchange_weak(previousHead, entry)); /*std::memory_order_release*/
    }
    T* pop() {
        Entry* popped = mPop.load(/*std::memory_order_acquire*/);
        if (popped) {
            // Single consumer so this is fine
            mPop.store(popped->mNext/* , std::memory_order_release */);
            auto value = popped->mValue;
            delete popped;
            return value;
        } else {
            Entry *grabbedList = mPush.exchange(nullptr/* , std::memory_order_acquire */);
            if (!grabbedList) return nullptr;
            mPop.store(grabbedList->mNext/* , std::memory_order_release */);
            auto value = grabbedList->mValue;
            delete grabbedList;
            return value;
        }
    }
};
+15 −12
Original line number Original line Diff line number Diff line
@@ -180,13 +180,13 @@ proto::LayerState TransactionProtoParser::toProto(const layer_state_t& layer) {
    }
    }


    if (layer.what & layer_state_t::eReparent) {
    if (layer.what & layer_state_t::eReparent) {
        int32_t layerId = layer.parentSurfaceControlForChild
        int64_t layerId = layer.parentSurfaceControlForChild
                ? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle())
                ? mMapper->getLayerId(layer.parentSurfaceControlForChild->getHandle())
                : -1;
                : -1;
        proto.set_parent_id(layerId);
        proto.set_parent_id(layerId);
    }
    }
    if (layer.what & layer_state_t::eRelativeLayerChanged) {
    if (layer.what & layer_state_t::eRelativeLayerChanged) {
        int32_t layerId = layer.relativeLayerSurfaceControl
        int64_t layerId = layer.relativeLayerSurfaceControl
                ? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle())
                ? mMapper->getLayerId(layer.relativeLayerSurfaceControl->getHandle())
                : -1;
                : -1;
        proto.set_relative_parent_id(layerId);
        proto.set_relative_parent_id(layerId);
@@ -342,13 +342,13 @@ void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto,
    outState.merge(state);
    outState.merge(state);


    if (state.what & layer_state_t::eReparent) {
    if (state.what & layer_state_t::eReparent) {
        outState.parentId = proto.parent_id();
        outState.parentId = static_cast<int32_t>(proto.parent_id());
    }
    }
    if (state.what & layer_state_t::eRelativeLayerChanged) {
    if (state.what & layer_state_t::eRelativeLayerChanged) {
        outState.relativeParentId = proto.relative_parent_id();
        outState.relativeParentId = static_cast<int32_t>(proto.relative_parent_id());
    }
    }
    if (state.what & layer_state_t::eInputInfoChanged) {
    if (state.what & layer_state_t::eInputInfoChanged) {
        outState.inputCropId = proto.window_info_handle().crop_layer_id();
        outState.inputCropId = static_cast<int32_t>(proto.window_info_handle().crop_layer_id());
    }
    }
    if (state.what & layer_state_t::eBufferChanged) {
    if (state.what & layer_state_t::eBufferChanged) {
        const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
        const proto::LayerState_BufferData& bufferProto = proto.buffer_data();
@@ -364,7 +364,7 @@ void TransactionProtoParser::mergeFromProto(const proto::LayerState& proto,
}
}


void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) {
void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_state_t& layer) {
    layer.layerId = proto.layer_id();
    layer.layerId = (int32_t)proto.layer_id();
    layer.what |= proto.what();
    layer.what |= proto.what();
    layer.surface = mMapper->getLayerHandle(layer.layerId);
    layer.surface = mMapper->getLayerHandle(layer.layerId);


@@ -451,23 +451,25 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta
    }
    }


    if (proto.what() & layer_state_t::eReparent) {
    if (proto.what() & layer_state_t::eReparent) {
        int32_t layerId = proto.parent_id();
        int64_t layerId = proto.parent_id();
        if (layerId == -1) {
        if (layerId == -1) {
            layer.parentSurfaceControlForChild = nullptr;
            layer.parentSurfaceControlForChild = nullptr;
        } else {
        } else {
            layer.parentSurfaceControlForChild =
            layer.parentSurfaceControlForChild =
                    new SurfaceControl(SurfaceComposerClient::getDefault(),
                    new SurfaceControl(SurfaceComposerClient::getDefault(),
                                       mMapper->getLayerHandle(layerId), nullptr, layerId);
                                       mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
                                       nullptr, static_cast<int32_t>(layerId));
        }
        }
    }
    }
    if (proto.what() & layer_state_t::eRelativeLayerChanged) {
    if (proto.what() & layer_state_t::eRelativeLayerChanged) {
        int32_t layerId = proto.relative_parent_id();
        int64_t layerId = proto.relative_parent_id();
        if (layerId == -1) {
        if (layerId == -1) {
            layer.relativeLayerSurfaceControl = nullptr;
            layer.relativeLayerSurfaceControl = nullptr;
        } else {
        } else {
            layer.relativeLayerSurfaceControl =
            layer.relativeLayerSurfaceControl =
                    new SurfaceControl(SurfaceComposerClient::getDefault(),
                    new SurfaceControl(SurfaceComposerClient::getDefault(),
                                       mMapper->getLayerHandle(layerId), nullptr, layerId);
                                       mMapper->getLayerHandle(static_cast<int32_t>(layerId)),
                                       nullptr, static_cast<int32_t>(layerId));
        }
        }
        layer.z = proto.z();
        layer.z = proto.z();
    }
    }
@@ -494,8 +496,9 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta
        inputInfo.transform.set(transformProto.tx(), transformProto.ty());
        inputInfo.transform.set(transformProto.tx(), transformProto.ty());
        inputInfo.replaceTouchableRegionWithCrop =
        inputInfo.replaceTouchableRegionWithCrop =
                windowInfoProto.replace_touchable_region_with_crop();
                windowInfoProto.replace_touchable_region_with_crop();
        int32_t layerId = windowInfoProto.crop_layer_id();
        int64_t layerId = windowInfoProto.crop_layer_id();
        inputInfo.touchableRegionCropHandle = mMapper->getLayerHandle(layerId);
        inputInfo.touchableRegionCropHandle =
                mMapper->getLayerHandle(static_cast<int32_t>(layerId));
        layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
        layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo);
    }
    }
    if (proto.what() & layer_state_t::eBackgroundColorChanged) {
    if (proto.what() & layer_state_t::eBackgroundColorChanged) {
+3 −2
Original line number Original line Diff line number Diff line
@@ -80,7 +80,8 @@ public:
    public:
    public:
        virtual ~FlingerDataMapper() = default;
        virtual ~FlingerDataMapper() = default;
        virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; }
        virtual sp<IBinder> getLayerHandle(int32_t /* layerId */) const { return nullptr; }
        virtual int32_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
        virtual int64_t getLayerId(const sp<IBinder>& /* layerHandle */) const { return -1; }
        virtual int64_t getLayerId(BBinder* /* layerHandle */) const { return -1; }
        virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; }
        virtual sp<IBinder> getDisplayHandle(int32_t /* displayId */) const { return nullptr; }
        virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; }
        virtual int32_t getDisplayId(const sp<IBinder>& /* displayHandle */) const { return -1; }
        virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
        virtual std::shared_ptr<BufferData> getGraphicData(uint64_t bufferId, uint32_t width,
@@ -106,6 +107,7 @@ public:
    TransactionState fromProto(const proto::TransactionState&);
    TransactionState fromProto(const proto::TransactionState&);
    void mergeFromProto(const proto::LayerState&, TracingLayerState& outState);
    void mergeFromProto(const proto::LayerState&, TracingLayerState& outState);
    void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
    void fromProto(const proto::LayerCreationArgs&, TracingLayerCreationArgs& outArgs);
    std::unique_ptr<FlingerDataMapper> mMapper;


private:
private:
    proto::LayerState toProto(const layer_state_t&);
    proto::LayerState toProto(const layer_state_t&);
@@ -113,7 +115,6 @@ private:
    void fromProto(const proto::LayerState&, layer_state_t& out);
    void fromProto(const proto::LayerState&, layer_state_t& out);
    DisplayState fromProto(const proto::DisplayState&);
    DisplayState fromProto(const proto::DisplayState&);


    std::unique_ptr<FlingerDataMapper> mMapper;
};
};


} // namespace android::surfaceflinger
} // namespace android::surfaceflinger
+69 −19
Original line number Original line Diff line number Diff line
@@ -29,23 +29,16 @@


namespace android {
namespace android {


class FlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
// Keeps the binder address as the layer id so we can avoid holding the tracing lock in the
    std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;
// binder thread.

class FlatDataMapper : public TransactionProtoParser::FlingerDataMapper {
public:
public:
    FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
    virtual int64_t getLayerId(const sp<IBinder>& layerHandle) const {
          : mLayerHandles(layerHandles) {}

    int32_t getLayerId(const sp<IBinder>& layerHandle) const override {
        if (layerHandle == nullptr) {
        if (layerHandle == nullptr) {
            return -1;
            return -1;
        }
        }
        auto it = mLayerHandles.find(layerHandle->localBinder());

        if (it == mLayerHandles.end()) {
        return reinterpret_cast<int64_t>(layerHandle->localBinder());
            ALOGW("Could not find layer handle %p", layerHandle->localBinder());
            return -1;
        }
        return it->second;
    }
    }


    void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
    void getGraphicBufferPropertiesFromCache(client_cache_t cachedBuffer, uint64_t* outBufferId,
@@ -72,8 +65,33 @@ public:
    }
    }
};
};


class FlingerDataMapper : public FlatDataMapper {
    std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */>& mLayerHandles;

public:
    FlingerDataMapper(std::unordered_map<BBinder* /* handle */, int32_t /* id */>& layerHandles)
          : mLayerHandles(layerHandles) {}

    int64_t getLayerId(const sp<IBinder>& layerHandle) const override {
        if (layerHandle == nullptr) {
            return -1;
        }
        return getLayerId(layerHandle->localBinder());
    }

    int64_t getLayerId(BBinder* localBinder) const {
        auto it = mLayerHandles.find(localBinder);
        if (it == mLayerHandles.end()) {
            ALOGW("Could not find layer handle %p", localBinder);
            return -1;
        }
        return it->second;
    }
};

TransactionTracing::TransactionTracing()
TransactionTracing::TransactionTracing()
      : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)) {
      : mProtoParser(std::make_unique<FlingerDataMapper>(mLayerHandles)),
        mLockfreeProtoParser(std::make_unique<FlatDataMapper>()) {
    std::scoped_lock lock(mTraceLock);
    std::scoped_lock lock(mTraceLock);


    mBuffer.setSize(mBufferSizeInBytes);
    mBuffer.setSize(mBufferSizeInBytes);
@@ -129,9 +147,9 @@ void TransactionTracing::dump(std::string& result) const {
}
}


void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
void TransactionTracing::addQueuedTransaction(const TransactionState& transaction) {
    std::scoped_lock lock(mTraceLock);
    proto::TransactionState* state =
    ATRACE_CALL();
            new proto::TransactionState(mLockfreeProtoParser.toProto(transaction));
    mQueuedTransactions[transaction.id] = mProtoParser.toProto(transaction);
    mTransactionQueue.push(state);
}
}


void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions,
@@ -182,6 +200,38 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm
    std::scoped_lock lock(mTraceLock);
    std::scoped_lock lock(mTraceLock);
    std::vector<std::string> removedEntries;
    std::vector<std::string> removedEntries;
    proto::TransactionTraceEntry entryProto;
    proto::TransactionTraceEntry entryProto;

    while (auto incomingTransaction = mTransactionQueue.pop()) {
        auto transaction = *incomingTransaction;
        int32_t layerCount = transaction.layer_changes_size();
        for (int i = 0; i < layerCount; i++) {
            auto layer = transaction.mutable_layer_changes(i);
            layer->set_layer_id(
                mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(layer->layer_id())));
            if ((layer->what() & layer_state_t::eReparent) && layer->parent_id() != -1) {
                layer->set_parent_id(
                    mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
                        layer->parent_id())));
            }

            if ((layer->what() & layer_state_t::eRelativeLayerChanged) &&
                layer->relative_parent_id() != -1) {
                layer->set_relative_parent_id(
                    mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
                        layer->relative_parent_id())));
            }

            if (layer->has_window_info_handle() &&
                layer->window_info_handle().crop_layer_id() != -1) {
                auto input = layer->mutable_window_info_handle();
                input->set_crop_layer_id(
                        mProtoParser.mMapper->getLayerId(reinterpret_cast<BBinder*>(
                            input->crop_layer_id())));
            }
        }
        mQueuedTransactions[incomingTransaction->transaction_id()] = transaction;
        delete incomingTransaction;
    }
    for (const CommittedTransactions& entry : committedTransactions) {
    for (const CommittedTransactions& entry : committedTransactions) {
        entryProto.set_elapsed_realtime_nanos(entry.timestamp);
        entryProto.set_elapsed_realtime_nanos(entry.timestamp);
        entryProto.set_vsync_id(entry.vsyncId);
        entryProto.set_vsync_id(entry.vsyncId);
@@ -317,9 +367,9 @@ void TransactionTracing::updateStartingStateLocked(
    // Merge layer states to starting transaction state.
    // Merge layer states to starting transaction state.
    for (const proto::TransactionState& transaction : removedEntry.transactions()) {
    for (const proto::TransactionState& transaction : removedEntry.transactions()) {
        for (const proto::LayerState& layerState : transaction.layer_changes()) {
        for (const proto::LayerState& layerState : transaction.layer_changes()) {
            auto it = mStartingStates.find(layerState.layer_id());
            auto it = mStartingStates.find((int32_t)layerState.layer_id());
            if (it == mStartingStates.end()) {
            if (it == mStartingStates.end()) {
                ALOGW("Could not find layer id %d", layerState.layer_id());
                ALOGW("Could not find layer id %d", (int32_t)layerState.layer_id());
                continue;
                continue;
            }
            }
            mProtoParser.mergeFromProto(layerState, it->second);
            mProtoParser.mergeFromProto(layerState, it->second);
+5 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@
#include <thread>
#include <thread>


#include "RingBuffer.h"
#include "RingBuffer.h"
#include "LocklessStack.h"
#include "TransactionProtoParser.h"
#include "TransactionProtoParser.h"


using namespace android::surfaceflinger;
using namespace android::surfaceflinger;
@@ -78,6 +79,7 @@ private:
    size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE;
    size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = CONTINUOUS_TRACING_BUFFER_SIZE;
    std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions
    std::unordered_map<uint64_t, proto::TransactionState> mQueuedTransactions
            GUARDED_BY(mTraceLock);
            GUARDED_BY(mTraceLock);
    LocklessStack<proto::TransactionState> mTransactionQueue;
    nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
    nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock);
    std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
    std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock);
    std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
    std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles
@@ -85,6 +87,9 @@ private:
    std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
    std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock);
    std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
    std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock);
    TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
    TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock);
    // Parses the transaction to proto without holding any tracing locks so we can generate proto
    // in the binder thread without any contention.
    TransactionProtoParser mLockfreeProtoParser;


    // We do not want main thread to block so main thread will try to acquire mMainThreadLock,
    // We do not want main thread to block so main thread will try to acquire mMainThreadLock,
    // otherwise will push data to temporary container.
    // otherwise will push data to temporary container.
Loading