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