xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/common/slice_tracker_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cstdint>
18 #include <memory>
19 #include <optional>
20 #include <ostream>
21 #include <tuple>
22 #include <vector>
23 
24 #include "src/trace_processor/importers/common/args_tracker.h"
25 #include "src/trace_processor/importers/common/args_translation_table.h"
26 #include "src/trace_processor/importers/common/slice_tracker.h"
27 #include "src/trace_processor/importers/common/slice_translation_table.h"
28 #include "src/trace_processor/storage/trace_storage.h"
29 #include "src/trace_processor/tables/slice_tables_py.h"
30 #include "src/trace_processor/types/trace_processor_context.h"
31 #include "src/trace_processor/types/variadic.h"
32 #include "test/gtest_and_gmock.h"
33 
34 namespace perfetto::trace_processor {
35 namespace {
36 
37 using ::testing::ElementsAre;
38 using ::testing::Eq;
39 
40 struct SliceInfo {
41   int64_t start;
42   int64_t duration;
43 
operator ==perfetto::trace_processor::__anon5ad6184d0111::SliceInfo44   bool operator==(const SliceInfo& other) const {
45     return std::tie(start, duration) == std::tie(other.start, other.duration);
46   }
47 };
48 
PrintTo(const SliceInfo & info,::std::ostream * os)49 inline void PrintTo(const SliceInfo& info, ::std::ostream* os) {
50   *os << "SliceInfo{" << info.start << ", " << info.duration << "}";
51 }
52 
ToSliceInfo(const tables::SliceTable & slices)53 std::vector<SliceInfo> ToSliceInfo(const tables::SliceTable& slices) {
54   std::vector<SliceInfo> infos;
55   for (auto it = slices.IterateRows(); it; ++it) {
56     infos.emplace_back(SliceInfo{it.ts(), it.dur()});
57   }
58   return infos;
59 }
60 
61 class SliceTrackerTest : public ::testing::Test {
62  public:
SliceTrackerTest()63   SliceTrackerTest() {
64     context_.storage = std::make_unique<TraceStorage>();
65     context_.global_args_tracker =
66         std::make_unique<GlobalArgsTracker>(context_.storage.get());
67     context_.args_translation_table =
68         std::make_unique<ArgsTranslationTable>(context_.storage.get());
69     context_.slice_translation_table =
70         std::make_unique<SliceTranslationTable>(context_.storage.get());
71   }
72 
73  protected:
74   TraceProcessorContext context_;
75 };
76 
TEST_F(SliceTrackerTest,OneSliceDetailed)77 TEST_F(SliceTrackerTest, OneSliceDetailed) {
78   SliceTracker tracker(&context_);
79 
80   constexpr TrackId track{22u};
81   tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/,
82                 StringId::Raw(1) /*name*/);
83   tracker.End(10 /*ts*/, track, kNullStringId /*cat*/,
84               StringId::Raw(1) /*name*/);
85 
86   const auto& slices = context_.storage->slice_table();
87   EXPECT_EQ(slices.row_count(), 1u);
88   EXPECT_EQ(slices[0].ts(), 2);
89   EXPECT_EQ(slices[0].dur(), 8);
90   EXPECT_EQ(slices[0].track_id(), track);
91   EXPECT_EQ(slices[0].category().value_or(kNullStringId).raw_id(), 0u);
92   EXPECT_EQ(slices[0].name().value_or(kNullStringId).raw_id(), 1u);
93   EXPECT_EQ(slices[0].depth(), 0u);
94   EXPECT_EQ(slices[0].arg_set_id(), kInvalidArgSetId);
95 }
96 
TEST_F(SliceTrackerTest,OneSliceDetailedWithTranslatedName)97 TEST_F(SliceTrackerTest, OneSliceDetailedWithTranslatedName) {
98   SliceTracker tracker(&context_);
99 
100   const StringId raw_name = context_.storage->InternString("raw_name");
101   const StringId mapped_name = context_.storage->InternString("mapped_name");
102   context_.slice_translation_table->AddNameTranslationRule("raw_name",
103                                                            "mapped_name");
104 
105   constexpr TrackId track{22u};
106   tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/, raw_name /*name*/);
107   tracker.End(10 /*ts*/, track, kNullStringId /*cat*/, raw_name /*name*/);
108 
109   const auto& slices = context_.storage->slice_table();
110   EXPECT_EQ(slices.row_count(), 1u);
111   EXPECT_EQ(slices[0].ts(), 2);
112   EXPECT_EQ(slices[0].dur(), 8);
113   EXPECT_EQ(slices[0].track_id(), track);
114   EXPECT_EQ(slices[0].category().value_or(kNullStringId).raw_id(), 0u);
115   EXPECT_EQ(slices[0].name().value_or(kNullStringId).raw_id(),
116             mapped_name.raw_id());
117   EXPECT_EQ(slices[0].depth(), 0u);
118   EXPECT_EQ(slices[0].arg_set_id(), kInvalidArgSetId);
119 }
120 
TEST_F(SliceTrackerTest,NegativeTimestamps)121 TEST_F(SliceTrackerTest, NegativeTimestamps) {
122   SliceTracker tracker(&context_);
123 
124   constexpr TrackId track{22u};
125   tracker.Begin(-1000 /*ts*/, track, kNullStringId /*cat*/,
126                 StringId::Raw(1) /*name*/);
127   tracker.End(-501 /*ts*/, track, kNullStringId /*cat*/,
128               StringId::Raw(1) /*name*/);
129 
130   const auto& slices = context_.storage->slice_table();
131   EXPECT_EQ(slices.row_count(), 1u);
132 
133   auto rr = slices[0];
134   EXPECT_EQ(rr.ts(), -1000);
135   EXPECT_EQ(rr.dur(), 499);
136   EXPECT_EQ(rr.track_id(), track);
137   EXPECT_EQ(rr.category().value_or(kNullStringId).raw_id(), 0u);
138   EXPECT_EQ(rr.name().value_or(kNullStringId).raw_id(), 1u);
139   EXPECT_EQ(rr.depth(), 0u);
140   EXPECT_EQ(rr.arg_set_id(), kInvalidArgSetId);
141 }
142 
TEST_F(SliceTrackerTest,OneSliceWithArgs)143 TEST_F(SliceTrackerTest, OneSliceWithArgs) {
144   SliceTracker tracker(&context_);
145 
146   constexpr TrackId track{22u};
147   tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/,
148                 StringId::Raw(1) /*name*/,
149                 [](ArgsTracker::BoundInserter* inserter) {
150                   inserter->AddArg(/*flat_key=*/StringId::Raw(1),
151                                    /*key=*/StringId::Raw(2),
152                                    /*v=*/Variadic::Integer(10));
153                 });
154   tracker.End(10 /*ts*/, track, kNullStringId /*cat*/,
155               StringId::Raw(1) /*name*/,
156               [](ArgsTracker::BoundInserter* inserter) {
157                 inserter->AddArg(/*flat_key=*/StringId::Raw(3),
158                                  /*key=*/StringId::Raw(4),
159                                  /*v=*/Variadic::Integer(20));
160               });
161 
162   const auto& slices = context_.storage->slice_table();
163   EXPECT_EQ(slices.row_count(), 1u);
164 
165   auto sr = slices[0];
166   EXPECT_EQ(sr.ts(), 2);
167   EXPECT_EQ(sr.dur(), 8);
168   EXPECT_EQ(sr.track_id(), track);
169   EXPECT_EQ(sr.category().value_or(kNullStringId).raw_id(), 0u);
170   EXPECT_EQ(sr.name().value_or(kNullStringId).raw_id(), 1u);
171   EXPECT_EQ(sr.depth(), 0u);
172   auto set_id = sr.arg_set_id();
173 
174   const auto& args = context_.storage->arg_table();
175   auto ar0 = args[0];
176   auto ar1 = args[1];
177   EXPECT_EQ(ar0.arg_set_id(), set_id);
178   EXPECT_EQ(ar0.flat_key().raw_id(), 1u);
179   EXPECT_EQ(ar0.key().raw_id(), 2u);
180   EXPECT_EQ(ar0.int_value(), 10);
181   EXPECT_EQ(ar1.arg_set_id(), set_id);
182   EXPECT_EQ(ar1.flat_key().raw_id(), 3u);
183   EXPECT_EQ(ar1.key().raw_id(), 4u);
184   EXPECT_EQ(ar1.int_value(), 20);
185 }
186 
TEST_F(SliceTrackerTest,OneSliceWithArgsWithTranslatedName)187 TEST_F(SliceTrackerTest, OneSliceWithArgsWithTranslatedName) {
188   SliceTracker tracker(&context_);
189 
190   const StringId raw_name = context_.storage->InternString("raw_name");
191   const StringId mapped_name = context_.storage->InternString("mapped_name");
192   context_.slice_translation_table->AddNameTranslationRule("raw_name",
193                                                            "mapped_name");
194 
195   constexpr TrackId track{22u};
196   tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/, raw_name /*name*/,
197                 [](ArgsTracker::BoundInserter* inserter) {
198                   inserter->AddArg(/*flat_key=*/StringId::Raw(1),
199                                    /*key=*/StringId::Raw(2),
200                                    /*v=*/Variadic::Integer(10));
201                 });
202   tracker.End(10 /*ts*/, track, kNullStringId /*cat*/, raw_name /*name*/,
203               [](ArgsTracker::BoundInserter* inserter) {
204                 inserter->AddArg(/*flat_key=*/StringId::Raw(3),
205                                  /*key=*/StringId::Raw(4),
206                                  /*v=*/Variadic::Integer(20));
207               });
208 
209   const auto& slices = context_.storage->slice_table();
210   EXPECT_EQ(slices.row_count(), 1u);
211 
212   auto sr = slices[0];
213   EXPECT_EQ(sr.ts(), 2);
214   EXPECT_EQ(sr.dur(), 8);
215   EXPECT_EQ(sr.track_id(), track);
216   EXPECT_EQ(sr.category().value_or(kNullStringId).raw_id(), 0u);
217   EXPECT_EQ(sr.name().value_or(kNullStringId).raw_id(), mapped_name.raw_id());
218   EXPECT_EQ(sr.depth(), 0u);
219   auto set_id = sr.arg_set_id();
220 
221   const auto& args = context_.storage->arg_table();
222   auto ar0 = args[0];
223   auto ar1 = args[1];
224   EXPECT_EQ(ar0.arg_set_id(), set_id);
225   EXPECT_EQ(ar0.flat_key().raw_id(), 1u);
226   EXPECT_EQ(ar0.key().raw_id(), 2u);
227   EXPECT_EQ(ar0.int_value(), 10);
228   EXPECT_EQ(ar1.arg_set_id(), set_id);
229   EXPECT_EQ(ar1.flat_key().raw_id(), 3u);
230   EXPECT_EQ(ar1.key().raw_id(), 4u);
231   EXPECT_EQ(ar1.int_value(), 20);
232 }
233 
TEST_F(SliceTrackerTest,TwoSliceDetailed)234 TEST_F(SliceTrackerTest, TwoSliceDetailed) {
235   SliceTracker tracker(&context_);
236 
237   constexpr TrackId track{22u};
238   tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/,
239                 StringId::Raw(1) /*name*/);
240   tracker.Begin(3 /*ts*/, track, kNullStringId /*cat*/,
241                 StringId::Raw(2) /*name*/);
242   tracker.End(5 /*ts*/, track);
243   tracker.End(10 /*ts*/, track);
244 
245   const auto& slices = context_.storage->slice_table();
246 
247   EXPECT_EQ(slices.row_count(), 2u);
248 
249   auto sr0 = slices[0];
250   EXPECT_EQ(sr0.ts(), 2);
251   EXPECT_EQ(sr0.dur(), 8);
252   EXPECT_EQ(sr0.track_id(), track);
253   EXPECT_EQ(sr0.category().value_or(kNullStringId).raw_id(), 0u);
254   EXPECT_EQ(sr0.name().value_or(kNullStringId).raw_id(), 1u);
255   EXPECT_EQ(sr0.depth(), 0u);
256   EXPECT_EQ(sr0.parent_stack_id(), 0);
257 
258   auto sr1 = slices[1];
259   EXPECT_EQ(sr1.ts(), 3);
260   EXPECT_EQ(sr1.dur(), 2);
261   EXPECT_EQ(sr1.track_id(), track);
262   EXPECT_EQ(sr1.category().value_or(kNullStringId).raw_id(), 0u);
263   EXPECT_EQ(sr1.name().value_or(kNullStringId).raw_id(), 2u);
264   EXPECT_EQ(sr1.depth(), 1u);
265   EXPECT_NE(sr1.stack_id(), 0);
266 
267   EXPECT_EQ(sr0.stack_id(), sr1.parent_stack_id());
268 }
269 
TEST_F(SliceTrackerTest,Scoped)270 TEST_F(SliceTrackerTest, Scoped) {
271   SliceTracker tracker(&context_);
272 
273   constexpr TrackId track{22u};
274   tracker.Begin(0 /*ts*/, track, kNullStringId, kNullStringId);
275   tracker.Begin(1 /*ts*/, track, kNullStringId, kNullStringId);
276   tracker.Scoped(2 /*ts*/, track, kNullStringId, kNullStringId, 6);
277   tracker.End(9 /*ts*/, track);
278   tracker.End(10 /*ts*/, track);
279 
280   auto slices = ToSliceInfo(context_.storage->slice_table());
281   EXPECT_THAT(slices,
282               ElementsAre(SliceInfo{0, 10}, SliceInfo{1, 8}, SliceInfo{2, 6}));
283 }
284 
TEST_F(SliceTrackerTest,ScopedWithTranslatedName)285 TEST_F(SliceTrackerTest, ScopedWithTranslatedName) {
286   SliceTracker tracker(&context_);
287 
288   const StringId raw_name = context_.storage->InternString("raw_name");
289   context_.slice_translation_table->AddNameTranslationRule("raw_name",
290                                                            "mapped_name");
291 
292   constexpr TrackId track{22u};
293   tracker.Begin(0 /*ts*/, track, kNullStringId, raw_name);
294   tracker.Begin(1 /*ts*/, track, kNullStringId, raw_name);
295   tracker.Scoped(2 /*ts*/, track, kNullStringId, raw_name, 6);
296   tracker.End(9 /*ts*/, track);
297   tracker.End(10 /*ts*/, track);
298 
299   auto slices = ToSliceInfo(context_.storage->slice_table());
300   EXPECT_THAT(slices,
301               ElementsAre(SliceInfo{0, 10}, SliceInfo{1, 8}, SliceInfo{2, 6}));
302 }
303 
TEST_F(SliceTrackerTest,ParentId)304 TEST_F(SliceTrackerTest, ParentId) {
305   SliceTracker tracker(&context_);
306 
307   constexpr TrackId track{22u};
308   tracker.Begin(100, track, kNullStringId, kNullStringId);
309   tracker.Begin(101, track, kNullStringId, kNullStringId);
310   tracker.Begin(102, track, kNullStringId, kNullStringId);
311   tracker.End(103, track);
312   tracker.End(150, track);
313   tracker.End(200, track);
314 
315   SliceId parent = context_.storage->slice_table()[0].id();
316   SliceId child = context_.storage->slice_table()[1].id();
317   EXPECT_THAT(context_.storage->slice_table().parent_id().ToVectorForTesting(),
318               ElementsAre(std::nullopt, parent, child));
319 }
320 
TEST_F(SliceTrackerTest,IgnoreMismatchedEnds)321 TEST_F(SliceTrackerTest, IgnoreMismatchedEnds) {
322   SliceTracker tracker(&context_);
323 
324   constexpr TrackId track{22u};
325   tracker.Begin(2 /*ts*/, track, StringId::Raw(5) /*cat*/,
326                 StringId::Raw(1) /*name*/);
327   tracker.End(3 /*ts*/, track, StringId::Raw(1) /*cat*/,
328               StringId::Raw(1) /*name*/);
329   tracker.End(4 /*ts*/, track, kNullStringId /*cat*/,
330               StringId::Raw(2) /*name*/);
331   tracker.End(5 /*ts*/, track, StringId::Raw(5) /*cat*/,
332               StringId::Raw(1) /*name*/);
333 
334   auto slices = ToSliceInfo(context_.storage->slice_table());
335   EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 3}));
336 }
337 
TEST_F(SliceTrackerTest,ZeroLengthScoped)338 TEST_F(SliceTrackerTest, ZeroLengthScoped) {
339   SliceTracker tracker(&context_);
340 
341   // Bug scenario: the second zero-length scoped slice prevents the first slice
342   // from being closed, leading to an inconsistency when we try to insert the
343   // final slice and it doesn't intersect with the still pending first slice.
344   constexpr TrackId track{22u};
345   tracker.Scoped(2 /*ts*/, track, kNullStringId /*cat*/,
346                  StringId::Raw(1) /*name*/, 10 /* dur */);
347   tracker.Scoped(2 /*ts*/, track, kNullStringId /*cat*/,
348                  StringId::Raw(1) /*name*/, 0 /* dur */);
349   tracker.Scoped(12 /*ts*/, track, kNullStringId /*cat*/,
350                  StringId::Raw(1) /*name*/, 1 /* dur */);
351   tracker.Scoped(13 /*ts*/, track, kNullStringId /*cat*/,
352                  StringId::Raw(1) /*name*/, 1 /* dur */);
353 
354   auto slices = ToSliceInfo(context_.storage->slice_table());
355   EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 10}, SliceInfo{2, 0},
356                                   SliceInfo{12, 1}, SliceInfo{13, 1}));
357 }
358 
TEST_F(SliceTrackerTest,DifferentTracks)359 TEST_F(SliceTrackerTest, DifferentTracks) {
360   SliceTracker tracker(&context_);
361 
362   constexpr TrackId track_a{22u};
363   constexpr TrackId track_b{23u};
364   tracker.Begin(0 /*ts*/, track_a, kNullStringId, kNullStringId);
365   tracker.Scoped(2 /*ts*/, track_b, kNullStringId, kNullStringId, 6);
366   tracker.Scoped(3 /*ts*/, track_b, kNullStringId, kNullStringId, 4);
367   tracker.End(10 /*ts*/, track_a);
368   tracker.FlushPendingSlices();
369 
370   const auto& table = context_.storage->slice_table();
371   auto slices = ToSliceInfo(table);
372   EXPECT_THAT(slices,
373               ElementsAre(SliceInfo{0, 10}, SliceInfo{2, 6}, SliceInfo{3, 4}));
374 
375   EXPECT_EQ(table[0].track_id(), track_a);
376   EXPECT_EQ(table[1].track_id(), track_b);
377   EXPECT_EQ(table[2].track_id(), track_b);
378   EXPECT_EQ(table[0].depth(), 0u);
379   EXPECT_EQ(table[1].depth(), 0u);
380   EXPECT_EQ(table[2].depth(), 1u);
381 }
382 
TEST_F(SliceTrackerTest,EndEventOutOfOrder)383 TEST_F(SliceTrackerTest, EndEventOutOfOrder) {
384   SliceTracker tracker(&context_);
385 
386   constexpr TrackId track{22u};
387   tracker.Scoped(50 /*ts*/, track, StringId::Raw(11) /*cat*/,
388                  StringId::Raw(21) /*name*/, 100 /*dur*/);
389   tracker.Begin(100 /*ts*/, track, StringId::Raw(12) /*cat*/,
390                 StringId::Raw(22) /*name*/);
391 
392   // This slice should now have depth 0.
393   tracker.Scoped(450 /*ts*/, track, StringId::Raw(12) /*cat*/,
394                  StringId::Raw(22) /*name*/, 100 /*dur*/);
395 
396   // This slice should be ignored.
397   tracker.End(500 /*ts*/, track, StringId::Raw(12) /*cat*/,
398               StringId::Raw(22) /*name*/);
399 
400   tracker.Begin(800 /*ts*/, track, StringId::Raw(13) /*cat*/,
401                 StringId::Raw(23) /*name*/);
402   // Null cat and name matches everything.
403   tracker.End(1000 /*ts*/, track, kNullStringId /*cat*/,
404               kNullStringId /*name*/);
405 
406   // Slice will not close if category is different.
407   tracker.Begin(1100 /*ts*/, track, StringId::Raw(11) /*cat*/,
408                 StringId::Raw(21) /*name*/);
409   tracker.End(1200 /*ts*/, track, StringId::Raw(12) /*cat*/,
410               StringId::Raw(21) /*name*/);
411 
412   // Slice will not close if name is different.
413   tracker.Begin(1300 /*ts*/, track, StringId::Raw(11) /*cat*/,
414                 StringId::Raw(21) /*name*/);
415   tracker.End(1400 /*ts*/, track, StringId::Raw(11) /*cat*/,
416               StringId::Raw(22) /*name*/);
417 
418   tracker.FlushPendingSlices();
419 
420   const auto& st = context_.storage->slice_table();
421   auto slices = ToSliceInfo(st);
422   EXPECT_THAT(slices, ElementsAre(SliceInfo{50, 100}, SliceInfo{100, 50},
423                                   SliceInfo{450, 100}, SliceInfo{800, 200},
424                                   SliceInfo{1100, -1}, SliceInfo{1300, 0 - 1}));
425 
426   EXPECT_EQ(st[0].depth(), 0u);
427   EXPECT_EQ(st[1].depth(), 1u);
428   EXPECT_EQ(st[2].depth(), 0u);
429   EXPECT_EQ(st[3].depth(), 0u);
430 }
431 
TEST_F(SliceTrackerTest,GetTopmostSliceOnTrack)432 TEST_F(SliceTrackerTest, GetTopmostSliceOnTrack) {
433   SliceTracker tracker(&context_);
434 
435   TrackId track{1u};
436   TrackId track2{2u};
437 
438   EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track), std::nullopt);
439 
440   tracker.Begin(100, track, StringId::Raw(11), StringId::Raw(11));
441   SliceId slice1 = context_.storage->slice_table()[0].id();
442 
443   EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track).value(), slice1);
444 
445   tracker.Begin(120, track, StringId::Raw(22), StringId::Raw(22));
446   SliceId slice2 = context_.storage->slice_table()[1].id();
447 
448   EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track).value(), slice2);
449 
450   EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track2), std::nullopt);
451 
452   tracker.End(140, track, StringId::Raw(22), StringId::Raw(22));
453 
454   EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track).value(), slice1);
455 
456   tracker.End(330, track, StringId::Raw(11), StringId::Raw(11));
457 
458   EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track), std::nullopt);
459 }
460 
TEST_F(SliceTrackerTest,OnSliceBeginCallback)461 TEST_F(SliceTrackerTest, OnSliceBeginCallback) {
462   SliceTracker tracker(&context_);
463 
464   TrackId track1{1u};
465   TrackId track2{2u};
466 
467   std::vector<TrackId> track_records;
468   std::vector<SliceId> slice_records;
469   tracker.SetOnSliceBeginCallback([&](TrackId track_id, SliceId slice_id) {
470     track_records.emplace_back(track_id);
471     slice_records.emplace_back(slice_id);
472   });
473 
474   EXPECT_TRUE(track_records.empty());
475   EXPECT_TRUE(slice_records.empty());
476 
477   tracker.Begin(100, track1, StringId::Raw(11), StringId::Raw(11));
478   SliceId slice1 = context_.storage->slice_table()[0].id();
479   EXPECT_THAT(track_records, ElementsAre(TrackId{1u}));
480   EXPECT_THAT(slice_records, ElementsAre(slice1));
481 
482   tracker.Begin(120, track2, StringId::Raw(22), StringId::Raw(22));
483   SliceId slice2 = context_.storage->slice_table()[1].id();
484   EXPECT_THAT(track_records, ElementsAre(TrackId{1u}, TrackId{2u}));
485   EXPECT_THAT(slice_records, ElementsAre(slice1, slice2));
486 
487   tracker.Begin(330, track1, StringId::Raw(33), StringId::Raw(33));
488   SliceId slice3 = context_.storage->slice_table()[2].id();
489   EXPECT_THAT(track_records,
490               ElementsAre(TrackId{1u}, TrackId{2u}, TrackId{1u}));
491   EXPECT_THAT(slice_records, ElementsAre(slice1, slice2, slice3));
492 }
493 
494 }  // namespace
495 }  // namespace perfetto::trace_processor
496