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