xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/fuchsia/fuchsia_parser_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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