1 /*
2 * Copyright (C) 2022 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 "src/trace_processor/importers/fuchsia/fuchsia_trace_parser.h"
18
19 #include "perfetto/base/logging.h"
20 #include "perfetto/ext/base/string_view.h"
21 #include "perfetto/protozero/scattered_heap_buffer.h"
22 #include "perfetto/trace_processor/trace_blob.h"
23
24 #include "src/trace_processor/importers/common/args_tracker.h"
25 #include "src/trace_processor/importers/common/args_translation_table.h"
26 #include "src/trace_processor/importers/common/clock_tracker.h"
27 #include "src/trace_processor/importers/common/cpu_tracker.h"
28 #include "src/trace_processor/importers/common/event_tracker.h"
29 #include "src/trace_processor/importers/common/flow_tracker.h"
30 #include "src/trace_processor/importers/common/machine_tracker.h"
31 #include "src/trace_processor/importers/common/metadata_tracker.h"
32 #include "src/trace_processor/importers/common/process_track_translation_table.h"
33 #include "src/trace_processor/importers/common/process_tracker.h"
34 #include "src/trace_processor/importers/common/slice_tracker.h"
35 #include "src/trace_processor/importers/common/stack_profile_tracker.h"
36 #include "src/trace_processor/importers/common/trace_parser.h"
37 #include "src/trace_processor/importers/common/track_tracker.h"
38 #include "src/trace_processor/importers/ftrace/ftrace_sched_event_tracker.h"
39 #include "src/trace_processor/importers/fuchsia/fuchsia_trace_tokenizer.h"
40 #include "src/trace_processor/importers/proto/additional_modules.h"
41 #include "src/trace_processor/importers/proto/default_modules.h"
42 #include "src/trace_processor/importers/proto/proto_trace_parser_impl.h"
43 #include "src/trace_processor/sorter/trace_sorter.h"
44 #include "src/trace_processor/storage/metadata.h"
45 #include "src/trace_processor/storage/trace_storage.h"
46 #include "src/trace_processor/util/descriptors.h"
47 #include "test/gtest_and_gmock.h"
48
49 #include "protos/perfetto/common/builtin_clock.pbzero.h"
50 #include "protos/perfetto/common/sys_stats_counters.pbzero.h"
51 #include "protos/perfetto/config/trace_config.pbzero.h"
52 #include "protos/perfetto/trace/android/packages_list.pbzero.h"
53 #include "protos/perfetto/trace/chrome/chrome_benchmark_metadata.pbzero.h"
54 #include "protos/perfetto/trace/chrome/chrome_trace_event.pbzero.h"
55 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
56 #include "protos/perfetto/trace/ftrace/ftrace.pbzero.h"
57 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
58 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
59 #include "protos/perfetto/trace/ftrace/generic.pbzero.h"
60 #include "protos/perfetto/trace/ftrace/power.pbzero.h"
61 #include "protos/perfetto/trace/ftrace/sched.pbzero.h"
62 #include "protos/perfetto/trace/ftrace/task.pbzero.h"
63 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
64 #include "protos/perfetto/trace/profiling/profile_packet.pbzero.h"
65 #include "protos/perfetto/trace/ps/process_tree.pbzero.h"
66 #include "protos/perfetto/trace/sys_stats/sys_stats.pbzero.h"
67 #include "protos/perfetto/trace/trace.pbzero.h"
68 #include "protos/perfetto/trace/trace_packet.pbzero.h"
69 #include "protos/perfetto/trace/track_event/chrome_thread_descriptor.pbzero.h"
70 #include "protos/perfetto/trace/track_event/counter_descriptor.pbzero.h"
71 #include "protos/perfetto/trace/track_event/debug_annotation.pbzero.h"
72 #include "protos/perfetto/trace/track_event/log_message.pbzero.h"
73 #include "protos/perfetto/trace/track_event/process_descriptor.pbzero.h"
74 #include "protos/perfetto/trace/track_event/source_location.pbzero.h"
75 #include "protos/perfetto/trace/track_event/task_execution.pbzero.h"
76 #include "protos/perfetto/trace/track_event/thread_descriptor.pbzero.h"
77 #include "protos/perfetto/trace/track_event/track_descriptor.pbzero.h"
78 #include "protos/perfetto/trace/track_event/track_event.pbzero.h"
79
80 namespace perfetto {
81 namespace trace_processor {
82 namespace {
83 using ::testing::_;
84 using ::testing::Args;
85 using ::testing::AtLeast;
86 using ::testing::DoAll;
87 using ::testing::ElementsAreArray;
88 using ::testing::Eq;
89 using ::testing::HasSubstr;
90 using ::testing::IgnoreResult;
91 using ::testing::InSequence;
92 using ::testing::Invoke;
93 using ::testing::InvokeArgument;
94 using ::testing::NiceMock;
95 using ::testing::Pointwise;
96 using ::testing::Return;
97 using ::testing::ReturnRef;
98 using ::testing::UnorderedElementsAreArray;
99 class MockSchedEventTracker : public FtraceSchedEventTracker {
100 public:
MockSchedEventTracker(TraceProcessorContext * context)101 explicit MockSchedEventTracker(TraceProcessorContext* context)
102 : FtraceSchedEventTracker(context) {}
103
104 MOCK_METHOD(void,
105 PushSchedSwitch,
106 (uint32_t cpu,
107 int64_t timestamp,
108 uint32_t prev_pid,
109 base::StringView prev_comm,
110 int32_t prev_prio,
111 int64_t prev_state,
112 uint32_t next_pid,
113 base::StringView next_comm,
114 int32_t next_prio),
115 (override));
116 };
117
118 class MockProcessTracker : public ProcessTracker {
119 public:
MockProcessTracker(TraceProcessorContext * context)120 explicit MockProcessTracker(TraceProcessorContext* context)
121 : ProcessTracker(context) {}
122
123 MOCK_METHOD(UniquePid,
124 SetProcessMetadata,
125 (uint32_t pid,
126 std::optional<uint32_t> ppid,
127 base::StringView process_name,
128 base::StringView cmdline),
129 (override));
130
131 MOCK_METHOD(UniqueTid,
132 UpdateThreadName,
133 (uint32_t tid,
134 StringId thread_name_id,
135 ThreadNamePriority priority),
136 (override));
137 MOCK_METHOD(void,
138 UpdateThreadNameByUtid,
139 (UniqueTid utid,
140 StringId thread_name_id,
141 ThreadNamePriority priority),
142 (override));
143 MOCK_METHOD(UniqueTid,
144 UpdateThread,
145 (uint32_t tid, uint32_t tgid),
146 (override));
147
148 MOCK_METHOD(UniquePid, GetOrCreateProcess, (uint32_t pid), (override));
149 MOCK_METHOD(void,
150 SetProcessNameIfUnset,
151 (UniquePid upid, StringId process_name_id),
152 (override));
153 };
154 class MockBoundInserter : public ArgsTracker::BoundInserter {
155 public:
MockBoundInserter()156 MockBoundInserter()
157 : ArgsTracker::BoundInserter(&tracker_, nullptr, 0u), tracker_(nullptr) {
158 ON_CALL(*this, AddArg(_, _, _, _)).WillByDefault(ReturnRef(*this));
159 }
160
161 MOCK_METHOD(ArgsTracker::BoundInserter&,
162 AddArg,
163 (StringId flat_key,
164 StringId key,
165 Variadic v,
166 ArgsTracker::UpdatePolicy update_policy),
167 (override));
168
169 private:
170 ArgsTracker tracker_;
171 };
172
173 class MockEventTracker : public EventTracker {
174 public:
MockEventTracker(TraceProcessorContext * context)175 explicit MockEventTracker(TraceProcessorContext* context)
176 : EventTracker(context) {}
177 ~MockEventTracker() override = default;
178
179 MOCK_METHOD(void,
180 PushSchedSwitch,
181 (uint32_t cpu,
182 int64_t timestamp,
183 uint32_t prev_pid,
184 base::StringView prev_comm,
185 int32_t prev_prio,
186 int64_t prev_state,
187 uint32_t next_pid,
188 base::StringView next_comm,
189 int32_t next_prio));
190
191 MOCK_METHOD(std::optional<CounterId>,
192 PushCounter,
193 (int64_t timestamp, double value, TrackId track_id),
194 (override));
195 };
196
197 class MockSliceTracker : public SliceTracker {
198 public:
MockSliceTracker(TraceProcessorContext * context)199 explicit MockSliceTracker(TraceProcessorContext* context)
200 : SliceTracker(context) {}
201
202 MOCK_METHOD(std::optional<SliceId>,
203 Begin,
204 (int64_t timestamp,
205 TrackId track_id,
206 StringId cat,
207 StringId name,
208 SetArgsCallback args_callback),
209 (override));
210 MOCK_METHOD(std::optional<SliceId>,
211 End,
212 (int64_t timestamp,
213 TrackId track_id,
214 StringId cat,
215 StringId name,
216 SetArgsCallback args_callback),
217 (override));
218 MOCK_METHOD(std::optional<SliceId>,
219 Scoped,
220 (int64_t timestamp,
221 TrackId track_id,
222 StringId cat,
223 StringId name,
224 int64_t duration,
225 SetArgsCallback args_callback),
226 (override));
227 MOCK_METHOD(std::optional<SliceId>,
228 StartSlice,
229 (int64_t timestamp,
230 TrackId track_id,
231 SetArgsCallback args_callback,
232 std::function<SliceId()> inserter),
233 (override));
234 };
235
236 class FuchsiaTraceParserTest : public ::testing::Test {
237 public:
FuchsiaTraceParserTest()238 FuchsiaTraceParserTest() {
239 context_.storage.reset(new TraceStorage());
240 storage_ = context_.storage.get();
241 context_.track_tracker.reset(new TrackTracker(&context_));
242 context_.global_args_tracker.reset(
243 new GlobalArgsTracker(context_.storage.get()));
244 context_.stack_profile_tracker.reset(new StackProfileTracker(&context_));
245 context_.args_tracker.reset(new ArgsTracker(&context_));
246 context_.args_translation_table.reset(new ArgsTranslationTable(storage_));
247 context_.metadata_tracker.reset(
248 new MetadataTracker(context_.storage.get()));
249 context_.machine_tracker.reset(new MachineTracker(&context_, 0));
250 context_.cpu_tracker.reset(new CpuTracker(&context_));
251 event_ = new MockEventTracker(&context_);
252 context_.event_tracker.reset(event_);
253 sched_ = new MockSchedEventTracker(&context_);
254 context_.ftrace_sched_tracker.reset(sched_);
255 process_ = new NiceMock<MockProcessTracker>(&context_);
256 context_.process_tracker.reset(process_);
257 context_.process_track_translation_table.reset(
258 new ProcessTrackTranslationTable(storage_));
259 slice_ = new NiceMock<MockSliceTracker>(&context_);
260 context_.slice_tracker.reset(slice_);
261 context_.slice_translation_table.reset(new SliceTranslationTable(storage_));
262 context_.clock_tracker.reset(new ClockTracker(&context_));
263 clock_ = context_.clock_tracker.get();
264 context_.flow_tracker.reset(new FlowTracker(&context_));
265 context_.fuchsia_record_parser.reset(new FuchsiaTraceParser(&context_));
266 context_.proto_trace_parser.reset(new ProtoTraceParserImpl(&context_));
267 context_.sorter.reset(
268 new TraceSorter(&context_, TraceSorter::SortingMode::kFullSort));
269 context_.descriptor_pool_.reset(new DescriptorPool());
270
271 RegisterDefaultModules(&context_);
272 RegisterAdditionalModules(&context_);
273 }
274
push_word(uint64_t word)275 void push_word(uint64_t word) { trace_bytes_.push_back(word); }
276
ResetTraceBuffers()277 void ResetTraceBuffers() {
278 trace_bytes_.clear();
279 // Write the FXT Magic Bytes
280 push_word(0x0016547846040010);
281 }
282
SetUp()283 void SetUp() override { ResetTraceBuffers(); }
284
Tokenize()285 util::Status Tokenize() {
286 const size_t num_bytes = trace_bytes_.size() * sizeof(uint64_t);
287 std::unique_ptr<uint8_t[]> raw_trace(new uint8_t[num_bytes]);
288 memcpy(raw_trace.get(), trace_bytes_.data(), num_bytes);
289 context_.chunk_reader.reset(new FuchsiaTraceTokenizer(&context_));
290 auto status = context_.chunk_reader->Parse(TraceBlobView(
291 TraceBlob::TakeOwnership(std::move(raw_trace), num_bytes)));
292
293 ResetTraceBuffers();
294 return status;
295 }
296
297 protected:
298 std::vector<uint64_t> trace_bytes_;
299
300 TraceProcessorContext context_;
301 MockEventTracker* event_;
302 MockSchedEventTracker* sched_;
303 MockProcessTracker* process_;
304 MockSliceTracker* slice_;
305 ClockTracker* clock_;
306 TraceStorage* storage_;
307 };
308
TEST_F(FuchsiaTraceParserTest,CorruptedFxt)309 TEST_F(FuchsiaTraceParserTest, CorruptedFxt) {
310 // Invalid record of size 0
311 push_word(0x0016547846040000);
312 EXPECT_FALSE(Tokenize().ok());
313 }
314
TEST_F(FuchsiaTraceParserTest,InlineInstantEvent)315 TEST_F(FuchsiaTraceParserTest, InlineInstantEvent) {
316 // Inline name of 8 bytes
317 uint64_t name_ref = uint64_t{0x8008} << 48;
318 // Inline category of 8 bytes
319 uint64_t category_ref = uint64_t{0x8008} << 32;
320 // Inline threadref
321 uint64_t threadref = uint64_t{0};
322 // Instant Event
323 uint64_t event_type = 0 << 16;
324 uint64_t size = 6 << 4;
325 uint64_t record_type = 4;
326
327 auto header =
328 name_ref | category_ref | threadref | event_type | size | record_type;
329 push_word(header);
330 // Timestamp
331 push_word(0xAAAAAAAAAAAAAAAA);
332 // Pid + tid
333 push_word(0xBBBBBBBBBBBBBBBB);
334 push_word(0xCCCCCCCCCCCCCCCC);
335 // Inline Category
336 push_word(0xDDDDDDDDDDDDDDDD);
337 // Inline Name
338 push_word(0xEEEEEEEEEEEEEEEE);
339 EXPECT_TRUE(Tokenize().ok());
340 EXPECT_EQ(context_.storage->stats()[stats::fuchsia_invalid_event].value, 0);
341 }
342
TEST_F(FuchsiaTraceParserTest,BooleanArguments)343 TEST_F(FuchsiaTraceParserTest, BooleanArguments) {
344 // Inline name of 8 bytes
345 uint64_t name_ref = uint64_t{0x8008} << 48;
346 // Inline category of 8 bytes
347 uint64_t category_ref = uint64_t{0x8008} << 32;
348 // Inline threadref
349 uint64_t threadref = uint64_t{0};
350 // 2 arguments
351 uint64_t argument_count = uint64_t{2} << 20;
352 // Instant Event
353 uint64_t event_type = 0 << 16;
354 uint64_t size = 8 << 4;
355 uint64_t record_type = 4;
356
357 auto header = name_ref | category_ref | threadref | event_type |
358 argument_count | size | record_type;
359 push_word(header);
360 // Timestamp
361 push_word(0xAAAAAAAAAAAAAAAA);
362 // Pid + tid
363 push_word(0xBBBBBBBBBBBBBBBB);
364 push_word(0xCCCCCCCCCCCCCCCC);
365 // Inline Category
366 push_word(0xDDDDDDDDDDDDDDDD);
367 // Inline Name
368 push_word(0xEEEEEEEEEEEEEEEE);
369 // Boolean argument true
370 push_word(0x0000'0001'8008'0029);
371 // 8 byte arg name stream
372 push_word(0x0000'0000'0000'0000);
373 // Boolean argument false
374 push_word(0x0000'0000'8008'002A);
375 // 8 byte arg name stream
376 push_word(0x0000'0000'0000'0000);
377 EXPECT_TRUE(Tokenize().ok());
378 EXPECT_EQ(context_.storage->stats()[stats::fuchsia_invalid_event].value, 0);
379 }
380
TEST_F(FuchsiaTraceParserTest,FxtWithProtos)381 TEST_F(FuchsiaTraceParserTest, FxtWithProtos) {
382 // Serialize some protos to bytes
383 protozero::HeapBuffered<protos::pbzero::Trace> protos;
384 {
385 auto* packet = protos->add_packet();
386 packet->set_trusted_packet_sequence_id(1);
387 packet->set_incremental_state_cleared(true);
388 auto* thread_desc = packet->set_thread_descriptor();
389 thread_desc->set_pid(15);
390 thread_desc->set_tid(16);
391 thread_desc->set_reference_timestamp_us(1000);
392 thread_desc->set_reference_thread_time_us(2000);
393 }
394 {
395 auto* packet = protos->add_packet();
396 packet->set_trusted_packet_sequence_id(1);
397 auto* event = packet->set_track_event();
398 event->set_timestamp_delta_us(10); // absolute: 1010.
399 event->set_thread_time_delta_us(5); // absolute: 2005.
400 event->add_category_iids(1);
401 auto* legacy_event = event->set_legacy_event();
402 legacy_event->set_name_iid(1);
403 legacy_event->set_phase('B');
404 }
405 {
406 auto* packet = protos->add_packet();
407 packet->set_trusted_packet_sequence_id(1);
408 auto* event = packet->set_track_event();
409 event->set_timestamp_delta_us(10); // absolute: 1020.
410 event->set_thread_time_delta_us(5); // absolute: 2010.
411 event->add_category_iids(1);
412 auto* legacy_event = event->set_legacy_event();
413 legacy_event->set_name_iid(1);
414 legacy_event->set_phase('E');
415 }
416 {
417 auto* packet = protos->add_packet();
418 packet->set_trusted_packet_sequence_id(1);
419 auto* event = packet->set_track_event();
420 event->set_timestamp_absolute_us(1005);
421 event->set_thread_time_absolute_us(2003);
422 event->add_category_iids(2);
423 event->add_category_iids(3);
424 auto* legacy_event = event->set_legacy_event();
425 legacy_event->set_name_iid(2);
426 legacy_event->set_phase('X');
427 legacy_event->set_duration_us(23); // absolute end: 1028.
428 legacy_event->set_thread_duration_us(12); // absolute end: 2015.
429 }
430
431 protos->Finalize();
432 std::vector<uint8_t> perfetto_bytes = protos.SerializeAsArray();
433
434 // Set up an FXT Perfetto Blob Header
435 uint64_t blob_type_perfetto = uint64_t{3} << 48;
436 uint64_t unpadded_blob_size_bytes = uint64_t{perfetto_bytes.size()} << 32;
437 uint64_t blob_name_ref = uint64_t{0x8008} << 16;
438 uint64_t size_words = ((perfetto_bytes.size() + 7) / 8 + 2) << 4;
439 uint64_t record_type = 5;
440
441 uint64_t header = blob_type_perfetto | unpadded_blob_size_bytes |
442 blob_name_ref | size_words | record_type;
443
444 // Pad the blob to a multiple of 8 bytes.
445 while (perfetto_bytes.size() % 8) {
446 perfetto_bytes.push_back(0);
447 }
448
449 push_word(header);
450 // Inline Name Ref
451 push_word(0xBBBBBBBBBBBBBBBB);
452 trace_bytes_.insert(trace_bytes_.end(),
453 reinterpret_cast<uint64_t*>(perfetto_bytes.data()),
454 reinterpret_cast<uint64_t*>(perfetto_bytes.data() +
455 perfetto_bytes.size()));
456 EXPECT_CALL(*process_, UpdateThread(16, 15)).WillRepeatedly(Return(1u));
457
458 tables::ThreadTable::Row row(16);
459 row.upid = 1u;
460 storage_->mutable_thread_table()->Insert(row);
461
462 MockBoundInserter inserter;
463
464 StringId unknown_cat = storage_->InternString("unknown(1)");
465 ASSERT_NE(storage_, nullptr);
466
467 constexpr TrackId track{0u};
468 constexpr TrackId thread_time_track{1u};
469
470 InSequence in_sequence; // Below slices should be sorted by timestamp.
471 // Only the begin thread time can be imported into the counter table.
472 EXPECT_CALL(*event_, PushCounter(1005000, testing::DoubleEq(2003000),
473 thread_time_track));
474 EXPECT_CALL(*slice_, StartSlice(1005000, track, _, _))
475 .WillOnce(DoAll(IgnoreResult(InvokeArgument<3>()),
476 InvokeArgument<2>(&inserter), Return(SliceId(0u))));
477 EXPECT_CALL(*event_, PushCounter(1010000, testing::DoubleEq(2005000),
478 thread_time_track));
479 EXPECT_CALL(*slice_, StartSlice(1010000, track, _, _))
480 .WillOnce(DoAll(IgnoreResult(InvokeArgument<3>()),
481 InvokeArgument<2>(&inserter), Return(SliceId(1u))));
482 EXPECT_CALL(*event_, PushCounter(1020000, testing::DoubleEq(2010000),
483 thread_time_track));
484 EXPECT_CALL(*slice_, End(1020000, track, unknown_cat, kNullStringId, _))
485 .WillOnce(DoAll(InvokeArgument<4>(&inserter), Return(SliceId(1u))));
486
487 auto status = Tokenize();
488 EXPECT_TRUE(status.ok());
489 context_.sorter->ExtractEventsForced();
490 }
491
TEST_F(FuchsiaTraceParserTest,SchedulerEvents)492 TEST_F(FuchsiaTraceParserTest, SchedulerEvents) {
493 uint64_t thread1_tid = 0x1AAA'AAAA'AAAA'AAAA;
494 uint64_t thread2_tid = 0x2CCC'CCCC'CCCC'CCCC;
495
496 // We'll emit a wake up for thread 1, a switch to thread 2, and a switch back
497 // to thread 1 and expect to see that the process tracker was properly updated
498
499 uint64_t wakeup_record_type = uint64_t{2} << 60;
500 uint64_t context_switch_record_type = uint64_t{1} << 60;
501 uint64_t cpu = 1 << 20;
502 uint64_t record_type = 8;
503
504 uint64_t wakeup_size = uint64_t{3} << 4;
505 uint64_t context_switch_size = uint64_t{4} << 4;
506
507 uint64_t wakeup_header = wakeup_record_type | cpu | record_type | wakeup_size;
508 push_word(wakeup_header);
509 // Timestamp
510 push_word(0x1);
511 // wakeup tid
512 push_word(thread1_tid);
513
514 uint64_t context_switch_header =
515 context_switch_record_type | cpu | record_type | context_switch_size;
516 push_word(context_switch_header);
517 // Timestamp
518 push_word(0x2);
519 // outgoing tid
520 push_word(thread1_tid);
521 // incoming tid
522 push_word(thread2_tid);
523
524 push_word(context_switch_header);
525 // Timestamp
526 push_word(0x3);
527 // outgoing tid
528 push_word(thread2_tid);
529 // incoming tid
530 push_word(thread1_tid);
531
532 // We should get:
533 // - A thread1 update call on wake up
534 // - thread1 & thread2 update calls on the first context switch
535 // - thread2 & thread1 update cals on the second context switch
536 EXPECT_CALL(*process_, UpdateThread(static_cast<uint32_t>(thread1_tid), _))
537 .Times(3);
538 EXPECT_CALL(*process_, UpdateThread(static_cast<uint32_t>(thread2_tid), _))
539 .Times(2);
540
541 EXPECT_TRUE(Tokenize().ok());
542 EXPECT_EQ(context_.storage->stats()[stats::fuchsia_invalid_event].value, 0);
543
544 context_.sorter->ExtractEventsForced();
545 }
546
TEST_F(FuchsiaTraceParserTest,LegacySchedulerEvents)547 TEST_F(FuchsiaTraceParserTest, LegacySchedulerEvents) {
548 uint64_t thread1_pid = 0x1AAA'AAAA'AAAA'AAAA;
549 uint64_t thread1_tid = 0x1BBB'BBBB'BBBB'BBBB;
550 uint64_t thread2_pid = 0x2CCC'CCCC'CCCC'CCCC;
551 uint64_t thread2_tid = 0x2DDD'DDDD'DDDD'DDDD;
552
553 // We'll emit a wake up for thread 1, a switch to thread 2, and a switch back
554 // to thread 1 and expect to see that the process tracker was properly updated
555
556 uint64_t context_switch_size = uint64_t{6} << 4;
557 uint64_t cpu = 1 << 16;
558 uint64_t record_type = 8;
559 uint64_t outoing_state = 2 << 24;
560 uint64_t outoing_thread = 0; // Inline thread-ref
561 uint64_t incoming_thread = 0; // Inline thread-ref
562 uint64_t outgoing_prio = uint64_t{1} << 44;
563 uint64_t incoming_prio = uint64_t{1} << 52;
564 uint64_t outgoing_idle_prio = uint64_t{0} << 44;
565
566 uint64_t context_switch_header =
567 record_type | context_switch_size | cpu | outoing_state | outoing_thread |
568 incoming_thread | outgoing_prio | incoming_prio;
569 uint64_t wakeup_header = record_type | context_switch_size | cpu |
570 outoing_state | outoing_thread | incoming_thread |
571 outgoing_idle_prio | incoming_prio;
572
573 push_word(wakeup_header);
574 // Timestamp
575 push_word(0x1);
576 // outgoing pid+tid
577 push_word(0); // Idle thread
578 push_word(0); // Idle thread
579 // incoming pid+tid
580 push_word(thread1_pid);
581 push_word(thread1_tid);
582
583 push_word(context_switch_header);
584 // Timestamp
585 push_word(0x2);
586 // outgoing pid+tid
587 push_word(thread1_pid);
588 push_word(thread1_tid);
589 // incoming pid+tid
590 push_word(thread2_pid);
591 push_word(thread2_tid);
592
593 push_word(context_switch_header);
594 // Timestamp
595 push_word(0x3);
596 // outgoing pid+tid
597 push_word(thread2_pid);
598 push_word(thread2_tid);
599 // incoming pid+tid
600 push_word(thread1_pid);
601 push_word(thread1_tid);
602
603 // We should get:
604 // - A thread1 update call on wake up
605 // - thread1 & thread2 update calls on the first context switch
606 // - thread2 & thread1 update cals on the second context switch
607 EXPECT_CALL(*process_, UpdateThread(static_cast<uint32_t>(thread1_tid), _))
608 .Times(3);
609 EXPECT_CALL(*process_, UpdateThread(static_cast<uint32_t>(thread2_tid), _))
610 .Times(2);
611
612 EXPECT_TRUE(Tokenize().ok());
613 EXPECT_EQ(context_.storage->stats()[stats::fuchsia_invalid_event].value, 0);
614
615 context_.sorter->ExtractEventsForced();
616 }
617
618 } // namespace
619 } // namespace trace_processor
620 } // namespace perfetto
621