Merge "processor: Only fall back to legacy tracks for legacy events"
diff --git a/Android.bp b/Android.bp
index 45bb558..2e749e4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -994,10 +994,6 @@
     ":perfetto_src_tracing_tracing",
     ":perfetto_test_test_helper",
   ],
-  static_libs: [
-    "libgmock",
-    "libgtest",
-  ],
   export_include_dirs: [
     "include",
     "include/perfetto/base/build_configs/android_tree",
@@ -6100,6 +6096,7 @@
     "src/trace_processor/heap_profile_tracker_unittest.cc",
     "src/trace_processor/importers/fuchsia/fuchsia_trace_utils_unittest.cc",
     "src/trace_processor/importers/proto/args_table_utils_unittest.cc",
+    "src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc",
     "src/trace_processor/importers/proto/heap_graph_walker_unittest.cc",
     "src/trace_processor/importers/proto/proto_trace_parser_unittest.cc",
     "src/trace_processor/importers/systrace/systrace_parser_unittest.cc",
diff --git a/BUILD b/BUILD
index b62b186..3bccd24 100644
--- a/BUILD
+++ b/BUILD
@@ -481,6 +481,7 @@
         "include/perfetto/tracing/track_event.h",
         "include/perfetto/tracing/track_event_category_registry.h",
         "include/perfetto/tracing/track_event_interned_data_index.h",
+        "include/perfetto/tracing/track_event_legacy.h",
     ],
 )
 
diff --git a/BUILD.gn b/BUILD.gn
index ea24c77..a86d3fd 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -39,7 +39,7 @@
   ]
 }
 
-if (enable_perfetto_trace_processor) {
+if (enable_perfetto_trace_processor && enable_perfetto_trace_processor_sqlite) {
   all_targets += [ "src/trace_processor:trace_processor_shell" ]
 }
 
diff --git a/gn/BUILD.gn b/gn/BUILD.gn
index 3440b62..7412aa3 100644
--- a/gn/BUILD.gn
+++ b/gn/BUILD.gn
@@ -254,16 +254,18 @@
   }
 }
 
-group("sqlite") {
-  if (perfetto_root_path == "//") {
-    public_deps = [
-      "//buildtools:sqlite",
-    ]
-  } else {
-    public_deps = [
-      "//third_party/sqlite:sqlite",
-    ]
-    public_configs = [ ":sqlite_third_party_include_path" ]
+if (enable_perfetto_trace_processor_sqlite) {
+  group("sqlite") {
+    if (perfetto_root_path == "//") {
+      public_deps = [
+        "//buildtools:sqlite",
+      ]
+    } else {
+      public_deps = [
+        "//third_party/sqlite:sqlite",
+      ]
+      public_configs = [ ":sqlite_third_party_include_path" ]
+    }
   }
 }
 
diff --git a/gn/perfetto.gni b/gn/perfetto.gni
index 563db03..57c27aa 100644
--- a/gn/perfetto.gni
+++ b/gn/perfetto.gni
@@ -200,6 +200,11 @@
   perfetto_verbose_logs_enabled =
       !build_with_chromium || perfetto_force_dlog == "on"
 
+  # Enables the SQL query layer of trace processor.
+  enable_perfetto_trace_processor_sqlite =
+      enable_perfetto_trace_processor &&
+      (build_with_chromium || !perfetto_build_with_embedder)
+
   # Enables the optional SQLite percentile module.
   enable_perfetto_trace_processor_percentile =
       enable_perfetto_trace_processor && perfetto_build_standalone
@@ -237,10 +242,12 @@
       !(build_with_chromium && is_android)
 
   # Enables the trace_to_text tool.
-  enable_perfetto_tools_trace_to_text = enable_perfetto_tools
+  enable_perfetto_tools_trace_to_text =
+      enable_perfetto_tools && enable_perfetto_trace_processor_sqlite
 
   # Allows to build the UI (TypeScript/ HTML / WASM)
-  enable_perfetto_ui = perfetto_build_standalone
+  enable_perfetto_ui =
+      perfetto_build_standalone && enable_perfetto_trace_processor_sqlite
 }
 
 # +---------------------------------------------------------------------------+
diff --git a/gn/perfetto_unittests.gni b/gn/perfetto_unittests.gni
index ead0c8b..11ba49f 100644
--- a/gn/perfetto_unittests.gni
+++ b/gn/perfetto_unittests.gni
@@ -61,8 +61,9 @@
 }
 
 if (enable_perfetto_trace_processor) {
-  perfetto_unittests_targets += [
-    "src/trace_processor:unittests",
-    "src/trace_processor/metrics:unittests",
-  ]
+  perfetto_unittests_targets += [ "src/trace_processor:unittests" ]
+
+  if (enable_perfetto_trace_processor_sqlite) {
+    perfetto_unittests_targets += [ "src/trace_processor/metrics:unittests" ]
+  }
 }
diff --git a/gn/standalone/BUILD.gn b/gn/standalone/BUILD.gn
index c52b7c1..79cdadf 100644
--- a/gn/standalone/BUILD.gn
+++ b/gn/standalone/BUILD.gn
@@ -23,6 +23,12 @@
     "-Wpedantic",
   ]
 
+  # Disable variadic macro warning as we make extensive use of them in trace
+  # processor and client API.
+  if (is_clang) {
+    cflags += [ "-Wno-gnu-zero-variadic-macro-arguments" ]
+  }
+
   # Disable Weverything on fuzzers to avoid breakages when new versions of clang
   # are rolled into OSS-fuzz.
   if (is_clang && !is_fuzzer) {
@@ -33,7 +39,6 @@
       "-Wno-disabled-macro-expansion",
       "-Wno-gnu-include-next",
       "-Wno-gnu-statement-expression",
-      "-Wno-gnu-zero-variadic-macro-arguments",
       "-Wno-padded",
       "-Wno-reserved-id-macro",
       "-Wno-unknown-sanitizers",
diff --git a/include/perfetto/tracing.h b/include/perfetto/tracing.h
index be9ef6d..fca7c70 100644
--- a/include/perfetto/tracing.h
+++ b/include/perfetto/tracing.h
@@ -33,5 +33,6 @@
 #include "perfetto/tracing/tracing_backend.h"
 #include "perfetto/tracing/track_event.h"
 #include "perfetto/tracing/track_event_interned_data_index.h"
+#include "perfetto/tracing/track_event_legacy.h"
 
 #endif  // INCLUDE_PERFETTO_TRACING_H_
diff --git a/include/perfetto/tracing/BUILD.gn b/include/perfetto/tracing/BUILD.gn
index 60f4d4e..5c7a79f 100644
--- a/include/perfetto/tracing/BUILD.gn
+++ b/include/perfetto/tracing/BUILD.gn
@@ -45,5 +45,6 @@
     "track_event.h",
     "track_event_category_registry.h",
     "track_event_interned_data_index.h",
+    "track_event_legacy.h",
   ]
 }
diff --git a/include/perfetto/tracing/track_event_legacy.h b/include/perfetto/tracing/track_event_legacy.h
new file mode 100644
index 0000000..8513024
--- /dev/null
+++ b/include/perfetto/tracing/track_event_legacy.h
@@ -0,0 +1,846 @@
+/*
+ * Copyright (C) 2020 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 INCLUDE_PERFETTO_TRACING_TRACK_EVENT_LEGACY_H_
+#define INCLUDE_PERFETTO_TRACING_TRACK_EVENT_LEGACY_H_
+
+// This file defines a compatibility shim between legacy (Chrome, V8) trace
+// event macros and track events. To avoid accidentally introducing legacy
+// events in new code, the PERFETTO_ENABLE_LEGACY_TRACE_EVENTS macro must be set
+// to 1 activate the compatibility layer.
+
+#include "perfetto/base/compiler.h"
+
+#include <stdint.h>
+
+#ifndef PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
+#define PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 0
+#endif
+
+#if PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
+
+// Ignore GCC warning about a missing argument for a variadic macro parameter.
+#pragma GCC system_header
+
+// ----------------------------------------------------------------------------
+// Constants.
+// ----------------------------------------------------------------------------
+
+// The following constants are defined in the global namespace, since they were
+// originally implemented as macros.
+
+// Event phases.
+static constexpr char TRACE_EVENT_PHASE_BEGIN = 'B';
+static constexpr char TRACE_EVENT_PHASE_END = 'E';
+static constexpr char TRACE_EVENT_PHASE_COMPLETE = 'X';
+static constexpr char TRACE_EVENT_PHASE_INSTANT = 'I';
+static constexpr char TRACE_EVENT_PHASE_ASYNC_BEGIN = 'S';
+static constexpr char TRACE_EVENT_PHASE_ASYNC_STEP_INTO = 'T';
+static constexpr char TRACE_EVENT_PHASE_ASYNC_STEP_PAST = 'p';
+static constexpr char TRACE_EVENT_PHASE_ASYNC_END = 'F';
+static constexpr char TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN = 'b';
+static constexpr char TRACE_EVENT_PHASE_NESTABLE_ASYNC_END = 'e';
+static constexpr char TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT = 'n';
+static constexpr char TRACE_EVENT_PHASE_FLOW_BEGIN = 's';
+static constexpr char TRACE_EVENT_PHASE_FLOW_STEP = 't';
+static constexpr char TRACE_EVENT_PHASE_FLOW_END = 'f';
+static constexpr char TRACE_EVENT_PHASE_METADATA = 'M';
+static constexpr char TRACE_EVENT_PHASE_COUNTER = 'C';
+static constexpr char TRACE_EVENT_PHASE_SAMPLE = 'P';
+static constexpr char TRACE_EVENT_PHASE_CREATE_OBJECT = 'N';
+static constexpr char TRACE_EVENT_PHASE_SNAPSHOT_OBJECT = 'O';
+static constexpr char TRACE_EVENT_PHASE_DELETE_OBJECT = 'D';
+static constexpr char TRACE_EVENT_PHASE_MEMORY_DUMP = 'v';
+static constexpr char TRACE_EVENT_PHASE_MARK = 'R';
+static constexpr char TRACE_EVENT_PHASE_CLOCK_SYNC = 'c';
+static constexpr char TRACE_EVENT_PHASE_ENTER_CONTEXT = '(';
+static constexpr char TRACE_EVENT_PHASE_LEAVE_CONTEXT = ')';
+
+// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
+static constexpr uint32_t TRACE_EVENT_FLAG_NONE = 0;
+static constexpr uint32_t TRACE_EVENT_FLAG_COPY = 1u << 0;
+static constexpr uint32_t TRACE_EVENT_FLAG_HAS_ID = 1u << 1;
+// TODO(crbug.com/639003): Free this bit after ID mangling is deprecated.
+static constexpr uint32_t TRACE_EVENT_FLAG_MANGLE_ID = 1u << 2;
+static constexpr uint32_t TRACE_EVENT_FLAG_SCOPE_OFFSET = 1u << 3;
+static constexpr uint32_t TRACE_EVENT_FLAG_SCOPE_EXTRA = 1u << 4;
+static constexpr uint32_t TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP = 1u << 5;
+static constexpr uint32_t TRACE_EVENT_FLAG_ASYNC_TTS = 1u << 6;
+static constexpr uint32_t TRACE_EVENT_FLAG_BIND_TO_ENCLOSING = 1u << 7;
+static constexpr uint32_t TRACE_EVENT_FLAG_FLOW_IN = 1u << 8;
+static constexpr uint32_t TRACE_EVENT_FLAG_FLOW_OUT = 1u << 9;
+static constexpr uint32_t TRACE_EVENT_FLAG_HAS_CONTEXT_ID = 1u << 10;
+static constexpr uint32_t TRACE_EVENT_FLAG_HAS_PROCESS_ID = 1u << 11;
+static constexpr uint32_t TRACE_EVENT_FLAG_HAS_LOCAL_ID = 1u << 12;
+static constexpr uint32_t TRACE_EVENT_FLAG_HAS_GLOBAL_ID = 1u << 13;
+// TODO(eseckler): Remove once we have native support for typed proto events in
+// TRACE_EVENT macros.
+static constexpr uint32_t TRACE_EVENT_FLAG_TYPED_PROTO_ARGS = 1u << 15;
+static constexpr uint32_t TRACE_EVENT_FLAG_JAVA_STRING_LITERALS = 1u << 16;
+
+static constexpr uint32_t TRACE_EVENT_FLAG_SCOPE_MASK =
+    TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA;
+
+// Type values for identifying types in the TraceValue union.
+static constexpr uint8_t TRACE_VALUE_TYPE_BOOL = 1;
+static constexpr uint8_t TRACE_VALUE_TYPE_UINT = 2;
+static constexpr uint8_t TRACE_VALUE_TYPE_INT = 3;
+static constexpr uint8_t TRACE_VALUE_TYPE_DOUBLE = 4;
+static constexpr uint8_t TRACE_VALUE_TYPE_POINTER = 5;
+static constexpr uint8_t TRACE_VALUE_TYPE_STRING = 6;
+static constexpr uint8_t TRACE_VALUE_TYPE_COPY_STRING = 7;
+static constexpr uint8_t TRACE_VALUE_TYPE_CONVERTABLE = 8;
+
+// Enum reflecting the scope of an INSTANT event. Must fit within
+// TRACE_EVENT_FLAG_SCOPE_MASK.
+static constexpr uint8_t TRACE_EVENT_SCOPE_GLOBAL = 0u << 3;
+static constexpr uint8_t TRACE_EVENT_SCOPE_PROCESS = 1u << 3;
+static constexpr uint8_t TRACE_EVENT_SCOPE_THREAD = 2u << 3;
+
+static constexpr char TRACE_EVENT_SCOPE_NAME_GLOBAL = 'g';
+static constexpr char TRACE_EVENT_SCOPE_NAME_PROCESS = 'p';
+static constexpr char TRACE_EVENT_SCOPE_NAME_THREAD = 't';
+
+// ----------------------------------------------------------------------------
+// Internal legacy trace point implementation.
+// ----------------------------------------------------------------------------
+
+// A black hole trace point where unsupported trace events are routed.
+#define PERFETTO_INTERNAL_EVENT_NOOP(cat, name, ...) \
+  do {                                               \
+    if (false) {                                     \
+      ::perfetto::base::ignore_result(cat);          \
+      ::perfetto::base::ignore_result(name);         \
+    }                                                \
+  } while (false)
+
+// Implementations for the INTERNAL_* adapter macros used by the trace points
+// below.
+#define INTERNAL_TRACE_EVENT_ADD(...) PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(...) \
+  PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(...) \
+  PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(...) \
+  PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(...) \
+  PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(...) \
+  PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
+#define INTERNAL_TRACE_EVENT_METADATA_ADD(...) \
+  PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
+
+#define INTERNAL_TRACE_TIME_TICKS_NOW() 0
+#define INTERNAL_TRACE_TIME_NOW() 0
+
+// ----------------------------------------------------------------------------
+// Legacy tracing common API (adapted from trace_event_common.h).
+// ----------------------------------------------------------------------------
+
+#define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name
+
+// Scoped events.
+#define TRACE_EVENT0(category_group, name) \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name)
+#define TRACE_EVENT_WITH_FLOW0(category_group, name, bind_id, flow_flags)  \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+                                            flow_flags)
+#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val)
+#define TRACE_EVENT_WITH_FLOW1(category_group, name, bind_id, flow_flags,  \
+                               arg1_name, arg1_val)                        \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
+                                            flow_flags, arg1_name, arg1_val)
+#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name,   \
+                     arg2_val)                                               \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val, \
+                                  arg2_name, arg2_val)
+#define TRACE_EVENT_WITH_FLOW2(category_group, name, bind_id, flow_flags,    \
+                               arg1_name, arg1_val, arg2_name, arg2_val)     \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id,   \
+                                            flow_flags, arg1_name, arg1_val, \
+                                            arg2_name, arg2_val)
+
+// Instant events.
+#define TRACE_EVENT_INSTANT0(category_group, name, scope)                   \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE | scope)
+#define TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name,    \
+                           TRACE_EVENT_FLAG_NONE | scope, arg1_name, arg1_val)
+#define TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \
+                             arg2_name, arg2_val)                              \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name,    \
+                           TRACE_EVENT_FLAG_NONE | scope, arg1_name, arg1_val, \
+                           arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_INSTANT0(category_group, name, scope)              \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY | scope)
+#define TRACE_EVENT_COPY_INSTANT1(category_group, name, scope, arg1_name,   \
+                                  arg1_val)                                 \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY | scope, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_INSTANT2(category_group, name, scope, arg1_name,      \
+                                  arg1_val, arg2_name, arg2_val)               \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name,    \
+                           TRACE_EVENT_FLAG_COPY | scope, arg1_name, arg1_val, \
+                           arg2_name, arg2_val)
+#define TRACE_EVENT_INSTANT_WITH_FLAGS0(category_group, name, scope_and_flags) \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name,    \
+                           scope_and_flags)
+#define TRACE_EVENT_INSTANT_WITH_FLAGS1(category_group, name, scope_and_flags, \
+                                        arg1_name, arg1_val)                   \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, category_group, name,    \
+                           scope_and_flags, arg1_name, arg1_val)
+
+// Instant events with explicit timestamps.
+#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope,   \
+                                            timestamp)                     \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(TRACE_EVENT_PHASE_INSTANT,       \
+                                          category_group, name, timestamp, \
+                                          TRACE_EVENT_FLAG_NONE | scope)
+
+#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP1(category_group, name, scope,  \
+                                            timestamp, arg_name, arg_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                \
+      TRACE_EVENT_PHASE_INSTANT, category_group, name, timestamp,         \
+      TRACE_EVENT_FLAG_NONE | scope, arg_name, arg_val)
+
+// Begin events.
+#define TRACE_EVENT_BEGIN0(category_group, name)                          \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_BEGIN1(category_group, name, arg1_name, arg1_val)     \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_BEGIN2(category_group, name, arg1_name, arg1_val,     \
+                           arg2_name, arg2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val,    \
+                           arg2_name, arg2_val)
+#define TRACE_EVENT_BEGIN_WITH_FLAGS0(category_group, name, flags) \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name, flags)
+#define TRACE_EVENT_BEGIN_WITH_FLAGS1(category_group, name, flags, arg1_name, \
+                                      arg1_val)                               \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name,     \
+                           flags, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN2(category_group, name, arg1_name, arg1_val, \
+                                arg2_name, arg2_val)                       \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, category_group, name,  \
+                           TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val,     \
+                           arg2_name, arg2_val)
+
+// Begin events with explicit timestamps.
+#define TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category_group, name, id, \
+                                                     thread_id, timestamp)     \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id,      \
+      timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(                \
+    category_group, name, id, thread_id, timestamp)                       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+      timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1(                \
+    category_group, name, id, thread_id, timestamp, arg1_name, arg1_val)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+      timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2(                \
+    category_group, name, id, thread_id, timestamp, arg1_name, arg1_val,  \
+    arg2_name, arg2_val)                                                  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+      timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name,   \
+      arg2_val)
+
+// End events.
+#define TRACE_EVENT_END0(category_group, name)                          \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_END1(category_group, name, arg1_name, arg1_val)     \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_END2(category_group, name, arg1_name, arg1_val, arg2_name, \
+                         arg2_val)                                             \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name,        \
+                           TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val,         \
+                           arg2_name, arg2_val)
+#define TRACE_EVENT_END_WITH_FLAGS0(category_group, name, flags) \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, flags)
+#define TRACE_EVENT_END_WITH_FLAGS1(category_group, name, flags, arg1_name,    \
+                                    arg1_val)                                  \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name, flags, \
+                           arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END2(category_group, name, arg1_name, arg1_val, \
+                              arg2_name, arg2_val)                       \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, category_group, name,  \
+                           TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val,   \
+                           arg2_name, arg2_val)
+
+// Mark events.
+#define TRACE_EVENT_MARK_WITH_TIMESTAMP0(category_group, name, timestamp)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(TRACE_EVENT_PHASE_MARK,          \
+                                          category_group, name, timestamp, \
+                                          TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_MARK_WITH_TIMESTAMP1(category_group, name, timestamp, \
+                                         arg1_name, arg1_val)             \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                \
+      TRACE_EVENT_PHASE_MARK, category_group, name, timestamp,            \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_MARK_WITH_TIMESTAMP2(                                      \
+    category_group, name, timestamp, arg1_name, arg1_val, arg2_name, arg2_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                     \
+      TRACE_EVENT_PHASE_MARK, category_group, name, timestamp,                 \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+#define TRACE_EVENT_COPY_MARK(category_group, name)                      \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY)
+
+#define TRACE_EVENT_COPY_MARK1(category_group, name, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name,  \
+                           TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+
+#define TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(TRACE_EVENT_PHASE_MARK,             \
+                                          category_group, name, timestamp,    \
+                                          TRACE_EVENT_FLAG_COPY)
+
+// End events with explicit thread and timestamp.
+#define TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(category_group, name, id, \
+                                                   thread_id, timestamp)     \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                        \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id,      \
+      timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0(                \
+    category_group, name, id, thread_id, timestamp)                     \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                   \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+      timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1(                 \
+    category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                    \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id,  \
+      timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2(                 \
+    category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+    arg2_name, arg2_val)                                                 \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                    \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id,  \
+      timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name,  \
+      arg2_val)
+
+// Counters.
+#define TRACE_COUNTER1(category_group, name, value)                         \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, "value",                  \
+                           static_cast<int>(value))
+#define TRACE_COUNTER_WITH_FLAG1(category_group, name, flag, value)         \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           flag, "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER1(category_group, name, value)                    \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY, "value",                  \
+                           static_cast<int>(value))
+#define TRACE_COUNTER2(category_group, name, value1_name, value1_val,       \
+                       value2_name, value2_val)                             \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           TRACE_EVENT_FLAG_NONE, value1_name,              \
+                           static_cast<int>(value1_val), value2_name,       \
+                           static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER2(category_group, name, value1_name, value1_val,  \
+                            value2_name, value2_val)                        \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, category_group, name, \
+                           TRACE_EVENT_FLAG_COPY, value1_name,              \
+                           static_cast<int>(value1_val), value2_name,       \
+                           static_cast<int>(value2_val))
+
+// Counters with explicit timestamps.
+#define TRACE_COUNTER_WITH_TIMESTAMP1(category_group, name, timestamp, value) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                    \
+      TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp,             \
+      TRACE_EVENT_FLAG_NONE, "value", static_cast<int>(value))
+
+#define TRACE_COUNTER_WITH_TIMESTAMP2(category_group, name, timestamp,      \
+                                      value1_name, value1_val, value2_name, \
+                                      value2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                  \
+      TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp,           \
+      TRACE_EVENT_FLAG_NONE, value1_name, static_cast<int>(value1_val),     \
+      value2_name, static_cast<int>(value2_val))
+
+// Counters with ids.
+#define TRACE_COUNTER_ID1(category_group, name, id, value)                    \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE, "value",  \
+                                   static_cast<int>(value))
+#define TRACE_COPY_COUNTER_ID1(category_group, name, id, value)               \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY, "value",  \
+                                   static_cast<int>(value))
+#define TRACE_COUNTER_ID2(category_group, name, id, value1_name, value1_val,  \
+                          value2_name, value2_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE,           \
+                                   value1_name, static_cast<int>(value1_val), \
+                                   value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER_ID2(category_group, name, id, value1_name,         \
+                               value1_val, value2_name, value2_val)           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY,           \
+                                   value1_name, static_cast<int>(value1_val), \
+                                   value2_name, static_cast<int>(value2_val))
+
+// Sampling profiler events.
+#define TRACE_EVENT_SAMPLE_WITH_ID1(category_group, name, id, arg1_name,       \
+                                    arg1_val)                                  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_SAMPLE, category_group,   \
+                                   name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \
+                                   arg1_val)
+
+// Legacy async events.
+#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+                                   category_group, name, id,      \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+                                 arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN,     \
+                                   category_group, name, id,          \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+                                 arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                   \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,        \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category_group, name, id)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+                                   category_group, name, id,      \
+                                   TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+                                      arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN,          \
+                                   category_group, name, id,               \
+                                   TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+                                      arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                        \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,             \
+      TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_FLAGS0(category_group, name, id, flags) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN,            \
+                                   category_group, name, id, flags)
+
+// Legacy async events with explicit timestamps.
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \
+                                                timestamp)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1(                           \
+    category_group, name, id, timestamp, arg1_name, arg1_val)              \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                      \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,             \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+      arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP2(category_group, name, id,      \
+                                                timestamp, arg1_name,          \
+                                                arg1_val, arg2_name, arg2_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,                 \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE,     \
+      arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \
+                                                     timestamp)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id,                 \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP_AND_FLAGS0(     \
+    category_group, name, id, timestamp, flags)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(          \
+      TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, flags)
+
+// Legacy async step into events.
+#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
+                                   category_group, name, id,          \
+                                   TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \
+                                     arg1_name, arg1_val)            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                  \
+      TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id,   \
+      TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val)
+
+// Legacy async step into events with timestamps.
+#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, id, \
+                                                    step, timestamp)          \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE,    \
+      "step", step)
+
+// Legacy async step past events.
+#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+                                   category_group, name, id,          \
+                                   TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \
+                                     arg1_name, arg1_val)            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                  \
+      TRACE_EVENT_PHASE_ASYNC_STEP_PAST, category_group, name, id,   \
+      TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val)
+
+// Legacy async end events.
+#define TRACE_EVENT_ASYNC_END0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+                                   category_group, name, id,    \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END,               \
+                                   category_group, name, id,                  \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_END2(category_group, name, id, arg1_name, arg1_val, \
+                               arg2_name, arg2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                           \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                  \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_END0(category_group, name, id)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+                                   category_group, name, id,    \
+                                   TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_END1(category_group, name, id, arg1_name, \
+                                    arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END,          \
+                                   category_group, name, id,             \
+                                   TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_END2(category_group, name, id, arg1_name, \
+                                    arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                      \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,             \
+      TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_ASYNC_END_WITH_FLAGS0(category_group, name, id, flags) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END,            \
+                                   category_group, name, id, flags)
+
+// Legacy async end events with explicit timestamps.
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, name, id, \
+                                              timestamp)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                   \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,            \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP1(category_group, name, id,       \
+                                              timestamp, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                  \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE,    \
+      arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP2(category_group, name, id,       \
+                                              timestamp, arg1_name, arg1_val, \
+                                              arg2_name, arg2_val)            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                  \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE,    \
+      arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_END_WITH_TIMESTAMP0(category_group, name, id, \
+                                                   timestamp)                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                        \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                 \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP_AND_FLAGS0(category_group, name, \
+                                                        id, timestamp, flags) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                         \
+      TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id,                  \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, flags)
+
+// Async events.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+                                   category_group, name, id,               \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+                                          arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN,     \
+                                   category_group, name, id,                   \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+                                          arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id,        \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Async end events.
+#define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+                                   category_group, name, id,             \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_END1(category_group, name, id, arg1_name, \
+                                        arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END,     \
+                                   category_group, name, id,                 \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
+                                        arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                          \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id,        \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Async instant events.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
+                                   category_group, name, id,                 \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT1(category_group, name, id,        \
+                                            arg1_name, arg1_val)             \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
+                                   category_group, name, id,                 \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2(                              \
+    category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                       \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, category_group, name, id, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(                       \
+    category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id,        \
+      TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+      arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(                         \
+    category_group, name, id, arg1_name, arg1_val, arg2_name, arg2_val)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id,          \
+      TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+      arg2_name, arg2_val)
+
+// Async events with explicit timestamps.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, \
+                                                         id, timestamp)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id,        \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(category_group, name, \
+                                                       id, timestamp)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                        \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id,        \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP1(                    \
+    category_group, name, id, timestamp, arg1_name, arg1_val)              \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                      \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id,      \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+      arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT_WITH_TIMESTAMP0(               \
+    category_group, name, id, timestamp)                                  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                     \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, category_group, name, id, \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(          \
+    category_group, name, id, timestamp)                                \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                   \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(          \
+    category_group, name, id, timestamp)                              \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                 \
+      TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
+
+// Legacy flow events.
+#define TRACE_EVENT_FLOW_BEGIN0(category_group, name, id)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+                                   category_group, name, id,     \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_BEGIN1(category_group, name, id, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN,               \
+                                   category_group, name, id,                   \
+                                   TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_BEGIN2(category_group, name, id, arg1_name, arg1_val, \
+                                arg2_name, arg2_val)                           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_FLOW_BEGIN, category_group, name, id,                  \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN0(category_group, name, id)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+                                   category_group, name, id,     \
+                                   TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_BEGIN1(category_group, name, id, arg1_name, \
+                                     arg1_val)                            \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN,          \
+                                   category_group, name, id,              \
+                                   TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN2(category_group, name, id, arg1_name, \
+                                     arg1_val, arg2_name, arg2_val)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                       \
+      TRACE_EVENT_PHASE_FLOW_BEGIN, category_group, name, id,             \
+      TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Legacy flow step events.
+#define TRACE_EVENT_FLOW_STEP0(category_group, name, id, step)  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+                                   category_group, name, id,    \
+                                   TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_FLOW_STEP1(category_group, name, id, step, arg1_name, \
+                               arg1_val)                                  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                       \
+      TRACE_EVENT_PHASE_FLOW_STEP, category_group, name, id,              \
+      TRACE_EVENT_FLAG_NONE, "step", step, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_STEP0(category_group, name, id, step) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP,     \
+                                   category_group, name, id,        \
+                                   TRACE_EVENT_FLAG_COPY, "step", step)
+#define TRACE_EVENT_COPY_FLOW_STEP1(category_group, name, id, step, arg1_name, \
+                                    arg1_val)                                  \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                            \
+      TRACE_EVENT_PHASE_FLOW_STEP, category_group, name, id,                   \
+      TRACE_EVENT_FLAG_COPY, "step", step, arg1_name, arg1_val)
+
+// Legacy flow end events.
+#define TRACE_EVENT_FLOW_END0(category_group, name, id)                        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(category_group, name, id)      \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id,                                   \
+                                   TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+#define TRACE_EVENT_FLOW_END1(category_group, name, id, arg1_name, arg1_val)   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \
+                                   arg1_val)
+#define TRACE_EVENT_FLOW_END2(category_group, name, id, arg1_name, arg1_val,   \
+                              arg2_name, arg2_val)                             \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_NONE, arg1_name, \
+                                   arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_END0(category_group, name, id)                   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_END1(category_group, name, id, arg1_name,        \
+                                   arg1_val)                                   \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \
+                                   arg1_val)
+#define TRACE_EVENT_COPY_FLOW_END2(category_group, name, id, arg1_name,        \
+                                   arg1_val, arg2_name, arg2_val)              \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, category_group, \
+                                   name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \
+                                   arg1_val, arg2_name, arg2_val)
+
+// Special strongly typed trace events.
+// TODO(skyostil): Migrate these to regular track event trace points.
+#define TRACE_TASK_EXECUTION(run_function, task) \
+  if (false) {                                   \
+    base::ignore_result(run_function);           \
+    base::ignore_result(task);                   \
+  }
+
+#define TRACE_LOG_MESSAGE(file, message, line) \
+  if (false) {                                 \
+    base::ignore_result(file);                 \
+    base::ignore_result(message);              \
+    base::ignore_result(line);                 \
+  }
+
+// Metadata events.
+#define TRACE_EVENT_METADATA1(category_group, name, arg1_name, arg1_val) \
+  INTERNAL_TRACE_EVENT_METADATA_ADD(category_group, name, arg1_name, arg1_val)
+
+// Clock sync events.
+#define TRACE_EVENT_CLOCK_SYNC_RECEIVER(sync_id)                           \
+  INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata",     \
+                           "clock_sync", TRACE_EVENT_FLAG_NONE, "sync_id", \
+                           sync_id)
+#define TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(                                    \
+      TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync", issue_end_ts, \
+      TRACE_EVENT_FLAG_NONE, "sync_id", sync_id, "issue_ts", issue_ts)
+
+// Object events.
+#define TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group, name, id) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_CREATE_OBJECT,  \
+                                   category_group, name, id,         \
+                                   TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group, name, id, \
+                                            snapshot)                 \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(                                   \
+      TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name, id,    \
+      TRACE_EVENT_FLAG_NONE, "snapshot", snapshot)
+
+#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP(                 \
+    category_group, name, id, timestamp, snapshot)                         \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                      \
+      TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, category_group, name, id,         \
+      TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+      "snapshot", snapshot)
+
+#define TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group, name, id) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_DELETE_OBJECT,  \
+                                   category_group, name, id,         \
+                                   TRACE_EVENT_FLAG_NONE)
+
+// Context events.
+#define TRACE_EVENT_ENTER_CONTEXT(category_group, name, context)    \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ENTER_CONTEXT, \
+                                   category_group, name, context,   \
+                                   TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_LEAVE_CONTEXT(category_group, name, context)    \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_LEAVE_CONTEXT, \
+                                   category_group, name, context,   \
+                                   TRACE_EVENT_FLAG_NONE)
+
+// Macro to efficiently determine if a given category group is enabled.
+// TODO(skyostil): Implement.
+#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \
+  do {                                                          \
+    *ret = false;                                               \
+  } while (0)
+
+// Macro to efficiently determine, through polling, if a new trace has begun.
+// TODO(skyostil): Implement.
+#define TRACE_EVENT_IS_NEW_TRACE(ret) \
+  do {                                \
+    *ret = false;                     \
+  } while (0)
+
+// Time queries.
+#define TRACE_TIME_TICKS_NOW() INTERNAL_TRACE_TIME_TICKS_NOW()
+#define TRACE_TIME_NOW() INTERNAL_TRACE_TIME_NOW()
+
+// ----------------------------------------------------------------------------
+// Legacy tracing API (adapted from trace_event.h).
+// ----------------------------------------------------------------------------
+
+// We can implement the following subset of the legacy tracing API without
+// involvement from the embedder. APIs such as TraceId and
+// TRACE_EVENT_API_ADD_TRACE_EVENT are still up to the embedder to define.
+
+#define TRACE_STR_COPY(str) (str)
+
+// TODO(skyostil): Implement properly using CategoryRegistry.
+#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category) \
+  [&] {                                                      \
+    static uint8_t enabled;                                  \
+    TRACE_EVENT_CATEGORY_GROUP_ENABLED(category, &enabled);  \
+    return &enabled;                                         \
+  }()
+
+#endif  // PERFETTO_ENABLE_LEGACY_TRACE_EVENTS
+
+#endif  // INCLUDE_PERFETTO_TRACING_TRACK_EVENT_LEGACY_H_
diff --git a/src/base/BUILD.gn b/src/base/BUILD.gn
index 53681bc..c786391 100644
--- a/src/base/BUILD.gn
+++ b/src/base/BUILD.gn
@@ -95,7 +95,6 @@
   deps = [
     ":base",
     "../../gn:default_deps",
-    "../../gn:gtest_and_gmock",
   ]
   sources = [
     "test/utils.cc",
diff --git a/src/base/test/utils.h b/src/base/test/utils.h
index a064fa2..673362a 100644
--- a/src/base/test/utils.h
+++ b/src/base/test/utils.h
@@ -20,7 +20,6 @@
 #include <string>
 
 #include "perfetto/base/logging.h"
-#include "test/gtest_and_gmock.h"
 
 #if PERFETTO_DCHECK_IS_ON()
 
@@ -31,20 +30,11 @@
 
 #else  // PERFETTO_DCHECK_IS_ON()
 
-// Since PERFETTO_DCHECK_IS_ON() is false these statements should not die (if
-// they should/do we should use EXPECT/ASSERT DEATH_TEST_IF_SUPPORTED directly).
-// Therefore if the platform supports DEATH_TESTS we can use the handy
-// GTEST_EXECUTE_STATEMENT_ which prevents optimizing the code away, and if not
-// we just fall back on executing the code directly.
-#if GTEST_HAS_DEATH_TEST
 #define EXPECT_DCHECK_DEATH(statement) \
     GTEST_EXECUTE_STATEMENT_(statement, "PERFETTO_CHECK")
 #define ASSERT_DCHECK_DEATH(statement) \
     GTEST_EXECUTE_STATEMENT_(statement, "PERFETTO_CHECK")
-#else
-#define EXPECT_DCHECK_DEATH(statement) statement
-#define ASSERT_DCHECK_DEATH(statement) statement
-#endif  // GTEST_HAS_DEATH_TEST
+
 #endif  // PERFETTO_DCHECK_IS_ON()
 
 namespace perfetto {
diff --git a/src/base/watchdog_posix.cc b/src/base/watchdog_posix.cc
index 3517afd..25782d9 100644
--- a/src/base/watchdog_posix.cc
+++ b/src/base/watchdog_posix.cc
@@ -47,7 +47,8 @@
   for (size_t i = 0; i < size; i++) {
     total += array[i];
   }
-  return total / size;
+  return static_cast<double>(total / size);
+
 }
 
 }  //  namespace
@@ -164,7 +165,7 @@
   // Add the current stat value to the ring buffer and check that the mean
   // remains under our threshold.
   if (memory_window_bytes_.Push(rss_bytes)) {
-    if (memory_window_bytes_.Mean() > memory_limit_bytes_) {
+    if (memory_window_bytes_.Mean() > static_cast<double>(memory_limit_bytes_)) {
       PERFETTO_ELOG(
           "Memory watchdog trigger. Memory window of %f bytes is above the "
           "%" PRIu64 " bytes limit.",
@@ -187,7 +188,7 @@
     double window_interval_ticks =
         (static_cast<double>(WindowTimeForRingBuffer(cpu_window_time_ticks_)) /
          1000.0) *
-        sysconf(_SC_CLK_TCK);
+        static_cast<double>(sysconf(_SC_CLK_TCK));
     double percentage = static_cast<double>(difference_ticks) /
                         static_cast<double>(window_interval_ticks) * 100;
     if (percentage > cpu_limit_percentage_) {
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index ebabeb3..f3cc961 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -23,11 +23,13 @@
 
 # The library which eases processing of Perfetto traces by exposing reading
 # friendly APIs.
-static_library("trace_processor") {
-  complete_static_lib = true
-  deps = [
-    ":lib",
-  ]
+if (enable_perfetto_trace_processor_sqlite) {
+  static_library("trace_processor") {
+    complete_static_lib = true
+    deps = [
+      ":lib",
+    ]
+  }
 }
 
 if (enable_perfetto_ui) {
@@ -286,94 +288,96 @@
   }
 }
 
-source_set("lib") {
-  sources = [
-    "filtered_row_index.cc",
-    "filtered_row_index.h",
-    "read_trace.cc",
-    "row_iterators.cc",
-    "row_iterators.h",
-    "sched_slice_table.cc",
-    "sched_slice_table.h",
-    "span_join_operator_table.cc",
-    "span_join_operator_table.h",
-    "sql_stats_table.cc",
-    "sql_stats_table.h",
-    "sqlite_raw_table.cc",
-    "sqlite_raw_table.h",
-    "stats_table.cc",
-    "stats_table.h",
-    "storage_columns.cc",
-    "storage_columns.h",
-    "storage_schema.cc",
-    "storage_schema.h",
-    "storage_table.cc",
-    "storage_table.h",
-    "trace_processor.cc",
-    "trace_processor_impl.cc",
-    "trace_processor_impl.h",
-    "window_operator_table.cc",
-    "window_operator_table.h",
-  ]
+if (enable_perfetto_trace_processor_sqlite) {
+  source_set("lib") {
+    sources = [
+      "filtered_row_index.cc",
+      "filtered_row_index.h",
+      "read_trace.cc",
+      "row_iterators.cc",
+      "row_iterators.h",
+      "sched_slice_table.cc",
+      "sched_slice_table.h",
+      "span_join_operator_table.cc",
+      "span_join_operator_table.h",
+      "sql_stats_table.cc",
+      "sql_stats_table.h",
+      "sqlite_raw_table.cc",
+      "sqlite_raw_table.h",
+      "stats_table.cc",
+      "stats_table.h",
+      "storage_columns.cc",
+      "storage_columns.h",
+      "storage_schema.cc",
+      "storage_schema.h",
+      "storage_table.cc",
+      "storage_table.h",
+      "trace_processor.cc",
+      "trace_processor_impl.cc",
+      "trace_processor_impl.h",
+      "window_operator_table.cc",
+      "window_operator_table.h",
+    ]
 
-  deps = [
-    ":storage_full",
-    "../../gn:default_deps",
-    "../../gn:sqlite",
-    "../../protos/perfetto/metrics:zero",
-    "../../protos/perfetto/metrics/android:zero",
-    "../../protos/perfetto/trace/ftrace:zero",
-    "../base",
-    "db:lib",
-    "metrics:lib",
-    "sqlite",
-    "tables",
-    "types",
-  ]
-  public_deps = [
-    "../../include/perfetto/trace_processor",
-  ]
-  if (enable_perfetto_trace_processor_json) {
-    deps += [ ":export_json" ]
+    deps = [
+      ":storage_full",
+      "../../gn:default_deps",
+      "../../gn:sqlite",
+      "../../protos/perfetto/metrics:zero",
+      "../../protos/perfetto/metrics/android:zero",
+      "../../protos/perfetto/trace/ftrace:zero",
+      "../base",
+      "db:lib",
+      "metrics:lib",
+      "sqlite",
+      "tables",
+      "types",
+    ]
+    public_deps = [
+      "../../include/perfetto/trace_processor",
+    ]
+    if (enable_perfetto_trace_processor_json) {
+      deps += [ ":export_json" ]
+    }
   }
-}
 
-perfetto_host_executable("trace_processor_shell") {
-  deps = [
-    ":lib",
-    "../../gn:default_deps",
-    "../../gn:protoc_lib",
-    "../../src/profiling/symbolizer",
-    "../../src/profiling/symbolizer:symbolize_database",
-    "../base",
-    "metrics:lib",
-  ]
-  if (enable_perfetto_version_gen) {
-    deps += [ "../../gn/standalone:gen_git_revision" ]
+  perfetto_host_executable("trace_processor_shell") {
+    deps = [
+      ":lib",
+      "../../gn:default_deps",
+      "../../gn:protoc_lib",
+      "../../src/profiling/symbolizer",
+      "../../src/profiling/symbolizer:symbolize_database",
+      "../base",
+      "metrics:lib",
+    ]
+    if (enable_perfetto_version_gen) {
+      deps += [ "../../gn/standalone:gen_git_revision" ]
+    }
+    if (enable_perfetto_trace_processor_linenoise) {
+      deps += [ "../../gn:linenoise" ]
+    }
+    if (enable_perfetto_trace_processor_httpd) {
+      deps += [ "rpc:httpd" ]
+    }
+    sources = [
+      "proto_to_json.cc",
+      "proto_to_json.h",
+      "trace_processor_shell.cc",
+    ]
   }
-  if (enable_perfetto_trace_processor_linenoise) {
-    deps += [ "../../gn:linenoise" ]
-  }
-  if (enable_perfetto_trace_processor_httpd) {
-    deps += [ "rpc:httpd" ]
-  }
-  sources = [
-    "proto_to_json.cc",
-    "proto_to_json.h",
-    "trace_processor_shell.cc",
-  ]
-}
+}  # if (enable_perfetto_trace_processor_sqlite)
 
 perfetto_unittest_source_set("unittests") {
   testonly = true
   sources = [
     "clock_tracker_unittest.cc",
     "event_tracker_unittest.cc",
-    "filtered_row_index_unittest.cc",
     "forwarding_trace_parser_unittest.cc",
     "ftrace_utils_unittest.cc",
     "heap_profile_tracker_unittest.cc",
     "importers/proto/args_table_utils_unittest.cc",
+    "importers/proto/heap_graph_tracker_unittest.cc",
     "importers/proto/heap_graph_walker_unittest.cc",
     "importers/proto/proto_trace_parser_unittest.cc",
     "importers/systrace/systrace_parser_unittest.cc",
@@ -381,18 +385,15 @@
     "protozero_to_text_unittests.cc",
     "sched_slice_table_unittest.cc",
     "slice_tracker_unittest.cc",
-    "span_join_operator_table_unittest.cc",
     "syscall_tracker_unittest.cc",
     "trace_sorter_unittest.cc",
   ]
   deps = [
     ":descriptors",
-    ":lib",
     ":protozero_to_text",
     ":storage_full",
     "../../gn:default_deps",
     "../../gn:gtest_and_gmock",
-    "../../gn:sqlite",
     "../../protos/perfetto/common:zero",
     "../../protos/perfetto/trace:minimal_zero",
     "../../protos/perfetto/trace:zero",
@@ -410,11 +411,22 @@
     "../protozero:testing_messages_zero",
     "containers:unittests",
     "db:unittests",
-    "sqlite",
-    "sqlite:unittests",
     "tables:unittests",
   ]
 
+  if (enable_perfetto_trace_processor_sqlite) {
+    sources += [
+      "filtered_row_index_unittest.cc",
+      "span_join_operator_table_unittest.cc",
+    ]
+    deps += [
+      ":lib",
+      "../../gn:sqlite",
+      "sqlite",
+      "sqlite:unittests",
+    ]
+  }
+
   if (enable_perfetto_trace_processor_json) {
     if (enable_perfetto_trace_processor_json_import) {
       sources += [
@@ -441,21 +453,22 @@
 
 source_set("integrationtests") {
   testonly = true
-  sources = [
-    "trace_database_integrationtest.cc",
-  ]
-  deps = [
-    ":lib",
-    ":storage_full",
-    "../../gn:default_deps",
-    "../../gn:gtest_and_gmock",
-    "../base",
-    "../base:test_support",
-    "sqlite",
-  ]
-
-  if (enable_perfetto_trace_processor_json_import) {
-    deps += [ "../../gn:jsoncpp" ]
+  sources = []
+  deps = []
+  if (enable_perfetto_trace_processor_sqlite) {
+    sources += [ "trace_database_integrationtest.cc" ]
+    deps += [
+      ":lib",
+      ":storage_full",
+      "../../gn:default_deps",
+      "../../gn:gtest_and_gmock",
+      "../base",
+      "../base:test_support",
+      "sqlite",
+    ]
+    if (enable_perfetto_trace_processor_json_import) {
+      deps += [ "../../gn:jsoncpp" ]
+    }
   }
 }
 
diff --git a/src/trace_processor/db/typed_column.h b/src/trace_processor/db/typed_column.h
index 9a3dd5e..5be1dcc 100644
--- a/src/trace_processor/db/typed_column.h
+++ b/src/trace_processor/db/typed_column.h
@@ -67,6 +67,13 @@
     return Column::IndexOf(NumericToSqlValue(v));
   }
 
+  std::vector<T> ToVectorForTesting() const {
+    std::vector<T> result(row_map().size());
+    for (uint32_t i = 0; i < row_map().size(); ++i)
+      result[i] = (*this)[i];
+    return result;
+  }
+
   // Implements equality between two items of type |T|.
   static bool Equals(T a, T b) {
     // We need to use equal_to here as it could be T == double and because we
@@ -104,6 +111,13 @@
   // Inserts the value at the end of the column.
   void Append(base::Optional<T> v) { mutable_sparse_vector<T>()->Append(v); }
 
+  std::vector<base::Optional<T>> ToVectorForTesting() const {
+    std::vector<T> result(row_map().size());
+    for (uint32_t i = 0; i < row_map().size(); ++i)
+      result[i] = (*this)[i];
+    return result;
+  }
+
   // Implements equality between two items of type |T|.
   static bool Equals(base::Optional<T> a, base::Optional<T> b) {
     // We need to use equal_to here as it could be T == double and because we
diff --git a/src/trace_processor/export_json.cc b/src/trace_processor/export_json.cc
index 60f1095..ed6e5f8 100644
--- a/src/trace_processor/export_json.cc
+++ b/src/trace_processor/export_json.cc
@@ -226,8 +226,8 @@
       value["cat"] = "__metadata";
       value["ts"] = 0;
       value["name"] = metadata_type;
-      value["pid"] = Json::UInt(pid);
-      value["tid"] = Json::UInt(tid);
+      value["pid"] = Json::Int(pid);
+      value["tid"] = Json::Int(tid);
 
       Json::Value args;
       args["name"] = metadata_value;
@@ -692,8 +692,8 @@
         // Synchronous (thread) slice or instant event.
         UniqueTid utid = thread_track.utid()[*opt_thread_track_row];
         auto pid_and_tid = UtidToPidAndTid(utid);
-        event["pid"] = Json::UInt(pid_and_tid.first);
-        event["tid"] = Json::UInt(pid_and_tid.second);
+        event["pid"] = Json::Int(pid_and_tid.first);
+        event["tid"] = Json::Int(pid_and_tid.second);
 
         if (duration_ns == 0) {
           // Use "I" instead of "i" phase for backwards-compat with old
@@ -739,10 +739,10 @@
           PERFETTO_DCHECK(track_args);
           uint32_t upid = process_track.upid()[*opt_process_row];
           uint32_t exported_pid = UpidToPid(upid);
-          event["pid"] = Json::UInt(exported_pid);
+          event["pid"] = Json::Int(exported_pid);
           event["tid"] =
-              Json::UInt(legacy_utid ? UtidToPidAndTid(*legacy_utid).second
-                                     : exported_pid);
+              Json::Int(legacy_utid ? UtidToPidAndTid(*legacy_utid).second
+                                    : exported_pid);
 
           // Preserve original event IDs for legacy tracks. This is so that e.g.
           // memory dump IDs show up correctly in the JSON trace.
@@ -770,10 +770,10 @@
             uint32_t upid = process_track.upid()[*opt_process_row];
             event["id2"]["local"] = PrintUint64(track_id);
             uint32_t exported_pid = UpidToPid(upid);
-            event["pid"] = Json::UInt(exported_pid);
+            event["pid"] = Json::Int(exported_pid);
             event["tid"] =
-                Json::UInt(legacy_utid ? UtidToPidAndTid(*legacy_utid).second
-                                       : exported_pid);
+                Json::Int(legacy_utid ? UtidToPidAndTid(*legacy_utid).second
+                                      : exported_pid);
           } else {
             // Some legacy importers don't understand "id2" fields, so we use
             // the "usually" global "id" field instead. This works as long as
@@ -826,10 +826,10 @@
         if (opt_process_row.has_value()) {
           uint32_t upid = process_track.upid()[*opt_process_row];
           uint32_t exported_pid = UpidToPid(upid);
-          event["pid"] = Json::UInt(exported_pid);
+          event["pid"] = Json::Int(exported_pid);
           event["tid"] =
-              Json::UInt(legacy_utid ? UtidToPidAndTid(*legacy_utid).second
-                                     : exported_pid);
+              Json::Int(legacy_utid ? UtidToPidAndTid(*legacy_utid).second
+                                    : exported_pid);
           event["s"] = "p";
         } else {
           event["s"] = "g";
@@ -848,8 +848,8 @@
 
     UniqueTid utid = static_cast<UniqueTid>(events.utid()[index]);
     auto pid_and_tid = UtidToPidAndTid(utid);
-    event["pid"] = Json::UInt(pid_and_tid.first);
-    event["tid"] = Json::UInt(pid_and_tid.second);
+    event["pid"] = Json::Int(pid_and_tid.first);
+    event["tid"] = Json::Int(pid_and_tid.second);
 
     // Raw legacy events store all other params in the arg set. Make a copy of
     // the converted args here, parse, and then remove the legacy params.
@@ -963,8 +963,8 @@
 
       UniqueTid utid = static_cast<UniqueTid>(samples.utid()[i]);
       auto pid_and_tid = UtidToPidAndTid(utid);
-      event["pid"] = Json::UInt(pid_and_tid.first);
-      event["tid"] = Json::UInt(pid_and_tid.second);
+      event["pid"] = Json::Int(pid_and_tid.first);
+      event["tid"] = Json::Int(pid_and_tid.second);
 
       event["ph"] = "n";
       event["cat"] = "disabled_by_default-cpu_profiler";
@@ -1035,7 +1035,7 @@
       // TODO(oysteine): Used for backwards compatibility with the memlog
       // pipeline, should remove once we've switched to looking directly at the
       // tid.
-      event["args"]["thread_id"] = Json::UInt(pid_and_tid.second);
+      event["args"]["thread_id"] = Json::Int(pid_and_tid.second);
 
       writer_.WriteCommonEvent(event);
     }
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index 447f0fe..2c9ec19 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -146,7 +146,7 @@
   EXPECT_EQ(event["tdur"].asInt64(), kThreadDuration / 1000);
   EXPECT_EQ(event["ticount"].asInt64(), kThreadInstructionCount);
   EXPECT_EQ(event["tidelta"].asInt64(), kThreadInstructionDelta);
-  EXPECT_EQ(event["tid"].asUInt(), kThreadID);
+  EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
   EXPECT_EQ(event["cat"].asString(), kCategory);
   EXPECT_EQ(event["name"].asString(), kName);
   EXPECT_TRUE(event["args"].isObject());
@@ -192,7 +192,7 @@
   EXPECT_FALSE(event.isMember("tdur"));
   EXPECT_EQ(event["ticount"].asInt64(), kThreadInstructionCount);
   EXPECT_FALSE(event.isMember("tidelta"));
-  EXPECT_EQ(event["tid"].asUInt(), kThreadID);
+  EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
   EXPECT_EQ(event["cat"].asString(), kCategory);
   EXPECT_EQ(event["name"].asString(), kName);
   EXPECT_TRUE(event["args"].isObject());
@@ -218,7 +218,7 @@
 
   Json::Value event = result["traceEvents"][0];
   EXPECT_EQ(event["ph"].asString(), "M");
-  EXPECT_EQ(event["tid"].asUInt(), kThreadID);
+  EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
   EXPECT_EQ(event["name"].asString(), "thread_name");
   EXPECT_EQ(event["args"]["name"].asString(), kName);
 }
@@ -768,7 +768,7 @@
   EXPECT_EQ(result["traceEvents"].size(), 1u);
 
   Json::Value event = result["traceEvents"][0];
-  EXPECT_EQ(event["tid"].asUInt(), kThreadID);
+  EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
   EXPECT_EQ(event["ph"].asString(), "I");
   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
   EXPECT_EQ(event["s"].asString(), "t");
@@ -842,40 +842,40 @@
   Json::Value result = ToJsonValue(ReadFile(output));
   EXPECT_EQ(result["traceEvents"].size(), 5u);
 
-  EXPECT_EQ(result["traceEvents"][0]["pid"].asUInt(), 1u);
-  EXPECT_EQ(result["traceEvents"][0]["tid"].asUInt(), 1u);
+  EXPECT_EQ(result["traceEvents"][0]["pid"].asInt(), 1);
+  EXPECT_EQ(result["traceEvents"][0]["tid"].asInt(), 1);
   EXPECT_EQ(result["traceEvents"][0]["ph"].asString(), "I");
   EXPECT_EQ(result["traceEvents"][0]["ts"].asInt64(), 10);
   EXPECT_EQ(result["traceEvents"][0]["cat"].asString(), "cat");
   EXPECT_EQ(result["traceEvents"][0]["name"].asString(), "name1a");
 
-  EXPECT_EQ(result["traceEvents"][1]["pid"].asUInt(), 1u);
-  EXPECT_EQ(result["traceEvents"][1]["tid"].asUInt(), 2u);
+  EXPECT_EQ(result["traceEvents"][1]["pid"].asInt(), 1);
+  EXPECT_EQ(result["traceEvents"][1]["tid"].asInt(), 2);
   EXPECT_EQ(result["traceEvents"][1]["ph"].asString(), "X");
   EXPECT_EQ(result["traceEvents"][1]["ts"].asInt64(), 20);
   EXPECT_EQ(result["traceEvents"][1]["dur"].asInt64(), 1);
   EXPECT_EQ(result["traceEvents"][1]["cat"].asString(), "cat");
   EXPECT_EQ(result["traceEvents"][1]["name"].asString(), "name1b");
 
-  EXPECT_EQ(result["traceEvents"][2]["pid"].asUInt(), 1u);
-  EXPECT_EQ(result["traceEvents"][2]["tid"].asUInt(),
-            static_cast<uint32_t>(std::numeric_limits<uint32_t>::max() - 1u));
+  EXPECT_EQ(result["traceEvents"][2]["pid"].asInt(), 1);
+  EXPECT_EQ(result["traceEvents"][2]["tid"].asInt(),
+            static_cast<int>(std::numeric_limits<uint32_t>::max() - 1u));
   EXPECT_EQ(result["traceEvents"][2]["ph"].asString(), "I");
   EXPECT_EQ(result["traceEvents"][2]["ts"].asInt64(), 30);
   EXPECT_EQ(result["traceEvents"][2]["cat"].asString(), "cat");
   EXPECT_EQ(result["traceEvents"][2]["name"].asString(), "name1c");
 
-  EXPECT_EQ(result["traceEvents"][3]["pid"].asUInt(),
-            std::numeric_limits<uint32_t>::max());
-  EXPECT_EQ(result["traceEvents"][3]["tid"].asUInt(), 1u);
+  EXPECT_EQ(result["traceEvents"][3]["pid"].asInt(),
+            static_cast<int>(std::numeric_limits<uint32_t>::max()));
+  EXPECT_EQ(result["traceEvents"][3]["tid"].asInt(), 1);
   EXPECT_EQ(result["traceEvents"][3]["ph"].asString(), "I");
   EXPECT_EQ(result["traceEvents"][3]["ts"].asInt64(), 40);
   EXPECT_EQ(result["traceEvents"][3]["cat"].asString(), "cat");
   EXPECT_EQ(result["traceEvents"][3]["name"].asString(), "name2a");
 
-  EXPECT_EQ(result["traceEvents"][4]["pid"].asUInt(),
-            std::numeric_limits<uint32_t>::max());
-  EXPECT_EQ(result["traceEvents"][4]["tid"].asUInt(), 2u);
+  EXPECT_EQ(result["traceEvents"][4]["pid"].asInt(),
+            static_cast<int>(std::numeric_limits<uint32_t>::max()));
+  EXPECT_EQ(result["traceEvents"][4]["tid"].asInt(), 2);
   EXPECT_EQ(result["traceEvents"][4]["ph"].asString(), "X");
   EXPECT_EQ(result["traceEvents"][4]["ts"].asInt64(), 50);
   EXPECT_EQ(result["traceEvents"][1]["dur"].asInt64(), 1);
@@ -931,7 +931,7 @@
   Json::Value begin_event1 = result["traceEvents"][0];
   EXPECT_EQ(begin_event1["ph"].asString(), "b");
   EXPECT_EQ(begin_event1["ts"].asInt64(), kTimestamp / 1000);
-  EXPECT_EQ(begin_event1["pid"].asUInt(), kProcessID);
+  EXPECT_EQ(begin_event1["pid"].asInt(), static_cast<int>(kProcessID));
   EXPECT_EQ(begin_event1["id2"]["local"].asString(), "0xeb");
   EXPECT_EQ(begin_event1["cat"].asString(), kCategory);
   EXPECT_EQ(begin_event1["name"].asString(), kName);
@@ -942,7 +942,7 @@
   Json::Value begin_event2 = result["traceEvents"][1];
   EXPECT_EQ(begin_event2["ph"].asString(), "b");
   EXPECT_EQ(begin_event2["ts"].asInt64(), kTimestamp / 1000);
-  EXPECT_EQ(begin_event2["pid"].asUInt(), kProcessID);
+  EXPECT_EQ(begin_event2["pid"].asInt(), static_cast<int>(kProcessID));
   EXPECT_EQ(begin_event2["id2"]["local"].asString(), "0xeb");
   EXPECT_EQ(begin_event2["cat"].asString(), kCategory);
   EXPECT_EQ(begin_event2["name"].asString(), kName2);
@@ -954,7 +954,7 @@
   Json::Value end_event2 = result["traceEvents"][3];
   EXPECT_EQ(end_event2["ph"].asString(), "e");
   EXPECT_EQ(end_event2["ts"].asInt64(), (kTimestamp + kDuration) / 1000);
-  EXPECT_EQ(end_event2["pid"].asUInt(), kProcessID);
+  EXPECT_EQ(end_event2["pid"].asInt(), static_cast<int>(kProcessID));
   EXPECT_EQ(end_event2["id2"]["local"].asString(), "0xeb");
   EXPECT_EQ(end_event2["cat"].asString(), kCategory);
   EXPECT_EQ(end_event2["name"].asString(), kName);
@@ -966,7 +966,7 @@
   Json::Value end_event1 = result["traceEvents"][3];
   EXPECT_EQ(end_event1["ph"].asString(), "e");
   EXPECT_EQ(end_event1["ts"].asInt64(), (kTimestamp + kDuration) / 1000);
-  EXPECT_EQ(end_event1["pid"].asUInt(), kProcessID);
+  EXPECT_EQ(end_event1["pid"].asInt(), static_cast<int>(kProcessID));
   EXPECT_EQ(end_event1["id2"]["local"].asString(), "0xeb");
   EXPECT_EQ(end_event1["cat"].asString(), kCategory);
   EXPECT_EQ(end_event1["name"].asString(), kName);
@@ -1014,7 +1014,7 @@
   EXPECT_EQ(begin_event["ts"].asInt64(), kTimestamp / 1000);
   EXPECT_EQ(begin_event["tts"].asInt64(), kThreadTimestamp / 1000);
   EXPECT_EQ(begin_event["use_async_tts"].asInt(), 1);
-  EXPECT_EQ(begin_event["pid"].asUInt(), kProcessID);
+  EXPECT_EQ(begin_event["pid"].asInt(), static_cast<int>(kProcessID));
   EXPECT_EQ(begin_event["id2"]["local"].asString(), "0xeb");
   EXPECT_EQ(begin_event["cat"].asString(), kCategory);
   EXPECT_EQ(begin_event["name"].asString(), kName);
@@ -1025,7 +1025,7 @@
   EXPECT_EQ(end_event["tts"].asInt64(),
             (kThreadTimestamp + kThreadDuration) / 1000);
   EXPECT_EQ(end_event["use_async_tts"].asInt(), 1);
-  EXPECT_EQ(end_event["pid"].asUInt(), kProcessID);
+  EXPECT_EQ(end_event["pid"].asInt(), static_cast<int>(kProcessID));
   EXPECT_EQ(end_event["id2"]["local"].asString(), "0xeb");
   EXPECT_EQ(end_event["cat"].asString(), kCategory);
   EXPECT_EQ(end_event["name"].asString(), kName);
@@ -1069,7 +1069,7 @@
   EXPECT_EQ(begin_event["ts"].asInt64(), kTimestamp / 1000);
   EXPECT_EQ(begin_event["tts"].asInt64(), kThreadTimestamp / 1000);
   EXPECT_EQ(begin_event["use_async_tts"].asInt(), 1);
-  EXPECT_EQ(begin_event["pid"].asUInt(), kProcessID);
+  EXPECT_EQ(begin_event["pid"].asInt(), static_cast<int>(kProcessID));
   EXPECT_EQ(begin_event["id2"]["local"].asString(), "0xeb");
   EXPECT_EQ(begin_event["cat"].asString(), kCategory);
   EXPECT_EQ(begin_event["name"].asString(), kName);
@@ -1116,7 +1116,7 @@
   Json::Value event = result["traceEvents"][0];
   EXPECT_EQ(event["ph"].asString(), "n");
   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
-  EXPECT_EQ(event["pid"].asUInt(), kProcessID);
+  EXPECT_EQ(event["pid"].asInt(), static_cast<int>(kProcessID));
   EXPECT_EQ(event["id2"]["local"].asString(), "0xeb");
   EXPECT_EQ(event["cat"].asString(), kCategory);
   EXPECT_EQ(event["name"].asString(), kName);
@@ -1204,7 +1204,7 @@
   EXPECT_EQ(event["tdur"].asInt64(), kThreadDuration / 1000);
   EXPECT_EQ(event["ticount"].asInt64(), kThreadInstructionCount);
   EXPECT_EQ(event["tidelta"].asInt64(), kThreadInstructionDelta);
-  EXPECT_EQ(event["tid"].asUInt(), kThreadID);
+  EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
   EXPECT_EQ(event["cat"].asString(), kCategory);
   EXPECT_EQ(event["name"].asString(), kName);
   EXPECT_EQ(event["use_async_tts"].asInt(), 1);
@@ -1328,7 +1328,7 @@
   EXPECT_EQ(event["ph"].asString(), "n");
   EXPECT_EQ(event["id"].asString(), "0x1");
   EXPECT_EQ(event["ts"].asInt64(), kTimestamp / 1000);
-  EXPECT_EQ(event["tid"].asUInt(), kThreadID);
+  EXPECT_EQ(event["tid"].asInt(), static_cast<int>(kThreadID));
   EXPECT_EQ(event["cat"].asString(), "disabled_by_default-cpu_profiler");
   EXPECT_EQ(event["name"].asString(), "StackCpuSampling");
   EXPECT_EQ(event["s"].asString(), "t");
@@ -1472,13 +1472,13 @@
   EXPECT_EQ(result[0]["ph"].asString(), "X");
   EXPECT_EQ(result[0]["ts"].asInt64(), kTimestamp1 / 1000);
   EXPECT_EQ(result[0]["dur"].asInt64(), kDuration / 1000);
-  EXPECT_EQ(result[0]["tid"].asUInt(), kThreadID);
+  EXPECT_EQ(result[0]["tid"].asInt(), static_cast<int>(kThreadID));
   EXPECT_EQ(result[0]["cat"].asString(), kCategory);
   EXPECT_EQ(result[0]["name"].asString(), kName);
   EXPECT_EQ(result[1]["ph"].asString(), "X");
   EXPECT_EQ(result[1]["ts"].asInt64(), kTimestamp2 / 1000);
   EXPECT_EQ(result[1]["dur"].asInt64(), kDuration / 1000);
-  EXPECT_EQ(result[1]["tid"].asUInt(), kThreadID);
+  EXPECT_EQ(result[1]["tid"].asInt(), static_cast<int>(kThreadID));
   EXPECT_EQ(result[1]["cat"].asString(), kCategory);
   EXPECT_EQ(result[1]["name"].asString(), kName);
 }
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index 3c1001f..cc631c5 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -187,25 +187,28 @@
     }
   }
 
-  auto* mapping_table =
-      context_->storage->mutable_stack_profile_mapping_table();
-
-  tables::StackProfileMappingTable::Row mapping_row{};
-  mapping_row.name = context_->storage->InternString("JAVA");
-  MappingId mapping_id = mapping_table->Insert(mapping_row);
-
-  uint32_t mapping_idx = *mapping_table->id().IndexOf(mapping_id);
-
   auto paths = sequence_state.walker.FindPathsFromRoot();
-  WriteFlamegraph(sequence_state, paths, mapping_idx);
+  walkers_.emplace(
+      std::make_pair(sequence_state.current_upid, sequence_state.current_ts),
+      std::move(sequence_state.walker));
 
   sequence_state_.erase(seq_id);
 }
 
-void HeapGraphTracker::WriteFlamegraph(
-    const SequenceState& sequence_state,
-    const HeapGraphWalker::PathFromRoot& init_path,
-    uint32_t mapping_row) {
+std::unique_ptr<tables::ExperimentalFlamegraphNodesTable>
+HeapGraphTracker::BuildFlamegraph(const UniquePid current_upid,
+                                  const int64_t current_ts) {
+  auto it = walkers_.find(std::make_pair(current_upid, current_ts));
+  if (it == walkers_.end())
+    return nullptr;
+
+  std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> tbl(
+      new tables::ExperimentalFlamegraphNodesTable(
+          context_->storage->mutable_string_pool(), nullptr));
+
+  HeapGraphWalker::PathFromRoot init_path = it->second.FindPathsFromRoot();
+  auto java_mapping = context_->storage->InternString("JAVA");
+
   std::vector<int32_t> node_to_cumulative_size(init_path.nodes.size());
   std::vector<int32_t> node_to_cumulative_count(init_path.nodes.size());
   // i > 0 is to skip the artifical root node.
@@ -218,41 +221,31 @@
     node_to_cumulative_count[node.parent_id] += node_to_cumulative_count[i];
   }
 
-  std::vector<int32_t> node_to_row_id(init_path.nodes.size());
-  node_to_row_id[0] = -1;  // We use parent_id -1 for roots.
+  std::vector<uint32_t> node_to_row_idx(init_path.nodes.size());
   // i = 1 is to skip the artifical root node.
   for (size_t i = 1; i < init_path.nodes.size(); ++i) {
     const HeapGraphWalker::PathFromRoot::Node& node = init_path.nodes[i];
     PERFETTO_CHECK(node.parent_id < i);
-    const int32_t parent_row_id = node_to_row_id[node.parent_id];
+    base::Optional<uint32_t> parent_id;
+    if (node.parent_id != 0)
+      parent_id = node_to_row_idx[node.parent_id];
     const uint32_t depth = node.depth - 1;  // -1 because we do not have the
                                             // artificial root in the database.
 
-    tables::StackProfileFrameTable::Row row{};
-    PERFETTO_CHECK(node.class_name > 0);
-    row.name = StringId::Raw(static_cast<uint32_t>(node.class_name));
-    row.mapping = mapping_row;
-
-    auto id =
-        context_->storage->mutable_stack_profile_frame_table()->Insert(row);
-    int32_t frame_id = static_cast<int32_t>(id.value);
-
-    auto* callsites = context_->storage->mutable_stack_profile_callsite_table();
-    auto callsite_id = callsites->Insert({depth, parent_row_id, frame_id});
-    int32_t row_id = static_cast<int32_t>(callsite_id.value);
-    node_to_row_id[i] = row_id;
-
     tables::ExperimentalFlamegraphNodesTable::Row alloc_row{
-        sequence_state.current_ts,
-        sequence_state.current_upid,
-        row_id,
+        current_ts,
+        current_upid,
+        depth,
+        StringId::Raw(static_cast<uint32_t>(node.class_name)),
+        java_mapping,
         static_cast<int64_t>(node.count),
         static_cast<int64_t>(node_to_cumulative_count[i]),
         static_cast<int64_t>(node.size),
-        static_cast<int64_t>(node_to_cumulative_size[i])};
-    context_->storage->mutable_experimental_flamegraph_nodes_table()->Insert(
-        alloc_row);
+        static_cast<int64_t>(node_to_cumulative_size[i]),
+        parent_id};
+    node_to_row_idx[i] = *tbl->id().IndexOf(tbl->Insert(alloc_row));
   }
+  return tbl;
 }
 
 void HeapGraphTracker::MarkReachable(int64_t row) {
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.h b/src/trace_processor/importers/proto/heap_graph_tracker.h
index 71bbb8f..3558410 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.h
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.h
@@ -86,6 +86,10 @@
     return &it->second;
   }
 
+  std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> BuildFlamegraph(
+      const UniquePid current_upid,
+      const int64_t current_ts);
+
  private:
   struct SequenceState {
     SequenceState(HeapGraphTracker* tracker) : walker(tracker) {}
@@ -104,12 +108,10 @@
   SequenceState& GetOrCreateSequence(uint32_t seq_id);
   bool SetPidAndTimestamp(SequenceState* seq, UniquePid upid, int64_t ts);
 
-  void WriteFlamegraph(const SequenceState& sequence_state,
-                       const HeapGraphWalker::PathFromRoot& path,
-                       uint32_t mapping_row);
 
   TraceProcessorContext* const context_;
   std::map<uint32_t, SequenceState> sequence_state_;
+  std::map<std::pair<UniquePid, int64_t /* ts */>, HeapGraphWalker> walkers_;
 
   std::map<StringPool::Id, std::vector<int64_t>> class_to_rows_;
   std::map<StringPool::Id, std::vector<int64_t>> field_to_rows_;
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc b/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc
new file mode 100644
index 0000000..3cb5c2a
--- /dev/null
+++ b/src/trace_processor/importers/proto/heap_graph_tracker_unittest.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 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 "src/trace_processor/importers/proto/heap_graph_tracker.h"
+
+#include "perfetto/base/logging.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+using ::testing::UnorderedElementsAre;
+
+TEST(HeapGraphTrackerTest, BuildFlamegraph) {
+  //           4@A 5@B
+  //             \ /
+  //         2@Y 3@Y
+  //           \ /
+  //           1@X
+
+  constexpr uint64_t kSeqId = 1;
+  constexpr UniquePid kPid = 1;
+  constexpr int64_t kTimestamp = 1;
+
+  TraceProcessorContext context;
+  context.storage.reset(new TraceStorage());
+
+  HeapGraphTracker tracker(&context);
+
+  constexpr uint64_t kField = 1;
+
+  constexpr uint64_t kX = 1;
+  constexpr uint64_t kY = 2;
+  constexpr uint64_t kA = 3;
+  constexpr uint64_t kB = 4;
+
+  StringPool::Id field = context.storage->InternString("foo");
+  StringPool::Id x = context.storage->InternString("X");
+  StringPool::Id y = context.storage->InternString("Y");
+  StringPool::Id a = context.storage->InternString("A");
+  StringPool::Id b = context.storage->InternString("B");
+
+  tracker.AddInternedFieldName(kSeqId, kField, field);
+
+  tracker.AddInternedTypeName(kSeqId, kX, x);
+  tracker.AddInternedTypeName(kSeqId, kY, y);
+  tracker.AddInternedTypeName(kSeqId, kA, a);
+  tracker.AddInternedTypeName(kSeqId, kB, b);
+
+  {
+    HeapGraphTracker::SourceObject obj;
+    obj.object_id = 1;
+    obj.self_size = 1;
+    obj.type_id = kX;
+    HeapGraphTracker::SourceObject::Reference ref;
+    ref.field_name_id = kField;
+    ref.owned_object_id = 2;
+    obj.references.emplace_back(std::move(ref));
+
+    ref.field_name_id = kField;
+    ref.owned_object_id = 3;
+    obj.references.emplace_back(std::move(ref));
+
+    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
+  }
+
+  {
+    HeapGraphTracker::SourceObject obj;
+    obj.object_id = 2;
+    obj.self_size = 2;
+    obj.type_id = kY;
+    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
+  }
+
+  {
+    HeapGraphTracker::SourceObject obj;
+    obj.object_id = 3;
+    obj.self_size = 3;
+    obj.type_id = kY;
+    HeapGraphTracker::SourceObject::Reference ref;
+    ref.field_name_id = kField;
+    ref.owned_object_id = 4;
+    obj.references.emplace_back(std::move(ref));
+
+    ref.field_name_id = kField;
+    ref.owned_object_id = 5;
+    obj.references.emplace_back(std::move(ref));
+
+    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
+  }
+
+  {
+    HeapGraphTracker::SourceObject obj;
+    obj.object_id = 4;
+    obj.self_size = 4;
+    obj.type_id = kA;
+    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
+  }
+
+  {
+    HeapGraphTracker::SourceObject obj;
+    obj.object_id = 5;
+    obj.self_size = 5;
+    obj.type_id = kB;
+    tracker.AddObject(kSeqId, kPid, kTimestamp, std::move(obj));
+  }
+
+  HeapGraphTracker::SourceRoot root;
+  root.root_type = context.storage->InternString("ROOT");
+  root.object_ids.emplace_back(1);
+  tracker.AddRoot(kSeqId, kPid, kTimestamp, root);
+
+  tracker.FinalizeProfile(kSeqId);
+  std::unique_ptr<tables::ExperimentalFlamegraphNodesTable> flame =
+      tracker.BuildFlamegraph(kPid, kTimestamp);
+  ASSERT_NE(flame, nullptr);
+
+  auto cumulative_sizes = flame->cumulative_size().ToVectorForTesting();
+  EXPECT_THAT(cumulative_sizes, UnorderedElementsAre(15, 4, 14, 5));
+
+  auto cumulative_counts = flame->cumulative_count().ToVectorForTesting();
+  EXPECT_THAT(cumulative_counts, UnorderedElementsAre(5, 4, 1, 1));
+
+  auto sizes = flame->size().ToVectorForTesting();
+  EXPECT_THAT(sizes, UnorderedElementsAre(1, 5, 4, 5));
+
+  auto counts = flame->count().ToVectorForTesting();
+  EXPECT_THAT(counts, UnorderedElementsAre(1, 2, 1, 1));
+}
+
+}  // namespace
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/metrics/BUILD.gn b/src/trace_processor/metrics/BUILD.gn
index 537f55e..0d2db64 100644
--- a/src/trace_processor/metrics/BUILD.gn
+++ b/src/trace_processor/metrics/BUILD.gn
@@ -62,40 +62,42 @@
   public_configs = [ ":gen_config" ]
 }
 
-source_set("lib") {
-  sources = [
-    "metrics.cc",
-    "metrics.descriptor.h",
-    "metrics.h",
-  ]
-  deps = [
-    "../../../gn:default_deps",
-    "../../../gn:sqlite",
-    "../../../include/perfetto/trace_processor",
-    "../../../protos/perfetto/common:zero",
-    "../../../protos/perfetto/metrics:zero",
-    "../../../protos/perfetto/metrics/android:zero",
-    "../../../protos/perfetto/trace_processor:metrics_impl_zero",
-    "../../base",
-    "../../protozero:protozero",
-    "../sqlite",
-  ]
-  public_deps = [
-    ":gen_merged_sql_metrics",
-    "../../trace_processor:descriptors",
-  ]
-}
+if (enable_perfetto_trace_processor_sqlite) {
+  source_set("lib") {
+    sources = [
+      "metrics.cc",
+      "metrics.descriptor.h",
+      "metrics.h",
+    ]
+    deps = [
+      "../../../gn:default_deps",
+      "../../../gn:sqlite",
+      "../../../include/perfetto/trace_processor",
+      "../../../protos/perfetto/common:zero",
+      "../../../protos/perfetto/metrics:zero",
+      "../../../protos/perfetto/metrics/android:zero",
+      "../../../protos/perfetto/trace_processor:metrics_impl_zero",
+      "../../base",
+      "../../protozero:protozero",
+      "../sqlite",
+    ]
+    public_deps = [
+      ":gen_merged_sql_metrics",
+      "../../trace_processor:descriptors",
+    ]
+  }
 
-perfetto_unittest_source_set("unittests") {
-  testonly = true
-  sources = [
-    "metrics_unittest.cc",
-  ]
-  deps = [
-    ":lib",
-    "../../../gn:default_deps",
-    "../../../gn:gtest_and_gmock",
-    "../../../gn:sqlite",
-    "../../../protos/perfetto/common:zero",
-  ]
+  perfetto_unittest_source_set("unittests") {
+    testonly = true
+    sources = [
+      "metrics_unittest.cc",
+    ]
+    deps = [
+      ":lib",
+      "../../../gn:default_deps",
+      "../../../gn:gtest_and_gmock",
+      "../../../gn:sqlite",
+      "../../../protos/perfetto/common:zero",
+    ]
+  }
 }
diff --git a/src/trace_processor/metrics/android/unmapped_java_symbols.sql b/src/trace_processor/metrics/android/unmapped_java_symbols.sql
index c2e7785..7cc314f 100644
--- a/src/trace_processor/metrics/android/unmapped_java_symbols.sql
+++ b/src/trace_processor/metrics/android/unmapped_java_symbols.sql
@@ -19,7 +19,11 @@
 CREATE TABLE IF NOT EXISTS types_per_upid AS
 WITH distinct_unmapped_type_names AS (
   SELECT DISTINCT upid, type_name
-  FROM heap_graph_object WHERE deobfuscated_type_name IS NULL
+  FROM heap_graph_object
+  WHERE deobfuscated_type_name IS NULL
+  AND INSTR(type_name, '.') = 0
+  AND RTRIM(type_name, '[]') NOT IN ('byte', 'char', 'short', 'int', 'long', 'boolean', 'float', 'double')
+  AND type_name NOT LIKE '$Proxy%'
 )
 SELECT upid, RepeatedField(type_name) AS types
 FROM distinct_unmapped_type_names GROUP BY 1;
@@ -29,6 +33,8 @@
   SELECT DISTINCT upid, field_name
   FROM heap_graph_object JOIN heap_graph_reference USING (reference_set_id)
   WHERE deobfuscated_type_name IS NULL
+  AND field_name NOT LIKE '%.%.%'
+  AND field_name NOT LIKE '$Proxy%'
 )
 SELECT upid, RepeatedField(field_name) AS fields
 FROM distinct_unmapped_field_names GROUP BY 1;
diff --git a/src/trace_processor/sqlite/BUILD.gn b/src/trace_processor/sqlite/BUILD.gn
index 5a81353..418e517 100644
--- a/src/trace_processor/sqlite/BUILD.gn
+++ b/src/trace_processor/sqlite/BUILD.gn
@@ -14,42 +14,44 @@
 
 import("../../../gn/test.gni")
 
-source_set("sqlite") {
-  sources = [
-    "db_sqlite_table.cc",
-    "db_sqlite_table.h",
-    "query_constraints.cc",
-    "query_constraints.h",
-    "scoped_db.h",
-    "sqlite3_str_split.cc",
-    "sqlite3_str_split.h",
-    "sqlite_table.cc",
-    "sqlite_table.h",
-    "sqlite_utils.h",
-  ]
-  deps = [
-    "../../../gn:default_deps",
-    "../../../gn:sqlite",
-    "../../../include/perfetto/trace_processor",
-    "../../../protos/perfetto/trace/ftrace:zero",
-    "../../base",
-    "../db:lib",
-    "../types",
-  ]
-}
+if (enable_perfetto_trace_processor_sqlite) {
+  source_set("sqlite") {
+    sources = [
+      "db_sqlite_table.cc",
+      "db_sqlite_table.h",
+      "query_constraints.cc",
+      "query_constraints.h",
+      "scoped_db.h",
+      "sqlite3_str_split.cc",
+      "sqlite3_str_split.h",
+      "sqlite_table.cc",
+      "sqlite_table.h",
+      "sqlite_utils.h",
+    ]
+    deps = [
+      "../../../gn:default_deps",
+      "../../../gn:sqlite",
+      "../../../include/perfetto/trace_processor",
+      "../../../protos/perfetto/trace/ftrace:zero",
+      "../../base",
+      "../db:lib",
+      "../types",
+    ]
+  }
 
-perfetto_unittest_source_set("unittests") {
-  testonly = true
-  sources = [
-    "db_sqlite_table_unittest.cc",
-    "query_constraints_unittest.cc",
-    "sqlite3_str_split_unittest.cc",
-  ]
-  deps = [
-    ":sqlite",
-    "../../../gn:default_deps",
-    "../../../gn:gtest_and_gmock",
-    "../../../gn:sqlite",
-    "../../base",
-  ]
+  perfetto_unittest_source_set("unittests") {
+    testonly = true
+    sources = [
+      "db_sqlite_table_unittest.cc",
+      "query_constraints_unittest.cc",
+      "sqlite3_str_split_unittest.cc",
+    ]
+    deps = [
+      ":sqlite",
+      "../../../gn:default_deps",
+      "../../../gn:gtest_and_gmock",
+      "../../../gn:sqlite",
+      "../../base",
+    ]
+  }
 }
diff --git a/src/trace_processor/stack_profile_tracker.cc b/src/trace_processor/stack_profile_tracker.cc
index 7331f85..b4f8f9b 100644
--- a/src/trace_processor/stack_profile_tracker.cc
+++ b/src/trace_processor/stack_profile_tracker.cc
@@ -60,7 +60,7 @@
                                           InternedStringType::kBuildId);
   if (!opt_build_id) {
     context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
-    PERFETTO_DFATAL("Invalid string.");
+    PERFETTO_DLOG("Invalid string.");
     return base::nullopt;
   }
   const StringId raw_build_id = opt_build_id.value();
@@ -127,7 +127,7 @@
                                         InternedStringType::kFunctionName);
   if (!opt_str_id) {
     context_->storage->IncrementStats(stats::stackprofile_invalid_string_id);
-    PERFETTO_DFATAL("Invalid string.");
+    PERFETTO_DLOG("Invalid string.");
     return base::nullopt;
   }
   const StringId& str_id = opt_str_id.value();
@@ -217,7 +217,7 @@
     SourceFrameId frame_id) {
   auto it = frames_.find(frame_id);
   if (it == frames_.end()) {
-    PERFETTO_DFATAL("Invalid frame.");
+    PERFETTO_DLOG("Invalid frame.");
     return -1;
   }
   return it->second;
@@ -251,7 +251,7 @@
       if (!str) {
         context_->storage->IncrementStats(
             stats::stackprofile_invalid_string_id);
-        PERFETTO_DFATAL("Invalid string.");
+        PERFETTO_DLOG("Invalid string.");
         return base::nullopt;
       }
       return str->ToStdString();
@@ -298,8 +298,7 @@
       }
     }
     context_->storage->IncrementStats(stats::stackprofile_invalid_frame_id);
-    PERFETTO_DFATAL("Unknown frame %" PRIu64 " : %zu", frame_id,
-                    frames_.size());
+    PERFETTO_DLOG("Unknown frame %" PRIu64 " : %zu", frame_id, frames_.size());
     return res;
   }
   res = it->second;
@@ -318,8 +317,8 @@
       return res;
     }
     context_->storage->IncrementStats(stats::stackprofile_invalid_callstack_id);
-    PERFETTO_DFATAL("Unknown callstack %" PRIu64 " : %zu", callstack_id,
-                    callstacks_.size());
+    PERFETTO_DLOG("Unknown callstack %" PRIu64 " : %zu", callstack_id,
+                  callstacks_.size());
     return res;
   }
   res = it->second;
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index 7cbf445..89f8cc5 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -87,18 +87,21 @@
 
 // This will eventually go away, when we also pre-compute the cumulative
 // sizes for native heap profiles.
-#define PERFETTO_TP_HEAP_GRAPH_ALLOCATION_DEF(NAME, PARENT, C)            \
+#define PERFETTO_TP_EXPERIMENTAL_FLAMEGRAPH_NODES(NAME, PARENT, C)        \
   NAME(ExperimentalFlamegraphNodesTable, "experimental_flamegraph_nodes") \
   PERFETTO_TP_ROOT_TABLE(PARENT, C)                                       \
   C(int64_t, ts, Column::Flag::kSorted)                                   \
   C(uint32_t, upid)                                                       \
-  C(int64_t, callsite_id)                                                 \
+  C(uint32_t, depth)                                                      \
+  C(StringPool::Id, name)                                                 \
+  C(StringPool::Id, map_name)                                             \
   C(int64_t, count)                                                       \
   C(int64_t, cumulative_count)                                            \
   C(int64_t, size)                                                        \
-  C(int64_t, cumulative_size)
+  C(int64_t, cumulative_size)                                             \
+  C(base::Optional<uint32_t>, parent_id)
 
-PERFETTO_TP_TABLE(PERFETTO_TP_HEAP_GRAPH_ALLOCATION_DEF);
+PERFETTO_TP_TABLE(PERFETTO_TP_EXPERIMENTAL_FLAMEGRAPH_NODES);
 
 #define PERFETTO_TP_HEAP_GRAPH_OBJECT_DEF(NAME, PARENT, C)  \
   NAME(HeapGraphObjectTable, "heap_graph_object")           \
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 9b44058..8c6f72d 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -448,9 +448,6 @@
       *db_, &storage->heap_profile_allocation_table(),
       storage->heap_profile_allocation_table().table_name());
   DbSqliteTable::RegisterTable(
-      *db_, &storage->experimental_flamegraph_nodes_table(),
-      storage->experimental_flamegraph_nodes_table().table_name());
-  DbSqliteTable::RegisterTable(
       *db_, &storage->cpu_profile_stack_sample_table(),
       storage->cpu_profile_stack_sample_table().table_name());
   DbSqliteTable::RegisterTable(
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 8b0634b..2970d97 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -558,15 +558,6 @@
     return &heap_profile_allocation_table_;
   }
 
-  const tables::ExperimentalFlamegraphNodesTable&
-  experimental_flamegraph_nodes_table() const {
-    return experimental_flamegraph_nodes_table_;
-  }
-  tables::ExperimentalFlamegraphNodesTable*
-  mutable_experimental_flamegraph_nodes_table() {
-    return &experimental_flamegraph_nodes_table_;
-  }
-
   const tables::CpuProfileStackSampleTable& cpu_profile_stack_sample_table()
       const {
     return cpu_profile_stack_sample_table_;
@@ -611,6 +602,7 @@
   }
 
   const StringPool& string_pool() const { return string_pool_; }
+  StringPool* mutable_string_pool() { return &string_pool_; }
 
   // Number of interned strings in the pool. Includes the empty string w/ ID=0.
   size_t string_count() const { return string_pool_.size(); }
@@ -794,8 +786,6 @@
                                                                   nullptr};
   tables::HeapProfileAllocationTable heap_profile_allocation_table_{
       &string_pool_, nullptr};
-  tables::ExperimentalFlamegraphNodesTable experimental_flamegraph_nodes_table_{
-      &string_pool_, nullptr};
   tables::CpuProfileStackSampleTable cpu_profile_stack_sample_table_{
       &string_pool_, nullptr};
 
diff --git a/src/tracing/api_integrationtest.cc b/src/tracing/api_integrationtest.cc
index cfeba05..2d43bf3 100644
--- a/src/tracing/api_integrationtest.cc
+++ b/src/tracing/api_integrationtest.cc
@@ -24,6 +24,9 @@
 #include <thread>
 #include <vector>
 
+// We also want to test legacy trace events.
+#define PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 1
+
 #include "perfetto/tracing.h"
 #include "test/gtest_and_gmock.h"
 
@@ -1948,6 +1951,36 @@
   EXPECT_EQ(packets_found, 1 | 2 | 4 | 8);
 }
 
+TEST_F(PerfettoApiTest, LegacyTraceEvents) {
+  // TODO(skyostil): For now we just test that all variants of legacy trace
+  // points compile. Test actual functionality when implemented.
+
+  // Basic events.
+  TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", 123);
+  TRACE_EVENT_END2("cat", "LegacyEvent", "arg", "string", "arg2", 0.123f);
+
+  // Scoped event.
+  { TRACE_EVENT0("cat", "ScopedLegacyEvent"); }
+
+  // Event with flow (and disabled category).
+  TRACE_EVENT_WITH_FLOW0(TRACE_DISABLED_BY_DEFAULT("cat"), "LegacyFlowEvent",
+                         0xdadacafe, TRACE_EVENT_FLAG_FLOW_IN);
+
+  // Event with timestamp.
+  TRACE_EVENT_INSTANT_WITH_TIMESTAMP0("cat", "LegacyInstantEvent",
+                                      TRACE_EVENT_SCOPE_GLOBAL, 123456789ul);
+
+  // Event with id, thread id and timestamp (and dynamic name).
+  TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
+      "cat", std::string("LegacyWithIdTidAndTimestamp").c_str(), 1, 2, 3);
+
+  // Event with id.
+  TRACE_COUNTER_ID1("cat", "LegacyCounter", 1234, 9000);
+
+  // Metadata event.
+  TRACE_EVENT_METADATA1("cat", "LegacyMetadata", "obsolete", true);
+}
+
 }  // namespace
 
 PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(MockDataSource);