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/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