[layertracegenerator] stream layer trace to file
Write the generated layer trace entry by entry
so we don't hold the entire unserialized layer trace
in memory.
Fixes: 272158947
Test: presubmit
Test: open streamed trace in winscope
Test: cat /proc/`pidof layertracegenerator`/status
old
VmHWM: 959496 kB
new
VmHWM: 21416 kB
Change-Id: I4bf0cd8fe98d1e2a44fb6b7c85c4e06e586a52ed
diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp
index 2918f7c..ecdeabe 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.cpp
+++ b/services/surfaceflinger/Tracing/LayerTracing.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "LayerTracing"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <filesystem>
+
#include <SurfaceFlinger.h>
#include <android-base/stringprintf.h>
#include <log/log.h>
@@ -44,30 +46,39 @@
return true;
}
-bool LayerTracing::disable(std::string filename) {
+bool LayerTracing::disable(std::string filename, bool writeToFile) {
std::scoped_lock lock(mTraceLock);
if (!mEnabled) {
return false;
}
mEnabled = false;
- LayersTraceFileProto fileProto = createTraceFileProto();
- mBuffer->writeToFile(fileProto, filename);
+ if (writeToFile) {
+ LayersTraceFileProto fileProto = createTraceFileProto();
+ mBuffer->writeToFile(fileProto, filename);
+ }
mBuffer->reset();
return true;
}
+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() {
+status_t LayerTracing::writeToFile(std::string filename) {
std::scoped_lock lock(mTraceLock);
if (!mEnabled) {
return STATUS_OK;
}
LayersTraceFileProto fileProto = createTraceFileProto();
- return mBuffer->writeToFile(fileProto, FILE_NAME);
+ return mBuffer->writeToFile(fileProto, filename);
}
void LayerTracing::setTraceFlags(uint32_t flags) {
diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h
index 11bb9f4..40b0fbe 100644
--- a/services/surfaceflinger/Tracing/LayerTracing.h
+++ b/services/surfaceflinger/Tracing/LayerTracing.h
@@ -43,9 +43,10 @@
LayerTracing();
~LayerTracing();
bool enable();
- bool disable(std::string filename = FILE_NAME);
+ bool disable(std::string filename = FILE_NAME, bool writeToFile = true);
+ void appendToStream(std::ofstream& out);
bool isEnabled() const;
- status_t writeToFile();
+ 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);
diff --git a/services/surfaceflinger/Tracing/RingBuffer.h b/services/surfaceflinger/Tracing/RingBuffer.h
index 7e38c55..b41c65b 100644
--- a/services/surfaceflinger/Tracing/RingBuffer.h
+++ b/services/surfaceflinger/Tracing/RingBuffer.h
@@ -24,6 +24,7 @@
#include <utils/Timers.h>
#include <utils/Trace.h>
#include <chrono>
+#include <fstream>
#include <queue>
namespace android {
@@ -73,6 +74,19 @@
return NO_ERROR;
}
+ status_t appendToStream(FileProto& fileProto, std::ofstream& out) {
+ ATRACE_CALL();
+ writeToProto(fileProto);
+ std::string output;
+ if (!fileProto.SerializeToString(&output)) {
+ ALOGE("Could not serialize proto.");
+ return UNKNOWN_ERROR;
+ }
+
+ out << output;
+ return NO_ERROR;
+ }
+
std::vector<std::string> emplace(std::string&& serializedProto) {
std::vector<std::string> replacedEntries;
size_t protoSize = static_cast<size_t>(serializedProto.size());
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 2418cf2..0ea421b 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <ios>
#include <memory>
#include <vector>
#include "FrontEnd/LayerCreationArgs.h"
@@ -62,8 +63,11 @@
LayerTracing layerTracing;
layerTracing.setTraceFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS);
- layerTracing.setBufferSize(512 * 1024 * 1024); // 512MB buffer size
+ // 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++) {
@@ -141,8 +145,10 @@
auto displayProtos = LayerProtoHelper::writeDisplayInfoToProto(displayInfos);
layerTracing.notify(visibleRegionsDirty, entry.elapsed_realtime_nanos(), entry.vsync_id(),
&layersProto, {}, &displayProtos);
+ layerTracing.appendToStream(out);
}
- layerTracing.disable(outputLayersTracePath);
+ layerTracing.disable("", /*writeToFile=*/false);
+ out.close();
ALOGD("End of generating trace file. File written to %s", outputLayersTracePath);
return true;
}
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 74541ac..82aac7e 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -21,8 +21,10 @@
#include <cstdint>
#include "Client.h"
+#include <layerproto/LayerProtoHeader.h>
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/Update.h"
+#include "Tracing/LayerTracing.h"
#include "Tracing/RingBuffer.h"
#include "Tracing/TransactionTracing.h"
@@ -305,4 +307,24 @@
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes().size(), 2);
EXPECT_EQ(proto.entry(0).transactions(0).layer_changes(1).z(), 43);
}
+
+// Verify we can write the layers traces by entry to reduce mem pressure
+// on the system when generating large traces.
+TEST(LayerTraceTest, canStreamLayersTrace) {
+ LayersTraceFileProto inProto = LayerTracing::createTraceFileProto();
+ inProto.add_entry();
+ inProto.add_entry();
+
+ std::string output;
+ inProto.SerializeToString(&output);
+ LayersTraceFileProto inProto2 = LayerTracing::createTraceFileProto();
+ inProto2.add_entry();
+ std::string output2;
+ inProto2.SerializeToString(&output2);
+
+ LayersTraceFileProto outProto;
+ outProto.ParseFromString(output + output2);
+ // magic?
+ EXPECT_EQ(outProto.entry().size(), 3);
+}
} // namespace android