Revert^2 Integrate layer tracing with perfetto
Define the perfetto custom data source LayerDataSource.
LayerDataSource is registered with perfetto. The data source
is used to listen to perfetto events (setup, start, stop, flush)
and to write trace packets to perfetto.
The user can configure/start/stop tracing via /system/bin/perfetto.
Tracing can operate in the following modes.
ACTIVE mode:
A layers snapshot is taken and written to perfetto for each vsyncid commit.
GENERATED mode:
Listens to the perfetto 'flush' event (e.g. when a bugreport is taken).
When a 'flush' event is received, the ring buffer of transactions (hold by TransactionTracing)
is processed by LayerTraceGenerator, a sequence of layers snapshots is generated
and written to perfetto.
DUMP mode:
When the 'start' event is received a single layers snapshot is taken
and written to perfetto.
Bug: b/284424784
Test: atest libsurfaceflinger_unittest && atest transactiontrace_testsuite
Change-Id: Ic1b10a040ec4533f0b56a4c8087c5a2898e3e34d
diff --git a/services/surfaceflinger/Tracing/LayerDataSource.cpp b/services/surfaceflinger/Tracing/LayerDataSource.cpp
new file mode 100644
index 0000000..474fef8
--- /dev/null
+++ b/services/surfaceflinger/Tracing/LayerDataSource.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerTracing"
+
+#include "LayerDataSource.h"
+
+#include <log/log.h>
+#include <perfetto/config/android/surfaceflinger_layers_config.pbzero.h>
+
+namespace android {
+
+void LayerDataSource::Initialize(LayerTracing& layerTracing) {
+ mLayerTracing.store(&layerTracing);
+
+ auto args = perfetto::TracingInitArgs{};
+ args.backends = perfetto::kSystemBackend;
+ // We are tracing ~50kb/entry and the default shmem buffer size (256kb) could be overrun.
+ // A shmem buffer overrun typically just stalls layer tracing, however when the stall
+ // lasts for too long perfetto assumes there is a deadlock and aborts surfaceflinger.
+ args.shmem_size_hint_kb = 1024;
+ perfetto::Tracing::Initialize(args);
+
+ perfetto::DataSourceDescriptor descriptor;
+ descriptor.set_name(android::LayerDataSource::kName);
+ LayerDataSource::Register(descriptor);
+}
+
+void LayerDataSource::UnregisterLayerTracing() {
+ mLayerTracing.store(nullptr);
+}
+
+void LayerDataSource::OnSetup(const LayerDataSource::SetupArgs& args) {
+ const auto configRaw = args.config->surfaceflinger_layers_config_raw();
+ const auto config = perfetto::protos::pbzero::SurfaceFlingerLayersConfig::Decoder{configRaw};
+
+ if (config.has_mode() && config.mode() != LayerTracing::Mode::MODE_UNSPECIFIED) {
+ mMode = static_cast<LayerTracing::Mode>(config.mode());
+ } else {
+ mMode = LayerTracing::Mode::MODE_GENERATED;
+ ALOGV("Received config with unspecified 'mode'. Using 'GENERATED' as default");
+ }
+
+ mFlags = 0;
+ for (auto it = config.trace_flags(); it; ++it) {
+ mFlags |= static_cast<uint32_t>(*it);
+ }
+}
+
+void LayerDataSource::OnStart(const LayerDataSource::StartArgs&) {
+ ALOGV("Received OnStart event (mode = 0x%02x, flags = 0x%02x)", mMode, mFlags);
+ if (auto* p = mLayerTracing.load()) {
+ p->onStart(mMode, mFlags);
+ }
+}
+
+void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs&) {
+ ALOGV("Received OnFlush event (mode = 0x%02x, flags = 0x%02x)", mMode, mFlags);
+ if (auto* p = mLayerTracing.load()) {
+ p->onFlush(mMode, mFlags);
+ }
+}
+
+void LayerDataSource::OnStop(const LayerDataSource::StopArgs&) {
+ ALOGV("Received OnStop event (mode = 0x%02x, flags = 0x%02x)", mMode, mFlags);
+ if (auto* p = mLayerTracing.load()) {
+ p->onStop(mMode);
+ }
+}
+
+LayerTracing::Mode LayerDataSource::GetMode() const {
+ return mMode;
+}
+
+std::atomic<LayerTracing*> LayerDataSource::mLayerTracing = nullptr;
+
+} // namespace android
+
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::LayerDataSource);
diff --git a/services/surfaceflinger/Tracing/LayerDataSource.h b/services/surfaceflinger/Tracing/LayerDataSource.h
new file mode 100644
index 0000000..7944092
--- /dev/null
+++ b/services/surfaceflinger/Tracing/LayerDataSource.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2023 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 "LayerTracing.h"
+
+#include <perfetto/tracing.h>
+
+#include <atomic>
+
+namespace android {
+
+/*
+ * Thread local storage used for fast (lock free) read of data source's properties.
+ *
+ */
+struct LayerDataSourceTlsState {
+ template <typename TraceContext>
+ explicit LayerDataSourceTlsState(const TraceContext& trace_context) {
+ auto dataSource = trace_context.GetDataSourceLocked();
+ mMode = dataSource.valid()
+ ? dataSource->GetMode()
+ : perfetto::protos::pbzero::SurfaceFlingerLayersConfig::Mode::MODE_GENERATED;
+ }
+
+ LayerTracing::Mode mMode;
+};
+
+struct LayerDataSourceTraits : public perfetto::DefaultDataSourceTraits {
+ using TlsStateType = LayerDataSourceTlsState;
+};
+
+/*
+ * Defines the Perfetto custom data source 'android.surfaceflinger.layers'.
+ *
+ * Registers the data source with Perfetto, listens to Perfetto events (setup/start/flush/stop)
+ * and writes trace packets to Perfetto.
+ *
+ */
+class LayerDataSource : public perfetto::DataSource<LayerDataSource, LayerDataSourceTraits> {
+public:
+ static void Initialize(LayerTracing&);
+ static void UnregisterLayerTracing();
+ void OnSetup(const SetupArgs&) override;
+ void OnStart(const StartArgs&) override;
+ void OnFlush(const FlushArgs&) override;
+ void OnStop(const StopArgs&) override;
+ LayerTracing::Mode GetMode() const;
+
+ static constexpr auto* kName = "android.surfaceflinger.layers";
+ static constexpr perfetto::BufferExhaustedPolicy kBufferExhaustedPolicy =
+ perfetto::BufferExhaustedPolicy::kStall;
+ static constexpr bool kRequiresCallbacksUnderLock = false;
+
+private:
+ static std::atomic<LayerTracing*> mLayerTracing;
+ LayerTracing::Mode mMode;
+ std::uint32_t mFlags;
+};
+
+} // namespace android
+
+PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(android::LayerDataSource);
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index b92d50b..e55b4c2 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -18,131 +18,177 @@
#define LOG_TAG "LayerTracing"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <filesystem>
-
-#include <SurfaceFlinger.h>
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-#include <utils/SystemClock.h>
-#include <utils/Trace.h>
-
#include "LayerTracing.h"
-#include "TransactionRingBuffer.h"
+
+#include "LayerDataSource.h"
+#include "Tracing/tools/LayerTraceGenerator.h"
+#include "TransactionTracing.h"
+
+#include <log/log.h>
+#include <perfetto/tracing.h>
+#include <utils/Timers.h>
+#include <utils/Trace.h>
namespace android {
-LayerTracing::LayerTracing()
- : mBuffer(std::make_unique<TransactionRingBuffer<LayersTraceFileProto, LayersTraceProto>>()) {
+LayerTracing::LayerTracing() {
+ mTakeLayersSnapshotProto = [](uint32_t) { return perfetto::protos::LayersSnapshotProto{}; };
+ LayerDataSource::Initialize(*this);
}
-LayerTracing::~LayerTracing() = default;
+LayerTracing::~LayerTracing() {
+ LayerDataSource::UnregisterLayerTracing();
+}
-bool LayerTracing::enable() {
- std::scoped_lock lock(mTraceLock);
- if (mEnabled) {
- return false;
+void LayerTracing::setTakeLayersSnapshotProtoFunction(
+ const std::function<perfetto::protos::LayersSnapshotProto(uint32_t)>& callback) {
+ mTakeLayersSnapshotProto = callback;
+}
+
+void LayerTracing::setTransactionTracing(TransactionTracing& transactionTracing) {
+ mTransactionTracing = &transactionTracing;
+}
+
+void LayerTracing::setOutputStream(std::ostream& outStream) {
+ mOutStream = std::ref(outStream);
+}
+
+void LayerTracing::onStart(Mode mode, uint32_t flags) {
+ switch (mode) {
+ case Mode::MODE_ACTIVE: {
+ mActiveTracingFlags.store(flags);
+ mIsActiveTracingStarted.store(true);
+ ALOGV("Starting active tracing (waiting for initial snapshot)");
+ // It might take a while before a layers change occurs and a "spontaneous" snapshot is
+ // taken. Let's manually take a snapshot, so that the trace's first entry will contain
+ // the current layers state.
+ addProtoSnapshotToOstream(mTakeLayersSnapshotProto(flags), Mode::MODE_ACTIVE);
+ ALOGV("Started active tracing (traced initial snapshot)");
+ break;
+ }
+ case Mode::MODE_GENERATED: {
+ ALOGV("Started generated tracing (waiting for OnFlush event to generated layers)");
+ break;
+ }
+ case Mode::MODE_DUMP: {
+ ALOGV("Starting dump tracing (dumping single snapshot)");
+ auto snapshot = mTakeLayersSnapshotProto(flags);
+ addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_DUMP);
+ ALOGV("Started dump tracing (dumped single snapshot)");
+ break;
+ }
+ default: {
+ ALOGE("Started unknown tracing mode (0x%02x)", mode);
+ }
}
- mBuffer->setSize(mBufferSizeInBytes);
- mEnabled = true;
- return true;
}
-bool LayerTracing::disable(std::string filename, bool writeToFile) {
- std::scoped_lock lock(mTraceLock);
- if (!mEnabled) {
- return false;
+void LayerTracing::onFlush(Mode mode, uint32_t flags) {
+ // In "generated" mode process the buffer of transactions (owned by TransactionTracing),
+ // generate a sequence of layers snapshots and write them to perfetto.
+ if (mode != Mode::MODE_GENERATED) {
+ return;
}
- mEnabled = false;
- if (writeToFile) {
- LayersTraceFileProto fileProto = createTraceFileProto();
- mBuffer->writeToFile(fileProto, filename);
+
+ if (!mTransactionTracing) {
+ ALOGV("Skipping layers trace generation (transactions tracing disabled)");
+ return;
}
- mBuffer->reset();
- return true;
+
+ auto transactionTrace = mTransactionTracing->writeToProto();
+ LayerTraceGenerator{}.generate(transactionTrace, flags);
+ ALOGV("Flushed generated tracing");
}
-void LayerTracing::appendToStream(std::ofstream& out) {
- std::scoped_lock lock(mTraceLock);
- LayersTraceFileProto fileProto = createTraceFileProto();
- mBuffer->appendToStream(fileProto, out);
- mBuffer->reset();
-}
-
-bool LayerTracing::isEnabled() const {
- std::scoped_lock lock(mTraceLock);
- return mEnabled;
-}
-
-status_t LayerTracing::writeToFile(std::string filename) {
- std::scoped_lock lock(mTraceLock);
- if (!mEnabled) {
- return STATUS_OK;
+void LayerTracing::onStop(Mode mode) {
+ if (mode == Mode::MODE_ACTIVE) {
+ mIsActiveTracingStarted.store(false);
+ ALOGV("Stopped active tracing");
}
- LayersTraceFileProto fileProto = createTraceFileProto();
- return mBuffer->writeToFile(fileProto, filename);
}
-void LayerTracing::setTraceFlags(uint32_t flags) {
- std::scoped_lock lock(mTraceLock);
- mFlags = flags;
+void LayerTracing::addProtoSnapshotToOstream(perfetto::protos::LayersSnapshotProto&& snapshot,
+ Mode mode) {
+ ATRACE_CALL();
+ if (mOutStream) {
+ writeSnapshotToStream(std::move(snapshot));
+ } else {
+ writeSnapshotToPerfetto(snapshot, mode);
+ }
}
-void LayerTracing::setBufferSize(size_t bufferSizeInBytes) {
- std::scoped_lock lock(mTraceLock);
- mBufferSizeInBytes = bufferSizeInBytes;
+bool LayerTracing::isActiveTracingStarted() const {
+ return mIsActiveTracingStarted.load();
}
-bool LayerTracing::flagIsSet(uint32_t flags) const {
- return (mFlags & flags) == flags;
-}
-uint32_t LayerTracing::getFlags() const {
- return mFlags;
+uint32_t LayerTracing::getActiveTracingFlags() const {
+ return mActiveTracingFlags.load();
}
-LayersTraceFileProto LayerTracing::createTraceFileProto() {
- LayersTraceFileProto fileProto;
- fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
- LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
- auto timeOffsetNs = static_cast<std::uint64_t>(systemTime(SYSTEM_TIME_REALTIME) -
- systemTime(SYSTEM_TIME_MONOTONIC));
+bool LayerTracing::isActiveTracingFlagSet(Flag flag) const {
+ return (mActiveTracingFlags.load() & flag) != 0;
+}
+
+perfetto::protos::LayersTraceFileProto LayerTracing::createTraceFileProto() {
+ perfetto::protos::LayersTraceFileProto fileProto;
+ fileProto.set_magic_number(
+ static_cast<uint64_t>(perfetto::protos::LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H)
+ << 32 |
+ perfetto::protos::LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
+ auto timeOffsetNs = static_cast<uint64_t>(systemTime(SYSTEM_TIME_REALTIME) -
+ systemTime(SYSTEM_TIME_MONOTONIC));
fileProto.set_real_to_elapsed_time_offset_nanos(timeOffsetNs);
return fileProto;
}
-void LayerTracing::dump(std::string& result) const {
- std::scoped_lock lock(mTraceLock);
- base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
- mBuffer->dump(result);
+void LayerTracing::writeSnapshotToStream(perfetto::protos::LayersSnapshotProto&& snapshot) const {
+ auto fileProto = createTraceFileProto();
+ *fileProto.add_entry() = std::move(snapshot);
+ mOutStream->get() << fileProto.SerializeAsString();
}
-void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId,
- LayersProto* layers, std::string hwcDump,
- google::protobuf::RepeatedPtrField<DisplayProto>* displays) {
- std::scoped_lock lock(mTraceLock);
- if (!mEnabled) {
- return;
+void LayerTracing::writeSnapshotToPerfetto(const perfetto::protos::LayersSnapshotProto& snapshot,
+ Mode mode) {
+ const auto snapshotBytes = snapshot.SerializeAsString();
+
+ LayerDataSource::Trace([&](LayerDataSource::TraceContext context) {
+ if (mode != context.GetCustomTlsState()->mMode) {
+ return;
+ }
+ if (!checkAndUpdateLastVsyncIdWrittenToPerfetto(mode, snapshot.vsync_id())) {
+ return;
+ }
+ {
+ auto packet = context.NewTracePacket();
+ packet->set_timestamp(static_cast<uint64_t>(snapshot.elapsed_realtime_nanos()));
+ packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
+ auto* snapshotProto = packet->set_surfaceflinger_layers_snapshot();
+ snapshotProto->AppendRawProtoBytes(snapshotBytes.data(), snapshotBytes.size());
+ }
+ {
+ // TODO (b/162206162): remove empty packet when perfetto bug is fixed.
+ // It is currently needed in order not to lose the last trace entry.
+ context.NewTracePacket();
+ }
+ });
+}
+
+bool LayerTracing::checkAndUpdateLastVsyncIdWrittenToPerfetto(Mode mode, std::int64_t vsyncId) {
+ // In some situations (e.g. two bugreports taken shortly one after the other) the generated
+ // sequence of layers snapshots might overlap. Here we check the snapshot's vsyncid to make
+ // sure that in generated tracing mode a given snapshot is written only once to perfetto.
+ if (mode != Mode::MODE_GENERATED) {
+ return true;
}
- if (!visibleRegionDirty && !flagIsSet(LayerTracing::TRACE_BUFFERS)) {
- return;
+ auto lastVsyncId = mLastVsyncIdWrittenToPerfetto.load();
+ while (lastVsyncId < vsyncId) {
+ if (mLastVsyncIdWrittenToPerfetto.compare_exchange_strong(lastVsyncId, vsyncId)) {
+ return true;
+ }
}
- ATRACE_CALL();
- LayersTraceProto entry;
- entry.set_elapsed_realtime_nanos(time);
- const char* where = visibleRegionDirty ? "visibleRegionsDirty" : "bufferLatched";
- entry.set_where(where);
- entry.mutable_layers()->Swap(layers);
-
- if (flagIsSet(LayerTracing::TRACE_HWC)) {
- entry.set_hwc_blob(hwcDump);
- }
- if (!flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
- entry.set_excludes_composition_state(true);
- }
- entry.mutable_displays()->Swap(displays);
- entry.set_vsync_id(vsyncId);
- mBuffer->emplace(std::move(entry));
+ return false;
}
} // namespace android
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
index 7c0d23d..349cc40 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -16,42 +16,77 @@
#pragma once
-#include <android-base/thread_annotations.h>
#include <layerproto/LayerProtoHeader.h>
-#include <utils/Errors.h>
-#include <utils/StrongPointer.h>
-#include <utils/Timers.h>
-#include <memory>
-#include <mutex>
-
-using namespace android::surfaceflinger;
+#include <atomic>
+#include <functional>
+#include <optional>
+#include <ostream>
namespace android {
-template <typename FileProto, typename EntryProto>
-class TransactionRingBuffer;
-
-class SurfaceFlinger;
+class TransactionTracing;
/*
* LayerTracing records layer states during surface flinging. Manages tracing state and
* configuration.
+ *
+ * The traced data can then be collected with Perfetto.
+ *
+ * The Perfetto custom data source LayerDataSource is registered with perfetto. The data source
+ * is used to listen to perfetto events (setup, start, stop, flush) and to write trace packets
+ * to perfetto.
+ *
+ * The user can configure/start/stop tracing via /system/bin/perfetto.
+ *
+ * Tracing can operate in the following modes.
+ *
+ * ACTIVE mode:
+ * A layers snapshot is taken and written to perfetto for each vsyncid commit.
+ *
+ * GENERATED mode:
+ * Listens to the perfetto 'flush' event (e.g. when a bugreport is taken).
+ * When a 'flush' event is received, the ring buffer of transactions (hold by TransactionTracing)
+ * is processed by LayerTraceGenerator, a sequence of layers snapshots is generated
+ * and written to perfetto.
+ *
+ * DUMP mode:
+ * When the 'start' event is received a single layers snapshot is taken
+ * and written to perfetto.
+ *
+ *
+ * E.g. start active mode tracing:
+ *
+ adb shell -t perfetto \
+ -c - --txt \
+ -o /data/misc/perfetto-traces/trace \
+ <<EOF
+ unique_session_name: "surfaceflinger_layers_active"
+ buffers: {
+ size_kb: 63488
+ fill_policy: RING_BUFFER
+ }
+ data_sources: {
+ config {
+ name: "android.surfaceflinger.layers"
+ surfaceflinger_layers_config: {
+ mode: MODE_ACTIVE
+ trace_flags: TRACE_FLAG_INPUT
+ trace_flags: TRACE_FLAG_COMPOSITION
+ trace_flags: TRACE_FLAG_HWC
+ trace_flags: TRACE_FLAG_BUFFERS
+ trace_flags: TRACE_FLAG_VIRTUAL_DISPLAYS
+ }
+ }
+ }
+ EOF
+ *
*/
class LayerTracing {
public:
- LayerTracing();
- ~LayerTracing();
- bool enable();
- bool disable(std::string filename = FILE_NAME, bool writeToFile = true);
- void appendToStream(std::ofstream& out);
- bool isEnabled() const;
- status_t writeToFile(std::string filename = FILE_NAME);
- static LayersTraceFileProto createTraceFileProto();
- void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId, LayersProto* layers,
- std::string hwcDump, google::protobuf::RepeatedPtrField<DisplayProto>* displays);
+ using Mode = perfetto::protos::pbzero::SurfaceFlingerLayersConfig::Mode;
- enum : uint32_t {
+ enum Flag : uint32_t {
TRACE_INPUT = 1 << 1,
TRACE_COMPOSITION = 1 << 2,
TRACE_EXTRA = 1 << 3,
@@ -60,20 +95,39 @@
TRACE_VIRTUAL_DISPLAYS = 1 << 6,
TRACE_ALL = TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA,
};
- void setTraceFlags(uint32_t flags);
- bool flagIsSet(uint32_t flags) const;
- uint32_t getFlags() const;
- void setBufferSize(size_t bufferSizeInBytes);
- void dump(std::string&) const;
+
+ LayerTracing();
+ ~LayerTracing();
+ void setTakeLayersSnapshotProtoFunction(
+ const std::function<perfetto::protos::LayersSnapshotProto(uint32_t)>&);
+ void setTransactionTracing(TransactionTracing&);
+ void setOutputStream(std::ostream&);
+
+ // Start event from perfetto data source
+ void onStart(Mode mode, uint32_t flags);
+ // Flush event from perfetto data source
+ void onFlush(Mode mode, uint32_t flags);
+ // Stop event from perfetto data source
+ void onStop(Mode mode);
+
+ void addProtoSnapshotToOstream(perfetto::protos::LayersSnapshotProto&& snapshot, Mode mode);
+ bool isActiveTracingStarted() const;
+ uint32_t getActiveTracingFlags() const;
+ bool isActiveTracingFlagSet(Flag flag) const;
+ static perfetto::protos::LayersTraceFileProto createTraceFileProto();
private:
- static constexpr auto FILE_NAME = "/data/misc/wmtrace/layers_trace.winscope";
- uint32_t mFlags = TRACE_INPUT;
- mutable std::mutex mTraceLock;
- bool mEnabled GUARDED_BY(mTraceLock) = false;
- std::unique_ptr<TransactionRingBuffer<LayersTraceFileProto, LayersTraceProto>> mBuffer
- GUARDED_BY(mTraceLock);
- size_t mBufferSizeInBytes GUARDED_BY(mTraceLock) = 20 * 1024 * 1024;
+ void writeSnapshotToStream(perfetto::protos::LayersSnapshotProto&& snapshot) const;
+ void writeSnapshotToPerfetto(const perfetto::protos::LayersSnapshotProto& snapshot, Mode mode);
+ bool checkAndUpdateLastVsyncIdWrittenToPerfetto(Mode mode, std::int64_t vsyncId);
+
+ std::function<perfetto::protos::LayersSnapshotProto(uint32_t)> mTakeLayersSnapshotProto;
+ TransactionTracing* mTransactionTracing;
+
+ std::atomic<bool> mIsActiveTracingStarted{false};
+ std::atomic<uint32_t> mActiveTracingFlags{0};
+ std::atomic<std::int64_t> mLastVsyncIdWrittenToPerfetto{-1};
+ std::optional<std::reference_wrapper<std::ostream>> mOutStream;
};
} // namespace android
diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp
index b6435a8..2ff09c3 100644
--- a/services/surfaceflinger/Tracing/tools/Android.bp
+++ b/services/surfaceflinger/Tracing/tools/Android.bp
@@ -31,7 +31,6 @@
srcs: [
":libsurfaceflinger_sources",
":libsurfaceflinger_mock_sources",
- ":layertracegenerator_sources",
"main.cpp",
],
static_libs: [
@@ -41,15 +40,3 @@
"libsurfaceflinger_mocks_headers",
],
}
-
-filegroup {
- name: "layertracegenerator_sources",
- srcs: [
- "LayerTraceGenerator.cpp",
- ],
-}
-
-cc_library_headers {
- name: "layertracegenerator_headers",
- export_include_dirs: ["."],
-}
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 9471e95..62c362e 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -41,7 +41,9 @@
using namespace ftl::flag_operators;
bool LayerTraceGenerator::generate(const perfetto::protos::TransactionTraceFile& traceFile,
- const char*, bool onlyLastEntry) {
+ std::uint32_t traceFlags,
+ std::optional<std::reference_wrapper<std::ostream>> outStream,
+ bool onlyLastEntry) {
if (traceFile.entry_size() == 0) {
ALOGD("Trace file is empty");
return false;
@@ -49,6 +51,11 @@
TransactionProtoParser parser(std::make_unique<TransactionProtoParser::FlingerDataMapper>());
+ LayerTracing layerTracing;
+ if (outStream) {
+ layerTracing.setOutputStream(outStream->get());
+ }
+
// frontend
frontend::LayerLifecycleManager lifecycleManager;
frontend::LayerHierarchyBuilder hierarchyBuilder{{}};
@@ -60,18 +67,10 @@
property_get("ro.surface_flinger.supports_background_blur", value, "0");
bool supportsBlur = atoi(value);
- LayerTracing layerTracing;
- layerTracing.setTraceFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS);
- // 10MB buffer size (large enough to hold a single entry)
- layerTracing.setBufferSize(10 * 1024 * 1024);
- layerTracing.enable();
- layerTracing.writeToFile(outputLayersTracePath);
- std::ofstream out(outputLayersTracePath, std::ios::binary | std::ios::app);
-
ALOGD("Generating %d transactions...", traceFile.entry_size());
for (int i = 0; i < traceFile.entry_size(); i++) {
// parse proto
- proto::TransactionTraceEntry entry = traceFile.entry(i);
+ perfetto::protos::TransactionTraceEntry entry = traceFile.entry(i);
ALOGV(" Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64
" layers +%d -%d handles -%d transactions=%d",
i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(),
@@ -154,19 +153,26 @@
lifecycleManager.commitChanges();
- LayersProto layersProto = LayerProtoFromSnapshotGenerator(snapshotBuilder, displayInfos, {},
- layerTracing.getFlags())
- .generate(hierarchyBuilder.getHierarchy());
+ auto layersProto =
+ LayerProtoFromSnapshotGenerator(snapshotBuilder, displayInfos, {}, traceFlags)
+ .generate(hierarchyBuilder.getHierarchy());
auto displayProtos = LayerProtoHelper::writeDisplayInfoToProto(displayInfos);
if (!onlyLastEntry || (i == traceFile.entry_size() - 1)) {
- layerTracing.notify(visibleRegionsDirty, entry.elapsed_realtime_nanos(),
- entry.vsync_id(), &layersProto, {}, &displayProtos);
- layerTracing.appendToStream(out);
+ perfetto::protos::LayersSnapshotProto snapshotProto{};
+ snapshotProto.set_vsync_id(entry.vsync_id());
+ snapshotProto.set_elapsed_realtime_nanos(entry.elapsed_realtime_nanos());
+ snapshotProto.set_where(visibleRegionsDirty ? "visibleRegionsDirty" : "bufferLatched");
+ *snapshotProto.mutable_layers() = std::move(layersProto);
+ if ((traceFlags & LayerTracing::TRACE_COMPOSITION) == 0) {
+ snapshotProto.set_excludes_composition_state(true);
+ }
+ *snapshotProto.mutable_displays() = std::move(displayProtos);
+
+ layerTracing.addProtoSnapshotToOstream(std::move(snapshotProto),
+ LayerTracing::Mode::MODE_GENERATED);
}
}
- layerTracing.disable("", /*writeToFile=*/false);
- out.close();
- ALOGD("End of generating trace file. File written to %s", outputLayersTracePath);
+ ALOGD("End of generating trace file");
return true;
}
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
index a1e5fc8..2bb6f51 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
@@ -18,10 +18,19 @@
#include <Tracing/TransactionTracing.h>
+#include <functional>
+#include <optional>
+#include <ostream>
+#include <string>
+
namespace android {
+
+class LayerTracing;
+
class LayerTraceGenerator {
public:
- bool generate(const perfetto::protos::TransactionTraceFile&, const char* outputLayersTracePath,
- bool onlyLastEntry);
+ bool generate(const perfetto::protos::TransactionTraceFile&, std::uint32_t traceFlags,
+ std::optional<std::reference_wrapper<std::ostream>> outStream = std::nullopt,
+ bool onlyLastEntry = false);
};
} // namespace android
diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp
index 0ff8f98..a8ac36a 100644
--- a/services/surfaceflinger/Tracing/tools/main.cpp
+++ b/services/surfaceflinger/Tracing/tools/main.cpp
@@ -21,6 +21,7 @@
#include <iostream>
#include <string>
+#include <Tracing/LayerTracing.h>
#include "LayerTraceGenerator.h"
using namespace android;
@@ -47,19 +48,22 @@
return -1;
}
- const char* outputLayersTracePath =
- (argc >= 3) ? argv[2] : "/data/misc/wmtrace/layers_trace.winscope";
+ const auto* outputLayersTracePath =
+ (argc == 3) ? argv[2] : "/data/misc/wmtrace/layers_trace.winscope";
+ auto outStream = std::ofstream{outputLayersTracePath, std::ios::binary | std::ios::app};
const bool generateLastEntryOnly =
argc >= 4 && std::string_view(argv[3]) == "--last-entry-only";
+ auto traceFlags = LayerTracing::Flag::TRACE_INPUT | LayerTracing::Flag::TRACE_BUFFERS;
+
ALOGD("Generating %s...", outputLayersTracePath);
std::cout << "Generating " << outputLayersTracePath << "\n";
- if (!LayerTraceGenerator().generate(transactionTraceFile, outputLayersTracePath,
+ if (!LayerTraceGenerator().generate(transactionTraceFile, traceFlags, outStream,
generateLastEntryOnly)) {
std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath;
return -1;
}
return 0;
-}
\ No newline at end of file
+}