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