trace_to_text: Refactor in preparation of userspace events json export
Extracts json export out of TraceToSystrace, so that we can add export
of userspace events in a follow-up patch.
Bug: 142222891
Change-Id: Ib75271f72a7712b00e93c2fcf76311da3f5cd070
diff --git a/Android.bp b/Android.bp
index 83e180e..80940d2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -4582,6 +4582,7 @@
srcs: [
"tools/trace_to_text/main.cc",
"tools/trace_to_text/symbolize_profile.cc",
+ "tools/trace_to_text/trace_to_json.cc",
"tools/trace_to_text/trace_to_profile.cc",
"tools/trace_to_text/trace_to_systrace.cc",
],
diff --git a/BUILD b/BUILD
index a0229d6..6267365 100644
--- a/BUILD
+++ b/BUILD
@@ -988,6 +988,8 @@
"tools/trace_to_text/main.cc",
"tools/trace_to_text/symbolize_profile.cc",
"tools/trace_to_text/symbolize_profile.h",
+ "tools/trace_to_text/trace_to_json.cc",
+ "tools/trace_to_text/trace_to_json.h",
"tools/trace_to_text/trace_to_profile.cc",
"tools/trace_to_text/trace_to_profile.h",
"tools/trace_to_text/trace_to_systrace.cc",
diff --git a/tools/trace_to_text/BUILD.gn b/tools/trace_to_text/BUILD.gn
index fb2cec7..5ddea68 100644
--- a/tools/trace_to_text/BUILD.gn
+++ b/tools/trace_to_text/BUILD.gn
@@ -42,6 +42,7 @@
]
public_deps = [
"../../gn:default_deps",
+ "../../gn:zlib",
"../../include/perfetto/base",
"../../include/perfetto/ext/base",
"../../include/perfetto/ext/traced:sys_stats_counters",
@@ -127,7 +128,6 @@
":pprofbuilder",
":symbolizer",
":utils",
- "../../gn:zlib",
]
public_deps = [
"../../gn:default_deps",
@@ -146,6 +146,8 @@
"main.cc",
"symbolize_profile.cc",
"symbolize_profile.h",
+ "trace_to_json.cc",
+ "trace_to_json.h",
"trace_to_profile.cc",
"trace_to_profile.h",
"trace_to_systrace.cc",
@@ -168,7 +170,7 @@
]
}
-# Full traget for the host. Depends on libprotobuf-full.
+# Full target for the host. Depends on libprotobuf-full.
source_set("full") {
testonly = true
deps = [
diff --git a/tools/trace_to_text/main.cc b/tools/trace_to_text/main.cc
index 52ff38e..eef61b0 100644
--- a/tools/trace_to_text/main.cc
+++ b/tools/trace_to_text/main.cc
@@ -21,6 +21,7 @@
#include "perfetto/base/logging.h"
#include "tools/trace_to_text/symbolize_profile.h"
+#include "tools/trace_to_text/trace_to_json.h"
#include "tools/trace_to_text/trace_to_profile.h"
#include "tools/trace_to_text/trace_to_systrace.h"
#include "tools/trace_to_text/trace_to_text.h"
@@ -105,15 +106,15 @@
std::string format(positional_args[0]);
if (format == "json")
- return TraceToSystrace(input_stream, output_stream, kSystraceJson,
- truncate_keep);
+ return TraceToJson(input_stream, output_stream, /*compress=*/false,
+ truncate_keep);
if (format == "systrace")
- return TraceToSystrace(input_stream, output_stream, kSystraceNormal,
+ return TraceToSystrace(input_stream, output_stream, /*compress=*/false,
truncate_keep);
if (format == "ctrace")
- return TraceToSystrace(input_stream, output_stream, kSystraceCompressed,
+ return TraceToSystrace(input_stream, output_stream, /*compress=*/true,
truncate_keep);
if (truncate_keep != Keep::kAll) {
diff --git a/tools/trace_to_text/trace_to_json.cc b/tools/trace_to_text/trace_to_json.cc
new file mode 100644
index 0000000..a7bcb6a
--- /dev/null
+++ b/tools/trace_to_text/trace_to_json.cc
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "tools/trace_to_text/trace_to_json.h"
+
+#include "perfetto/base/logging.h"
+#include "perfetto/trace_processor/trace_processor.h"
+#include "tools/trace_to_text/utils.h"
+
+namespace perfetto {
+namespace trace_to_text {
+
+namespace {
+
+const char kTraceHeader[] = R"({
+ "traceEvents": [
+)";
+
+const char kTraceFooter[] = R"(\n",
+ "controllerTraceDataKey": "systraceController"
+})";
+
+} // namespace
+
+int TraceToJson(std::istream* input,
+ std::ostream* output,
+ bool compress,
+ Keep truncate_keep) {
+ std::unique_ptr<TraceWriter> trace_writer(
+ compress ? new DeflateTraceWriter(output) : new TraceWriter(output));
+
+ trace_processor::Config config;
+ std::unique_ptr<trace_processor::TraceProcessor> tp =
+ trace_processor::TraceProcessor::CreateInstance(config);
+
+ if (!ReadTrace(tp.get(), input))
+ return 1;
+ tp->NotifyEndOfFile();
+
+ trace_writer->Write(kTraceHeader);
+
+ // TODO(eseckler): support userspace event conversion.
+ fprintf(stderr, "Converting userspace events%c", kProgressChar);
+ fflush(stderr);
+
+ trace_writer->Write("],\n");
+
+ int ret = ExtractSystrace(tp.get(), trace_writer.get(),
+ /*wrapped_in_json=*/true, truncate_keep);
+ if (ret)
+ return ret;
+
+ trace_writer->Write(kTraceFooter);
+ return 0;
+}
+
+} // namespace trace_to_text
+} // namespace perfetto
diff --git a/tools/trace_to_text/trace_to_json.h b/tools/trace_to_text/trace_to_json.h
new file mode 100644
index 0000000..03237fd
--- /dev/null
+++ b/tools/trace_to_text/trace_to_json.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#ifndef TOOLS_TRACE_TO_TEXT_TRACE_TO_JSON_H_
+#define TOOLS_TRACE_TO_TEXT_TRACE_TO_JSON_H_
+
+#include <iostream>
+
+#include "tools/trace_to_text/trace_to_systrace.h"
+
+namespace perfetto {
+namespace trace_to_text {
+
+int TraceToJson(std::istream* input,
+ std::ostream* output,
+ bool compress,
+ Keep truncate_keep);
+
+} // namespace trace_to_text
+} // namespace perfetto
+
+#endif // TOOLS_TRACE_TO_TEXT_TRACE_TO_JSON_H_
diff --git a/tools/trace_to_text/trace_to_systrace.cc b/tools/trace_to_text/trace_to_systrace.cc
index a7afb5d..3f7406b 100644
--- a/tools/trace_to_text/trace_to_systrace.cc
+++ b/tools/trace_to_text/trace_to_systrace.cc
@@ -25,41 +25,21 @@
#include <memory>
#include <utility>
-#include <zlib.h>
-
#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
-#include "perfetto/ext/base/paged_memory.h"
#include "perfetto/ext/base/string_writer.h"
#include "perfetto/ext/base/utils.h"
#include "perfetto/trace_processor/trace_processor.h"
#include "tools/trace_to_text/utils.h"
-// When running in Web Assembly, fflush() is a no-op and the stdio buffering
-// sends progress updates to JS only when a write ends with \n.
-#if PERFETTO_BUILDFLAG(PERFETTO_OS_WASM)
-#define PROGRESS_CHAR "\n"
-#else
-#define PROGRESS_CHAR "\r"
-#endif
+#define FILTER_RAW_EVENTS \
+ " where not (name like \"chrome_event.%\" or name like \"track_event.%\")"
namespace perfetto {
namespace trace_to_text {
namespace {
-const size_t kCompressionBufferSize = 500 * 1024;
-
-// Having an empty traceEvents object is necessary for trace viewer to
-// load the json properly.
-const char kTraceHeader[] = R"({
- "traceEvents": [],
-)";
-
-const char kTraceFooter[] = R"(\n",
- "controllerTraceDataKey": "systraceController"
-})";
-
const char kProcessDumpHeader[] =
""
"\"androidProcessDump\": "
@@ -127,72 +107,6 @@
}
}
-class TraceWriter {
- public:
- TraceWriter(std::ostream* output) : output_(output) {}
- virtual ~TraceWriter() = default;
-
- void Write(std::string s) { Write(s.data(), s.size()); }
-
- virtual void Write(const char* data, size_t sz) {
- output_->write(data, static_cast<std::streamsize>(sz));
- }
-
- private:
- std::ostream* output_;
-};
-
-class DeflateTraceWriter : public TraceWriter {
- public:
- DeflateTraceWriter(std::ostream* output)
- : TraceWriter(output),
- buf_(base::PagedMemory::Allocate(kCompressionBufferSize)),
- start_(static_cast<uint8_t*>(buf_.Get())),
- end_(start_ + buf_.size()) {
- CheckEq(deflateInit(&stream_, 9), Z_OK);
- stream_.next_out = start_;
- stream_.avail_out = static_cast<unsigned int>(end_ - start_);
- }
-
- ~DeflateTraceWriter() override {
- while (deflate(&stream_, Z_FINISH) != Z_STREAM_END) {
- Flush();
- }
- CheckEq(deflateEnd(&stream_), Z_OK);
- }
-
- void Write(const char* data, size_t sz) override {
- stream_.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(data));
- stream_.avail_in = static_cast<unsigned int>(sz);
- while (stream_.avail_in > 0) {
- CheckEq(deflate(&stream_, Z_NO_FLUSH), Z_OK);
- if (stream_.avail_out == 0) {
- Flush();
- }
- }
- }
-
- private:
- void Flush() {
- TraceWriter::Write(reinterpret_cast<char*>(start_),
- static_cast<size_t>(stream_.next_out - start_));
- stream_.next_out = start_;
- stream_.avail_out = static_cast<unsigned int>(end_ - start_);
- }
-
- void CheckEq(int actual_code, int expected_code) {
- if (actual_code == expected_code)
- return;
- PERFETTO_FATAL("Expected %d got %d: %s", actual_code, expected_code,
- stream_.msg);
- }
-
- z_stream stream_{};
- base::PagedMemory buf_;
- uint8_t* const start_;
- uint8_t* const end_;
-};
-
class QueryWriter {
public:
QueryWriter(trace_processor::TraceProcessor* tp, TraceWriter* trace_writer)
@@ -210,7 +124,7 @@
callback(&iterator, &line_writer);
if (global_writer_.pos() + line_writer.pos() >= global_writer_.size()) {
- fprintf(stderr, "Writing row %" PRIu32 PROGRESS_CHAR, rows);
+ fprintf(stderr, "Writing row %" PRIu32 "%c", rows, kProgressChar);
auto str = global_writer_.GetStringView();
trace_writer_->Write(str.data(), str.size());
global_writer_.reset();
@@ -245,11 +159,8 @@
int TraceToSystrace(std::istream* input,
std::ostream* output,
- SystraceKind kind,
+ bool compress,
Keep truncate_keep) {
- bool wrap_in_json = kind == kSystraceJson;
- bool compress = kind == kSystraceCompressed;
-
std::unique_ptr<TraceWriter> trace_writer(
compress ? new DeflateTraceWriter(output) : new TraceWriter(output));
@@ -260,13 +171,21 @@
if (!ReadTrace(tp.get(), input))
return 1;
tp->NotifyEndOfFile();
+
+ *output << "TRACE:\n";
+ return ExtractSystrace(tp.get(), trace_writer.get(),
+ /*wrapped_in_json=*/false, truncate_keep);
+}
+
+int ExtractSystrace(trace_processor::TraceProcessor* tp,
+ TraceWriter* trace_writer,
+ bool wrapped_in_json,
+ Keep truncate_keep) {
using Iterator = trace_processor::TraceProcessor::Iterator;
- QueryWriter q_writer(tp.get(), trace_writer.get());
- if (wrap_in_json) {
- *output << kTraceHeader;
-
- *output << kProcessDumpHeader;
+ QueryWriter q_writer(tp, trace_writer);
+ if (wrapped_in_json) {
+ trace_writer->Write(kProcessDumpHeader);
// Write out all the processes in the trace.
// TODO(lalitm): change this query to actually use ppid when it is exposed
@@ -284,7 +203,7 @@
if (!q_writer.RunQuery(kPSql, p_callback))
return 1;
- *output << kThreadHeader;
+ trace_writer->Write(kThreadHeader);
// Write out all the threads in the trace.
static const char kTSql[] =
@@ -302,18 +221,18 @@
if (!q_writer.RunQuery(kTSql, t_callback))
return 1;
- *output << "\",";
- *output << kSystemTraceEvents;
- *output << kFtraceJsonHeader;
+ trace_writer->Write("\",");
+ trace_writer->Write(kSystemTraceEvents);
+ trace_writer->Write(kFtraceJsonHeader);
} else {
- *output << "TRACE:\n";
trace_writer->Write(kFtraceHeader);
}
- fprintf(stderr, "Converting trace events" PROGRESS_CHAR);
+ fprintf(stderr, "Converting ftrace events%c", kProgressChar);
fflush(stderr);
- static const char kEstimateSql[] = "select count(1) from raw";
+ static const char kEstimateSql[] =
+ "select count(1) from raw" FILTER_RAW_EVENTS;
uint32_t raw_events = 0;
auto e_callback = [&raw_events](Iterator* it, base::StringWriter*) {
raw_events = static_cast<uint32_t>(it->Get(0).long_value);
@@ -321,9 +240,10 @@
if (!q_writer.RunQuery(kEstimateSql, e_callback))
return 1;
- auto raw_callback = [wrap_in_json](Iterator* it, base::StringWriter* writer) {
+ auto raw_callback = [wrapped_in_json](Iterator* it,
+ base::StringWriter* writer) {
const char* line = it->Get(0 /* col */).string_value;
- if (wrap_in_json) {
+ if (wrapped_in_json) {
for (uint32_t i = 0; line[i] != '\0'; i++) {
char c = line[i];
switch (c) {
@@ -365,29 +285,25 @@
// and threads.
const uint32_t max_ftrace_events = (140 * 1024 * 1024) / 130;
- char kEndTrunc[100];
- sprintf(kEndTrunc,
- "select to_ftrace(id) from raw limit %d "
- "offset %d",
- max_ftrace_events, raw_events - max_ftrace_events);
- char kStartTruncate[100];
- sprintf(kStartTruncate, "select to_ftrace(id) from raw limit %d",
- max_ftrace_events);
+ static const char kRawEventsQuery[] =
+ "select to_ftrace(id) from raw" FILTER_RAW_EVENTS;
if (truncate_keep == Keep::kEnd && raw_events > max_ftrace_events) {
- if (!q_writer.RunQuery(kEndTrunc, raw_callback))
+ char end_truncate[150];
+ sprintf(end_truncate, "%s limit %d offset %d", kRawEventsQuery,
+ max_ftrace_events, raw_events - max_ftrace_events);
+ if (!q_writer.RunQuery(end_truncate, raw_callback))
return 1;
} else if (truncate_keep == Keep::kStart) {
- if (!q_writer.RunQuery(kStartTruncate, raw_callback))
+ char start_truncate[150];
+ sprintf(start_truncate, "%s limit %d", kRawEventsQuery, max_ftrace_events);
+ if (!q_writer.RunQuery(start_truncate, raw_callback))
return 1;
} else {
- if (!q_writer.RunQuery("select to_ftrace(id) from raw", raw_callback))
+ if (!q_writer.RunQuery(kRawEventsQuery, raw_callback))
return 1;
}
- if (wrap_in_json)
- *output << kTraceFooter;
-
return 0;
}
diff --git a/tools/trace_to_text/trace_to_systrace.h b/tools/trace_to_text/trace_to_systrace.h
index 3862578..edd62c7 100644
--- a/tools/trace_to_text/trace_to_systrace.h
+++ b/tools/trace_to_text/trace_to_systrace.h
@@ -20,14 +20,25 @@
#include <iostream>
namespace perfetto {
+
+namespace trace_processor {
+class TraceProcessor;
+} // namespace trace_processor
+
namespace trace_to_text {
+class TraceWriter;
+
enum class Keep { kStart = 0, kEnd, kAll };
-enum SystraceKind { kSystraceNormal = 0, kSystraceCompressed, kSystraceJson };
int TraceToSystrace(std::istream* input,
std::ostream* output,
- SystraceKind kind,
+ bool compress,
+ Keep truncate_keep);
+
+int ExtractSystrace(trace_processor::TraceProcessor*,
+ TraceWriter*,
+ bool wrapped_in_json,
Keep truncate_keep);
} // namespace trace_to_text
diff --git a/tools/trace_to_text/utils.cc b/tools/trace_to_text/utils.cc
index 4f5169f..5055b98 100644
--- a/tools/trace_to_text/utils.cc
+++ b/tools/trace_to_text/utils.cc
@@ -44,6 +44,8 @@
"on spf.mapping = spm.id "
"where spm.build_id != '' and spf.symbol_set_id == 0";
+constexpr size_t kCompressionBufferSize = 500 * 1024;
+
std::string FromHex(const char* str, size_t size) {
if (size % 2) {
PERFETTO_DFATAL_OR_ELOG("Failed to parse hex %s", str);
@@ -236,5 +238,59 @@
}
}
+TraceWriter::TraceWriter(std::ostream* output) : output_(output) {}
+
+TraceWriter::~TraceWriter() = default;
+
+void TraceWriter::Write(std::string s) {
+ Write(s.data(), s.size());
+}
+
+void TraceWriter::Write(const char* data, size_t sz) {
+ output_->write(data, static_cast<std::streamsize>(sz));
+}
+
+DeflateTraceWriter::DeflateTraceWriter(std::ostream* output)
+ : TraceWriter(output),
+ buf_(base::PagedMemory::Allocate(kCompressionBufferSize)),
+ start_(static_cast<uint8_t*>(buf_.Get())),
+ end_(start_ + buf_.size()) {
+ CheckEq(deflateInit(&stream_, 9), Z_OK);
+ stream_.next_out = start_;
+ stream_.avail_out = static_cast<unsigned int>(end_ - start_);
+}
+
+DeflateTraceWriter::~DeflateTraceWriter() {
+ while (deflate(&stream_, Z_FINISH) != Z_STREAM_END) {
+ Flush();
+ }
+ CheckEq(deflateEnd(&stream_), Z_OK);
+}
+
+void DeflateTraceWriter::Write(const char* data, size_t sz) {
+ stream_.next_in = reinterpret_cast<uint8_t*>(const_cast<char*>(data));
+ stream_.avail_in = static_cast<unsigned int>(sz);
+ while (stream_.avail_in > 0) {
+ CheckEq(deflate(&stream_, Z_NO_FLUSH), Z_OK);
+ if (stream_.avail_out == 0) {
+ Flush();
+ }
+ }
+}
+
+void DeflateTraceWriter::Flush() {
+ TraceWriter::Write(reinterpret_cast<char*>(start_),
+ static_cast<size_t>(stream_.next_out - start_));
+ stream_.next_out = start_;
+ stream_.avail_out = static_cast<unsigned int>(end_ - start_);
+}
+
+void DeflateTraceWriter::CheckEq(int actual_code, int expected_code) {
+ if (actual_code == expected_code)
+ return;
+ PERFETTO_FATAL("Expected %d got %d: %s", actual_code, expected_code,
+ stream_.msg);
+}
+
} // namespace trace_to_text
} // namespace perfetto
diff --git a/tools/trace_to_text/utils.h b/tools/trace_to_text/utils.h
index 4bbcb98..f4004c3 100644
--- a/tools/trace_to_text/utils.h
+++ b/tools/trace_to_text/utils.h
@@ -26,7 +26,10 @@
#include <memory>
#include <vector>
+#include <zlib.h>
+
#include "perfetto/base/build_config.h"
+#include "perfetto/ext/base/paged_memory.h"
#include "perfetto/profiling/symbolizer.h"
#include "perfetto/trace_processor/trace_processor.h"
@@ -63,6 +66,35 @@
Symbolizer* symbolizer,
std::function<void(perfetto::protos::TracePacket)> callback);
+class TraceWriter {
+ public:
+ TraceWriter(std::ostream* output);
+ virtual ~TraceWriter();
+
+ void Write(std::string s);
+ virtual void Write(const char* data, size_t sz);
+
+ private:
+ std::ostream* output_;
+};
+
+class DeflateTraceWriter : public TraceWriter {
+ public:
+ DeflateTraceWriter(std::ostream* output);
+ ~DeflateTraceWriter() override;
+
+ void Write(const char* data, size_t sz) override;
+
+ private:
+ void Flush();
+ void CheckEq(int actual_code, int expected_code);
+
+ z_stream stream_{};
+ base::PagedMemory buf_;
+ uint8_t* const start_;
+ uint8_t* const end_;
+};
+
} // namespace trace_to_text
} // namespace perfetto