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