Loading services/surfaceflinger/SurfaceFlinger.cpp +22 −17 Original line number Diff line number Diff line Loading @@ -1850,16 +1850,18 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT bool refreshNeeded; { ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled); mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) || mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) || mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS); const bool tracePreComposition = mTracingEnabled && !mTracePostComposition; ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition); mFrameTimeline->setSfWakeUp(vsyncId, frameStart); refreshNeeded = handleMessageTransaction(); refreshNeeded |= handleMessageInvalidate(); if (mTracingEnabled) { mAddCompositionStateToTrace = mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION); if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) { if (tracePreComposition) { if (mVisibleRegionsDirty) { mTracing.notifyLocked("visibleRegionsDirty"); } } Loading Loading @@ -2009,12 +2011,15 @@ void SurfaceFlinger::onMessageRefresh() { modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition); mLayersWithQueuedFrames.clear(); if (mTracingEnabled && mTracePostComposition) { // This may block if SurfaceTracing is running in sync mode. if (mVisibleRegionsDirty) { mVisibleRegionsDirty = false; if (mTracingEnabled && mAddCompositionStateToTrace) { mTracing.notify("visibleRegionsDirty"); } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) { mTracing.notify("bufferLatched"); } } mVisibleRegionsDirty = false; if (mCompositionEngine->needsAnotherUpdate()) { signalLayerUpdate(); Loading Loading @@ -4279,7 +4284,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) { if (asProto && mTracing.isEnabled()) { mTracing.writeToFileAsync(); mTracing.writeToFile(); } return doDump(fd, DumpArgs(), asProto); Loading Loading @@ -5103,19 +5108,19 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1025: { // Set layer tracing n = data.readInt32(); bool tracingEnabledChanged; if (n) { ALOGD("LayerTracing enabled"); mTracingEnabledChanged = mTracing.enable(); reply->writeInt32(NO_ERROR); tracingEnabledChanged = mTracing.enable(); if (tracingEnabledChanged) { schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait(); } } else { ALOGD("LayerTracing disabled"); mTracingEnabledChanged = mTracing.disable(); if (mTracingEnabledChanged) { reply->writeInt32(mTracing.writeToFile()); } else { reply->writeInt32(NO_ERROR); } tracingEnabledChanged = mTracing.disable(); } mTracingEnabledChanged = tracingEnabledChanged; reply->writeInt32(NO_ERROR); return NO_ERROR; } case 1026: { // Get layer tracing status Loading services/surfaceflinger/SurfaceFlinger.h +1 −1 Original line number Diff line number Diff line Loading @@ -1134,7 +1134,7 @@ private: SurfaceTracing mTracing{*this}; std::mutex mTracingLock; bool mTracingEnabled = false; bool mAddCompositionStateToTrace = false; bool mTracePostComposition = false; std::atomic<bool> mTracingEnabledChanged = false; const std::shared_ptr<TimeStats> mTimeStats; Loading services/surfaceflinger/SurfaceTracing.cpp +130 −116 Original line number Diff line number Diff line Loading @@ -14,9 +14,6 @@ * limitations under the License. */ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #undef LOG_TAG #define LOG_TAG "SurfaceTracing" #define ATRACE_TAG ATRACE_TAG_GRAPHICS Loading @@ -32,65 +29,65 @@ namespace android { SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger), mSfLock(flinger.mTracingLock) {} SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {} void SurfaceTracing::mainLoop() { bool enabled = addFirstEntry(); while (enabled) { LayersTraceProto entry = traceWhenNotified(); enabled = addTraceToBuffer(entry); bool SurfaceTracing::enable() { std::scoped_lock lock(mTraceLock); if (mEnabled) { return false; } if (flagIsSet(TRACE_SYNC)) { runner = std::make_unique<SurfaceTracing::Runner>(mFlinger, mConfig); } else { runner = std::make_unique<SurfaceTracing::AsyncRunner>(mFlinger, mConfig, mFlinger.mTracingLock); } mEnabled = true; return true; } bool SurfaceTracing::addFirstEntry() { LayersTraceProto entry; { std::scoped_lock lock(mSfLock); entry = traceLayersLocked("tracing.enable"); bool SurfaceTracing::disable() { std::scoped_lock lock(mTraceLock); if (!mEnabled) { return false; } return addTraceToBuffer(entry); mEnabled = false; runner->stop(); return true; } LayersTraceProto SurfaceTracing::traceWhenNotified() { std::unique_lock<std::mutex> lock(mSfLock); mCanStartTrace.wait(lock); android::base::ScopedLockAssertion assumeLock(mSfLock); LayersTraceProto entry = traceLayersLocked(mWhere); mTracingInProgress = false; mMissedTraceEntries = 0; lock.unlock(); return entry; bool SurfaceTracing::isEnabled() const { std::scoped_lock lock(mTraceLock); return mEnabled; } bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) { status_t SurfaceTracing::writeToFile() { std::scoped_lock lock(mTraceLock); mBuffer.emplace(std::move(entry)); if (mWriteToFile) { writeProtoFileLocked(); mWriteToFile = false; if (!mEnabled) { return STATUS_OK; } return mEnabled; return runner->writeToFile(); } void SurfaceTracing::notify(const char* where) { std::scoped_lock lock(mSfLock); notifyLocked(where); if (mEnabled) { runner->notify(where); } } void SurfaceTracing::notifyLocked(const char* where) { mWhere = where; if (mTracingInProgress) { mMissedTraceEntries++; if (mEnabled) { runner->notifyLocked(where); } mTracingInProgress = true; mCanStartTrace.notify_one(); } void SurfaceTracing::writeToFileAsync() { void SurfaceTracing::dump(std::string& result) const { std::scoped_lock lock(mTraceLock); mWriteToFile = true; mCanStartTrace.notify_one(); base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); if (mEnabled) { runner->dump(result); } } void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) { Loading @@ -101,12 +98,12 @@ void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) { } void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) { auto protoSize = proto.ByteSize(); size_t protoSize = static_cast<size_t>(proto.ByteSize()); while (mUsedInBytes + protoSize > mSizeInBytes) { if (mStorage.empty()) { return; } mUsedInBytes -= mStorage.front().ByteSize(); mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize()); mStorage.pop(); } mUsedInBytes += protoSize; Loading @@ -115,7 +112,7 @@ void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) { } void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) { fileProto->mutable_entry()->Reserve(mStorage.size()); fileProto->mutable_entry()->Reserve(static_cast<int>(mStorage.size())); while (!mStorage.empty()) { auto entry = fileProto->add_entry(); Loading @@ -124,77 +121,66 @@ void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) { } } bool SurfaceTracing::enable() { std::scoped_lock lock(mTraceLock); if (mEnabled) { return false; SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config) : mFlinger(flinger), mConfig(config) { mBuffer.setSize(mConfig.bufferSize); } mBuffer.reset(mBufferSize); mEnabled = true; mThread = std::thread(&SurfaceTracing::mainLoop, this); return true; void SurfaceTracing::Runner::notify(const char* where) { LayersTraceProto entry = traceLayers(where); mBuffer.emplace(std::move(entry)); } status_t SurfaceTracing::writeToFile() { std::thread thread; { std::scoped_lock lock(mTraceLock); thread = std::move(mThread); } thread.join(); return mLastErr; status_t SurfaceTracing::Runner::stop() { return writeToFile(); } bool SurfaceTracing::disable() { std::scoped_lock lock(mTraceLock); status_t SurfaceTracing::Runner::writeToFile() { ATRACE_CALL(); if (!mEnabled) { return false; } LayersTraceFileProto fileProto; std::string output; mEnabled = false; mWriteToFile = true; mCanStartTrace.notify_all(); return true; } fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); mBuffer.flush(&fileProto); mBuffer.reset(mConfig.bufferSize); bool SurfaceTracing::isEnabled() const { std::scoped_lock lock(mTraceLock); return mEnabled; if (!fileProto.SerializeToString(&output)) { ALOGE("Could not save the proto file! Permission denied"); return PERMISSION_DENIED; } void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) { std::scoped_lock lock(mTraceLock); mBufferSize = bufferSizeInByte; mBuffer.setSize(bufferSizeInByte); // -rw-r--r-- const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(), true)) { ALOGE("Could not save the proto file! There are missing fields"); return PERMISSION_DENIED; } void SurfaceTracing::setTraceFlags(uint32_t flags) { std::scoped_lock lock(mSfLock); mTraceFlags = flags; return NO_ERROR; } LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) { ATRACE_CALL(); LayersTraceProto entry; entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); entry.set_where(where); LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags)); LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags)); if (flagIsSetLocked(SurfaceTracing::TRACE_EXTRA)) { if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) { mFlinger.dumpOffscreenLayersProto(layers); } entry.mutable_layers()->Swap(&layers); if (mTraceFlags & SurfaceTracing::TRACE_HWC) { if (flagIsSet(SurfaceTracing::TRACE_HWC)) { std::string hwcDump; mFlinger.dumpHwc(hwcDump); entry.set_hwc_blob(hwcDump); } if (!flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION)) { if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) { entry.set_excludes_composition_state(true); } entry.set_missed_entries(mMissedTraceEntries); Loading @@ -202,42 +188,70 @@ LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { return entry; } void SurfaceTracing::writeProtoFileLocked() { ATRACE_CALL(); void SurfaceTracing::Runner::dump(std::string& result) const { base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n", mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB), float(mBuffer.size()) / float(1_MB)); } LayersTraceFileProto fileProto; std::string output; SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock) : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) { mEnabled = true; mThread = std::thread(&AsyncRunner::loop, this); } fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); mBuffer.flush(&fileProto); mBuffer.reset(mBufferSize); void SurfaceTracing::AsyncRunner::loop() { while (mEnabled) { LayersTraceProto entry; bool entryAdded = traceWhenNotified(&entry); if (entryAdded) { mBuffer.emplace(std::move(entry)); } if (mWriteToFile) { Runner::writeToFile(); mWriteToFile = false; } } } if (!fileProto.SerializeToString(&output)) { ALOGE("Could not save the proto file! Permission denied"); mLastErr = PERMISSION_DENIED; bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) { std::unique_lock<std::mutex> lock(mSfLock); mCanStartTrace.wait(lock); if (!mAddEntry) { return false; } *outProto = traceLayers(mWhere); mAddEntry = false; mMissedTraceEntries = 0; return true; } // -rw-r--r-- const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; if (!android::base::WriteStringToFile(output, kDefaultFileName, mode, getuid(), getgid(), true)) { ALOGE("Could not save the proto file! There are missing fields"); mLastErr = PERMISSION_DENIED; void SurfaceTracing::AsyncRunner::notify(const char* where) { std::scoped_lock lock(mSfLock); notifyLocked(where); } void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) { mWhere = where; if (mAddEntry) { mMissedTraceEntries++; } mAddEntry = true; mCanStartTrace.notify_one(); } mLastErr = NO_ERROR; status_t SurfaceTracing::AsyncRunner::writeToFile() { mWriteToFile = true; mCanStartTrace.notify_one(); return STATUS_OK; } void SurfaceTracing::dump(std::string& result) const { std::scoped_lock lock(mTraceLock); base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n", mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB), float(mBuffer.size()) / float(1_MB)); status_t SurfaceTracing::AsyncRunner::stop() { mEnabled = false; mCanStartTrace.notify_one(); mThread.join(); return Runner::writeToFile(); } } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion" services/surfaceflinger/SurfaceTracing.h +84 −38 Original line number Diff line number Diff line Loading @@ -32,25 +32,31 @@ using namespace android::surfaceflinger; namespace android { class SurfaceFlinger; constexpr auto operator""_MB(unsigned long long const num) { return num * 1024 * 1024; } /* * SurfaceTracing records layer states during surface flinging. * SurfaceTracing records layer states during surface flinging. Manages tracing state and * configuration. */ class SurfaceTracing { public: explicit SurfaceTracing(SurfaceFlinger& flinger); SurfaceTracing(SurfaceFlinger& flinger); bool enable(); bool disable(); status_t writeToFile(); bool isEnabled() const; /* * Adds a trace entry, must be called from the drawing thread or while holding the * SurfaceFlinger tracing lock. */ void notify(const char* where); void notifyLocked(const char* where) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */; /* * Adds a trace entry, called while holding the SurfaceFlinger tracing lock. */ void notifyLocked(const char* where) /* REQUIRES(mSfLock) */; void setBufferSize(size_t bufferSizeInByte); void writeToFileAsync(); void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; } void dump(std::string& result) const; enum : uint32_t { Loading @@ -59,18 +65,34 @@ public: TRACE_COMPOSITION = 1 << 2, TRACE_EXTRA = 1 << 3, TRACE_HWC = 1 << 4, TRACE_ALL = 0xffffffff // Add non-geometry composition changes to the trace. TRACE_BUFFERS = 1 << 5, // Add entries from the drawing thread post composition. TRACE_SYNC = 1 << 6, TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA, }; void setTraceFlags(uint32_t flags); bool flagIsSetLocked(uint32_t flags) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */ { return (mTraceFlags & flags) == flags; } void setTraceFlags(uint32_t flags) { mConfig.flags = flags; } bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } private: static constexpr auto kDefaultBufferCapInByte = 5_MB; static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb"; class Runner; static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB; static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb"; class LayersTraceBuffer { // ring buffer SurfaceFlinger& mFlinger; mutable std::mutex mTraceLock; bool mEnabled = false; std::unique_ptr<Runner> runner; struct Config { uint32_t flags = TRACE_CRITICAL | TRACE_INPUT; size_t bufferSize = DEFAULT_BUFFER_SIZE; } mConfig; /* * ring buffer. */ class LayersTraceBuffer { public: size_t size() const { return mSizeInBytes; } size_t used() const { return mUsedInBytes; } Loading @@ -83,35 +105,59 @@ private: private: size_t mUsedInBytes = 0U; size_t mSizeInBytes = 0U; size_t mSizeInBytes = DEFAULT_BUFFER_SIZE; std::queue<LayersTraceProto> mStorage; }; void mainLoop(); bool addFirstEntry(); LayersTraceProto traceWhenNotified(); LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock); // Returns true if trace is enabled. bool addTraceToBuffer(LayersTraceProto& entry); void writeProtoFileLocked() REQUIRES(mTraceLock); /* * Implements a synchronous way of adding trace entries. This must be called * from the drawing thread. */ class Runner { public: Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config); virtual ~Runner() = default; virtual status_t stop(); virtual status_t writeToFile(); virtual void notify(const char* where); /* Cannot be called with a synchronous runner. */ virtual void notifyLocked(const char* /* where */) {} void dump(std::string& result) const; protected: bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } SurfaceFlinger& mFlinger; status_t mLastErr = NO_ERROR; std::thread mThread; std::condition_variable mCanStartTrace; SurfaceTracing::Config mConfig; SurfaceTracing::LayersTraceBuffer mBuffer; uint32_t mMissedTraceEntries = 0; LayersTraceProto traceLayers(const char* where); }; std::mutex& mSfLock; uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT; const char* mWhere GUARDED_BY(mSfLock) = ""; uint32_t mMissedTraceEntries GUARDED_BY(mSfLock) = 0; bool mTracingInProgress GUARDED_BY(mSfLock) = false; /* * Implements asynchronous way to add trace entries called from a separate thread while holding * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not * scheduled in time. */ class AsyncRunner : public Runner { public: AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock); virtual ~AsyncRunner() = default; status_t stop() override; status_t writeToFile() override; void notify(const char* where) override; void notifyLocked(const char* where); mutable std::mutex mTraceLock; LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock); size_t mBufferSize GUARDED_BY(mTraceLock) = kDefaultBufferCapInByte; bool mEnabled GUARDED_BY(mTraceLock) = false; bool mWriteToFile GUARDED_BY(mTraceLock) = false; private: std::mutex& mSfLock; std::condition_variable mCanStartTrace; std::thread mThread; const char* mWhere = ""; bool mWriteToFile = false; bool mEnabled = false; bool mAddEntry = false; void loop(); bool traceWhenNotified(LayersTraceProto* outProto); }; }; } // namespace android services/surfaceflinger/layerproto/layerstrace.proto +2 −2 Original line number Diff line number Diff line Loading @@ -42,7 +42,7 @@ message LayersTraceFileProto { /* one window manager trace entry. */ message LayersTraceProto { /* required: elapsed realtime in nanos since boot of when this entry was logged */ optional fixed64 elapsed_realtime_nanos = 1; optional sfixed64 elapsed_realtime_nanos = 1; /* where the trace originated */ optional string where = 2; Loading @@ -56,5 +56,5 @@ message LayersTraceProto { optional bool excludes_composition_state = 5; /* Number of missed entries since the last entry was recorded. */ optional int32 missed_entries = 6; optional uint32 missed_entries = 6; } Loading
services/surfaceflinger/SurfaceFlinger.cpp +22 −17 Original line number Diff line number Diff line Loading @@ -1850,16 +1850,18 @@ void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncT bool refreshNeeded; { ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled); mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) || mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) || mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS); const bool tracePreComposition = mTracingEnabled && !mTracePostComposition; ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition); mFrameTimeline->setSfWakeUp(vsyncId, frameStart); refreshNeeded = handleMessageTransaction(); refreshNeeded |= handleMessageInvalidate(); if (mTracingEnabled) { mAddCompositionStateToTrace = mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION); if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) { if (tracePreComposition) { if (mVisibleRegionsDirty) { mTracing.notifyLocked("visibleRegionsDirty"); } } Loading Loading @@ -2009,12 +2011,15 @@ void SurfaceFlinger::onMessageRefresh() { modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition); mLayersWithQueuedFrames.clear(); if (mTracingEnabled && mTracePostComposition) { // This may block if SurfaceTracing is running in sync mode. if (mVisibleRegionsDirty) { mVisibleRegionsDirty = false; if (mTracingEnabled && mAddCompositionStateToTrace) { mTracing.notify("visibleRegionsDirty"); } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) { mTracing.notify("bufferLatched"); } } mVisibleRegionsDirty = false; if (mCompositionEngine->needsAnotherUpdate()) { signalLayerUpdate(); Loading Loading @@ -4279,7 +4284,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) { if (asProto && mTracing.isEnabled()) { mTracing.writeToFileAsync(); mTracing.writeToFile(); } return doDump(fd, DumpArgs(), asProto); Loading Loading @@ -5103,19 +5108,19 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } case 1025: { // Set layer tracing n = data.readInt32(); bool tracingEnabledChanged; if (n) { ALOGD("LayerTracing enabled"); mTracingEnabledChanged = mTracing.enable(); reply->writeInt32(NO_ERROR); tracingEnabledChanged = mTracing.enable(); if (tracingEnabledChanged) { schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait(); } } else { ALOGD("LayerTracing disabled"); mTracingEnabledChanged = mTracing.disable(); if (mTracingEnabledChanged) { reply->writeInt32(mTracing.writeToFile()); } else { reply->writeInt32(NO_ERROR); } tracingEnabledChanged = mTracing.disable(); } mTracingEnabledChanged = tracingEnabledChanged; reply->writeInt32(NO_ERROR); return NO_ERROR; } case 1026: { // Get layer tracing status Loading
services/surfaceflinger/SurfaceFlinger.h +1 −1 Original line number Diff line number Diff line Loading @@ -1134,7 +1134,7 @@ private: SurfaceTracing mTracing{*this}; std::mutex mTracingLock; bool mTracingEnabled = false; bool mAddCompositionStateToTrace = false; bool mTracePostComposition = false; std::atomic<bool> mTracingEnabledChanged = false; const std::shared_ptr<TimeStats> mTimeStats; Loading
services/surfaceflinger/SurfaceTracing.cpp +130 −116 Original line number Diff line number Diff line Loading @@ -14,9 +14,6 @@ * limitations under the License. */ // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" #undef LOG_TAG #define LOG_TAG "SurfaceTracing" #define ATRACE_TAG ATRACE_TAG_GRAPHICS Loading @@ -32,65 +29,65 @@ namespace android { SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger), mSfLock(flinger.mTracingLock) {} SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {} void SurfaceTracing::mainLoop() { bool enabled = addFirstEntry(); while (enabled) { LayersTraceProto entry = traceWhenNotified(); enabled = addTraceToBuffer(entry); bool SurfaceTracing::enable() { std::scoped_lock lock(mTraceLock); if (mEnabled) { return false; } if (flagIsSet(TRACE_SYNC)) { runner = std::make_unique<SurfaceTracing::Runner>(mFlinger, mConfig); } else { runner = std::make_unique<SurfaceTracing::AsyncRunner>(mFlinger, mConfig, mFlinger.mTracingLock); } mEnabled = true; return true; } bool SurfaceTracing::addFirstEntry() { LayersTraceProto entry; { std::scoped_lock lock(mSfLock); entry = traceLayersLocked("tracing.enable"); bool SurfaceTracing::disable() { std::scoped_lock lock(mTraceLock); if (!mEnabled) { return false; } return addTraceToBuffer(entry); mEnabled = false; runner->stop(); return true; } LayersTraceProto SurfaceTracing::traceWhenNotified() { std::unique_lock<std::mutex> lock(mSfLock); mCanStartTrace.wait(lock); android::base::ScopedLockAssertion assumeLock(mSfLock); LayersTraceProto entry = traceLayersLocked(mWhere); mTracingInProgress = false; mMissedTraceEntries = 0; lock.unlock(); return entry; bool SurfaceTracing::isEnabled() const { std::scoped_lock lock(mTraceLock); return mEnabled; } bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) { status_t SurfaceTracing::writeToFile() { std::scoped_lock lock(mTraceLock); mBuffer.emplace(std::move(entry)); if (mWriteToFile) { writeProtoFileLocked(); mWriteToFile = false; if (!mEnabled) { return STATUS_OK; } return mEnabled; return runner->writeToFile(); } void SurfaceTracing::notify(const char* where) { std::scoped_lock lock(mSfLock); notifyLocked(where); if (mEnabled) { runner->notify(where); } } void SurfaceTracing::notifyLocked(const char* where) { mWhere = where; if (mTracingInProgress) { mMissedTraceEntries++; if (mEnabled) { runner->notifyLocked(where); } mTracingInProgress = true; mCanStartTrace.notify_one(); } void SurfaceTracing::writeToFileAsync() { void SurfaceTracing::dump(std::string& result) const { std::scoped_lock lock(mTraceLock); mWriteToFile = true; mCanStartTrace.notify_one(); base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); if (mEnabled) { runner->dump(result); } } void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) { Loading @@ -101,12 +98,12 @@ void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) { } void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) { auto protoSize = proto.ByteSize(); size_t protoSize = static_cast<size_t>(proto.ByteSize()); while (mUsedInBytes + protoSize > mSizeInBytes) { if (mStorage.empty()) { return; } mUsedInBytes -= mStorage.front().ByteSize(); mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize()); mStorage.pop(); } mUsedInBytes += protoSize; Loading @@ -115,7 +112,7 @@ void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) { } void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) { fileProto->mutable_entry()->Reserve(mStorage.size()); fileProto->mutable_entry()->Reserve(static_cast<int>(mStorage.size())); while (!mStorage.empty()) { auto entry = fileProto->add_entry(); Loading @@ -124,77 +121,66 @@ void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) { } } bool SurfaceTracing::enable() { std::scoped_lock lock(mTraceLock); if (mEnabled) { return false; SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config) : mFlinger(flinger), mConfig(config) { mBuffer.setSize(mConfig.bufferSize); } mBuffer.reset(mBufferSize); mEnabled = true; mThread = std::thread(&SurfaceTracing::mainLoop, this); return true; void SurfaceTracing::Runner::notify(const char* where) { LayersTraceProto entry = traceLayers(where); mBuffer.emplace(std::move(entry)); } status_t SurfaceTracing::writeToFile() { std::thread thread; { std::scoped_lock lock(mTraceLock); thread = std::move(mThread); } thread.join(); return mLastErr; status_t SurfaceTracing::Runner::stop() { return writeToFile(); } bool SurfaceTracing::disable() { std::scoped_lock lock(mTraceLock); status_t SurfaceTracing::Runner::writeToFile() { ATRACE_CALL(); if (!mEnabled) { return false; } LayersTraceFileProto fileProto; std::string output; mEnabled = false; mWriteToFile = true; mCanStartTrace.notify_all(); return true; } fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); mBuffer.flush(&fileProto); mBuffer.reset(mConfig.bufferSize); bool SurfaceTracing::isEnabled() const { std::scoped_lock lock(mTraceLock); return mEnabled; if (!fileProto.SerializeToString(&output)) { ALOGE("Could not save the proto file! Permission denied"); return PERMISSION_DENIED; } void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) { std::scoped_lock lock(mTraceLock); mBufferSize = bufferSizeInByte; mBuffer.setSize(bufferSizeInByte); // -rw-r--r-- const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(), true)) { ALOGE("Could not save the proto file! There are missing fields"); return PERMISSION_DENIED; } void SurfaceTracing::setTraceFlags(uint32_t flags) { std::scoped_lock lock(mSfLock); mTraceFlags = flags; return NO_ERROR; } LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) { ATRACE_CALL(); LayersTraceProto entry; entry.set_elapsed_realtime_nanos(elapsedRealtimeNano()); entry.set_where(where); LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags)); LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags)); if (flagIsSetLocked(SurfaceTracing::TRACE_EXTRA)) { if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) { mFlinger.dumpOffscreenLayersProto(layers); } entry.mutable_layers()->Swap(&layers); if (mTraceFlags & SurfaceTracing::TRACE_HWC) { if (flagIsSet(SurfaceTracing::TRACE_HWC)) { std::string hwcDump; mFlinger.dumpHwc(hwcDump); entry.set_hwc_blob(hwcDump); } if (!flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION)) { if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) { entry.set_excludes_composition_state(true); } entry.set_missed_entries(mMissedTraceEntries); Loading @@ -202,42 +188,70 @@ LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) { return entry; } void SurfaceTracing::writeProtoFileLocked() { ATRACE_CALL(); void SurfaceTracing::Runner::dump(std::string& result) const { base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n", mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB), float(mBuffer.size()) / float(1_MB)); } LayersTraceFileProto fileProto; std::string output; SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock) : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) { mEnabled = true; mThread = std::thread(&AsyncRunner::loop, this); } fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 | LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L); mBuffer.flush(&fileProto); mBuffer.reset(mBufferSize); void SurfaceTracing::AsyncRunner::loop() { while (mEnabled) { LayersTraceProto entry; bool entryAdded = traceWhenNotified(&entry); if (entryAdded) { mBuffer.emplace(std::move(entry)); } if (mWriteToFile) { Runner::writeToFile(); mWriteToFile = false; } } } if (!fileProto.SerializeToString(&output)) { ALOGE("Could not save the proto file! Permission denied"); mLastErr = PERMISSION_DENIED; bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) { std::unique_lock<std::mutex> lock(mSfLock); mCanStartTrace.wait(lock); if (!mAddEntry) { return false; } *outProto = traceLayers(mWhere); mAddEntry = false; mMissedTraceEntries = 0; return true; } // -rw-r--r-- const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; if (!android::base::WriteStringToFile(output, kDefaultFileName, mode, getuid(), getgid(), true)) { ALOGE("Could not save the proto file! There are missing fields"); mLastErr = PERMISSION_DENIED; void SurfaceTracing::AsyncRunner::notify(const char* where) { std::scoped_lock lock(mSfLock); notifyLocked(where); } void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) { mWhere = where; if (mAddEntry) { mMissedTraceEntries++; } mAddEntry = true; mCanStartTrace.notify_one(); } mLastErr = NO_ERROR; status_t SurfaceTracing::AsyncRunner::writeToFile() { mWriteToFile = true; mCanStartTrace.notify_one(); return STATUS_OK; } void SurfaceTracing::dump(std::string& result) const { std::scoped_lock lock(mTraceLock); base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled"); base::StringAppendF(&result, " number of entries: %zu (%.2fMB / %.2fMB)\n", mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB), float(mBuffer.size()) / float(1_MB)); status_t SurfaceTracing::AsyncRunner::stop() { mEnabled = false; mCanStartTrace.notify_one(); mThread.join(); return Runner::writeToFile(); } } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues #pragma clang diagnostic pop // ignored "-Wconversion"
services/surfaceflinger/SurfaceTracing.h +84 −38 Original line number Diff line number Diff line Loading @@ -32,25 +32,31 @@ using namespace android::surfaceflinger; namespace android { class SurfaceFlinger; constexpr auto operator""_MB(unsigned long long const num) { return num * 1024 * 1024; } /* * SurfaceTracing records layer states during surface flinging. * SurfaceTracing records layer states during surface flinging. Manages tracing state and * configuration. */ class SurfaceTracing { public: explicit SurfaceTracing(SurfaceFlinger& flinger); SurfaceTracing(SurfaceFlinger& flinger); bool enable(); bool disable(); status_t writeToFile(); bool isEnabled() const; /* * Adds a trace entry, must be called from the drawing thread or while holding the * SurfaceFlinger tracing lock. */ void notify(const char* where); void notifyLocked(const char* where) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */; /* * Adds a trace entry, called while holding the SurfaceFlinger tracing lock. */ void notifyLocked(const char* where) /* REQUIRES(mSfLock) */; void setBufferSize(size_t bufferSizeInByte); void writeToFileAsync(); void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; } void dump(std::string& result) const; enum : uint32_t { Loading @@ -59,18 +65,34 @@ public: TRACE_COMPOSITION = 1 << 2, TRACE_EXTRA = 1 << 3, TRACE_HWC = 1 << 4, TRACE_ALL = 0xffffffff // Add non-geometry composition changes to the trace. TRACE_BUFFERS = 1 << 5, // Add entries from the drawing thread post composition. TRACE_SYNC = 1 << 6, TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA, }; void setTraceFlags(uint32_t flags); bool flagIsSetLocked(uint32_t flags) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */ { return (mTraceFlags & flags) == flags; } void setTraceFlags(uint32_t flags) { mConfig.flags = flags; } bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } private: static constexpr auto kDefaultBufferCapInByte = 5_MB; static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb"; class Runner; static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB; static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb"; class LayersTraceBuffer { // ring buffer SurfaceFlinger& mFlinger; mutable std::mutex mTraceLock; bool mEnabled = false; std::unique_ptr<Runner> runner; struct Config { uint32_t flags = TRACE_CRITICAL | TRACE_INPUT; size_t bufferSize = DEFAULT_BUFFER_SIZE; } mConfig; /* * ring buffer. */ class LayersTraceBuffer { public: size_t size() const { return mSizeInBytes; } size_t used() const { return mUsedInBytes; } Loading @@ -83,35 +105,59 @@ private: private: size_t mUsedInBytes = 0U; size_t mSizeInBytes = 0U; size_t mSizeInBytes = DEFAULT_BUFFER_SIZE; std::queue<LayersTraceProto> mStorage; }; void mainLoop(); bool addFirstEntry(); LayersTraceProto traceWhenNotified(); LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock); // Returns true if trace is enabled. bool addTraceToBuffer(LayersTraceProto& entry); void writeProtoFileLocked() REQUIRES(mTraceLock); /* * Implements a synchronous way of adding trace entries. This must be called * from the drawing thread. */ class Runner { public: Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config); virtual ~Runner() = default; virtual status_t stop(); virtual status_t writeToFile(); virtual void notify(const char* where); /* Cannot be called with a synchronous runner. */ virtual void notifyLocked(const char* /* where */) {} void dump(std::string& result) const; protected: bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; } SurfaceFlinger& mFlinger; status_t mLastErr = NO_ERROR; std::thread mThread; std::condition_variable mCanStartTrace; SurfaceTracing::Config mConfig; SurfaceTracing::LayersTraceBuffer mBuffer; uint32_t mMissedTraceEntries = 0; LayersTraceProto traceLayers(const char* where); }; std::mutex& mSfLock; uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT; const char* mWhere GUARDED_BY(mSfLock) = ""; uint32_t mMissedTraceEntries GUARDED_BY(mSfLock) = 0; bool mTracingInProgress GUARDED_BY(mSfLock) = false; /* * Implements asynchronous way to add trace entries called from a separate thread while holding * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not * scheduled in time. */ class AsyncRunner : public Runner { public: AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock); virtual ~AsyncRunner() = default; status_t stop() override; status_t writeToFile() override; void notify(const char* where) override; void notifyLocked(const char* where); mutable std::mutex mTraceLock; LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock); size_t mBufferSize GUARDED_BY(mTraceLock) = kDefaultBufferCapInByte; bool mEnabled GUARDED_BY(mTraceLock) = false; bool mWriteToFile GUARDED_BY(mTraceLock) = false; private: std::mutex& mSfLock; std::condition_variable mCanStartTrace; std::thread mThread; const char* mWhere = ""; bool mWriteToFile = false; bool mEnabled = false; bool mAddEntry = false; void loop(); bool traceWhenNotified(LayersTraceProto* outProto); }; }; } // namespace android
services/surfaceflinger/layerproto/layerstrace.proto +2 −2 Original line number Diff line number Diff line Loading @@ -42,7 +42,7 @@ message LayersTraceFileProto { /* one window manager trace entry. */ message LayersTraceProto { /* required: elapsed realtime in nanos since boot of when this entry was logged */ optional fixed64 elapsed_realtime_nanos = 1; optional sfixed64 elapsed_realtime_nanos = 1; /* where the trace originated */ optional string where = 2; Loading @@ -56,5 +56,5 @@ message LayersTraceProto { optional bool excludes_composition_state = 5; /* Number of missed entries since the last entry was recorded. */ optional int32 missed_entries = 6; optional uint32 missed_entries = 6; }