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