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