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