trace_processor: add track_id column to slice table

This CL adds the track_id column to the slice table; this column
is always filled and contains the track id associated with the slice.

This CL also changes the slice tracker to use the track id instead
of ref + ref_type to figure out the nesting of tracks.

Context: go/perfetto-tp-refactor
Bug: 135177627
Change-Id: I9e82425b2a9cdce57ef57fdb26e56b4b56cdae98
diff --git a/src/trace_processor/export_json_unittest.cc b/src/trace_processor/export_json_unittest.cc
index 4c41255..5e9cd14 100644
--- a/src/trace_processor/export_json_unittest.cc
+++ b/src/trace_processor/export_json_unittest.cc
@@ -67,13 +67,15 @@
   const int64_t kThreadID = 100;
   const char* kCategory = "cat";
   const char* kName = "name";
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   UniqueTid utid = storage.AddEmptyThread(kThreadID);
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
-  storage.mutable_nestable_slices()->AddSlice(
-      kTimestamp, kDuration, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(kTimestamp, kDuration, track,
+                                              utid, RefType::kRefUtid, cat_id,
+                                              name_id, 0, 0, 0);
   storage.mutable_thread_slices()->AddThreadSlice(
       0, kThreadTimestamp, kThreadDuration, kThreadInstructionCount,
       kThreadInstructionDelta);
@@ -112,13 +114,15 @@
   const int64_t kThreadID = 100;
   const char* kCategory = "cat";
   const char* kName = "name";
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   UniqueTid utid = storage.AddEmptyThread(kThreadID);
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
-  storage.mutable_nestable_slices()->AddSlice(
-      kTimestamp, kDuration, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(kTimestamp, kDuration, track,
+                                              utid, RefType::kRefUtid, cat_id,
+                                              name_id, 0, 0, 0);
   storage.mutable_thread_slices()->AddThreadSlice(
       0, kThreadTimestamp, kThreadDuration, kThreadInstructionCount,
       kThreadInstructionDelta);
@@ -176,11 +180,13 @@
 }
 
 TEST(ExportJsonTest, WrongRefType) {
+  constexpr TrackId track = 22;
+
   TraceStorage storage;
   StringId cat_id = storage.InternString("cat");
   StringId name_id = storage.InternString("name");
-  storage.mutable_nestable_slices()->AddSlice(0, 0, 0, RefType::kRefCpuId,
-                                              cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(
+      0, 0, track, 0, RefType::kRefCpuId, cat_id, name_id, 0, 0, 0);
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
@@ -339,13 +345,14 @@
   const char* kCategory = "cat";
   const char* kName = "name";
   const char* kSrc = "source_file.cc";
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   UniqueTid utid = storage.AddEmptyThread(0);
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
-  storage.mutable_nestable_slices()->AddSlice(0, 0, utid, RefType::kRefUtid,
-                                              cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(
+      0, 0, track, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
 
   StringId arg_key_id =
       storage.InternString(base::StringView("task.posted_from.file_name"));
@@ -378,13 +385,14 @@
   const char* kCategory = "cat";
   const char* kName = "name";
   double kValues[] = {1.234, 2.345};
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   UniqueTid utid = storage.AddEmptyThread(0);
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
-  storage.mutable_nestable_slices()->AddSlice(0, 0, utid, RefType::kRefUtid,
-                                              cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(
+      0, 0, track, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
 
   StringId arg_flat_key_id =
       storage.InternString(base::StringView("debug.draw_duration_ms"));
@@ -427,13 +435,14 @@
   const char* kName = "name";
   uint64_t kValue0 = 1;
   uint64_t kValue1 = std::numeric_limits<uint64_t>::max();
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   UniqueTid utid = storage.AddEmptyThread(0);
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
-  storage.mutable_nestable_slices()->AddSlice(0, 0, utid, RefType::kRefUtid,
-                                              cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(
+      0, 0, track, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
 
   StringId arg_key0_id = storage.InternString(base::StringView("arg0"));
   StringId arg_key1_id = storage.InternString(base::StringView("arg1"));
@@ -470,13 +479,14 @@
   const char* kCategory = "cat";
   const char* kName = "name";
   int kValues[] = {123, 234};
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   UniqueTid utid = storage.AddEmptyThread(0);
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
-  storage.mutable_nestable_slices()->AddSlice(0, 0, utid, RefType::kRefUtid,
-                                              cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(
+      0, 0, track, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
 
   StringId arg_flat_key_id = storage.InternString(base::StringView("a.b"));
   StringId arg_key0_id = storage.InternString(base::StringView("a[0].b"));
@@ -515,13 +525,14 @@
   const char* kCategory = "cat";
   const char* kName = "name";
   int kValues[] = {123, 234};
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   UniqueTid utid = storage.AddEmptyThread(0);
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
-  storage.mutable_nestable_slices()->AddSlice(0, 0, utid, RefType::kRefUtid,
-                                              cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(
+      0, 0, track, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
 
   StringId arg_flat_key_id = storage.InternString(base::StringView("a"));
   StringId arg_key0_id = storage.InternString(base::StringView("a[0][0]"));
@@ -560,13 +571,14 @@
 TEST(ExportJsonTest, StorageWithLegacyJsonArgs) {
   const char* kCategory = "cat";
   const char* kName = "name";
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   UniqueTid utid = storage.AddEmptyThread(0);
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
-  storage.mutable_nestable_slices()->AddSlice(0, 0, utid, RefType::kRefUtid,
-                                              cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(
+      0, 0, track, utid, RefType::kRefUtid, cat_id, name_id, 0, 0, 0);
 
   StringId arg_key_id = storage.InternString(base::StringView("a"));
   StringId arg_value_id = storage.InternString(base::StringView("{\"b\":123}"));
@@ -598,12 +610,13 @@
   const int64_t kTimestamp = 10000000;
   const char* kCategory = "cat";
   const char* kName = "name";
+  constexpr TrackId track = 22;
 
   TraceStorage storage;
   StringId cat_id = storage.InternString(base::StringView(kCategory));
   StringId name_id = storage.InternString(base::StringView(kName));
   storage.mutable_nestable_slices()->AddSlice(
-      kTimestamp, 0, 0, RefType::kRefNoRef, cat_id, name_id, 0, 0, 0);
+      kTimestamp, 0, track, 0, RefType::kRefNoRef, cat_id, name_id, 0, 0, 0);
 
   base::TempFile temp_file = base::TempFile::Create();
   FILE* output = fopen(temp_file.path().c_str(), "w+");
@@ -643,8 +656,8 @@
   TrackId track_id = storage.mutable_process_track_table()->Insert(track);
 
   storage.mutable_nestable_slices()->AddSlice(kTimestamp, kDuration, track_id,
-                                              RefType::kRefTrack, cat_id,
-                                              name_id, 0, 0, 0);
+                                              track_id, RefType::kRefTrack,
+                                              cat_id, name_id, 0, 0, 0);
   StringId arg_key_id = storage.InternString(base::StringView(kArgName));
   TraceStorage::Args::Arg arg;
   arg.flat_key = arg_key_id;
@@ -706,8 +719,8 @@
   TrackId track_id = storage.mutable_process_track_table()->Insert(track);
 
   auto slice_id = storage.mutable_nestable_slices()->AddSlice(
-      kTimestamp, kDuration, track_id, RefType::kRefTrack, cat_id, name_id, 0,
-      0, 0);
+      kTimestamp, kDuration, track_id, track_id, RefType::kRefTrack, cat_id,
+      name_id, 0, 0, 0);
   storage.mutable_virtual_track_slices()->AddVirtualTrackSlice(
       slice_id, kThreadTimestamp, kThreadDuration, 0, 0);
 
@@ -763,8 +776,8 @@
   TrackId track_id = storage.mutable_process_track_table()->Insert(track);
 
   auto slice_id = storage.mutable_nestable_slices()->AddSlice(
-      kTimestamp, kDuration, track_id, RefType::kRefTrack, cat_id, name_id, 0,
-      0, 0);
+      kTimestamp, kDuration, track_id, track_id, RefType::kRefTrack, cat_id,
+      name_id, 0, 0, 0);
   storage.mutable_virtual_track_slices()->AddVirtualTrackSlice(
       slice_id, kThreadTimestamp, kThreadDuration, 0, 0);
 
@@ -807,8 +820,9 @@
   track.upid = upid;
   TrackId track_id = storage.mutable_process_track_table()->Insert(track);
 
-  storage.mutable_nestable_slices()->AddSlice(
-      kTimestamp, 0, track_id, RefType::kRefTrack, cat_id, name_id, 0, 0, 0);
+  storage.mutable_nestable_slices()->AddSlice(kTimestamp, 0, track_id, track_id,
+                                              RefType::kRefTrack, cat_id,
+                                              name_id, 0, 0, 0);
   StringId arg_key_id = storage.InternString(base::StringView("arg_name"));
   TraceStorage::Args::Arg arg;
   arg.flat_key = arg_key_id;
diff --git a/src/trace_processor/fuchsia_trace_parser.cc b/src/trace_processor/fuchsia_trace_parser.cc
index 9afcfe8..74df7f3 100644
--- a/src/trace_processor/fuchsia_trace_parser.cc
+++ b/src/trace_processor/fuchsia_trace_parser.cc
@@ -197,9 +197,6 @@
           UniqueTid utid =
               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
                                   static_cast<uint32_t>(tinfo.pid));
-          // TODO(lalitm): make use of this track id.
-          TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-          perfetto::base::ignore_result(track_id);
           RowId row = context_->event_tracker->PushInstant(ts, name, 0, utid,
                                                            RefType::kRefUtid);
           for (const Arg& arg : args) {
@@ -260,7 +257,7 @@
                   ts, counter_value,
                   context_->storage->InternString(
                       base::StringView(counter_name_str)),
-                  utid, kRefUtid);
+                  utid, RefType::kRefUtid);
             }
           }
           break;
@@ -269,23 +266,19 @@
           UniqueTid utid =
               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
                                   static_cast<uint32_t>(tinfo.pid));
-          // TODO(lalitm): make use of this track id.
           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-          perfetto::base::ignore_result(track_id);
-          slices->Begin(ts, utid, RefType::kRefUtid, cat, name);
+          slices->Begin(ts, track_id, utid, RefType::kRefUtid, cat, name);
           break;
         }
         case kDurationEnd: {
           UniqueTid utid =
               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
                                   static_cast<uint32_t>(tinfo.pid));
-          // TODO(lalitm): make use of this track id.
           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-          perfetto::base::ignore_result(track_id);
           // TODO(b/131181693): |cat| and |name| are not passed here so that
           // if two slices end at the same timestep, the slices get closed in
           // the correct order regardless of which end event is processed first.
-          slices->End(ts, utid, RefType::kRefUtid);
+          slices->End(ts, track_id);
           break;
         }
         case kDurationComplete: {
@@ -294,17 +287,16 @@
           UniqueTid utid =
               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
                                   static_cast<uint32_t>(tinfo.pid));
-          // TODO(lalitm): make use of this track id.
           TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-          perfetto::base::ignore_result(track_id);
-          slices->Scoped(ts, utid, RefType::kRefUtid, cat, name, end_ts - ts);
+          slices->Scoped(ts, track_id, utid, RefType::kRefUtid, cat, name,
+                         end_ts - ts);
           break;
         }
         case kAsyncBegin: {
           int64_t correlation_id = static_cast<int64_t>(*current++);
           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
               name, correlation_id);
-          slices->Begin(ts, track_id, RefType::kRefTrack, cat, name);
+          slices->Begin(ts, track_id, track_id, RefType::kRefTrack, cat, name);
           break;
         }
         case kAsyncInstant: {
@@ -328,7 +320,7 @@
           int64_t correlation_id = static_cast<int64_t>(*current++);
           TrackId track_id = context_->track_tracker->InternFuchsiaAsyncTrack(
               name, correlation_id);
-          slices->End(ts, track_id, RefType::kRefTrack, cat, name);
+          slices->End(ts, track_id, cat, name);
           break;
         }
       }
diff --git a/src/trace_processor/graphics_event_parser.cc b/src/trace_processor/graphics_event_parser.cc
index 6044d2f..f6b8eae 100644
--- a/src/trace_processor/graphics_event_parser.cc
+++ b/src/trace_processor/graphics_event_parser.cc
@@ -192,9 +192,10 @@
       snprintf(buffer, 64, "render stage(%zu)", stage_id);
       stage_name = context_->storage->InternString(buffer);
     }
+    TrackId track_id =
+        gpu_hw_queue_ids_[static_cast<size_t>(event.hw_queue_id())];
     const auto slice_id = context_->slice_tracker->Scoped(
-        ts, gpu_hw_queue_ids_[static_cast<size_t>(event.hw_queue_id())],
-        RefType::kRefTrack, 0 /* cat */, stage_name,
+        ts, track_id, track_id, RefType::kRefTrack, 0 /* cat */, stage_name,
         static_cast<int64_t>(event.duration()), args_callback);
 
     context_->storage->mutable_gpu_slice_table()->Insert(
@@ -270,8 +271,9 @@
   TrackId track_id = context_->track_tracker->InternGpuTrack(track);
 
   const auto slice_id = context_->slice_tracker->Scoped(
-      timestamp, track_id, RefType::kRefTrack, 0 /* cat */, event_name_id,
-      duration, [this, layer_name_id](ArgsTracker* args_tracker, RowId row_id) {
+      timestamp, track_id, track_id, RefType::kRefTrack, 0 /* cat */,
+      event_name_id, duration,
+      [this, layer_name_id](ArgsTracker* args_tracker, RowId row_id) {
         args_tracker->AddArg(row_id, layer_name_key_id_, layer_name_key_id_,
                              Variadic::String(layer_name_id));
       });
diff --git a/src/trace_processor/json_trace_parser.cc b/src/trace_processor/json_trace_parser.cc
index 1f0dbb4..54a548f 100644
--- a/src/trace_processor/json_trace_parser.cc
+++ b/src/trace_processor/json_trace_parser.cc
@@ -87,17 +87,14 @@
 
   switch (phase) {
     case 'B': {  // TRACE_EVENT_BEGIN.
-      // TODO(lalitm): make use of this track id.
       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-      perfetto::base::ignore_result(track_id);
-      slice_tracker->Begin(timestamp, utid, RefType::kRefUtid, cat_id, name_id);
+      slice_tracker->Begin(timestamp, track_id, utid, RefType::kRefUtid, cat_id,
+                           name_id);
       break;
     }
     case 'E': {  // TRACE_EVENT_END.
-      // TODO(lalitm): make use of this track id.
       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-      perfetto::base::ignore_result(track_id);
-      slice_tracker->End(timestamp, utid, RefType::kRefUtid, cat_id, name_id);
+      slice_tracker->End(timestamp, track_id, cat_id, name_id);
       break;
     }
     case 'X': {  // TRACE_EVENT (scoped event).
@@ -105,11 +102,9 @@
           json_trace_utils::CoerceToNs(value["dur"]);
       if (!opt_dur.has_value())
         return;
-      // TODO(lalitm): make use of this track id.
       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-      perfetto::base::ignore_result(track_id);
-      slice_tracker->Scoped(timestamp, utid, RefType::kRefUtid, cat_id, name_id,
-                            opt_dur.value());
+      slice_tracker->Scoped(timestamp, track_id, utid, RefType::kRefUtid,
+                            cat_id, name_id, opt_dur.value());
       break;
     }
     case 'M': {  // Metadata events (process and thread names).
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index b496848..5b4e3be 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -1893,9 +1893,9 @@
         return;
       }
 
-      // TODO(lalitm): Associate thread slices with track instead.
-      auto opt_slice_id = slice_tracker->Begin(
-          ts, *utid, RefType::kRefUtid, category_id, name_id, args_callback);
+      auto opt_slice_id =
+          slice_tracker->Begin(ts, track_id, *utid, RefType::kRefUtid,
+                               category_id, name_id, args_callback);
       if (opt_slice_id.has_value()) {
         auto* thread_slices = storage->mutable_thread_slices();
         PERFETTO_DCHECK(!thread_slices->slice_count() ||
@@ -1914,9 +1914,8 @@
         return;
       }
 
-      // TODO(lalitm): Associate thread slices with track instead.
-      auto opt_slice_id = slice_tracker->End(
-          ts, *utid, RefType::kRefUtid, category_id, name_id, args_callback);
+      auto opt_slice_id =
+          slice_tracker->End(ts, track_id, category_id, name_id, args_callback);
       if (opt_slice_id.has_value()) {
         auto* thread_slices = storage->mutable_thread_slices();
         thread_slices->UpdateThreadDeltasForSliceId(opt_slice_id.value(), tts,
@@ -1934,10 +1933,9 @@
       auto duration_ns = legacy_event.duration_us() * 1000;
       if (duration_ns < 0)
         return;
-      // TODO(lalitm): Associate thread slices with track instead.
-      auto opt_slice_id =
-          slice_tracker->Scoped(ts, *utid, RefType::kRefUtid, category_id,
-                                name_id, duration_ns, args_callback);
+      auto opt_slice_id = slice_tracker->Scoped(
+          ts, track_id, *utid, RefType::kRefUtid, category_id, name_id,
+          duration_ns, args_callback);
       if (opt_slice_id.has_value()) {
         auto* thread_slices = storage->mutable_thread_slices();
         PERFETTO_DCHECK(!thread_slices->slice_count() ||
@@ -1961,9 +1959,9 @@
         case LegacyEvent::SCOPE_UNSPECIFIED:
         case LegacyEvent::SCOPE_THREAD: {
           // TODO(lalitm): Associate thread slices with track instead.
-          auto opt_slice_id =
-              slice_tracker->Scoped(ts, *utid, RefType::kRefUtid, category_id,
-                                    name_id, duration_ns, args_callback);
+          auto opt_slice_id = slice_tracker->Scoped(
+              ts, track_id, *utid, RefType::kRefUtid, category_id, name_id,
+              duration_ns, args_callback);
           if (opt_slice_id.has_value()) {
             auto* thread_slices = storage->mutable_thread_slices();
             PERFETTO_DCHECK(!thread_slices->slice_count() ||
@@ -1975,15 +1973,15 @@
           break;
         }
         case LegacyEvent::SCOPE_GLOBAL: {
-          // TODO(lalitm): Associate global slices with track instead.
-          slice_tracker->Scoped(ts, /*ref=*/0, RefType::kRefNoRef, category_id,
-                                name_id, duration_ns, args_callback);
+          slice_tracker->Scoped(ts, track_id, /*ref=*/0, RefType::kRefNoRef,
+                                category_id, name_id, duration_ns,
+                                args_callback);
           break;
         }
         case LegacyEvent::SCOPE_PROCESS: {
-          // TODO(lalitm): Associate process slices with track instead.
-          slice_tracker->Scoped(ts, *upid, RefType::kRefUpid, category_id,
-                                name_id, duration_ns, args_callback);
+          slice_tracker->Scoped(ts, track_id, *upid, RefType::kRefUpid,
+                                category_id, name_id, duration_ns,
+                                args_callback);
           break;
         }
         default: {
@@ -1996,8 +1994,8 @@
     }
     case 'b': {  // TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN
       auto opt_slice_id =
-          slice_tracker->Begin(ts, track_id, RefType::kRefTrack, category_id,
-                               name_id, args_callback);
+          slice_tracker->Begin(ts, track_id, track_id, RefType::kRefTrack,
+                               category_id, name_id, args_callback);
       // For the time beeing, we only create vtrack slice rows if we need to
       // store thread timestamps/counters.
       if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
@@ -2013,8 +2011,7 @@
     }
     case 'e': {  // TRACE_EVENT_PHASE_NESTABLE_ASYNC_END
       auto opt_slice_id =
-          slice_tracker->End(ts, track_id, RefType::kRefTrack, category_id,
-                             name_id, args_callback);
+          slice_tracker->End(ts, track_id, category_id, name_id, args_callback);
       if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
         auto* vtrack_slices = storage->mutable_virtual_track_slices();
         vtrack_slices->UpdateThreadDeltasForSliceId(opt_slice_id.value(), tts,
@@ -2027,9 +2024,9 @@
       // nested underneath their parent slices.
       int64_t duration_ns = 0;
       int64_t tidelta = 0;
-      auto opt_slice_id =
-          slice_tracker->Scoped(ts, track_id, RefType::kRefTrack, category_id,
-                                name_id, duration_ns, args_callback);
+      auto opt_slice_id = slice_tracker->Scoped(
+          ts, track_id, track_id, RefType::kRefTrack, category_id, name_id,
+          duration_ns, args_callback);
       if (legacy_event.use_async_tts() && opt_slice_id.has_value()) {
         auto* vtrack_slices = storage->mutable_virtual_track_slices();
         PERFETTO_DCHECK(!vtrack_slices->slice_count() ||
@@ -2596,11 +2593,9 @@
       sprintf(fallback, "Event %d", eid);
       name_id = context_->storage->InternString(fallback);
     }
-    // TODO(lalitm): make use of this track id.
     TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-    perfetto::base::ignore_result(track_id);
-    context_->slice_tracker->Scoped(ts, utid, RefType::kRefUtid, cat_id,
-                                    name_id, event.event_duration_ns());
+    context_->slice_tracker->Scoped(ts, track_id, utid, RefType::kRefUtid,
+                                    cat_id, name_id, event.event_duration_ns());
   } else if (event.has_counter_id()) {
     auto cid = event.counter_id();
     if (cid < metatrace::COUNTERS_MAX) {
diff --git a/src/trace_processor/proto_trace_parser_unittest.cc b/src/trace_processor/proto_trace_parser_unittest.cc
index 0f023d7..70552cf 100644
--- a/src/trace_processor/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/proto_trace_parser_unittest.cc
@@ -171,22 +171,23 @@
  public:
   MockSliceTracker(TraceProcessorContext* context) : SliceTracker(context) {}
 
-  MOCK_METHOD6(Begin,
+  MOCK_METHOD7(Begin,
                base::Optional<uint32_t>(int64_t timestamp,
+                                        TrackId track_id,
                                         int64_t ref,
                                         RefType ref_type,
                                         StringId cat,
                                         StringId name,
                                         SetArgsCallback args_callback));
-  MOCK_METHOD6(End,
+  MOCK_METHOD5(End,
                base::Optional<uint32_t>(int64_t timestamp,
-                                        int64_t ref,
-                                        RefType ref_type,
+                                        TrackId track_id,
                                         StringId cat,
                                         StringId name,
                                         SetArgsCallback args_callback));
-  MOCK_METHOD7(Scoped,
+  MOCK_METHOD8(Scoped,
                base::Optional<uint32_t>(int64_t timestamp,
+                                        TrackId track_id,
                                         int64_t ref,
                                         RefType ref_type,
                                         StringId cat,
@@ -730,23 +731,23 @@
 
   MockArgsTracker args(&context_);
 
+  constexpr TrackId track = 0u;
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
-  EXPECT_CALL(*slice_, Scoped(1005000, 1, RefType::kRefUtid, kNullStringId,
-                              kNullStringId, 23000, _))
+  EXPECT_CALL(*slice_, Scoped(1005000, track, 1, RefType::kRefUtid,
+                              kNullStringId, kNullStringId, 23000, _))
       .WillOnce(DoAll(
-          InvokeArgument<6>(
+          InvokeArgument<7>(
               &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 0u)),
           Return(0u)));
-  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, kNullStringId,
-                             kNullStringId, _))
+  EXPECT_CALL(*slice_, Begin(1010000, track, 1, RefType::kRefUtid,
+                             kNullStringId, kNullStringId, _))
       .WillOnce(DoAll(
-          InvokeArgument<5>(
+          InvokeArgument<6>(
               &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 1u)),
           Return(1u)));
-  EXPECT_CALL(*slice_, End(1020000, 1, RefType::kRefUtid, kNullStringId,
-                           kNullStringId, _))
+  EXPECT_CALL(*slice_, End(1020000, track, kNullStringId, kNullStringId, _))
       .WillOnce(DoAll(
-          InvokeArgument<5>(
+          InvokeArgument<4>(
               &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 1u)),
           Return(1u)));
 
@@ -823,23 +824,23 @@
 
   MockArgsTracker args(&context_);
 
+  constexpr TrackId track = 0u;
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
-  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, kNullStringId,
-                             kNullStringId, _))
-      .WillOnce(DoAll(
-          InvokeArgument<5>(
-              &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 0u)),
-          Return(0u)));
-  EXPECT_CALL(*slice_, Scoped(1015000, 1, RefType::kRefUtid, kNullStringId,
-                              kNullStringId, 0, _))
+  EXPECT_CALL(*slice_, Begin(1010000, track, 1, RefType::kRefUtid,
+                             kNullStringId, kNullStringId, _))
       .WillOnce(DoAll(
           InvokeArgument<6>(
+              &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 0u)),
+          Return(0u)));
+  EXPECT_CALL(*slice_, Scoped(1015000, track, 1, RefType::kRefUtid,
+                              kNullStringId, kNullStringId, 0, _))
+      .WillOnce(DoAll(
+          InvokeArgument<7>(
               &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 1u)),
           Return(1u)));
-  EXPECT_CALL(*slice_, End(1020000, 1, RefType::kRefUtid, kNullStringId,
-                           kNullStringId, _))
+  EXPECT_CALL(*slice_, End(1020000, track, kNullStringId, kNullStringId, _))
       .WillOnce(DoAll(
-          InvokeArgument<5>(
+          InvokeArgument<4>(
               &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 0u)),
           Return(0u)));
 
@@ -967,16 +968,19 @@
 
   MockArgsTracker args(&context_);
 
+  constexpr TrackId thread_1_track = 0u;
+  constexpr TrackId process_2_track = 1u;
+
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
   EXPECT_CALL(*storage_, InternString(base::StringView("cat2,cat3")))
       .WillOnce(Return(1));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
       .WillOnce(Return(2));
-  EXPECT_CALL(*slice_, Scoped(1005000, 1, RefType::kRefUtid, StringId(1),
-                              StringId(2), 23000, _))
+  EXPECT_CALL(*slice_, Scoped(1005000, thread_1_track, 1, RefType::kRefUtid,
+                              StringId(1), StringId(2), 23000, _))
       .WillOnce(DoAll(
-          InvokeArgument<6>(
+          InvokeArgument<7>(
               &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 0u)),
           Return(0u)));
 
@@ -984,31 +988,31 @@
       .WillOnce(Return(3));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(4));
-  EXPECT_CALL(*slice_,
-              Begin(1010000, 1, RefType::kRefUtid, StringId(3), StringId(4), _))
-      .WillOnce(DoAll(
-          InvokeArgument<5>(
-              &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 1u)),
-          Return(1u)));
-
-  EXPECT_CALL(*slice_,
-              End(1020000, 1, RefType::kRefUtid, StringId(3), StringId(4), _))
-      .WillOnce(DoAll(
-          InvokeArgument<5>(
-              &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 1u)),
-          Return(1u)));
-
-  EXPECT_CALL(*slice_, Scoped(1040000, 1, RefType::kRefUtid, StringId(3),
-                              StringId(4), 0, _))
+  EXPECT_CALL(*slice_, Begin(1010000, thread_1_track, 1, RefType::kRefUtid,
+                             StringId(3), StringId(4), _))
       .WillOnce(DoAll(
           InvokeArgument<6>(
+              &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 1u)),
+          Return(1u)));
+
+  EXPECT_CALL(*slice_,
+              End(1020000, thread_1_track, StringId(3), StringId(4), _))
+      .WillOnce(DoAll(
+          InvokeArgument<4>(
+              &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 1u)),
+          Return(1u)));
+
+  EXPECT_CALL(*slice_, Scoped(1040000, thread_1_track, 1, RefType::kRefUtid,
+                              StringId(3), StringId(4), 0, _))
+      .WillOnce(DoAll(
+          InvokeArgument<7>(
               &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 2u)),
           Return(2u)));
 
-  EXPECT_CALL(*slice_, Scoped(1050000, 2, RefType::kRefUpid, StringId(3),
-                              StringId(4), 0, _))
+  EXPECT_CALL(*slice_, Scoped(1050000, process_2_track, 2, RefType::kRefUpid,
+                              StringId(3), StringId(4), 0, _))
       .WillOnce(DoAll(
-          InvokeArgument<6>(
+          InvokeArgument<7>(
               &args, TraceStorage::CreateRowId(TableId::kNestableSlices, 3u)),
           Return(3u)));
 
@@ -1133,7 +1137,7 @@
       .WillOnce(Return(1));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(2));
-  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefTrack, StringId(1),
+  EXPECT_CALL(*slice_, Begin(1010000, 1, 1, RefType::kRefTrack, StringId(1),
                              StringId(2), _))
       .WillOnce(Return(0u));
 
@@ -1141,16 +1145,15 @@
       .WillOnce(Return(3));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
       .WillOnce(Return(4));
-  EXPECT_CALL(*slice_, Scoped(1015000, 1, RefType::kRefTrack, StringId(3),
+  EXPECT_CALL(*slice_, Scoped(1015000, 1, 1, RefType::kRefTrack, StringId(3),
                               StringId(4), 0, _));
 
-  EXPECT_CALL(*slice_,
-              End(1020000, 1, RefType::kRefTrack, StringId(1), StringId(2), _))
+  EXPECT_CALL(*slice_, End(1020000, 1, StringId(1), StringId(2), _))
       .WillOnce(Return(0u));
 
   EXPECT_CALL(*storage_, InternString(base::StringView("scope1")))
       .WillOnce(Return(5));
-  EXPECT_CALL(*slice_, Scoped(1030000, 2, RefType::kRefTrack, StringId(3),
+  EXPECT_CALL(*slice_, Scoped(1030000, 2, 2, RefType::kRefTrack, StringId(3),
                               StringId(4), 0, _));
 
   context_.sorter->ExtractEventsForced();
@@ -1332,7 +1335,7 @@
       .WillOnce(Return(1));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(2));
-  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefTrack, StringId(1),
+  EXPECT_CALL(*slice_, Begin(1010000, 1, 1, RefType::kRefTrack, StringId(1),
                              StringId(2), _))
       .WillOnce(Return(0u));
 
@@ -1340,7 +1343,7 @@
       .WillOnce(Return(3));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
       .WillOnce(Return(4));
-  EXPECT_CALL(*slice_, Scoped(1015000, 1, RefType::kRefUtid, StringId(3),
+  EXPECT_CALL(*slice_, Scoped(1015000, 0, 1, RefType::kRefUtid, StringId(3),
                               StringId(4), 0, _))
       .WillOnce(Return(1u));
 
@@ -1348,12 +1351,11 @@
       .WillOnce(Return(5));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev3")))
       .WillOnce(Return(6));
-  EXPECT_CALL(*slice_, Scoped(1016000, 2, RefType::kRefUtid, StringId(5),
+  EXPECT_CALL(*slice_, Scoped(1016000, 2, 2, RefType::kRefUtid, StringId(5),
                               StringId(6), 0, _))
       .WillOnce(Return(2u));
 
-  EXPECT_CALL(*slice_,
-              End(1020000, 1, RefType::kRefTrack, StringId(0), StringId(0), _))
+  EXPECT_CALL(*slice_, End(1020000, 1, StringId(0), StringId(0), _))
       .WillOnce(Return(0u));
 
   context_.sorter->ExtractEventsForced();
@@ -1412,7 +1414,7 @@
 
   Tokenize();
 
-  EXPECT_CALL(*slice_, Begin(_, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(*slice_, Begin(_, _, _, _, _, _, _)).Times(0);
   context_.sorter->ExtractEventsForced();
 }
 
@@ -1436,7 +1438,7 @@
 
   Tokenize();
 
-  EXPECT_CALL(*slice_, Begin(_, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(*slice_, Begin(_, _, _, _, _, _, _)).Times(0);
   context_.sorter->ExtractEventsForced();
 }
 
@@ -1536,11 +1538,11 @@
       .Times(2)
       .WillRepeatedly(testing::ReturnRef(thread));
 
+  constexpr TrackId track = 0u;
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
-  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, kNullStringId,
-                             kNullStringId, _));
-  EXPECT_CALL(*slice_, End(2010000, 1, RefType::kRefUtid, kNullStringId,
-                           kNullStringId, _));
+  EXPECT_CALL(*slice_, Begin(1010000, track, 1, RefType::kRefUtid,
+                             kNullStringId, kNullStringId, _));
+  EXPECT_CALL(*slice_, End(2010000, track, kNullStringId, kNullStringId, _));
 
   context_.sorter->ExtractEventsForced();
 }
@@ -1651,6 +1653,8 @@
       .Times(2)
       .WillRepeatedly(testing::ReturnRef(thread2));
 
+  constexpr TrackId thread_2_track = 0u;
+  constexpr TrackId thread_1_track = 1u;
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
   EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
@@ -1658,20 +1662,20 @@
   EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
       .WillOnce(Return(2));
 
-  EXPECT_CALL(*slice_, Begin(1005000, 2, RefType::kRefUtid, StringId(1),
-                             StringId(2), _));
+  EXPECT_CALL(*slice_, Begin(1005000, thread_2_track, 2, RefType::kRefUtid,
+                             StringId(1), StringId(2), _));
 
   EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
       .WillOnce(Return(1));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(3));
 
-  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, StringId(1),
-                             StringId(3), _));
+  EXPECT_CALL(*slice_, Begin(1010000, thread_1_track, 1, RefType::kRefUtid,
+                             StringId(1), StringId(3), _));
   EXPECT_CALL(*slice_,
-              End(1015000, 2, RefType::kRefUtid, StringId(1), StringId(2), _));
+              End(1015000, thread_2_track, StringId(1), StringId(2), _));
   EXPECT_CALL(*slice_,
-              End(1020000, 1, RefType::kRefUtid, StringId(1), StringId(3), _));
+              End(1020000, thread_1_track, StringId(1), StringId(3), _));
 
   context_.sorter->ExtractEventsForced();
 }
@@ -1806,15 +1810,16 @@
       .Times(2)
       .WillRepeatedly(testing::ReturnRef(thread));
 
+  constexpr TrackId track = 0u;
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
   EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
       .WillOnce(Return(1));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(2));
-  EXPECT_CALL(*slice_,
-              Begin(1010000, 1, RefType::kRefUtid, StringId(1), StringId(2), _))
-      .WillOnce(DoAll(InvokeArgument<5>(&args, 1u), Return(1u)));
+  EXPECT_CALL(*slice_, Begin(1010000, track, 1, RefType::kRefUtid, StringId(1),
+                             StringId(2), _))
+      .WillOnce(DoAll(InvokeArgument<6>(&args, 1u), Return(1u)));
   EXPECT_CALL(*storage_, InternString(base::StringView("debug.an1")))
       .WillOnce(Return(3));
   EXPECT_CALL(args, AddArg(1u, StringId(3), StringId(3),
@@ -1851,9 +1856,8 @@
   EXPECT_CALL(args,
               AddArg(1u, StringId(6), StringId(10), Variadic::Integer(23)));
 
-  EXPECT_CALL(*slice_,
-              End(1020000, 1, RefType::kRefUtid, StringId(1), StringId(2), _))
-      .WillOnce(DoAll(InvokeArgument<5>(&args, 1u), Return(1u)));
+  EXPECT_CALL(*slice_, End(1020000, track, StringId(1), StringId(2), _))
+      .WillOnce(DoAll(InvokeArgument<4>(&args, 1u), Return(1u)));
 
   EXPECT_CALL(*storage_, InternString(base::StringView("debug.an3")))
       .WillOnce(Return(11));
@@ -1936,15 +1940,16 @@
   thread.upid = 1u;
   EXPECT_CALL(*storage_, GetThread(1)).WillOnce(testing::ReturnRef(thread));
 
+  constexpr TrackId track = 0u;
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
   EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
       .WillOnce(Return(1));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(2));
-  EXPECT_CALL(*slice_,
-              Begin(1010000, 1, RefType::kRefUtid, StringId(1), StringId(2), _))
-      .WillOnce(DoAll(InvokeArgument<5>(&args, 1u), Return(1u)));
+  EXPECT_CALL(*slice_, Begin(1010000, track, 1, RefType::kRefUtid, StringId(1),
+                             StringId(2), _))
+      .WillOnce(DoAll(InvokeArgument<6>(&args, 1u), Return(1u)));
   EXPECT_CALL(*storage_, InternString(base::StringView("file1")))
       .WillOnce(Return(3));
   EXPECT_CALL(*storage_, InternString(base::StringView("func1")))
@@ -2015,6 +2020,7 @@
   thread.upid = 1u;
   EXPECT_CALL(*storage_, GetThread(1)).WillOnce(testing::ReturnRef(thread));
 
+  constexpr TrackId track = 0;
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
 
   EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
@@ -2022,9 +2028,9 @@
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(2));
 
-  EXPECT_CALL(*slice_, Scoped(1010000, 1, RefType::kRefUtid, StringId(1),
+  EXPECT_CALL(*slice_, Scoped(1010000, track, 1, RefType::kRefUtid, StringId(1),
                               StringId(2), 0, _))
-      .WillOnce(DoAll(InvokeArgument<6>(&args, 1u), Return(1u)));
+      .WillOnce(DoAll(InvokeArgument<7>(&args, 1u), Return(1u)));
 
   EXPECT_CALL(*storage_, InternString(base::StringView("body1")))
       .WillOnce(Return(3));
diff --git a/src/trace_processor/slice_table.cc b/src/trace_processor/slice_table.cc
index 70a96f2..d2dca83 100644
--- a/src/trace_processor/slice_table.cc
+++ b/src/trace_processor/slice_table.cc
@@ -34,6 +34,7 @@
       .AddGenericNumericColumn("slice_id", RowAccessor())
       .AddOrderedNumericColumn("ts", &slices.start_ns())
       .AddNumericColumn("dur", &slices.durations())
+      .AddNumericColumn("track_id", &slices.track_id())
       .AddNumericColumn("ref", &slices.refs())
       .AddStringColumn("ref_type", &slices.types(), &GetRefTypeStringMap())
       .AddStringColumn("category", &slices.categories(),
diff --git a/src/trace_processor/slice_tracker.cc b/src/trace_processor/slice_tracker.cc
index 500d23c..0ab1183 100644
--- a/src/trace_processor/slice_tracker.cc
+++ b/src/trace_processor/slice_tracker.cc
@@ -46,13 +46,13 @@
   UniqueTid utid =
       context_->process_tracker->UpdateThread(ftrace_tid, atrace_tgid);
   ftrace_to_atrace_tgid_[ftrace_tid] = atrace_tgid;
-  // TODO(lalitm): make use of this track id.
+
   TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-  perfetto::base::ignore_result(track_id);
-  return Begin(timestamp, utid, RefType::kRefUtid, category, name);
+  return Begin(timestamp, track_id, utid, RefType::kRefUtid, category, name);
 }
 
 base::Optional<uint32_t> SliceTracker::Begin(int64_t timestamp,
+                                             TrackId track_id,
                                              int64_t ref,
                                              RefType ref_type,
                                              StringId category,
@@ -65,12 +65,13 @@
   }
   prev_timestamp_ = timestamp;
 
-  MaybeCloseStack(timestamp, &stacks_[{ref, ref_type}]);
-  return StartSlice(timestamp, kPendingDuration, ref, ref_type, category, name,
-                    args_callback);
+  MaybeCloseStack(timestamp, &stacks_[track_id]);
+  return StartSlice(timestamp, kPendingDuration, track_id, ref, ref_type,
+                    category, name, args_callback);
 }
 
 base::Optional<uint32_t> SliceTracker::Scoped(int64_t timestamp,
+                                              TrackId track_id,
                                               int64_t ref,
                                               RefType ref_type,
                                               StringId category,
@@ -85,20 +86,21 @@
   prev_timestamp_ = timestamp;
 
   PERFETTO_DCHECK(duration >= 0);
-  MaybeCloseStack(timestamp, &stacks_[{ref, ref_type}]);
-  return StartSlice(timestamp, duration, ref, ref_type, category, name,
-                    args_callback);
+  MaybeCloseStack(timestamp, &stacks_[track_id]);
+  return StartSlice(timestamp, duration, track_id, ref, ref_type, category,
+                    name, args_callback);
 }
 
 base::Optional<uint32_t> SliceTracker::StartSlice(
     int64_t timestamp,
     int64_t duration,
+    TrackId track_id,
     int64_t ref,
     RefType ref_type,
     StringId category,
     StringId name,
     SetArgsCallback args_callback) {
-  auto* stack = &stacks_[{ref, ref_type}];
+  auto* stack = &stacks_[track_id];
   auto* slices = context_->storage->mutable_nestable_slices();
 
   const uint8_t depth = static_cast<uint8_t>(stack->size());
@@ -109,8 +111,8 @@
   int64_t parent_stack_id =
       depth == 0 ? 0 : slices->stack_ids()[stack->back().first];
   uint32_t slice_idx =
-      slices->AddSlice(timestamp, duration, ref, ref_type, category, name,
-                       depth, 0, parent_stack_id);
+      slices->AddSlice(timestamp, duration, track_id, ref, ref_type, category,
+                       name, depth, 0, parent_stack_id);
   stack->emplace_back(std::make_pair(slice_idx, ArgsTracker(context_)));
 
   if (args_callback) {
@@ -141,15 +143,12 @@
   }
   UniqueTid utid =
       context_->process_tracker->UpdateThread(ftrace_tid, actual_tgid);
-  // TODO(lalitm): make use of this track id.
   TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-  perfetto::base::ignore_result(track_id);
-  return End(timestamp, utid, RefType::kRefUtid);
+  return End(timestamp, track_id);
 }
 
 base::Optional<uint32_t> SliceTracker::End(int64_t timestamp,
-                                           int64_t ref,
-                                           RefType ref_type,
+                                           TrackId track_id,
                                            StringId category,
                                            StringId name,
                                            SetArgsCallback args_callback) {
@@ -160,10 +159,9 @@
   }
   prev_timestamp_ = timestamp;
 
-  StackMapKey stack_key = {ref, ref_type};
-  MaybeCloseStack(timestamp, &stacks_[stack_key]);
+  MaybeCloseStack(timestamp, &stacks_[track_id]);
 
-  auto& stack = stacks_[stack_key];
+  auto& stack = stacks_[track_id];
   if (stack.empty())
     return base::nullopt;
 
@@ -186,7 +184,7 @@
         TraceStorage::CreateRowId(TableId::kNestableSlices, slice_idx));
   }
 
-  return CompleteSlice(stack_key);
+  return CompleteSlice(track_id);
   // TODO(primiano): auto-close B slices left open at the end.
 }
 
@@ -201,8 +199,8 @@
   stacks_.clear();
 }
 
-base::Optional<uint32_t> SliceTracker::CompleteSlice(StackMapKey stack_key) {
-  auto& stack = stacks_[stack_key];
+base::Optional<uint32_t> SliceTracker::CompleteSlice(TrackId track_id) {
+  auto& stack = stacks_[track_id];
   uint32_t slice_idx = stack.back().first;
   stack.pop_back();
   return slice_idx;
diff --git a/src/trace_processor/slice_tracker.h b/src/trace_processor/slice_tracker.h
index 351aea0..658d32c 100644
--- a/src/trace_processor/slice_tracker.h
+++ b/src/trace_processor/slice_tracker.h
@@ -43,6 +43,7 @@
   // virtual for testing
   virtual base::Optional<uint32_t> Begin(
       int64_t timestamp,
+      TrackId track_id,
       int64_t ref,
       RefType ref_type,
       StringId category,
@@ -52,6 +53,7 @@
   // virtual for testing
   virtual base::Optional<uint32_t> Scoped(
       int64_t timestamp,
+      TrackId track_id,
       int64_t ref,
       RefType ref_type,
       StringId category,
@@ -66,8 +68,7 @@
   // virtual for testing
   virtual base::Optional<uint32_t> End(
       int64_t timestamp,
-      int64_t ref,
-      RefType ref_type,
+      TrackId track_id,
       StringId opt_category = {},
       StringId opt_name = {},
       SetArgsCallback args_callback = SetArgsCallback());
@@ -76,35 +77,17 @@
 
  private:
   using SlicesStack = std::vector<std::pair<uint32_t /* row */, ArgsTracker>>;
-
-  struct StackMapKey {
-    int64_t ref;
-    RefType type;
-
-    bool operator==(const StackMapKey& rhs) const {
-      return std::tie(ref, type) == std::tie(rhs.ref, rhs.type);
-    }
-  };
-
-  struct StackMapHash {
-    size_t operator()(const StackMapKey& p) const {
-      base::Hash hash;
-      hash.Update(p.ref);
-      hash.Update(p.type);
-      return static_cast<size_t>(hash.digest());
-    }
-  };
-
-  using StackMap = std::unordered_map<StackMapKey, SlicesStack, StackMapHash>;
+  using StackMap = std::unordered_map<TrackId, SlicesStack>;
 
   base::Optional<uint32_t> StartSlice(int64_t timestamp,
                                       int64_t duration,
+                                      TrackId track_id,
                                       int64_t ref,
                                       RefType ref_type,
                                       StringId category,
                                       StringId name,
                                       SetArgsCallback args_callback);
-  base::Optional<uint32_t> CompleteSlice(StackMapKey stack_key);
+  base::Optional<uint32_t> CompleteSlice(TrackId track_id);
 
   void MaybeCloseStack(int64_t end_ts, SlicesStack*);
   int64_t GetStackHash(const SlicesStack&);
diff --git a/src/trace_processor/slice_tracker_unittest.cc b/src/trace_processor/slice_tracker_unittest.cc
index 203941e..b547ad1 100644
--- a/src/trace_processor/slice_tracker_unittest.cc
+++ b/src/trace_processor/slice_tracker_unittest.cc
@@ -55,17 +55,20 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(2 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/);
-  tracker.End(10 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/);
+  constexpr TrackId track = 22u;
+  tracker.Begin(2 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+                1 /*name*/);
+  tracker.End(10 /*ts*/, track, 0 /*cat*/, 1 /*name*/);
 
   auto slices = context.storage->nestable_slices();
   EXPECT_EQ(slices.slice_count(), 1u);
   EXPECT_EQ(slices.start_ns()[0], 2);
   EXPECT_EQ(slices.durations()[0], 8);
+  EXPECT_EQ(slices.track_id()[0], track);
   EXPECT_EQ(slices.categories()[0], 0u);
   EXPECT_EQ(slices.names()[0], 1u);
   EXPECT_EQ(slices.refs()[0], 42);
-  EXPECT_EQ(slices.types()[0], kRefUtid);
+  EXPECT_EQ(slices.types()[0], RefType::kRefUtid);
   EXPECT_EQ(slices.depths()[0], 0);
   EXPECT_EQ(slices.arg_set_ids()[0], kInvalidArgSetId);
 }
@@ -75,12 +78,13 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(2 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/,
-                [](ArgsTracker* args_tracker, RowId row) {
+  constexpr TrackId track = 22u;
+  tracker.Begin(2 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+                1 /*name*/, [](ArgsTracker* args_tracker, RowId row) {
                   args_tracker->AddArg(row, /*flat_key=*/1, /*key=*/2,
                                        /*value=*/Variadic::Integer(10));
                 });
-  tracker.End(10 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/,
+  tracker.End(10 /*ts*/, track, 0 /*cat*/, 1 /*name*/,
               [](ArgsTracker* args_tracker, RowId row) {
                 args_tracker->AddArg(row, /*flat_key=*/3, /*key=*/4,
                                      /*value=*/Variadic::Integer(20));
@@ -90,10 +94,11 @@
   EXPECT_EQ(slices.slice_count(), 1u);
   EXPECT_EQ(slices.start_ns()[0], 2);
   EXPECT_EQ(slices.durations()[0], 8);
+  EXPECT_EQ(slices.track_id()[0], track);
   EXPECT_EQ(slices.categories()[0], 0u);
   EXPECT_EQ(slices.names()[0], 1u);
   EXPECT_EQ(slices.refs()[0], 42);
-  EXPECT_EQ(slices.types()[0], kRefUtid);
+  EXPECT_EQ(slices.types()[0], RefType::kRefUtid);
   EXPECT_EQ(slices.depths()[0], 0);
   auto set_id = slices.arg_set_ids()[0];
 
@@ -113,10 +118,13 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(2 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/);
-  tracker.Begin(3 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 2 /*name*/);
-  tracker.End(5 /*ts*/, 42 /*ref*/, RefType::kRefUtid);
-  tracker.End(10 /*ts*/, 42 /*ref*/, RefType::kRefUtid);
+  constexpr TrackId track = 22u;
+  tracker.Begin(2 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+                1 /*name*/);
+  tracker.Begin(3 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+                2 /*name*/);
+  tracker.End(5 /*ts*/, track);
+  tracker.End(10 /*ts*/, track);
 
   auto slices = context.storage->nestable_slices();
 
@@ -125,18 +133,20 @@
   size_t idx = 0;
   EXPECT_EQ(slices.start_ns()[idx], 2);
   EXPECT_EQ(slices.durations()[idx], 8);
+  EXPECT_EQ(slices.track_id()[idx], track);
   EXPECT_EQ(slices.categories()[idx], 0u);
   EXPECT_EQ(slices.names()[idx], 1u);
   EXPECT_EQ(slices.refs()[idx], 42);
-  EXPECT_EQ(slices.types()[idx], kRefUtid);
+  EXPECT_EQ(slices.types()[idx], RefType::kRefUtid);
   EXPECT_EQ(slices.depths()[idx++], 0);
 
   EXPECT_EQ(slices.start_ns()[idx], 3);
   EXPECT_EQ(slices.durations()[idx], 2);
+  EXPECT_EQ(slices.track_id()[idx], track);
   EXPECT_EQ(slices.categories()[idx], 0u);
   EXPECT_EQ(slices.names()[idx], 2u);
   EXPECT_EQ(slices.refs()[idx], 42);
-  EXPECT_EQ(slices.types()[idx], kRefUtid);
+  EXPECT_EQ(slices.types()[idx], RefType::kRefUtid);
   EXPECT_EQ(slices.depths()[idx], 1);
 
   EXPECT_EQ(slices.parent_stack_ids()[0], 0);
@@ -149,11 +159,12 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(0 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0, 0);
-  tracker.Begin(1 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0, 0);
-  tracker.Scoped(2 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0, 0, 6);
-  tracker.End(9 /*ts*/, 42 /*ref*/, RefType::kRefUtid);
-  tracker.End(10 /*ts*/, 42 /*ref*/, RefType::kRefUtid);
+  constexpr TrackId track = 22u;
+  tracker.Begin(0 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0, 0);
+  tracker.Begin(1 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0, 0);
+  tracker.Scoped(2 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0, 0, 6);
+  tracker.End(9 /*ts*/, track);
+  tracker.End(10 /*ts*/, track);
 
   auto slices = ToSliceInfo(context.storage->nestable_slices());
   EXPECT_THAT(slices,
@@ -165,10 +176,12 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(2 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/);
-  tracker.End(3 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 1 /*cat*/, 1 /*name*/);
-  tracker.End(4 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 2 /*name*/);
-  tracker.End(5 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/);
+  constexpr TrackId track = 22u;
+  tracker.Begin(2 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+                1 /*name*/);
+  tracker.End(3 /*ts*/, track, 1 /*cat*/, 1 /*name*/);
+  tracker.End(4 /*ts*/, track, 0 /*cat*/, 2 /*name*/);
+  tracker.End(5 /*ts*/, track, 0 /*cat*/, 1 /*name*/);
 
   auto slices = ToSliceInfo(context.storage->nestable_slices());
   EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 3}));
@@ -182,13 +195,14 @@
   // Bug scenario: the second zero-length scoped slice prevents the first slice
   // from being closed, leading to an inconsistency when we try to insert the
   // final slice and it doesn't intersect with the still pending first slice.
-  tracker.Scoped(2 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/,
-                 10 /* dur */);
-  tracker.Scoped(2 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/,
-                 0 /* dur */);
-  tracker.Scoped(12 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+  constexpr TrackId track = 22u;
+  tracker.Scoped(2 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+                 1 /*name*/, 10 /* dur */);
+  tracker.Scoped(2 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+                 1 /*name*/, 0 /* dur */);
+  tracker.Scoped(12 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
                  1 /*name*/, 1 /* dur */);
-  tracker.Scoped(13 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+  tracker.Scoped(13 /*ts*/, track, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
                  1 /*name*/, 1 /* dur */);
 
   auto slices = ToSliceInfo(context.storage->nestable_slices());
@@ -196,24 +210,26 @@
                                   SliceInfo{12, 1}, SliceInfo{13, 1}));
 }
 
-TEST(SliceTrackerTest, DifferentRefTypes) {
+TEST(SliceTrackerTest, DifferentTracks) {
   TraceProcessorContext context;
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(0 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0, 0);
-  tracker.Scoped(2 /*ts*/, 42 /*ref*/, RefType::kRefUpid, 0, 0, 6);
-  tracker.Scoped(3 /*ts*/, 42 /*ref*/, RefType::kRefUpid, 0, 0, 4);
-  tracker.End(10 /*ts*/, 42 /*ref*/, RefType::kRefUtid);
+  constexpr TrackId track_a = 22u;
+  constexpr TrackId track_b = 23u;
+  tracker.Begin(0 /*ts*/, track_a, 42 /*ref*/, RefType::kRefUtid, 0, 0);
+  tracker.Scoped(2 /*ts*/, track_b, 42 /*ref*/, RefType::kRefUtid, 0, 0, 6);
+  tracker.Scoped(3 /*ts*/, track_b, 42 /*ref*/, RefType::kRefUtid, 0, 0, 4);
+  tracker.End(10 /*ts*/, track_a);
   tracker.FlushPendingSlices();
 
   auto slices = ToSliceInfo(context.storage->nestable_slices());
   EXPECT_THAT(slices,
               ElementsAre(SliceInfo{0, 10}, SliceInfo{2, 6}, SliceInfo{3, 4}));
 
-  EXPECT_EQ(context.storage->nestable_slices().types()[0], RefType::kRefUtid);
-  EXPECT_EQ(context.storage->nestable_slices().types()[1], RefType::kRefUpid);
-  EXPECT_EQ(context.storage->nestable_slices().types()[2], RefType::kRefUpid);
+  EXPECT_EQ(context.storage->nestable_slices().track_id()[0], track_a);
+  EXPECT_EQ(context.storage->nestable_slices().track_id()[1], track_b);
+  EXPECT_EQ(context.storage->nestable_slices().track_id()[2], track_b);
   EXPECT_EQ(context.storage->nestable_slices().depths()[0], 0);
   EXPECT_EQ(context.storage->nestable_slices().depths()[1], 0);
   EXPECT_EQ(context.storage->nestable_slices().depths()[2], 1);
diff --git a/src/trace_processor/storage_columns.h b/src/trace_processor/storage_columns.h
index 5bde9c9..83e855b 100644
--- a/src/trace_processor/storage_columns.h
+++ b/src/trace_processor/storage_columns.h
@@ -334,7 +334,7 @@
   }
 
   NullTermStringView Get(uint32_t idx) const override {
-    const char* ptr = (*string_map_)[(*deque_)[idx]];
+    const char* ptr = (*string_map_)[static_cast<size_t>((*deque_)[idx])];
     return ptr ? NullTermStringView(ptr) : NullTermStringView();
   }
 
diff --git a/src/trace_processor/syscall_tracker.h b/src/trace_processor/syscall_tracker.h
index 4ad84a1..f367309 100644
--- a/src/trace_processor/syscall_tracker.h
+++ b/src/trace_processor/syscall_tracker.h
@@ -51,22 +51,17 @@
   void Enter(int64_t ts, UniqueTid utid, uint32_t syscall_num) {
     StringId name = SyscallNumberToStringId(syscall_num);
     if (!name.is_null()) {
-      // TODO(lalitm): make use of this track id.
       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-      perfetto::base::ignore_result(track_id);
-      context_->slice_tracker->Begin(ts, utid, RefType::kRefUtid, 0 /* cat */,
-                                     name);
+      context_->slice_tracker->Begin(ts, track_id, utid, RefType::kRefUtid,
+                                     0 /* cat */, name);
     }
   }
 
   void Exit(int64_t ts, UniqueTid utid, uint32_t syscall_num) {
     StringId name = SyscallNumberToStringId(syscall_num);
     if (!name.is_null()) {
-      // TODO(lalitm): make use of this track id.
       TrackId track_id = context_->track_tracker->InternThreadTrack(utid);
-      perfetto::base::ignore_result(track_id);
-      context_->slice_tracker->End(ts, utid, RefType::kRefUtid, 0 /* cat */,
-                                   name);
+      context_->slice_tracker->End(ts, track_id, 0 /* cat */, name);
     }
   }
 
diff --git a/src/trace_processor/syscall_tracker_unittest.cc b/src/trace_processor/syscall_tracker_unittest.cc
index 21861ec..70bf075 100644
--- a/src/trace_processor/syscall_tracker_unittest.cc
+++ b/src/trace_processor/syscall_tracker_unittest.cc
@@ -32,17 +32,17 @@
   MockSliceTracker(TraceProcessorContext* context) : SliceTracker(context) {}
   virtual ~MockSliceTracker() = default;
 
-  MOCK_METHOD6(Begin,
+  MOCK_METHOD7(Begin,
                base::Optional<uint32_t>(int64_t timestamp,
+                                        TrackId track_id,
                                         int64_t ref,
                                         RefType ref_type,
                                         StringId cat,
                                         StringId name,
                                         SetArgsCallback args_callback));
-  MOCK_METHOD6(End,
+  MOCK_METHOD5(End,
                base::Optional<uint32_t>(int64_t timestamp,
-                                        int64_t ref,
-                                        RefType ref_type,
+                                        TrackId track_id,
                                         StringId cat,
                                         StringId name,
                                         SetArgsCallback args_callback));
@@ -66,14 +66,14 @@
 };
 
 TEST_F(SyscallTrackerTest, ReportUnknownSyscalls) {
+  constexpr TrackId track = 0u;
   StringId begin_name = 0;
   StringId end_name = 0;
   EXPECT_CALL(*slice_tracker,
-              Begin(100, 42, RefType::kRefUtid, kNullStringId, _, _))
-      .WillOnce(DoAll(SaveArg<4>(&begin_name), Return(base::nullopt)));
-  EXPECT_CALL(*slice_tracker,
-              End(110, 42, RefType::kRefUtid, kNullStringId, _, _))
-      .WillOnce(DoAll(SaveArg<4>(&end_name), Return(base::nullopt)));
+              Begin(100, track, 42, RefType::kRefUtid, kNullStringId, _, _))
+      .WillOnce(DoAll(SaveArg<5>(&begin_name), Return(base::nullopt)));
+  EXPECT_CALL(*slice_tracker, End(110, track, kNullStringId, _, _))
+      .WillOnce(DoAll(SaveArg<3>(&end_name), Return(base::nullopt)));
 
   context.syscall_tracker->Enter(100 /*ts*/, 42 /*utid*/, 57 /*sys_read*/);
   context.syscall_tracker->Exit(110 /*ts*/, 42 /*utid*/, 57 /*sys_read*/);
@@ -83,22 +83,22 @@
 
 TEST_F(SyscallTrackerTest, IgnoreWriteSyscalls) {
   context.syscall_tracker->SetArchitecture(kAarch64);
-  EXPECT_CALL(*slice_tracker, Begin(_, _, _, _, _, _)).Times(0);
-  EXPECT_CALL(*slice_tracker, End(_, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(*slice_tracker, Begin(_, _, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(*slice_tracker, End(_, _, _, _, _)).Times(0);
 
   context.syscall_tracker->Enter(100 /*ts*/, 42 /*utid*/, 64 /*sys_write*/);
   context.syscall_tracker->Exit(110 /*ts*/, 42 /*utid*/, 64 /*sys_write*/);
 }
 
 TEST_F(SyscallTrackerTest, Aarch64) {
+  constexpr TrackId track = 0u;
   StringId begin_name = 0;
   StringId end_name = 0;
   EXPECT_CALL(*slice_tracker,
-              Begin(100, 42, RefType::kRefUtid, kNullStringId, _, _))
-      .WillOnce(DoAll(SaveArg<4>(&begin_name), Return(base::nullopt)));
-  EXPECT_CALL(*slice_tracker,
-              End(110, 42, RefType::kRefUtid, kNullStringId, _, _))
-      .WillOnce(DoAll(SaveArg<4>(&end_name), Return(base::nullopt)));
+              Begin(100, track, 42, RefType::kRefUtid, kNullStringId, _, _))
+      .WillOnce(DoAll(SaveArg<5>(&begin_name), Return(base::nullopt)));
+  EXPECT_CALL(*slice_tracker, End(110, track, kNullStringId, _, _))
+      .WillOnce(DoAll(SaveArg<3>(&end_name), Return(base::nullopt)));
 
   context.syscall_tracker->SetArchitecture(kAarch64);
   context.syscall_tracker->Enter(100 /*ts*/, 42 /*utid*/, 63 /*sys_read*/);
@@ -108,14 +108,14 @@
 }
 
 TEST_F(SyscallTrackerTest, x8664) {
+  constexpr TrackId track = 0u;
   StringId begin_name = 0;
   StringId end_name = 0;
   EXPECT_CALL(*slice_tracker,
-              Begin(100, 42, RefType::kRefUtid, kNullStringId, _, _))
-      .WillOnce(DoAll(SaveArg<4>(&begin_name), Return(base::nullopt)));
-  EXPECT_CALL(*slice_tracker,
-              End(110, 42, RefType::kRefUtid, kNullStringId, _, _))
-      .WillOnce(DoAll(SaveArg<4>(&end_name), Return(base::nullopt)));
+              Begin(100, track, 42, RefType::kRefUtid, kNullStringId, _, _))
+      .WillOnce(DoAll(SaveArg<5>(&begin_name), Return(base::nullopt)));
+  EXPECT_CALL(*slice_tracker, End(110, track, kNullStringId, _, _))
+      .WillOnce(DoAll(SaveArg<3>(&end_name), Return(base::nullopt)));
 
   context.syscall_tracker->SetArchitecture(kX86_64);
   context.syscall_tracker->Enter(100 /*ts*/, 42 /*utid*/, 0 /*sys_read*/);
@@ -125,8 +125,8 @@
 }
 
 TEST_F(SyscallTrackerTest, SyscallNumberTooLarge) {
-  EXPECT_CALL(*slice_tracker, Begin(_, _, _, _, _, _)).Times(0);
-  EXPECT_CALL(*slice_tracker, End(_, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(*slice_tracker, Begin(_, _, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(*slice_tracker, End(_, _, _, _, _)).Times(0);
   context.syscall_tracker->SetArchitecture(kAarch64);
   context.syscall_tracker->Enter(100 /*ts*/, 42 /*utid*/, 9999);
   context.syscall_tracker->Exit(110 /*ts*/, 42 /*utid*/, 9999);
diff --git a/src/trace_processor/systrace_parser.cc b/src/trace_processor/systrace_parser.cc
index 082dec5..6bb6b72 100644
--- a/src/trace_processor/systrace_parser.cc
+++ b/src/trace_processor/systrace_parser.cc
@@ -101,10 +101,10 @@
       TrackId track_id = context_->track_tracker->InternAndroidAsyncTrack(
           name_id, upid, cookie);
       if (point.phase == 'S') {
-        context_->slice_tracker->Begin(ts, track_id, RefType::kRefTrack, 0,
-                                       name_id);
+        context_->slice_tracker->Begin(ts, track_id, track_id,
+                                       RefType::kRefTrack, 0, name_id);
       } else {
-        context_->slice_tracker->End(ts, track_id, RefType::kRefTrack);
+        context_->slice_tracker->End(ts, track_id);
       }
       break;
     }
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 3935b37..3b73e0e 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -306,6 +306,8 @@
   const TraceStorage* storage = context_.storage.get();
   DbSqliteTable::RegisterTable(*db_, &storage->track_table(),
                                storage->track_table().table_name());
+  DbSqliteTable::RegisterTable(*db_, &storage->thread_track_table(),
+                               storage->thread_track_table().table_name());
   DbSqliteTable::RegisterTable(*db_, &storage->process_track_table(),
                                storage->process_track_table().table_name());
   DbSqliteTable::RegisterTable(*db_, &storage->gpu_slice_table(),
diff --git a/src/trace_processor/trace_storage.cc b/src/trace_processor/trace_storage.cc
index 4fed429..662c460 100644
--- a/src/trace_processor/trace_storage.cc
+++ b/src/trace_processor/trace_storage.cc
@@ -41,15 +41,15 @@
 }
 
 std::vector<const char*> CreateRefTypeStringMap() {
-  std::vector<const char*> map(RefType::kRefMax);
-  map[RefType::kRefNoRef] = nullptr;
-  map[RefType::kRefUtid] = "utid";
-  map[RefType::kRefCpuId] = "cpu";
-  map[RefType::kRefGpuId] = "gpu";
-  map[RefType::kRefIrq] = "irq";
-  map[RefType::kRefSoftIrq] = "softirq";
-  map[RefType::kRefUpid] = "upid";
-  map[RefType::kRefTrack] = "track";
+  std::vector<const char*> map(static_cast<size_t>(RefType::kRefMax));
+  map[static_cast<size_t>(RefType::kRefNoRef)] = nullptr;
+  map[static_cast<size_t>(RefType::kRefUtid)] = "utid";
+  map[static_cast<size_t>(RefType::kRefCpuId)] = "cpu";
+  map[static_cast<size_t>(RefType::kRefGpuId)] = "gpu";
+  map[static_cast<size_t>(RefType::kRefIrq)] = "irq";
+  map[static_cast<size_t>(RefType::kRefSoftIrq)] = "softirq";
+  map[static_cast<size_t>(RefType::kRefUpid)] = "upid";
+  map[static_cast<size_t>(RefType::kRefTrack)] = "track";
   return map;
 }
 
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index b34e483..6b17cae 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -79,7 +79,7 @@
 
 using TrackId = uint32_t;
 
-enum RefType {
+enum class RefType {
   kRefNoRef = 0,
   kRefUtid = 1,
   kRefCpuId = 2,
@@ -320,6 +320,7 @@
    public:
     inline uint32_t AddSlice(int64_t start_ns,
                              int64_t duration_ns,
+                             TrackId track_id,
                              int64_t ref,
                              RefType type,
                              StringId category,
@@ -329,6 +330,7 @@
                              int64_t parent_stack_id) {
       start_ns_.emplace_back(start_ns);
       durations_.emplace_back(duration_ns);
+      track_id_.emplace_back(track_id);
       refs_.emplace_back(ref);
       types_.emplace_back(type);
       categories_.emplace_back(category);
@@ -358,6 +360,7 @@
 
     const std::deque<int64_t>& start_ns() const { return start_ns_; }
     const std::deque<int64_t>& durations() const { return durations_; }
+    const std::deque<TrackId>& track_id() const { return track_id_; }
     const std::deque<int64_t>& refs() const { return refs_; }
     const std::deque<RefType>& types() const { return types_; }
     const std::deque<StringId>& categories() const { return categories_; }
@@ -372,6 +375,7 @@
    private:
     std::deque<int64_t> start_ns_;
     std::deque<int64_t> durations_;
+    std::deque<TrackId> track_id_;
     std::deque<int64_t> refs_;
     std::deque<RefType> types_;
     std::deque<StringId> categories_;