Loading services/surfaceflinger/Tracing/LocklessStack.h 0 → 100644 +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; } } }; services/surfaceflinger/Tracing/TransactionProtoParser.cpp +15 −12 Original line number Original line Diff line number Diff line Loading @@ -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); Loading Loading @@ -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(); Loading @@ -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); Loading Loading @@ -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(); } } Loading @@ -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) { Loading services/surfaceflinger/Tracing/TransactionProtoParser.h +3 −2 Original line number Original line Diff line number Diff line Loading @@ -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, Loading @@ -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&); Loading @@ -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 services/surfaceflinger/Tracing/TransactionTracing.cpp +69 −19 Original line number Original line Diff line number Diff line Loading @@ -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, Loading @@ -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); Loading Loading @@ -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, Loading Loading @@ -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); Loading Loading @@ -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); Loading services/surfaceflinger/Tracing/TransactionTracing.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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 Loading
services/surfaceflinger/Tracing/LocklessStack.h 0 → 100644 +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; } } };
services/surfaceflinger/Tracing/TransactionProtoParser.cpp +15 −12 Original line number Original line Diff line number Diff line Loading @@ -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); Loading Loading @@ -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(); Loading @@ -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); Loading Loading @@ -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(); } } Loading @@ -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) { Loading
services/surfaceflinger/Tracing/TransactionProtoParser.h +3 −2 Original line number Original line Diff line number Diff line Loading @@ -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, Loading @@ -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&); Loading @@ -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
services/surfaceflinger/Tracing/TransactionTracing.cpp +69 −19 Original line number Original line Diff line number Diff line Loading @@ -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, Loading @@ -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); Loading Loading @@ -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, Loading Loading @@ -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); Loading Loading @@ -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); Loading
services/surfaceflinger/Tracing/TransactionTracing.h +5 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading @@ -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