1 /*
2  * Copyright (C) 2023 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/ftrace/ftrace_sched_event_tracker.h"
18 #include <cstdint>
19 #include <memory>
20 #include <optional>
21 
22 #include "perfetto/base/logging.h"
23 #include "src/trace_processor/importers/common/args_tracker.h"
24 #include "src/trace_processor/importers/common/cpu_tracker.h"
25 #include "src/trace_processor/importers/common/event_tracker.h"
26 #include "src/trace_processor/importers/common/global_args_tracker.h"
27 #include "src/trace_processor/importers/common/machine_tracker.h"
28 #include "src/trace_processor/importers/common/process_tracker.h"
29 #include "src/trace_processor/importers/common/sched_event_tracker.h"
30 #include "src/trace_processor/storage/trace_storage.h"
31 #include "test/gtest_and_gmock.h"
32 
33 namespace perfetto {
34 namespace trace_processor {
35 namespace {
36 
37 using ::testing::_;
38 using ::testing::InSequence;
39 using ::testing::Invoke;
40 
41 class SchedEventTrackerTest : public ::testing::Test {
42  public:
SchedEventTrackerTest()43   SchedEventTrackerTest() {
44     context.storage = std::make_shared<TraceStorage>();
45     context.global_args_tracker =
46         std::make_unique<GlobalArgsTracker>(context.storage.get());
47     context.args_tracker = std::make_unique<ArgsTracker>(&context);
48     context.event_tracker = std::make_unique<EventTracker>(&context);
49     context.process_tracker = std::make_unique<ProcessTracker>(&context);
50     context.machine_tracker = std::make_unique<MachineTracker>(&context, 0);
51     context.cpu_tracker = std::make_unique<CpuTracker>(&context);
52     context.sched_event_tracker = std::make_unique<SchedEventTracker>(&context);
53     sched_tracker = FtraceSchedEventTracker::GetOrCreate(&context);
54   }
55 
56  protected:
57   TraceProcessorContext context;
58   FtraceSchedEventTracker* sched_tracker;
59 };
60 
TEST_F(SchedEventTrackerTest,InsertSecondSched)61 TEST_F(SchedEventTrackerTest, InsertSecondSched) {
62   uint32_t cpu = 3;
63   int64_t timestamp = 100;
64   uint32_t pid_1 = 2;
65   int64_t prev_state = 32;
66   static const char kCommProc1[] = "process1";
67   static const char kCommProc2[] = "process2";
68   uint32_t pid_2 = 4;
69   int32_t prio = 1024;
70 
71   sched_tracker->PushSchedSwitch(cpu, timestamp, pid_1, kCommProc2, prio,
72                                  prev_state, pid_2, kCommProc1, prio);
73   ASSERT_EQ(context.storage->sched_slice_table().row_count(), 1ul);
74 
75   sched_tracker->PushSchedSwitch(cpu, timestamp + 1, pid_2, kCommProc1, prio,
76                                  prev_state, pid_1, kCommProc2, prio);
77 
78   ASSERT_EQ(context.storage->sched_slice_table().row_count(), 2ul);
79 
80   const auto& sched = context.storage->sched_slice_table();
81   ASSERT_EQ(sched[0].ts(), timestamp);
82   ASSERT_EQ(context.storage->thread_table()[1].start_ts(), std::nullopt);
83 
84   auto name =
85       context.storage->GetString(*context.storage->thread_table()[1].name());
86   ASSERT_STREQ(name.c_str(), kCommProc1);
87   ASSERT_EQ(context.storage->sched_slice_table()[0].utid(), 1u);
88   ASSERT_EQ(context.storage->sched_slice_table()[0].dur(), 1);
89 }
90 
TEST_F(SchedEventTrackerTest,InsertThirdSched_SameThread)91 TEST_F(SchedEventTrackerTest, InsertThirdSched_SameThread) {
92   uint32_t cpu = 3;
93   int64_t timestamp = 100;
94   int64_t prev_state = 32;
95   static const char kCommProc1[] = "process1";
96   static const char kCommProc2[] = "process2";
97   int32_t prio = 1024;
98 
99   sched_tracker->PushSchedSwitch(cpu, timestamp, /*prev_pid=*/4, kCommProc2,
100                                  prio, prev_state,
101                                  /*tid=*/2, kCommProc1, prio);
102   ASSERT_EQ(context.storage->sched_slice_table().row_count(), 1u);
103 
104   sched_tracker->PushSchedSwitch(cpu, timestamp + 1, /*prev_pid=*/2, kCommProc1,
105                                  prio, prev_state,
106                                  /*tid=*/4, kCommProc2, prio);
107   sched_tracker->PushSchedSwitch(cpu, timestamp + 11, /*prev_pid=*/4,
108                                  kCommProc2, prio, prev_state,
109                                  /*tid=*/2, kCommProc1, prio);
110   sched_tracker->PushSchedSwitch(cpu, timestamp + 31, /*tid=*/2, kCommProc1,
111                                  prio, prev_state,
112                                  /*tid=*/4, kCommProc2, prio);
113   ASSERT_EQ(context.storage->sched_slice_table().row_count(), 4ul);
114 
115   ASSERT_EQ(context.storage->sched_slice_table()[0].ts(), timestamp);
116   ASSERT_EQ(context.storage->thread_table()[1].start_ts(), std::nullopt);
117   ASSERT_EQ(context.storage->sched_slice_table()[0].dur(), 1u);
118   ASSERT_EQ(context.storage->sched_slice_table()[1].dur(), 11u - 1u);
119   ASSERT_EQ(context.storage->sched_slice_table()[2].dur(), 31u - 11u);
120   ASSERT_EQ(context.storage->sched_slice_table()[0].utid(),
121             context.storage->sched_slice_table()[2].utid());
122 }
123 
TEST_F(SchedEventTrackerTest,UpdateThreadMatch)124 TEST_F(SchedEventTrackerTest, UpdateThreadMatch) {
125   uint32_t cpu = 3;
126   int64_t timestamp = 100;
127   int64_t prev_state = 32;
128   static const char kCommProc1[] = "process1";
129   static const char kCommProc2[] = "process2";
130   int32_t prio = 1024;
131 
132   sched_tracker->PushSchedSwitch(cpu, timestamp, /*tid=*/1, kCommProc2, prio,
133                                  prev_state,
134                                  /*tid=*/4, kCommProc1, prio);
135   sched_tracker->PushSchedSwitch(cpu, timestamp + 1, /*tid=*/4, kCommProc1,
136                                  prio, prev_state,
137                                  /*tid=*/1, kCommProc2, prio);
138 
139   context.process_tracker->SetProcessMetadata(2, std::nullopt, "test",
140                                               base::StringView());
141   context.process_tracker->UpdateThread(4, 2);
142 
143   ASSERT_EQ(context.storage->thread_table()[1].tid(), 4u);
144   ASSERT_EQ(context.storage->thread_table()[1].upid().value(), 1u);
145   ASSERT_EQ(context.storage->process_table()[1].pid(), 2u);
146   ASSERT_EQ(context.storage->process_table()[1].start_ts(), std::nullopt);
147 }
148 
149 }  // namespace
150 }  // namespace trace_processor
151 }  // namespace perfetto
152