Add support for long running traces This CL adds the ability to pass a file descriptor to the service when enabling tracing and periodically draining the trace buffers into that file directly from the service. This CL does not change the default behavior (which is: stream the trace over IPC) but allows to change it when setting |write_into_file|==true into the trace config. More in details this CL: - Adds new fields to the trace config to support passing the FD, as well as tuning the write period and max file size. - Adds an explicit OnTracingStop() notification to the Consumer, as it can no longer rely on OnTraceData(has_more==false) to determine when tracing ended. - Removes the OptimizeFor argument of TraceConfig, which ended up being never-used. - Adds a SIGINT signal handler to the perfetto cmdline client, allowing to gracefully stop the trace and get back the results when hitting CTRL-c once. - Stops using a temporary file when NOT using --dropbox, as the trace file will be valid even if not finalized. - Add large traces support to trace_to_text by tokenizing the packets before passing them to the protobuf decoder (which would accept at most a 64M protobuf) Matching SELinux CL: aosp/648831 Test: perfetto_unittests --gtest_filter=TracingIntegrationTest.* Bug: 73625179 Change-Id: I28043bdbef6cac730f1797b6bc5b72ecf0acac79
diff --git a/tools/trace_to_text/main.cc b/tools/trace_to_text/main.cc index 5e05b8f..e3c01fe 100644 --- a/tools/trace_to_text/main.cc +++ b/tools/trace_to_text/main.cc
@@ -2195,17 +2195,43 @@ int TraceToSystrace(std::istream* input, std::ostream* output) { std::multimap<uint64_t, std::string> sorted; + size_t bytes_processed = 0; + // The trace stream can be very large. We cannot just pass it in one go to + // libprotobuf as that will refuse to parse messages > 64MB. However we know + // that a trace is merely a sequence of TracePackets. Here we just manually + // tokenize the repeated TracePacket messages and parse them individually + // using libprotobuf. + for (;;) { + fprintf(stderr, "Processing trace: %8zu KB\r", bytes_processed / 1024); + fflush(stderr); + // A TracePacket consists in one byte stating its field id and type ... + char preamble; + input->get(preamble); + if (!input->good()) + break; + bytes_processed++; + PERFETTO_DCHECK(preamble == 0x0a); // Field ID:1, type:length delimited. - std::string raw; - std::istreambuf_iterator<char> begin(*input), end; - raw.assign(begin, end); - Trace trace; - if (!trace.ParseFromString(raw)) { - PERFETTO_ELOG("Could not parse input."); - return 1; - } + // ... a varint stating its size ... + uint32_t field_size = 0; + uint32_t shift = 0; + for (;;) { + char c = 0; + input->get(c); + field_size |= static_cast<uint32_t>(c & 0x7f) << shift; + shift += 7; + bytes_processed++; + if (!(c & 0x80)) + break; + } - for (const TracePacket& packet : trace.packet()) { + // ... and the actual TracePacket itself. + std::unique_ptr<char[]> buf(new char[field_size]); + input->read(buf.get(), field_size); + bytes_processed += field_size; + + protos::TracePacket packet; + PERFETTO_CHECK(packet.ParseFromArray(buf.get(), field_size)); if (!packet.has_ftrace_events()) continue; @@ -2767,8 +2793,17 @@ *output << kTraceHeader; *output << kFtraceHeader; - for (auto it = sorted.begin(); it != sorted.end(); it++) + fprintf(stderr, "\n"); + size_t total_events = sorted.size(); + size_t written_events = 0; + for (auto it = sorted.begin(); it != sorted.end(); it++) { *output << it->second; + if (written_events++ % 100 == 0) { + fprintf(stderr, "Writing trace: %.2f %%\r", + written_events * 100.0 / total_events); + fflush(stderr); + } + } *output << kTraceFooter;