Merge changes I2c6ef9a4,I196e54e8

* changes:
  Do not display total percentage next to self size.
  Improve display of sizes in flamegraph.
diff --git a/include/perfetto/tracing/debug_annotation.h b/include/perfetto/tracing/debug_annotation.h
index 996861c..f13fbd9 100644
--- a/include/perfetto/tracing/debug_annotation.h
+++ b/include/perfetto/tracing/debug_annotation.h
@@ -21,6 +21,7 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 
 namespace perfetto {
@@ -56,6 +57,12 @@
 void WriteDebugAnnotation(protos::pbzero::DebugAnnotation*,
                           const DebugAnnotation&);
 
+template <typename T>
+void WriteDebugAnnotation(protos::pbzero::DebugAnnotation* annotation,
+                          const std::unique_ptr<T>& value) {
+  WriteDebugAnnotation(annotation, *value);
+}
+
 }  // namespace internal
 }  // namespace perfetto
 
diff --git a/include/perfetto/tracing/track_event_legacy.h b/include/perfetto/tracing/track_event_legacy.h
index 8513024..bf83ca4 100644
--- a/include/perfetto/tracing/track_event_legacy.h
+++ b/include/perfetto/tracing/track_event_legacy.h
@@ -23,6 +23,7 @@
 // to 1 activate the compatibility layer.
 
 #include "perfetto/base/compiler.h"
+#include "perfetto/tracing/track_event.h"
 
 #include <stdint.h>
 
@@ -118,6 +119,81 @@
 // Internal legacy trace point implementation.
 // ----------------------------------------------------------------------------
 
+namespace perfetto {
+namespace internal {
+
+class TrackEventLegacy {
+ public:
+  static constexpr protos::pbzero::TrackEvent::Type PhaseToType(char phase) {
+    // clang-format off
+    return (phase == TRACE_EVENT_PHASE_BEGIN) ?
+               protos::pbzero::TrackEvent::TYPE_SLICE_BEGIN :
+           (phase == TRACE_EVENT_PHASE_END) ?
+               protos::pbzero::TrackEvent::TYPE_SLICE_END :
+           (phase == TRACE_EVENT_PHASE_INSTANT) ?
+               protos::pbzero::TrackEvent::TYPE_INSTANT :
+           protos::pbzero::TrackEvent::TYPE_UNSPECIFIED;
+    // clang-format on
+  }
+
+  // Reduce binary size overhead by outlining most of the code for writing a
+  // legacy trace event.
+  template <typename... Args>
+  static void WriteLegacyEvent(EventContext ctx,
+                               char phase,
+                               uint32_t flags,
+                               Args&&... args) PERFETTO_NO_INLINE {
+    AddDebugAnnotations(&ctx, std::forward<Args>(args)...);
+    SetTrackIfNeeded(&ctx, flags);
+    if (PhaseToType(phase) == protos::pbzero::TrackEvent::TYPE_UNSPECIFIED) {
+      auto legacy_event = ctx.event()->set_legacy_event();
+      legacy_event->set_phase(phase);
+    }
+  }
+
+  // No arguments.
+  static void AddDebugAnnotations(EventContext*) {}
+
+  // One argument.
+  template <typename ArgType>
+  static void AddDebugAnnotations(EventContext* ctx,
+                                  const char* arg_name,
+                                  ArgType&& arg_value) {
+    TrackEventInternal::AddDebugAnnotation(ctx, arg_name, arg_value);
+  }
+
+  // Two arguments.
+  template <typename ArgType, typename ArgType2>
+  static void AddDebugAnnotations(EventContext* ctx,
+                                  const char* arg_name,
+                                  ArgType&& arg_value,
+                                  const char* arg_name2,
+                                  ArgType2&& arg_value2) {
+    TrackEventInternal::AddDebugAnnotation(ctx, arg_name, arg_value);
+    TrackEventInternal::AddDebugAnnotation(ctx, arg_name2, arg_value2);
+  }
+
+ private:
+  static void SetTrackIfNeeded(EventContext* ctx, uint32_t flags) {
+    auto scope = flags & TRACE_EVENT_FLAG_SCOPE_MASK;
+    switch (scope) {
+      case TRACE_EVENT_SCOPE_GLOBAL:
+        ctx->event()->set_track_uuid(0);
+        break;
+      case TRACE_EVENT_SCOPE_PROCESS:
+        ctx->event()->set_track_uuid(ProcessTrack::Current().uuid);
+        break;
+      default:
+      case TRACE_EVENT_SCOPE_THREAD:
+        // Thread scope is already the default.
+        break;
+    }
+  }
+};
+
+}  // namespace internal
+}  // namespace perfetto
+
 // A black hole trace point where unsupported trace events are routed.
 #define PERFETTO_INTERNAL_EVENT_NOOP(cat, name, ...) \
   do {                                               \
@@ -129,9 +205,23 @@
 
 // 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(phase, category, name, flags, ...)      \
+  PERFETTO_INTERNAL_TRACK_EVENT(                                         \
+      category, name,                                                    \
+      ::perfetto::internal::TrackEventLegacy::PhaseToType(phase),        \
+      [&](perfetto::EventContext ctx) {                                  \
+        using ::perfetto::internal::TrackEventLegacy;                    \
+        TrackEventLegacy::WriteLegacyEvent(std::move(ctx), phase, flags, \
+                                           ##__VA_ARGS__);               \
+      })
+
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...)        \
+  PERFETTO_INTERNAL_SCOPED_TRACK_EVENT(                             \
+      category, name, [&](perfetto::EventContext ctx) {             \
+        using ::perfetto::internal::TrackEventLegacy;               \
+        TrackEventLegacy::AddDebugAnnotations(&ctx, ##__VA_ARGS__); \
+      })
+
 #define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(...) \
   PERFETTO_INTERNAL_EVENT_NOOP(__VA_ARGS__)
 #define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(...) \
diff --git a/src/trace_processor/containers/bit_vector_benchmark.cc b/src/trace_processor/containers/bit_vector_benchmark.cc
index 206bc5d..2deb904 100644
--- a/src/trace_processor/containers/bit_vector_benchmark.cc
+++ b/src/trace_processor/containers/bit_vector_benchmark.cc
@@ -143,6 +143,9 @@
   static constexpr uint32_t kPoolSize = 1024 * 1024;
   std::vector<uint32_t> row_pool(kPoolSize);
   uint32_t set_bit_count = bv.GetNumBitsSet();
+  if (set_bit_count == 0)
+    return;
+
   for (uint32_t i = 0; i < kPoolSize; ++i) {
     row_pool[i] = rnd_engine() % set_bit_count;
   }
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index f96cf6e..9eb166b 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -230,8 +230,7 @@
     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.
+    const uint32_t depth = node.depth;
 
     tables::ExperimentalFlamegraphNodesTable::Row alloc_row{
         current_ts, current_upid, profile_type, depth,
diff --git a/src/trace_processor/tables/macros_benchmark.cc b/src/trace_processor/tables/macros_benchmark.cc
index 2e7bfbb..fec67ed 100644
--- a/src/trace_processor/tables/macros_benchmark.cc
+++ b/src/trace_processor/tables/macros_benchmark.cc
@@ -27,6 +27,7 @@
   PERFETTO_TP_ROOT_TABLE(PARENT, C)                  \
   C(uint32_t, root_sorted, Column::Flag::kSorted)    \
   C(uint32_t, root_non_null)                         \
+  C(uint32_t, root_non_null_2)                       \
   C(base::Optional<uint32_t>, root_nullable)
 
 PERFETTO_TP_TABLE(PERFETTO_TP_ROOT_TEST_TABLE);
@@ -200,6 +201,28 @@
 }
 BENCHMARK(BM_TableFilterRootNonNullEqMatchMany)->Apply(TableFilterArgs);
 
+static void BM_TableFilterRootMultipleNonNull(benchmark::State& state) {
+  StringPool pool;
+  RootTestTable root(&pool, nullptr);
+
+  uint32_t size = static_cast<uint32_t>(state.range(0));
+  uint32_t partitions = size / 512;
+
+  std::minstd_rand0 rnd_engine;
+  for (uint32_t i = 0; i < size; ++i) {
+    RootTestTable::Row row;
+    row.root_non_null = rnd_engine() % partitions;
+    row.root_non_null_2 = rnd_engine() % partitions;
+    root.Insert(row);
+  }
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(root.Filter(
+        {root.root_non_null().lt(4), root.root_non_null_2().lt(10)}));
+  }
+}
+BENCHMARK(BM_TableFilterRootMultipleNonNull)->Apply(TableFilterArgs);
+
 static void BM_TableFilterRootNullableEqMatchMany(benchmark::State& state) {
   StringPool pool;
   RootTestTable root(&pool, nullptr);
diff --git a/src/trace_processor/trace_storage.cc b/src/trace_processor/trace_storage.cc
index cbd01b5..74d22bf 100644
--- a/src/trace_processor/trace_storage.cc
+++ b/src/trace_processor/trace_storage.cc
@@ -147,6 +147,14 @@
                            &end_ns);
   DbTableMaybeUpdateMinMax(instant_table_.ts(), &start_ns, &end_ns);
   DbTableMaybeUpdateMinMax(android_log_table_.ts(), &start_ns, &end_ns);
+  DbTableMaybeUpdateMinMax(heap_graph_object_table_.graph_sample_ts(),
+                           &start_ns, &end_ns);
+
+  if (heap_graph_object_table_.row_count() != 0) {
+    // TODO(fmayer): Remove this.
+    // Work around UI bug that the heap marker is not displayed.
+    end_ns += 50000000;  // 50 ms
+  }
 
   if (start_ns == std::numeric_limits<int64_t>::max()) {
     return std::make_pair(0, 0);
diff --git a/src/tracing/api_integrationtest.cc b/src/tracing/api_integrationtest.cc
index c4edec1..63a682e 100644
--- a/src/tracing/api_integrationtest.cc
+++ b/src/tracing/api_integrationtest.cc
@@ -72,7 +72,8 @@
 // Trace categories used in the tests.
 PERFETTO_DEFINE_CATEGORIES(PERFETTO_CATEGORY(test),
                            PERFETTO_CATEGORY(foo),
-                           PERFETTO_CATEGORY(bar));
+                           PERFETTO_CATEGORY(bar),
+                           PERFETTO_CATEGORY(cat));
 PERFETTO_TRACK_EVENT_STATIC_STORAGE();
 
 // For testing interning of complex objects.
@@ -237,6 +238,16 @@
   WaitableTestEvent on_stop;
 };
 
+class MyDebugAnnotation : public perfetto::DebugAnnotation {
+ public:
+  ~MyDebugAnnotation() override = default;
+
+  void Add(
+      perfetto::protos::pbzero::DebugAnnotation* annotation) const override {
+    annotation->set_legacy_json_value(R"({"key": 123})");
+  }
+};
+
 // -------------------------
 // Declaration of test class
 // -------------------------
@@ -398,9 +409,16 @@
         case perfetto::protos::gen::TrackEvent::TYPE_INSTANT:
           slice += "I";
           break;
-        default:
-        case perfetto::protos::gen::TrackEvent::TYPE_UNSPECIFIED:
+        case perfetto::protos::gen::TrackEvent::TYPE_UNSPECIFIED: {
+          EXPECT_TRUE(track_event.has_legacy_event());
           EXPECT_FALSE(track_event.type());
+          auto legacy_event = track_event.legacy_event();
+          slice += "Legacy_" +
+                   std::string(1, static_cast<char>(legacy_event.phase()));
+          break;
+        }
+        default:
+          ADD_FAILURE();
       }
       if (!track_event.category_iids().empty())
         slice += ":" + categories[track_event.category_iids()[0]];
@@ -1455,23 +1473,15 @@
   ds_cfg->set_name("track_event");
   ds_cfg->set_legacy_config("test");
 
-  class MyDebugAnnotation : public perfetto::DebugAnnotation {
-   public:
-    ~MyDebugAnnotation() override = default;
-
-    void Add(
-        perfetto::protos::pbzero::DebugAnnotation* annotation) const override {
-      annotation->set_legacy_json_value(R"({"key": 123})");
-    }
-  };
-
   // Create a new trace session.
   auto* tracing_session = NewTrace(cfg);
   tracing_session->get()->StartBlocking();
 
+  std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
+
   TRACE_EVENT_BEGIN("test", "E", "custom_arg", MyDebugAnnotation());
   TRACE_EVENT_BEGIN("test", "E", "normal_arg", "x", "custom_arg",
-                    MyDebugAnnotation());
+                    std::move(owned_annotation));
   perfetto::TrackEvent::Flush();
 
   tracing_session->get()->StopBlocking();
@@ -1952,7 +1962,19 @@
   // TODO(skyostil): For now we just test that all variants of legacy trace
   // points compile. Test actual functionality when implemented.
 
+  // Setup the trace config.
+  perfetto::TraceConfig cfg;
+  cfg.set_duration_ms(500);
+  cfg.add_buffers()->set_size_kb(1024);
+  auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+  ds_cfg->set_name("track_event");
+
+  // Create a new trace session.
+  auto* tracing_session = NewTrace(cfg);
+  tracing_session->get()->StartBlocking();
+
   // Basic events.
+  TRACE_EVENT_INSTANT0("cat", "LegacyEvent", TRACE_EVENT_SCOPE_GLOBAL);
   TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", 123);
   TRACE_EVENT_END2("cat", "LegacyEvent", "arg", "string", "arg2", 0.123f);
 
@@ -1972,10 +1994,79 @@
       "cat", std::string("LegacyWithIdTidAndTimestamp").c_str(), 1, 2, 3);
 
   // Event with id.
-  TRACE_COUNTER_ID1("cat", "LegacyCounter", 1234, 9000);
+  TRACE_COUNTER1("cat", "LegacyCounter", 1234);
+  TRACE_COUNTER_ID1("cat", "LegacyCounterWithId", 1234, 9000);
 
   // Metadata event.
   TRACE_EVENT_METADATA1("cat", "LegacyMetadata", "obsolete", true);
+
+  perfetto::TrackEvent::Flush();
+  tracing_session->get()->StopBlocking();
+  auto slices = ReadSlicesFromTrace(tracing_session->get());
+  EXPECT_THAT(
+      slices,
+      ElementsAre("I:cat.LegacyEvent", "B:cat.LegacyEvent(arg=(int)123)",
+                  "E.LegacyEvent(arg=(string)string,arg2=(double)0.123)",
+                  "B:cat.ScopedLegacyEvent", "E",
+                  "Legacy_C:cat.LegacyCounter(value=(int)1234)"));
+}
+
+TEST_F(PerfettoApiTest, LegacyTraceEventsWithCustomAnnotation) {
+  // Setup the trace config.
+  perfetto::TraceConfig cfg;
+  cfg.set_duration_ms(500);
+  cfg.add_buffers()->set_size_kb(1024);
+  auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+  ds_cfg->set_name("track_event");
+
+  // Create a new trace session.
+  auto* tracing_session = NewTrace(cfg);
+  tracing_session->get()->StartBlocking();
+
+  MyDebugAnnotation annotation;
+  TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", annotation);
+
+  std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
+  TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", std::move(owned_annotation));
+
+  perfetto::TrackEvent::Flush();
+  tracing_session->get()->StopBlocking();
+  auto slices = ReadSlicesFromTrace(tracing_session->get());
+  EXPECT_THAT(slices,
+              ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})",
+                          "B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
+}
+
+TEST_F(PerfettoApiTest, LegacyTraceEventsWithConcurrentSessions) {
+  // Make sure that a uniquely owned debug annotation can be written into
+  // multiple concurrent tracing sessions.
+
+  // Setup the trace config.
+  perfetto::TraceConfig cfg;
+  cfg.set_duration_ms(500);
+  cfg.add_buffers()->set_size_kb(1024);
+  auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+  ds_cfg->set_name("track_event");
+
+  auto* tracing_session = NewTrace(cfg);
+  tracing_session->get()->StartBlocking();
+
+  auto* tracing_session2 = NewTrace(cfg);
+  tracing_session2->get()->StartBlocking();
+
+  std::unique_ptr<MyDebugAnnotation> owned_annotation(new MyDebugAnnotation());
+  TRACE_EVENT_BEGIN1("cat", "LegacyEvent", "arg", std::move(owned_annotation));
+
+  perfetto::TrackEvent::Flush();
+  tracing_session->get()->StopBlocking();
+  auto slices = ReadSlicesFromTrace(tracing_session->get());
+  EXPECT_THAT(slices,
+              ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
+
+  tracing_session2->get()->StopBlocking();
+  slices = ReadSlicesFromTrace(tracing_session2->get());
+  EXPECT_THAT(slices,
+              ElementsAre("B:cat.LegacyEvent(arg=(json){\"key\": 123})"));
 }
 
 }  // namespace
diff --git a/src/tracing/internal/track_event_internal.cc b/src/tracing/internal/track_event_internal.cc
index 9a84aeb..4c0c86b 100644
--- a/src/tracing/internal/track_event_internal.cc
+++ b/src/tracing/internal/track_event_internal.cc
@@ -202,7 +202,8 @@
   EventContext ctx(std::move(packet), incr_state);
 
   auto track_event = ctx.event();
-  track_event->set_type(type);
+  if (type != protos::pbzero::TrackEvent::TYPE_UNSPECIFIED)
+    track_event->set_type(type);
 
   // We assume that |category| and |name| point to strings with static lifetime.
   // This means we can use their addresses as interning keys.
diff --git a/src/tracing/test/tracing_module.cc b/src/tracing/test/tracing_module.cc
index 7c10d4e..d4fef2e 100644
--- a/src/tracing/test/tracing_module.cc
+++ b/src/tracing/test/tracing_module.cc
@@ -89,4 +89,18 @@
   puts("Hello");
 }
 
+void FunctionWithOneLegacyEvent() {
+  TRACE_EVENT_BEGIN("cat1", "LegacyEventWithArgs", "arg1", 42, "arg2", .5f);
+  // Simulates the non-tracing work of this function, which should take priority
+  // over the above trace event in terms of instruction scheduling.
+  puts("Hello");
+}
+
+void FunctionWithOneScopedLegacyEvent() {
+  TRACE_EVENT("cat1", "ScopedLegacyEventWithArgs", "arg1", 42, "arg2", .5f);
+  // Simulates the non-tracing work of this function, which should take priority
+  // over the above trace event in terms of instruction scheduling.
+  puts("Hello");
+}
+
 }  // namespace tracing_module
diff --git a/src/tracing/test/tracing_module.h b/src/tracing/test/tracing_module.h
index c005a6f..7ed9364 100644
--- a/src/tracing/test/tracing_module.h
+++ b/src/tracing/test/tracing_module.h
@@ -39,6 +39,10 @@
 void FunctionWithOneTrackEventWithDebugAnnotations();
 void FunctionWithOneTrackEventWithCustomTrack();
 
+// Legacy events.
+void FunctionWithOneLegacyEvent();
+void FunctionWithOneScopedLegacyEvent();
+
 }  // namespace tracing_module
 
 #endif  // SRC_TRACING_TEST_TRACING_MODULE_H_
diff --git a/src/tracing/test/tracing_module_categories.h b/src/tracing/test/tracing_module_categories.h
index f776894..b492db8 100644
--- a/src/tracing/test/tracing_module_categories.h
+++ b/src/tracing/test/tracing_module_categories.h
@@ -23,6 +23,7 @@
 // categories can be written to the same trace writer.
 
 #define PERFETTO_TRACK_EVENT_NAMESPACE tracing_module
+#define PERFETTO_ENABLE_LEGACY_TRACE_EVENTS 1
 
 #include "perfetto/tracing.h"
 
diff --git a/test/trace_processor/heap_graph_flamegraph_system-server-heap-graph.out b/test/trace_processor/heap_graph_flamegraph_system-server-heap-graph.out
index 102c246..8f822d1 100644
--- a/test/trace_processor/heap_graph_flamegraph_system-server-heap-graph.out
+++ b/test/trace_processor/heap_graph_flamegraph_system-server-heap-graph.out
@@ -1,11 +1,11 @@
 "id","depth","name","map_name","count","cumulative_count","size","cumulative_size","parent_id"
-0,4294967295,"java.lang.Class<boolean>","JAVA",2,4,240,276,"[NULL]"
-1,0,"java.lang.Object[]","JAVA",1,1,12,12,0
-2,0,"java.lang.String","JAVA",1,1,24,24,0
-3,4294967295,"java.lang.Class<byte>","JAVA",3,4,360,384,"[NULL]"
-4,0,"java.lang.String","JAVA",1,1,24,24,3
-5,4294967295,"java.lang.Class<short>","JAVA",2,3,240,264,"[NULL]"
-6,0,"java.lang.String","JAVA",1,1,24,24,5
-7,4294967295,"java.lang.Class<char>","JAVA",2,3,240,264,"[NULL]"
-8,0,"java.lang.String","JAVA",1,1,24,24,7
-9,4294967295,"java.lang.Class<int>","JAVA",2,3,240,264,"[NULL]"
+0,0,"java.lang.Class<boolean>","JAVA",2,4,240,276,"[NULL]"
+1,1,"java.lang.Object[]","JAVA",1,1,12,12,0
+2,1,"java.lang.String","JAVA",1,1,24,24,0
+3,0,"java.lang.Class<byte>","JAVA",3,4,360,384,"[NULL]"
+4,1,"java.lang.String","JAVA",1,1,24,24,3
+5,0,"java.lang.Class<short>","JAVA",2,3,240,264,"[NULL]"
+6,1,"java.lang.String","JAVA",1,1,24,24,5
+7,0,"java.lang.Class<char>","JAVA",2,3,240,264,"[NULL]"
+8,1,"java.lang.String","JAVA",1,1,24,24,7
+9,0,"java.lang.Class<int>","JAVA",2,3,240,264,"[NULL]"
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index c5f7f63..8e43ca5 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -426,18 +426,26 @@
       },
 
   selectHeapProfile(
-      state: StateDraft, args: {id: number, upid: number, ts: number}): void {
-    state.currentSelection =
-        {kind: 'HEAP_PROFILE', id: args.id, upid: args.upid, ts: args.ts};
+      state: StateDraft,
+      args: {id: number, upid: number, ts: number, type: string}): void {
+    state.currentSelection = {
+      kind: 'HEAP_PROFILE',
+      id: args.id,
+      upid: args.upid,
+      ts: args.ts,
+      type: args.type
+    };
   },
 
   showHeapProfileFlamegraph(
-      state: StateDraft, args: {id: number, upid: number, ts: number}): void {
+      state: StateDraft,
+      args: {id: number, upid: number, ts: number, type: string}): void {
     state.currentHeapProfileFlamegraph = {
       kind: 'HEAP_PROFILE_FLAMEGRAPH',
       id: args.id,
       upid: args.upid,
       ts: args.ts,
+      type: args.type,
     };
   },
 
diff --git a/ui/src/common/state.ts b/ui/src/common/state.ts
index 2b6d2b2..b7f2f40 100644
--- a/ui/src/common/state.ts
+++ b/ui/src/common/state.ts
@@ -163,6 +163,7 @@
   id: number;
   upid: number;
   ts: number;
+  type: string;
 }
 
 export interface HeapProfileFlamegraph {
@@ -170,6 +171,7 @@
   id: number;
   upid: number;
   ts: number;
+  type: string;
   expandedCallsite?: CallsiteInfo;
   viewingOption?: string;
 }
diff --git a/ui/src/controller/heap_profile_controller.ts b/ui/src/controller/heap_profile_controller.ts
index eadb704..2f5d5f7 100644
--- a/ui/src/controller/heap_profile_controller.ts
+++ b/ui/src/controller/heap_profile_controller.ts
@@ -85,7 +85,8 @@
                           selectedHeapProfile.viewingOption :
                           DEFAULT_VIEWING_OPTION,
                       selection.ts,
-                      selectedHeapProfile.upid)
+                      selectedHeapProfile.upid,
+                      selectedHeapProfile.type)
                   .then(flamegraphData => {
                     if (flamegraphData !== undefined && selection &&
                         selection.kind === selectedHeapProfile.kind &&
@@ -119,6 +120,7 @@
       id: heapProfile.id,
       upid: heapProfile.upid,
       ts: heapProfile.ts,
+      type: heapProfile.type,
       expandedCallsite: heapProfile.expandedCallsite,
       viewingOption: heapProfile.viewingOption
     };
@@ -130,6 +132,7 @@
          (this.lastSelectedHeapProfile !== undefined &&
           (this.lastSelectedHeapProfile.id !== selection.id ||
            this.lastSelectedHeapProfile.ts !== selection.ts ||
+           this.lastSelectedHeapProfile.type !== selection.type ||
            this.lastSelectedHeapProfile.upid !== selection.upid ||
            this.lastSelectedHeapProfile.viewingOption !==
                selection.viewingOption ||
@@ -151,8 +154,8 @@
 
 
   async getFlamegraphData(
-      baseKey: string, viewingOption: string, ts: number,
-      upid: number): Promise<CallsiteInfo[]> {
+      baseKey: string, viewingOption: string, ts: number, upid: number,
+      type: string): Promise<CallsiteInfo[]> {
     let currentData: CallsiteInfo[];
     const key = `${baseKey}-${viewingOption}`;
     if (this.flamegraphDatasets.has(key)) {
@@ -163,7 +166,7 @@
       // Collecting data for drawing flamegraph for selected heap profile.
       // Data needs to be in following format:
       // id, name, parent_id, depth, total_size
-      const tableName = await this.prepareViewsAndTables(ts, upid);
+      const tableName = await this.prepareViewsAndTables(ts, upid, type);
       currentData =
           await this.getFlamegraphDataFromTables(tableName, viewingOption);
       this.flamegraphDatasets.set(key, currentData);
@@ -201,7 +204,7 @@
     }
 
     const callsites = await this.args.engine.query(
-        `SELECT id, name, parent_id, depth, cumulative_size,
+        `SELECT id, name, IFNULL(parent_id, -1), depth, cumulative_size,
         cumulative_alloc_size, cumulative_count,
         cumulative_alloc_count, map_name, size from ${tableName} ${orderBy}`);
 
@@ -227,7 +230,7 @@
     return flamegraphData;
   }
 
-  private async prepareViewsAndTables(ts: number, upid: number):
+  private async prepareViewsAndTables(ts: number, upid: number, type: string):
       Promise<string> {
     // Creating unique names for views so we can reuse and not delete them
     // for each marker.
@@ -239,7 +242,7 @@
         select id, name, map_name, parent_id, depth, cumulative_size,
           cumulative_alloc_size, cumulative_count, cumulative_alloc_count,
           size, alloc_size, count, alloc_count
-        from experimental_flamegraph(${ts}, ${upid}, 'native')`);
+        from experimental_flamegraph(${ts}, ${upid}, '${type}')`);
     return tableNameGroupedCallsitesForFlamegraph;
   }
 
diff --git a/ui/src/controller/trace_controller.ts b/ui/src/controller/trace_controller.ts
index c5b6130..76acaa9 100644
--- a/ui/src/controller/trace_controller.ts
+++ b/ui/src/controller/trace_controller.ts
@@ -407,7 +407,9 @@
     }
 
     const heapProfiles = await engine.query(`
-      select distinct(upid) from heap_profile_allocation`);
+      select distinct(upid) from heap_profile_allocation
+      union
+      select distinct(upid) from heap_graph_object`);
 
     const heapUpids: Set<number> = new Set();
     for (let i = 0; i < heapProfiles.numRecords; i++) {
diff --git a/ui/src/tracks/heap_profile/common.ts b/ui/src/tracks/heap_profile/common.ts
index fc9da62..0a8a16d 100644
--- a/ui/src/tracks/heap_profile/common.ts
+++ b/ui/src/tracks/heap_profile/common.ts
@@ -17,6 +17,7 @@
 
 export interface Data extends TrackData {
   tsStarts: Float64Array;
+  types: string[];
 }
 
 export interface Config {
diff --git a/ui/src/tracks/heap_profile/controller.ts b/ui/src/tracks/heap_profile/controller.ts
index 61ad335..bab0b15 100644
--- a/ui/src/tracks/heap_profile/controller.ts
+++ b/ui/src/tracks/heap_profile/controller.ts
@@ -28,11 +28,23 @@
   async onBoundsChange(start: number, end: number, resolution: number):
       Promise<Data> {
     if (this.config.upid === undefined) {
-      return {start, end, resolution, length: 0, tsStarts: new Float64Array()};
+      return {
+        start,
+        end,
+        resolution,
+        length: 0,
+        tsStarts: new Float64Array(),
+        types: new Array<string>()
+      };
     }
     const result = await this.query(`
-    select distinct(ts) from heap_profile_allocation where upid = ${
-        this.config.upid}`);
+    select * from
+    (select distinct(ts) as ts, 'native' as type from heap_profile_allocation
+     where upid = ${this.config.upid}
+        union
+        select distinct(graph_sample_ts) as ts, 'graph' as type from
+        heap_graph_object
+        where upid = ${this.config.upid}) order by ts`);
     const numRows = +result.numRecords;
     const data: Data = {
       start,
@@ -40,10 +52,12 @@
       resolution,
       length: numRows,
       tsStarts: new Float64Array(numRows),
+      types: new Array<string>(numRows),
     };
 
     for (let row = 0; row < numRows; row++) {
       data.tsStarts[row] = +result.columns[0].longValues![row];
+      data.types[row] = result.columns[1].stringValues![row];
     }
 
     return data;
diff --git a/ui/src/tracks/heap_profile/frontend.ts b/ui/src/tracks/heap_profile/frontend.ts
index 8eaba5e..86d177e 100644
--- a/ui/src/tracks/heap_profile/frontend.ts
+++ b/ui/src/tracks/heap_profile/frontend.ts
@@ -118,10 +118,11 @@
 
     if (index !== -1) {
       const ts = data.tsStarts[index];
+      const type = data.types[index];
       globals.dispatch(Actions.showHeapProfileFlamegraph(
-          {id: index, upid: this.config.upid, ts}));
-      globals.makeSelection(
-          Actions.selectHeapProfile({id: index, upid: this.config.upid, ts}));
+          {id: index, upid: this.config.upid, ts, type}));
+      globals.makeSelection(Actions.selectHeapProfile(
+          {id: index, upid: this.config.upid, ts, type}));
       return true;
     }
     return false;