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::__anonaf71f4430111::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(new GlobalArgsTracker(&context));
134 context.slice_translation_table.reset(
135 new SliceTranslationTable(context.storage.get()));
136 SliceTracker tracker(&context);
137
138 constexpr TrackId track{22u};
139 tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/,
140 StringId::Raw(1) /*name*/,
141 [](ArgsTracker::BoundInserter* inserter) {
142 inserter->AddArg(/*flat_key=*/StringId::Raw(1),
143 /*key=*/StringId::Raw(2),
144 /*value=*/Variadic::Integer(10));
145 });
146 tracker.End(10 /*ts*/, track, kNullStringId /*cat*/,
147 StringId::Raw(1) /*name*/,
148 [](ArgsTracker::BoundInserter* inserter) {
149 inserter->AddArg(/*flat_key=*/StringId::Raw(3),
150 /*key=*/StringId::Raw(4),
151 /*value=*/Variadic::Integer(20));
152 });
153
154 const auto& slices = context.storage->slice_table();
155 EXPECT_EQ(slices.row_count(), 1u);
156 EXPECT_EQ(slices.ts()[0], 2);
157 EXPECT_EQ(slices.dur()[0], 8);
158 EXPECT_EQ(slices.track_id()[0], track);
159 EXPECT_EQ(slices.category()[0].value_or(kNullStringId).raw_id(), 0u);
160 EXPECT_EQ(slices.name()[0].value_or(kNullStringId).raw_id(), 1u);
161 EXPECT_EQ(slices.depth()[0], 0u);
162 auto set_id = slices.arg_set_id()[0];
163
164 const auto& args = context.storage->arg_table();
165 EXPECT_EQ(args.arg_set_id()[0], set_id);
166 EXPECT_EQ(args.flat_key()[0].raw_id(), 1u);
167 EXPECT_EQ(args.key()[0].raw_id(), 2u);
168 EXPECT_EQ(args.int_value()[0], 10);
169 EXPECT_EQ(args.arg_set_id()[1], set_id);
170 EXPECT_EQ(args.flat_key()[1].raw_id(), 3u);
171 EXPECT_EQ(args.key()[1].raw_id(), 4u);
172 EXPECT_EQ(args.int_value()[1], 20);
173 }
174
TEST(SliceTrackerTest,OneSliceWithArgsWithTranslatedName)175 TEST(SliceTrackerTest, OneSliceWithArgsWithTranslatedName) {
176 TraceProcessorContext context;
177 context.storage.reset(new TraceStorage());
178 context.global_args_tracker.reset(new GlobalArgsTracker(&context));
179 context.slice_translation_table.reset(
180 new SliceTranslationTable(context.storage.get()));
181 SliceTracker tracker(&context);
182
183 const StringId raw_name = context.storage->InternString("raw_name");
184 const StringId mapped_name = context.storage->InternString("mapped_name");
185 context.slice_translation_table->AddNameTranslationRule("raw_name",
186 "mapped_name");
187
188 constexpr TrackId track{22u};
189 tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/, raw_name /*name*/,
190 [](ArgsTracker::BoundInserter* inserter) {
191 inserter->AddArg(/*flat_key=*/StringId::Raw(1),
192 /*key=*/StringId::Raw(2),
193 /*value=*/Variadic::Integer(10));
194 });
195 tracker.End(10 /*ts*/, track, kNullStringId /*cat*/, raw_name /*name*/,
196 [](ArgsTracker::BoundInserter* inserter) {
197 inserter->AddArg(/*flat_key=*/StringId::Raw(3),
198 /*key=*/StringId::Raw(4),
199 /*value=*/Variadic::Integer(20));
200 });
201
202 const auto& slices = context.storage->slice_table();
203 EXPECT_EQ(slices.row_count(), 1u);
204 EXPECT_EQ(slices.ts()[0], 2);
205 EXPECT_EQ(slices.dur()[0], 8);
206 EXPECT_EQ(slices.track_id()[0], track);
207 EXPECT_EQ(slices.category()[0].value_or(kNullStringId).raw_id(), 0u);
208 EXPECT_EQ(slices.name()[0].value_or(kNullStringId).raw_id(),
209 mapped_name.raw_id());
210 EXPECT_EQ(slices.depth()[0], 0u);
211 auto set_id = slices.arg_set_id()[0];
212
213 const auto& args = context.storage->arg_table();
214 EXPECT_EQ(args.arg_set_id()[0], set_id);
215 EXPECT_EQ(args.flat_key()[0].raw_id(), 1u);
216 EXPECT_EQ(args.key()[0].raw_id(), 2u);
217 EXPECT_EQ(args.int_value()[0], 10);
218 EXPECT_EQ(args.arg_set_id()[1], set_id);
219 EXPECT_EQ(args.flat_key()[1].raw_id(), 3u);
220 EXPECT_EQ(args.key()[1].raw_id(), 4u);
221 EXPECT_EQ(args.int_value()[1], 20);
222 }
223
TEST(SliceTrackerTest,TwoSliceDetailed)224 TEST(SliceTrackerTest, TwoSliceDetailed) {
225 TraceProcessorContext context;
226 context.storage.reset(new TraceStorage());
227 context.slice_translation_table.reset(
228 new SliceTranslationTable(context.storage.get()));
229 SliceTracker tracker(&context);
230
231 constexpr TrackId track{22u};
232 tracker.Begin(2 /*ts*/, track, kNullStringId /*cat*/,
233 StringId::Raw(1) /*name*/);
234 tracker.Begin(3 /*ts*/, track, kNullStringId /*cat*/,
235 StringId::Raw(2) /*name*/);
236 tracker.End(5 /*ts*/, track);
237 tracker.End(10 /*ts*/, track);
238
239 const auto& slices = context.storage->slice_table();
240
241 EXPECT_EQ(slices.row_count(), 2u);
242
243 uint32_t idx = 0;
244 EXPECT_EQ(slices.ts()[idx], 2);
245 EXPECT_EQ(slices.dur()[idx], 8);
246 EXPECT_EQ(slices.track_id()[idx], track);
247 EXPECT_EQ(slices.category()[idx].value_or(kNullStringId).raw_id(), 0u);
248 EXPECT_EQ(slices.name()[idx].value_or(kNullStringId).raw_id(), 1u);
249 EXPECT_EQ(slices.depth()[idx++], 0u);
250
251 EXPECT_EQ(slices.ts()[idx], 3);
252 EXPECT_EQ(slices.dur()[idx], 2);
253 EXPECT_EQ(slices.track_id()[idx], track);
254 EXPECT_EQ(slices.category()[idx].value_or(kNullStringId).raw_id(), 0u);
255 EXPECT_EQ(slices.name()[idx].value_or(kNullStringId).raw_id(), 2u);
256 EXPECT_EQ(slices.depth()[idx], 1u);
257
258 EXPECT_EQ(slices.parent_stack_id()[0], 0);
259 EXPECT_EQ(slices.stack_id()[0], slices.parent_stack_id()[1]);
260 EXPECT_NE(slices.stack_id()[1], 0);
261 }
262
TEST(SliceTrackerTest,Scoped)263 TEST(SliceTrackerTest, Scoped) {
264 TraceProcessorContext context;
265 context.storage.reset(new TraceStorage());
266 context.slice_translation_table.reset(
267 new SliceTranslationTable(context.storage.get()));
268 SliceTracker tracker(&context);
269
270 constexpr TrackId track{22u};
271 tracker.Begin(0 /*ts*/, track, kNullStringId, kNullStringId);
272 tracker.Begin(1 /*ts*/, track, kNullStringId, kNullStringId);
273 tracker.Scoped(2 /*ts*/, track, kNullStringId, kNullStringId, 6);
274 tracker.End(9 /*ts*/, track);
275 tracker.End(10 /*ts*/, track);
276
277 auto slices = ToSliceInfo(context.storage->slice_table());
278 EXPECT_THAT(slices,
279 ElementsAre(SliceInfo{0, 10}, SliceInfo{1, 8}, SliceInfo{2, 6}));
280 }
281
TEST(SliceTrackerTest,ScopedWithTranslatedName)282 TEST(SliceTrackerTest, ScopedWithTranslatedName) {
283 TraceProcessorContext context;
284 context.storage.reset(new TraceStorage());
285 context.slice_translation_table.reset(
286 new SliceTranslationTable(context.storage.get()));
287 SliceTracker tracker(&context);
288
289 const StringId raw_name = context.storage->InternString("raw_name");
290 context.slice_translation_table->AddNameTranslationRule("raw_name",
291 "mapped_name");
292
293 constexpr TrackId track{22u};
294 tracker.Begin(0 /*ts*/, track, kNullStringId, raw_name);
295 tracker.Begin(1 /*ts*/, track, kNullStringId, raw_name);
296 tracker.Scoped(2 /*ts*/, track, kNullStringId, raw_name, 6);
297 tracker.End(9 /*ts*/, track);
298 tracker.End(10 /*ts*/, track);
299
300 auto slices = ToSliceInfo(context.storage->slice_table());
301 EXPECT_THAT(slices,
302 ElementsAre(SliceInfo{0, 10}, SliceInfo{1, 8}, SliceInfo{2, 6}));
303 }
304
TEST(SliceTrackerTest,ParentId)305 TEST(SliceTrackerTest, ParentId) {
306 TraceProcessorContext context;
307 context.storage.reset(new TraceStorage());
308 context.slice_translation_table.reset(
309 new SliceTranslationTable(context.storage.get()));
310 SliceTracker tracker(&context);
311
312 constexpr TrackId track{22u};
313 tracker.Begin(100, track, kNullStringId, kNullStringId);
314 tracker.Begin(101, track, kNullStringId, kNullStringId);
315 tracker.Begin(102, track, kNullStringId, kNullStringId);
316 tracker.End(103, track);
317 tracker.End(150, track);
318 tracker.End(200, track);
319
320 SliceId parent = context.storage->slice_table().id()[0];
321 SliceId child = context.storage->slice_table().id()[1];
322 EXPECT_THAT(context.storage->slice_table().parent_id().ToVectorForTesting(),
323 ElementsAre(base::nullopt, parent, child));
324 }
325
TEST(SliceTrackerTest,IgnoreMismatchedEnds)326 TEST(SliceTrackerTest, IgnoreMismatchedEnds) {
327 TraceProcessorContext context;
328 context.storage.reset(new TraceStorage());
329 context.slice_translation_table.reset(
330 new SliceTranslationTable(context.storage.get()));
331 SliceTracker tracker(&context);
332
333 constexpr TrackId track{22u};
334 tracker.Begin(2 /*ts*/, track, StringId::Raw(5) /*cat*/,
335 StringId::Raw(1) /*name*/);
336 tracker.End(3 /*ts*/, track, StringId::Raw(1) /*cat*/,
337 StringId::Raw(1) /*name*/);
338 tracker.End(4 /*ts*/, track, kNullStringId /*cat*/,
339 StringId::Raw(2) /*name*/);
340 tracker.End(5 /*ts*/, track, StringId::Raw(5) /*cat*/,
341 StringId::Raw(1) /*name*/);
342
343 auto slices = ToSliceInfo(context.storage->slice_table());
344 EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 3}));
345 }
346
TEST(SliceTrackerTest,ZeroLengthScoped)347 TEST(SliceTrackerTest, ZeroLengthScoped) {
348 TraceProcessorContext context;
349 context.storage.reset(new TraceStorage());
350 context.slice_translation_table.reset(
351 new SliceTranslationTable(context.storage.get()));
352 SliceTracker tracker(&context);
353
354 // Bug scenario: the second zero-length scoped slice prevents the first slice
355 // from being closed, leading to an inconsistency when we try to insert the
356 // final slice and it doesn't intersect with the still pending first slice.
357 constexpr TrackId track{22u};
358 tracker.Scoped(2 /*ts*/, track, kNullStringId /*cat*/,
359 StringId::Raw(1) /*name*/, 10 /* dur */);
360 tracker.Scoped(2 /*ts*/, track, kNullStringId /*cat*/,
361 StringId::Raw(1) /*name*/, 0 /* dur */);
362 tracker.Scoped(12 /*ts*/, track, kNullStringId /*cat*/,
363 StringId::Raw(1) /*name*/, 1 /* dur */);
364 tracker.Scoped(13 /*ts*/, track, kNullStringId /*cat*/,
365 StringId::Raw(1) /*name*/, 1 /* dur */);
366
367 auto slices = ToSliceInfo(context.storage->slice_table());
368 EXPECT_THAT(slices, ElementsAre(SliceInfo{2, 10}, SliceInfo{2, 0},
369 SliceInfo{12, 1}, SliceInfo{13, 1}));
370 }
371
TEST(SliceTrackerTest,DifferentTracks)372 TEST(SliceTrackerTest, DifferentTracks) {
373 TraceProcessorContext context;
374 context.storage.reset(new TraceStorage());
375 context.slice_translation_table.reset(
376 new SliceTranslationTable(context.storage.get()));
377 SliceTracker tracker(&context);
378
379 constexpr TrackId track_a{22u};
380 constexpr TrackId track_b{23u};
381 tracker.Begin(0 /*ts*/, track_a, kNullStringId, kNullStringId);
382 tracker.Scoped(2 /*ts*/, track_b, kNullStringId, kNullStringId, 6);
383 tracker.Scoped(3 /*ts*/, track_b, kNullStringId, kNullStringId, 4);
384 tracker.End(10 /*ts*/, track_a);
385 tracker.FlushPendingSlices();
386
387 auto slices = ToSliceInfo(context.storage->slice_table());
388 EXPECT_THAT(slices,
389 ElementsAre(SliceInfo{0, 10}, SliceInfo{2, 6}, SliceInfo{3, 4}));
390
391 EXPECT_EQ(context.storage->slice_table().track_id()[0], track_a);
392 EXPECT_EQ(context.storage->slice_table().track_id()[1], track_b);
393 EXPECT_EQ(context.storage->slice_table().track_id()[2], track_b);
394 EXPECT_EQ(context.storage->slice_table().depth()[0], 0u);
395 EXPECT_EQ(context.storage->slice_table().depth()[1], 0u);
396 EXPECT_EQ(context.storage->slice_table().depth()[2], 1u);
397 }
398
TEST(SliceTrackerTest,EndEventOutOfOrder)399 TEST(SliceTrackerTest, EndEventOutOfOrder) {
400 TraceProcessorContext context;
401 context.storage.reset(new TraceStorage());
402 context.slice_translation_table.reset(
403 new SliceTranslationTable(context.storage.get()));
404 SliceTracker tracker(&context);
405
406 constexpr TrackId track{22u};
407 tracker.Scoped(50 /*ts*/, track, StringId::Raw(11) /*cat*/,
408 StringId::Raw(21) /*name*/, 100 /*dur*/);
409 tracker.Begin(100 /*ts*/, track, StringId::Raw(12) /*cat*/,
410 StringId::Raw(22) /*name*/);
411
412 // This slice should now have depth 0.
413 tracker.Scoped(450 /*ts*/, track, StringId::Raw(12) /*cat*/,
414 StringId::Raw(22) /*name*/, 100 /*dur*/);
415
416 // This slice should be ignored.
417 tracker.End(500 /*ts*/, track, StringId::Raw(12) /*cat*/,
418 StringId::Raw(22) /*name*/);
419
420 tracker.Begin(800 /*ts*/, track, StringId::Raw(13) /*cat*/,
421 StringId::Raw(23) /*name*/);
422 // Null cat and name matches everything.
423 tracker.End(1000 /*ts*/, track, kNullStringId /*cat*/,
424 kNullStringId /*name*/);
425
426 // Slice will not close if category is different.
427 tracker.Begin(1100 /*ts*/, track, StringId::Raw(11) /*cat*/,
428 StringId::Raw(21) /*name*/);
429 tracker.End(1200 /*ts*/, track, StringId::Raw(12) /*cat*/,
430 StringId::Raw(21) /*name*/);
431
432 // Slice will not close if name is different.
433 tracker.Begin(1300 /*ts*/, track, StringId::Raw(11) /*cat*/,
434 StringId::Raw(21) /*name*/);
435 tracker.End(1400 /*ts*/, track, StringId::Raw(11) /*cat*/,
436 StringId::Raw(22) /*name*/);
437
438 tracker.FlushPendingSlices();
439
440 auto slices = ToSliceInfo(context.storage->slice_table());
441 EXPECT_THAT(slices, ElementsAre(SliceInfo{50, 100}, SliceInfo{100, 50},
442 SliceInfo{450, 100}, SliceInfo{800, 200},
443 SliceInfo{1100, -1}, SliceInfo{1300, 0 - 1}));
444
445 EXPECT_EQ(context.storage->slice_table().depth()[0], 0u);
446 EXPECT_EQ(context.storage->slice_table().depth()[1], 1u);
447 EXPECT_EQ(context.storage->slice_table().depth()[2], 0u);
448 EXPECT_EQ(context.storage->slice_table().depth()[3], 0u);
449 }
450
TEST(SliceTrackerTest,GetTopmostSliceOnTrack)451 TEST(SliceTrackerTest, GetTopmostSliceOnTrack) {
452 TraceProcessorContext context;
453 context.storage.reset(new TraceStorage());
454 context.slice_translation_table.reset(
455 new SliceTranslationTable(context.storage.get()));
456 SliceTracker tracker(&context);
457
458 TrackId track{1u};
459 TrackId track2{2u};
460
461 EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track), base::nullopt);
462
463 tracker.Begin(100, track, StringId::Raw(11), StringId::Raw(11));
464 SliceId slice1 = context.storage->slice_table().id()[0];
465
466 EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track).value(), slice1);
467
468 tracker.Begin(120, track, StringId::Raw(22), StringId::Raw(22));
469 SliceId slice2 = context.storage->slice_table().id()[1];
470
471 EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track).value(), slice2);
472
473 EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track2), base::nullopt);
474
475 tracker.End(140, track, StringId::Raw(22), StringId::Raw(22));
476
477 EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track).value(), slice1);
478
479 tracker.End(330, track, StringId::Raw(11), StringId::Raw(11));
480
481 EXPECT_EQ(tracker.GetTopmostSliceOnTrack(track), base::nullopt);
482 }
483
TEST(SliceTrackerTest,OnSliceBeginCallback)484 TEST(SliceTrackerTest, OnSliceBeginCallback) {
485 TraceProcessorContext context;
486 context.storage.reset(new TraceStorage());
487 context.slice_translation_table.reset(
488 new SliceTranslationTable(context.storage.get()));
489 SliceTracker tracker(&context);
490
491 TrackId track1{1u};
492 TrackId track2{2u};
493
494 std::vector<TrackId> track_records;
495 std::vector<SliceId> slice_records;
496 tracker.SetOnSliceBeginCallback([&](TrackId track_id, SliceId slice_id) {
497 track_records.emplace_back(track_id);
498 slice_records.emplace_back(slice_id);
499 });
500
501 EXPECT_TRUE(track_records.empty());
502 EXPECT_TRUE(slice_records.empty());
503
504 tracker.Begin(100, track1, StringId::Raw(11), StringId::Raw(11));
505 SliceId slice1 = context.storage->slice_table().id()[0];
506 EXPECT_THAT(track_records, ElementsAre(TrackId{1u}));
507 EXPECT_THAT(slice_records, ElementsAre(slice1));
508
509 tracker.Begin(120, track2, StringId::Raw(22), StringId::Raw(22));
510 SliceId slice2 = context.storage->slice_table().id()[1];
511 EXPECT_THAT(track_records, ElementsAre(TrackId{1u}, TrackId{2u}));
512 EXPECT_THAT(slice_records, ElementsAre(slice1, slice2));
513
514 tracker.Begin(330, track1, StringId::Raw(33), StringId::Raw(33));
515 SliceId slice3 = context.storage->slice_table().id()[2];
516 EXPECT_THAT(track_records,
517 ElementsAre(TrackId{1u}, TrackId{2u}, TrackId{1u}));
518 EXPECT_THAT(slice_records, ElementsAre(slice1, slice2, slice3));
519 }
520
521 } // namespace
522 } // namespace trace_processor
523 } // namespace perfetto
524