processor: Support RefType in SliceTracker + TrackEvent instant scopes

Adds support for tracking slice stacks for different RefTypes to
SliceTracker and uses this new support to implement handling of instant
event scopes from TrackEvent::LegacyEvent.

Bug: 130786981
Change-Id: I84205b63da0a489ed66b8f416c8bf96628076099
diff --git a/src/trace_processor/fuchsia_trace_parser.cc b/src/trace_processor/fuchsia_trace_parser.cc
index fa08d5b..4845e4d 100644
--- a/src/trace_processor/fuchsia_trace_parser.cc
+++ b/src/trace_processor/fuchsia_trace_parser.cc
@@ -206,7 +206,7 @@
           UniqueTid utid =
               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
                                   static_cast<uint32_t>(tinfo.pid));
-          slices->Begin(ts, utid, cat, name);
+          slices->Begin(ts, utid, RefType::kRefUtid, cat, name);
           break;
         }
         case kDurationEnd: {
@@ -216,7 +216,7 @@
           // 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);
+          slices->End(ts, utid, RefType::kRefUtid);
           break;
         }
         case kDurationComplete: {
@@ -225,7 +225,7 @@
           UniqueTid utid =
               procs->UpdateThread(static_cast<uint32_t>(tinfo.tid),
                                   static_cast<uint32_t>(tinfo.pid));
-          slices->Scoped(ts, utid, cat, name, end_ts - ts);
+          slices->Scoped(ts, utid, RefType::kRefUtid, cat, name, end_ts - ts);
           break;
         }
       }
diff --git a/src/trace_processor/json_trace_parser.cc b/src/trace_processor/json_trace_parser.cc
index 8c1812e..4129bf1 100644
--- a/src/trace_processor/json_trace_parser.cc
+++ b/src/trace_processor/json_trace_parser.cc
@@ -90,11 +90,11 @@
 
   switch (phase) {
     case 'B': {  // TRACE_EVENT_BEGIN.
-      slice_tracker->Begin(timestamp, utid, cat_id, name_id);
+      slice_tracker->Begin(timestamp, utid, RefType::kRefUtid, cat_id, name_id);
       break;
     }
     case 'E': {  // TRACE_EVENT_END.
-      slice_tracker->End(timestamp, utid, cat_id, name_id);
+      slice_tracker->End(timestamp, utid, RefType::kRefUtid, cat_id, name_id);
       break;
     }
     case 'X': {  // TRACE_EVENT (scoped event).
@@ -102,7 +102,8 @@
           json_trace_utils::CoerceToNs(value["dur"]);
       if (!opt_dur.has_value())
         return;
-      slice_tracker->Scoped(timestamp, utid, cat_id, name_id, opt_dur.value());
+      slice_tracker->Scoped(timestamp, 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 b1c5a50..4849ffd 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -1451,30 +1451,54 @@
     }
   };
 
+  using LegacyEvent = protos::pbzero::TrackEvent::LegacyEvent;
+
   int32_t phase = legacy_event.phase();
   switch (static_cast<char>(phase)) {
     case 'B': {  // TRACE_EVENT_PHASE_BEGIN.
-      slice_tracker->Begin(ts, utid, category_id, name_id, args_callback);
+      slice_tracker->Begin(ts, utid, RefType::kRefUtid, category_id, name_id,
+                           args_callback);
       break;
     }
     case 'E': {  // TRACE_EVENT_PHASE_END.
-      slice_tracker->End(ts, utid, category_id, name_id, args_callback);
+      slice_tracker->End(ts, utid, RefType::kRefUtid, category_id, name_id,
+                         args_callback);
       break;
     }
     case 'X': {  // TRACE_EVENT_PHASE_COMPLETE.
       auto duration_ns = legacy_event.duration_us() * 1000;
       if (duration_ns < 0)
         return;
-      slice_tracker->Scoped(ts, utid, category_id, name_id, duration_ns,
-                            args_callback);
+      slice_tracker->Scoped(ts, utid, RefType::kRefUtid, category_id, name_id,
+                            duration_ns, args_callback);
       break;
     }
+    case 'i':
     case 'I': {  // TRACE_EVENT_PHASE_INSTANT.
       // Handle instant events as slices with zero duration, so that they end
       // up nested underneath their parent slices.
       int64_t duration_ns = 0;
-      slice_tracker->Scoped(ts, utid, category_id, name_id, duration_ns,
-                            args_callback);
+
+      switch (legacy_event.instant_event_scope()) {
+        case LegacyEvent::SCOPE_UNSPECIFIED:
+        case LegacyEvent::SCOPE_THREAD:
+          slice_tracker->Scoped(ts, utid, RefType::kRefUtid, category_id,
+                                name_id, duration_ns, args_callback);
+          break;
+        case LegacyEvent::SCOPE_GLOBAL:
+          slice_tracker->Scoped(ts, /*ref=*/0, RefType::kRefNoRef, category_id,
+                                name_id, duration_ns, args_callback);
+          break;
+        case LegacyEvent::SCOPE_PROCESS:
+          slice_tracker->Scoped(ts, procs->GetOrCreateProcess(pid),
+                                RefType::kRefUpid, category_id, name_id,
+                                duration_ns, args_callback);
+          break;
+        default:
+          PERFETTO_FATAL("Unknown instant event scope: %u",
+                         legacy_event.instant_event_scope());
+          break;
+      }
       break;
     }
     case 'M': {  // TRACE_EVENT_PHASE_METADATA (process and thread names).
@@ -1742,8 +1766,8 @@
       sprintf(fallback, "Event %d", eid);
       name_id = context_->storage->InternString(fallback);
     }
-    context_->slice_tracker->Scoped(ts, utid, cat_id, name_id,
-                                    event.event_duration_ns());
+    context_->slice_tracker->Scoped(ts, 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 020219b..4f605f2 100644
--- a/src/trace_processor/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/proto_trace_parser_unittest.cc
@@ -106,6 +106,8 @@
                          base::StringView process_name));
 
   MOCK_METHOD2(UpdateThread, UniqueTid(uint32_t tid, uint32_t tgid));
+
+  MOCK_METHOD1(GetOrCreateProcess, UniquePid(uint32_t pid));
 };
 
 class MockTraceStorage : public TraceStorage {
@@ -131,21 +133,24 @@
  public:
   MockSliceTracker(TraceProcessorContext* context) : SliceTracker(context) {}
 
-  MOCK_METHOD5(Begin,
+  MOCK_METHOD6(Begin,
                void(int64_t timestamp,
-                    UniqueTid utid,
+                    int64_t ref,
+                    RefType ref_type,
                     StringId cat,
                     StringId name,
                     SetArgsCallback args_callback));
-  MOCK_METHOD5(End,
+  MOCK_METHOD6(End,
                void(int64_t timestamp,
-                    UniqueTid utid,
+                    int64_t ref,
+                    RefType ref_type,
                     StringId cat,
                     StringId name,
                     SetArgsCallback args_callback));
-  MOCK_METHOD6(Scoped,
+  MOCK_METHOD7(Scoped,
                void(int64_t timestamp,
-                    UniqueTid utid,
+                    int64_t ref,
+                    RefType ref_type,
                     StringId cat,
                     StringId name,
                     int64_t duration,
@@ -609,9 +614,9 @@
       .WillRepeatedly(Return(1));
 
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
-  EXPECT_CALL(*slice_, Scoped(1005000, 1, 0, 0, 23000, _));
-  EXPECT_CALL(*slice_, Begin(1010000, 1, 0, 0, _));
-  EXPECT_CALL(*slice_, End(1020000, 1, 0, 0, _));
+  EXPECT_CALL(*slice_, Scoped(1005000, 1, RefType::kRefUtid, 0, 0, 23000, _));
+  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, 0, 0, _));
+  EXPECT_CALL(*slice_, End(1020000, 1, RefType::kRefUtid, 0, 0, _));
 
   context_.sorter->ExtractEventsForced();
 }
@@ -665,6 +670,18 @@
     auto* packet = trace_.add_packet();
     packet->set_trusted_packet_sequence_id(1);
     auto* event = packet->set_track_event();
+    event->set_timestamp_absolute_us(1050);
+    event->add_category_iids(1);
+    auto* legacy_event = event->set_legacy_event();
+    legacy_event->set_name_iid(1);
+    legacy_event->set_phase('i');
+    legacy_event->set_instant_event_scope(
+        protos::pbzero::TrackEvent::LegacyEvent::SCOPE_PROCESS);
+  }
+  {
+    auto* packet = trace_.add_packet();
+    packet->set_trusted_packet_sequence_id(1);
+    auto* event = packet->set_track_event();
     event->set_timestamp_delta_us(10);   // absolute: 1020.
     event->set_thread_time_delta_us(5);  // absolute: 2010.
     event->add_category_iids(1);
@@ -701,26 +718,30 @@
   Tokenize();
 
   EXPECT_CALL(*process_, UpdateThread(16, 15))
-      .Times(4)
+      .Times(5)
       .WillRepeatedly(Return(1));
 
+  EXPECT_CALL(*process_, GetOrCreateProcess(15)).WillOnce(Return(2));
+
   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, 1, 2, 23000, _));
+  EXPECT_CALL(*slice_, Scoped(1005000, 1, RefType::kRefUtid, 1, 2, 23000, _));
 
   EXPECT_CALL(*storage_, InternString(base::StringView("cat1")))
       .WillOnce(Return(3));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(4));
-  EXPECT_CALL(*slice_, Begin(1010000, 1, 3, 4, _));
+  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, 3, 4, _));
 
-  EXPECT_CALL(*slice_, End(1020000, 1, 3, 4, _));
+  EXPECT_CALL(*slice_, End(1020000, 1, RefType::kRefUtid, 3, 4, _));
 
-  EXPECT_CALL(*slice_, Scoped(1040000, 1, 3, 4, 0, _));
+  EXPECT_CALL(*slice_, Scoped(1040000, 1, RefType::kRefUtid, 3, 4, 0, _));
+
+  EXPECT_CALL(*slice_, Scoped(1050000, 2, RefType::kRefUpid, 3, 4, 0, _));
 
   context_.sorter->ExtractEventsForced();
 }
@@ -754,7 +775,7 @@
 
   Tokenize();
 
-  EXPECT_CALL(*slice_, Begin(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(*slice_, Begin(_, _, _, _, _, _)).Times(0);
   context_.sorter->ExtractEventsForced();
 }
 
@@ -779,7 +800,7 @@
 
   Tokenize();
 
-  EXPECT_CALL(*slice_, Begin(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(*slice_, Begin(_, _, _, _, _, _)).Times(0);
   context_.sorter->ExtractEventsForced();
 }
 
@@ -875,8 +896,8 @@
       .WillRepeatedly(Return(1));
 
   InSequence in_sequence;  // Below slices should be sorted by timestamp.
-  EXPECT_CALL(*slice_, Begin(1010000, 1, 0, 0, _));
-  EXPECT_CALL(*slice_, End(2010000, 1, 0, 0, _));
+  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, 0, 0, _));
+  EXPECT_CALL(*slice_, End(2010000, 1, RefType::kRefUtid, 0, 0, _));
 
   context_.sorter->ExtractEventsForced();
 }
@@ -983,16 +1004,16 @@
   EXPECT_CALL(*storage_, InternString(base::StringView("ev2")))
       .WillOnce(Return(2));
 
-  EXPECT_CALL(*slice_, Begin(1005000, 2, 1, 2, _));
+  EXPECT_CALL(*slice_, Begin(1005000, 2, RefType::kRefUtid, 1, 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, 1, 3, _));
-  EXPECT_CALL(*slice_, End(1015000, 2, 1, 2, _));
-  EXPECT_CALL(*slice_, End(1020000, 1, 1, 3, _));
+  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, 1, 3, _));
+  EXPECT_CALL(*slice_, End(1015000, 2, RefType::kRefUtid, 1, 2, _));
+  EXPECT_CALL(*slice_, End(1020000, 1, RefType::kRefUtid, 1, 3, _));
 
   context_.sorter->ExtractEventsForced();
 }
@@ -1128,8 +1149,8 @@
       .WillOnce(Return(1));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(2));
-  EXPECT_CALL(*slice_, Begin(1010000, 1, 1, 2, _))
-      .WillOnce(testing::InvokeArgument<4>(&args, 1u));
+  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, 1, 2, _))
+      .WillOnce(testing::InvokeArgument<5>(&args, 1u));
   EXPECT_CALL(*storage_, InternString(base::StringView("debug.an1")))
       .WillOnce(Return(3));
   EXPECT_CALL(args, AddArg(1u, 3, 3, Variadic::UnsignedInteger(10u)));
@@ -1162,8 +1183,8 @@
       .WillOnce(Return(10));
   EXPECT_CALL(args, AddArg(1u, 6, 10, Variadic::Integer(23)));
 
-  EXPECT_CALL(*slice_, End(1020000, 1, 1, 2, _))
-      .WillOnce(testing::InvokeArgument<4>(&args, 1u));
+  EXPECT_CALL(*slice_, End(1020000, 1, RefType::kRefUtid, 1, 2, _))
+      .WillOnce(testing::InvokeArgument<5>(&args, 1u));
 
   EXPECT_CALL(*storage_, InternString(base::StringView("debug.an3")))
       .WillOnce(Return(11));
@@ -1243,8 +1264,8 @@
       .WillOnce(Return(1));
   EXPECT_CALL(*storage_, InternString(base::StringView("ev1")))
       .WillOnce(Return(2));
-  EXPECT_CALL(*slice_, Begin(1010000, 1, 1, 2, _))
-      .WillOnce(testing::InvokeArgument<4>(&args, 1u));
+  EXPECT_CALL(*slice_, Begin(1010000, 1, RefType::kRefUtid, 1, 2, _))
+      .WillOnce(testing::InvokeArgument<5>(&args, 1u));
   EXPECT_CALL(*storage_, InternString(base::StringView("file1")))
       .WillOnce(Return(3));
   EXPECT_CALL(*storage_, InternString(base::StringView("func1")))
diff --git a/src/trace_processor/slice_tracker.cc b/src/trace_processor/slice_tracker.cc
index 281b279..1f51f11 100644
--- a/src/trace_processor/slice_tracker.cc
+++ b/src/trace_processor/slice_tracker.cc
@@ -45,11 +45,12 @@
   UniqueTid utid =
       context_->process_tracker->UpdateThread(ftrace_tid, atrace_tgid);
   ftrace_to_atrace_tgid_[ftrace_tid] = atrace_tgid;
-  Begin(timestamp, utid, cat, name);
+  Begin(timestamp, utid, RefType::kRefUtid, cat, name);
 }
 
 void SliceTracker::Begin(int64_t timestamp,
-                         UniqueTid utid,
+                         int64_t ref,
+                         RefType ref_type,
                          StringId cat,
                          StringId name,
                          SetArgsCallback args_callback) {
@@ -60,12 +61,14 @@
   }
   prev_timestamp_ = timestamp;
 
-  MaybeCloseStack(timestamp, &threads_[utid]);
-  StartSlice(timestamp, kPendingDuration, utid, cat, name, args_callback);
+  MaybeCloseStack(timestamp, &stacks_[std::make_pair(ref, ref_type)]);
+  StartSlice(timestamp, kPendingDuration, ref, ref_type, cat, name,
+             args_callback);
 }
 
 void SliceTracker::Scoped(int64_t timestamp,
-                          UniqueTid utid,
+                          int64_t ref,
+                          RefType ref_type,
                           StringId cat,
                           StringId name,
                           int64_t duration,
@@ -78,17 +81,18 @@
   prev_timestamp_ = timestamp;
 
   PERFETTO_DCHECK(duration >= 0);
-  MaybeCloseStack(timestamp, &threads_[utid]);
-  StartSlice(timestamp, duration, utid, cat, name, args_callback);
+  MaybeCloseStack(timestamp, &stacks_[std::make_pair(ref, ref_type)]);
+  StartSlice(timestamp, duration, ref, ref_type, cat, name, args_callback);
 }
 
 void SliceTracker::StartSlice(int64_t timestamp,
                               int64_t duration,
-                              UniqueTid utid,
+                              int64_t ref,
+                              RefType ref_type,
                               StringId cat,
                               StringId name,
                               SetArgsCallback args_callback) {
-  auto* stack = &threads_[utid];
+  auto* stack = &stacks_[std::make_pair(ref, ref_type)];
   auto* slices = context_->storage->mutable_nestable_slices();
 
   const uint8_t depth = static_cast<uint8_t>(stack->size());
@@ -98,9 +102,8 @@
   }
   int64_t parent_stack_id =
       depth == 0 ? 0 : slices->stack_ids()[stack->back().first];
-  uint32_t slice_idx =
-      slices->AddSlice(timestamp, duration, utid, RefType::kRefUtid, cat, name,
-                       depth, 0, parent_stack_id);
+  uint32_t slice_idx = slices->AddSlice(timestamp, duration, ref, ref_type, cat,
+                                        name, depth, 0, parent_stack_id);
   stack->emplace_back(std::make_pair(slice_idx, ArgsTracker(context_)));
 
   if (args_callback) {
@@ -131,11 +134,12 @@
   }
   UniqueTid utid =
       context_->process_tracker->UpdateThread(ftrace_tid, actual_tgid);
-  End(timestamp, utid);
+  End(timestamp, utid, RefType::kRefUtid);
 }
 
 void SliceTracker::End(int64_t timestamp,
-                       UniqueTid utid,
+                       int64_t ref,
+                       RefType ref_type,
                        StringId cat,
                        StringId name,
                        SetArgsCallback args_callback) {
@@ -146,9 +150,10 @@
   }
   prev_timestamp_ = timestamp;
 
-  MaybeCloseStack(timestamp, &threads_[utid]);
+  auto ref_and_type = std::make_pair(ref, ref_type);
+  MaybeCloseStack(timestamp, &stacks_[ref_and_type]);
 
-  auto& stack = threads_[utid];
+  auto& stack = stacks_[ref_and_type];
   if (stack.empty())
     return;
 
@@ -171,12 +176,12 @@
         TraceStorage::CreateRowId(TableId::kNestableSlices, slice_idx));
   }
 
-  CompleteSlice(utid);
+  CompleteSlice(ref_and_type);
   // TODO(primiano): auto-close B slices left open at the end.
 }
 
-void SliceTracker::CompleteSlice(UniqueTid utid) {
-  threads_[utid].pop_back();
+void SliceTracker::CompleteSlice(StackMapKey ref_and_type) {
+  stacks_[ref_and_type].pop_back();
 }
 
 void SliceTracker::MaybeCloseStack(int64_t ts, SlicesStack* stack) {
diff --git a/src/trace_processor/slice_tracker.h b/src/trace_processor/slice_tracker.h
index 58c3f2b..9354c51 100644
--- a/src/trace_processor/slice_tracker.h
+++ b/src/trace_processor/slice_tracker.h
@@ -42,14 +42,16 @@
 
   // virtual for testing
   virtual void Begin(int64_t timestamp,
-                     UniqueTid utid,
+                     int64_t ref,
+                     RefType ref_type,
                      StringId cat,
                      StringId name,
                      SetArgsCallback args_callback = SetArgsCallback());
 
   // virtual for testing
   virtual void Scoped(int64_t timestamp,
-                      UniqueTid utid,
+                      int64_t ref,
+                      RefType ref_type,
                       StringId cat,
                       StringId name,
                       int64_t duration,
@@ -59,7 +61,8 @@
 
   // virtual for testing
   virtual void End(int64_t timestamp,
-                   UniqueTid utid,
+                   int64_t ref,
+                   RefType ref_type,
                    StringId opt_cat = {},
                    StringId opt_name = {},
                    SetArgsCallback args_callback = SetArgsCallback());
@@ -67,13 +70,25 @@
  private:
   using SlicesStack = std::vector<std::pair<uint32_t /* row */, ArgsTracker>>;
 
+  using StackMapKey = std::pair<int64_t, RefType>;
+  struct StackMapHash {
+    size_t operator()(const StackMapKey& p) const {
+      base::Hash hash;
+      hash.Update(p.first);
+      hash.Update(p.second);
+      return static_cast<size_t>(hash.digest());
+    }
+  };
+  using StackMap = std::unordered_map<StackMapKey, SlicesStack, StackMapHash>;
+
   void StartSlice(int64_t timestamp,
                   int64_t duration,
-                  UniqueTid utid,
+                  int64_t ref,
+                  RefType ref_type,
                   StringId cat,
                   StringId name,
                   SetArgsCallback args_callback);
-  void CompleteSlice(UniqueTid tid);
+  void CompleteSlice(StackMapKey ref_and_type);
 
   void MaybeCloseStack(int64_t end_ts, SlicesStack*);
   int64_t GetStackHash(const SlicesStack&);
@@ -83,7 +98,7 @@
   int64_t prev_timestamp_ = 0;
 
   TraceProcessorContext* const context_;
-  std::unordered_map<UniqueTid, SlicesStack> threads_;
+  StackMap stacks_;
   std::unordered_map<uint32_t, uint32_t> ftrace_to_atrace_tgid_;
 };
 
diff --git a/src/trace_processor/slice_tracker_unittest.cc b/src/trace_processor/slice_tracker_unittest.cc
index 88b1e1d..78a32ee 100644
--- a/src/trace_processor/slice_tracker_unittest.cc
+++ b/src/trace_processor/slice_tracker_unittest.cc
@@ -57,8 +57,8 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(2 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/);
-  tracker.End(10 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/);
+  tracker.Begin(2 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/);
+  tracker.End(10 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/);
 
   auto slices = context.storage->nestable_slices();
   EXPECT_EQ(slices.slice_count(), 1u);
@@ -77,12 +77,12 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(2 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/,
+  tracker.Begin(2 /*ts*/, 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 /*tid*/, 0 /*cat*/, 1 /*name*/,
+  tracker.End(10 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/, 1 /*name*/,
               [](ArgsTracker* args_tracker, RowId row) {
                 args_tracker->AddArg(row, /*flat_key=*/3, /*key=*/4,
                                      /*value=*/Variadic::Integer(20));
@@ -115,10 +115,10 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(2 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/);
-  tracker.Begin(3 /*ts*/, 42 /*tid*/, 0 /*cat*/, 2 /*name*/);
-  tracker.End(5 /*ts*/, 42 /*tid*/);
-  tracker.End(10 /*ts*/, 42 /*tid*/);
+  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);
 
   auto slices = context.storage->nestable_slices();
 
@@ -151,11 +151,11 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(0 /*ts*/, 42 /*tid*/, 0, 0);
-  tracker.Begin(1 /*ts*/, 42 /*tid*/, 0, 0);
-  tracker.Scoped(2 /*ts*/, 42 /*tid*/, 0, 0, 6);
-  tracker.End(9 /*ts*/, 42 /*tid*/);
-  tracker.End(10 /*ts*/, 42 /*tid*/);
+  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);
 
   auto slices = ToSliceInfo(context.storage->nestable_slices());
   EXPECT_THAT(slices,
@@ -167,10 +167,10 @@
   context.storage.reset(new TraceStorage());
   SliceTracker tracker(&context);
 
-  tracker.Begin(2 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/);
-  tracker.End(3 /*ts*/, 42 /*tid*/, 1 /*cat*/, 1 /*name*/);
-  tracker.End(4 /*ts*/, 42 /*tid*/, 0 /*cat*/, 2 /*name*/);
-  tracker.End(5 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/);
+  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*/);
 
   auto slices = ToSliceInfo(context.storage->nestable_slices());
   EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 3}));
@@ -184,16 +184,38 @@
   // 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 /*tid*/, 0 /*cat*/, 1 /*name*/, 10 /* dur */);
-  tracker.Scoped(2 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/, 0 /* dur */);
-  tracker.Scoped(12 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/, 1 /* dur */);
-  tracker.Scoped(13 /*ts*/, 42 /*tid*/, 0 /*cat*/, 1 /*name*/, 1 /* dur */);
+  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*/,
+                 1 /*name*/, 1 /* dur */);
+  tracker.Scoped(13 /*ts*/, 42 /*ref*/, RefType::kRefUtid, 0 /*cat*/,
+                 1 /*name*/, 1 /* dur */);
 
   auto slices = ToSliceInfo(context.storage->nestable_slices());
   EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 10}, SliceInfo{2, 0},
                                   SliceInfo{12, 1}, SliceInfo{13, 1}));
 }
 
+TEST(SliceTrackerTest, DifferentRefTypes) {
+  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.End(10 /*ts*/, 42 /*ref*/, RefType::kRefUtid);
+
+  auto slices = ToSliceInfo(context.storage->nestable_slices());
+  EXPECT_THAT(slices, ElementsAre(SliceInfo{0, 10}, SliceInfo{2, 6}));
+
+  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().depths()[0], 0);
+  EXPECT_EQ(context.storage->nestable_slices().depths()[1], 0);
+}
+
 }  // namespace
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/syscall_tracker.h b/src/trace_processor/syscall_tracker.h
index d2c910f..b797395 100644
--- a/src/trace_processor/syscall_tracker.h
+++ b/src/trace_processor/syscall_tracker.h
@@ -49,14 +49,18 @@
 
   void Enter(int64_t ts, UniqueTid utid, uint32_t syscall_num) {
     StringId name = SyscallNumberToStringId(syscall_num);
-    if (name)
-      context_->slice_tracker->Begin(ts, utid, 0 /* cat */, name);
+    if (name) {
+      context_->slice_tracker->Begin(ts, utid, RefType::kRefUtid, 0 /* cat */,
+                                     name);
+    }
   }
 
   void Exit(int64_t ts, UniqueTid utid, uint32_t syscall_num) {
     StringId name = SyscallNumberToStringId(syscall_num);
-    if (name)
-      context_->slice_tracker->End(ts, utid, 0 /* cat */, name);
+    if (name) {
+      context_->slice_tracker->End(ts, utid, RefType::kRefUtid, 0 /* cat */,
+                                   name);
+    }
   }
 
  private:
diff --git a/src/trace_processor/syscall_tracker_unittest.cc b/src/trace_processor/syscall_tracker_unittest.cc
index 716889a..a5a5318 100644
--- a/src/trace_processor/syscall_tracker_unittest.cc
+++ b/src/trace_processor/syscall_tracker_unittest.cc
@@ -33,15 +33,17 @@
   MockSliceTracker(TraceProcessorContext* context) : SliceTracker(context) {}
   virtual ~MockSliceTracker() = default;
 
-  MOCK_METHOD5(Begin,
+  MOCK_METHOD6(Begin,
                void(int64_t timestamp,
-                    UniqueTid utid,
+                    int64_t ref,
+                    RefType ref_type,
                     StringId cat,
                     StringId name,
                     SetArgsCallback args_callback));
-  MOCK_METHOD5(End,
+  MOCK_METHOD6(End,
                void(int64_t timestamp,
-                    UniqueTid utid,
+                    int64_t ref,
+                    RefType ref_type,
                     StringId cat,
                     StringId name,
                     SetArgsCallback args_callback));
@@ -64,10 +66,10 @@
 TEST_F(SyscallTrackerTest, ReportUnknownSyscalls) {
   StringId begin_name = 0;
   StringId end_name = 0;
-  EXPECT_CALL(*slice_tracker, Begin(100, 42, 0, _, _))
-      .WillOnce(SaveArg<3>(&begin_name));
-  EXPECT_CALL(*slice_tracker, End(110, 42, 0, _, _))
-      .WillOnce(SaveArg<3>(&end_name));
+  EXPECT_CALL(*slice_tracker, Begin(100, 42, RefType::kRefUtid, 0, _, _))
+      .WillOnce(SaveArg<4>(&begin_name));
+  EXPECT_CALL(*slice_tracker, End(110, 42, RefType::kRefUtid, 0, _, _))
+      .WillOnce(SaveArg<4>(&end_name));
 
   context.syscall_tracker->Enter(100 /*ts*/, 42 /*utid*/, 57 /*sys_read*/);
   context.syscall_tracker->Exit(110 /*ts*/, 42 /*utid*/, 57 /*sys_read*/);
@@ -77,8 +79,8 @@
 
 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*/);
@@ -87,10 +89,10 @@
 TEST_F(SyscallTrackerTest, Aarch64) {
   StringId begin_name = 0;
   StringId end_name = 0;
-  EXPECT_CALL(*slice_tracker, Begin(100, 42, 0, _, _))
-      .WillOnce(SaveArg<3>(&begin_name));
-  EXPECT_CALL(*slice_tracker, End(110, 42, 0, _, _))
-      .WillOnce(SaveArg<3>(&end_name));
+  EXPECT_CALL(*slice_tracker, Begin(100, 42, RefType::kRefUtid, 0, _, _))
+      .WillOnce(SaveArg<4>(&begin_name));
+  EXPECT_CALL(*slice_tracker, End(110, 42, RefType::kRefUtid, 0, _, _))
+      .WillOnce(SaveArg<4>(&end_name));
 
   context.syscall_tracker->SetArchitecture(kAarch64);
   context.syscall_tracker->Enter(100 /*ts*/, 42 /*utid*/, 63 /*sys_read*/);
@@ -102,10 +104,10 @@
 TEST_F(SyscallTrackerTest, x8664) {
   StringId begin_name = 0;
   StringId end_name = 0;
-  EXPECT_CALL(*slice_tracker, Begin(100, 42, 0, _, _))
-      .WillOnce(SaveArg<3>(&begin_name));
-  EXPECT_CALL(*slice_tracker, End(110, 42, 0, _, _))
-      .WillOnce(SaveArg<3>(&end_name));
+  EXPECT_CALL(*slice_tracker, Begin(100, 42, RefType::kRefUtid, 0, _, _))
+      .WillOnce(SaveArg<4>(&begin_name));
+  EXPECT_CALL(*slice_tracker, End(110, 42, RefType::kRefUtid, 0, _, _))
+      .WillOnce(SaveArg<4>(&end_name));
 
   context.syscall_tracker->SetArchitecture(kX86_64);
   context.syscall_tracker->Enter(100 /*ts*/, 42 /*utid*/, 0 /*sys_read*/);
@@ -115,8 +117,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);