blob: 1042221913a702aa2f2e12eec4126660efb7c982 [file] [log] [blame]
Dmitri Plotnikov266d5a22020-10-20 11:11:15 -07001/*
2 * Copyright (C) 2021 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 <bpf_timeinstate.h>
18#include <gtest/gtest.h>
19#include <test/mock_bpf_helpers.h>
20
21extern "C" {
22
23uint64_t* bpf_cpu_last_update_map_lookup_elem(uint32_t* zero);
24uint64_t* bpf_uid_last_update_map_lookup_elem(uint32_t* uid);
25int bpf_cpu_last_update_map_update_elem(uint32_t* zero, uint64_t* time, uint64_t flags);
26int bpf_nr_active_map_update_elem(uint32_t* zero, uint32_t* time, uint64_t flags);
27int bpf_cpu_policy_map_update_elem(uint32_t* zero, uint32_t* time, uint64_t flags);
28int bpf_policy_freq_idx_map_update_elem(uint32_t* policy, uint8_t* index, uint64_t flags);
29int bpf_policy_nr_active_map_update_elem(uint32_t* policy, uint32_t* active, uint64_t flags);
30uint8_t* bpf_policy_freq_idx_map_lookup_elem(uint32_t* policy);
31int bpf_policy_freq_idx_map_update_elem(uint32_t* policy, uint8_t* index, uint64_t flags);
32int bpf_freq_to_idx_map_update_elem(freq_idx_key_t* freq_idx_key, uint8_t* index, uint64_t flags);
33tis_val_t* bpf_uid_time_in_state_map_lookup_elem(time_key_t* key);
34concurrent_val_t* bpf_uid_concurrent_times_map_lookup_elem(time_key_t* key);
Connor O'Brien8d866e62021-10-14 14:18:24 -070035int bpf_cpu_last_pid_map_update_elem(uint32_t* zero, pid_t* pid, uint64_t flags);
Dmitri Plotnikov266d5a22020-10-20 11:11:15 -070036
37struct switch_args {
38 unsigned long long ignore;
39 char prev_comm[16];
40 int prev_pid;
41 int prev_prio;
42 long long prev_state;
43 char next_comm[16];
44 int next_pid;
45 int next_prio;
46};
47
48int tp_sched_switch(struct switch_args* args);
49
50struct cpufreq_args {
51 unsigned long long ignore;
52 unsigned int state;
53 unsigned int cpu_id;
54};
55
56int tp_cpufreq(struct cpufreq_args* args);
57
58} // extern "C"
59
60static void enableTracking() {
61 uint32_t zero = 0;
Connor O'Brien9ba78132021-10-18 19:29:05 -070062 bpf_nr_active_map_update_elem(&zero, &zero, BPF_ANY);
Dmitri Plotnikov266d5a22020-10-20 11:11:15 -070063}
64
65// Defines a CPU cluster <policy> containing CPUs <cpu_ids> with available frequencies
66// <frequencies> and marks it as <active>
67static void initCpuPolicy(uint32_t policy, std::vector<uint32_t> cpuIds,
68 std::vector<uint32_t> frequencies, bool active) {
69 for (uint32_t cpuId : cpuIds) {
70 bpf_cpu_policy_map_update_elem(&cpuId, &policy, BPF_ANY);
71
72 mock_bpf_set_smp_processor_id(cpuId);
73
74 // Initialize time - this must be done per-CPU
75 uint32_t zero = 0;
76 uint64_t time = 0;
77 bpf_cpu_last_update_map_update_elem(&zero, &time, BPF_ANY);
Connor O'Brien8d866e62021-10-14 14:18:24 -070078
79 pid_t pid = 0;
80 bpf_cpu_last_pid_map_update_elem(&zero, &pid, BPF_ANY);
Dmitri Plotnikov266d5a22020-10-20 11:11:15 -070081 }
82 for (uint8_t i = 0; i < frequencies.size(); i++) {
83 uint8_t index = i + 1; // Frequency indexes start with 1
84 freq_idx_key_t freqIdxKey{.policy = policy, .freq = frequencies[i]};
85 bpf_freq_to_idx_map_update_elem(&freqIdxKey, &index, BPF_ANY);
86 }
87 if (active) {
88 uint32_t zero = 0;
Connor O'Brien9ba78132021-10-18 19:29:05 -070089 bpf_policy_nr_active_map_update_elem(&policy, &zero, BPF_ANY);
Dmitri Plotnikov266d5a22020-10-20 11:11:15 -070090 }
91}
92
93static void noteCpuFrequencyChange(uint32_t cpuId, uint32_t frequency) {
94 cpufreq_args args{.cpu_id = cpuId, .state = frequency};
95 int ret = tp_cpufreq(&args); // Tracepoint event power/cpu_frequency
Connor O'Brienf78a0a32022-03-04 13:14:47 -080096 ASSERT_EQ(1, ret);
Dmitri Plotnikov266d5a22020-10-20 11:11:15 -070097}
98
99static void noteSchedSwitch(pid_t prevPid, pid_t nextPid) {
100 switch_args args{.prev_pid = prevPid, .next_pid = nextPid};
101 int ret = tp_sched_switch(&args); // Tracepoint event sched/sched_switch
102 ASSERT_EQ(1, ret);
103}
104
105static void assertTimeInState(uint32_t uid, uint32_t bucket,
106 std::vector<uint64_t> expectedTimeInState) {
107 time_key_t timeKey{.uid = uid, .bucket = bucket};
108 tis_val_t* value = bpf_uid_time_in_state_map_lookup_elem(&timeKey);
109 ASSERT_TRUE(value);
110
111 for (int i = 0; i < FREQS_PER_ENTRY; i++) {
112 if (i < expectedTimeInState.size()) {
113 ASSERT_EQ(expectedTimeInState[i], value->ar[i]);
114 } else {
115 ASSERT_EQ(0, value->ar[i]);
116 }
117 }
118}
119
120static void assertConcurrentTimes(uint32_t uid, uint32_t bucket,
121 std::vector<uint64_t> expectedPolicy,
122 std::vector<uint64_t> expectedActive) {
123 time_key_t timeKey{.uid = uid, .bucket = bucket};
124 concurrent_val_t* value = bpf_uid_concurrent_times_map_lookup_elem(&timeKey);
125 ASSERT_TRUE(value);
126
127 for (int i = 0; i < CPUS_PER_ENTRY; i++) {
128 if (i < expectedPolicy.size()) {
129 ASSERT_EQ(expectedPolicy[i], value->policy[i]);
130 } else {
131 ASSERT_EQ(0, value->policy[i]);
132 }
133 }
134
135 for (int i = 0; i < CPUS_PER_ENTRY; i++) {
136 if (i < expectedActive.size()) {
137 ASSERT_EQ(expectedActive[i], value->active[i]);
138 } else {
139 ASSERT_EQ(0, value->active[i]);
140 }
141 }
142}
143
144static void assertUidLastUpdateTime(uint32_t uid, uint64_t expectedTime) {
145 uint64_t* value = bpf_uid_last_update_map_lookup_elem(&uid);
146 ASSERT_TRUE(value);
147 ASSERT_EQ(expectedTime, *value);
148}
149
150TEST(time_in_state, tp_cpufreq) {
151 initCpuPolicy(0, {0, 1, 2}, {1000, 2000}, true);
152 initCpuPolicy(1, {3, 4}, {3000, 4000, 5000}, true);
153
154 noteCpuFrequencyChange(1, 2000);
155 {
156 uint32_t policy = 0; // CPU 1 belongs to Cluster 0
157 uint8_t* freqIndex = bpf_policy_freq_idx_map_lookup_elem(&policy);
158 ASSERT_TRUE(freqIndex);
159 // Freq idx starts with 1. Cluster 0 is now running at the _second_ frequency
160 ASSERT_EQ(2, *freqIndex);
161 }
162
163 noteCpuFrequencyChange(4, 5000);
164 {
165 uint32_t policy = 1; // CPU 4 belongs to Cluster 1
166 uint8_t* freqIndex = bpf_policy_freq_idx_map_lookup_elem(&policy);
167 ASSERT_TRUE(freqIndex);
168 // Freq idx starts with 1. Cluster 1 is now running at the _third_ frequency
169 ASSERT_EQ(3, *freqIndex);
170 }
171}
172
173TEST(time_in_state, tp_sched_switch) {
174 mock_bpf_set_ktime_ns(1000);
175 mock_bpf_set_current_uid_gid(42);
176
177 initCpuPolicy(0, {0, 1, 2}, {1000, 2000}, true);
178 initCpuPolicy(1, {3, 4}, {3000, 4000, 5000}, true);
179
180 enableTracking();
181
182 mock_bpf_set_smp_processor_id(2);
183
184 // First call is ignored, because there is no "delta" to be computed
185 noteSchedSwitch(0, 100);
186
187 noteCpuFrequencyChange(2, 1000);
188
189 mock_bpf_set_ktime_ns(1314);
190
191 noteSchedSwitch(100, 200);
192
193 // 1314 - 1000 = 314
194 assertTimeInState(42, 0, {314, 0});
Connor O'Brien9ba78132021-10-18 19:29:05 -0700195 assertConcurrentTimes(42, 0, {314, 0, 0, 0, 0}, {314, 0, 0, 0, 0});
Dmitri Plotnikov266d5a22020-10-20 11:11:15 -0700196
197 mock_bpf_set_current_uid_gid(51);
198 mock_bpf_set_smp_processor_id(3);
199
200 // First call on this CPU is also ignored
201 noteSchedSwitch(200, 300);
202
203 mock_bpf_set_ktime_ns(2718);
204
205 noteCpuFrequencyChange(3, 5000);
206 noteSchedSwitch(300, 400);
207
208 mock_bpf_set_ktime_ns(5859);
209
210 noteCpuFrequencyChange(3, 4000);
211 noteSchedSwitch(400, 500);
212
213 assertTimeInState(51, 0, {0, 5859 - 2718, 2718 - 1314});
214
215 // (2718-1314)+(5859-2718) = 4545
Connor O'Brien9ba78132021-10-18 19:29:05 -0700216 assertConcurrentTimes(51, 0, {4545, 0, 0, 0, 0}, {0, 4545, 0, 0, 0});
Dmitri Plotnikov266d5a22020-10-20 11:11:15 -0700217
218 assertUidLastUpdateTime(42, 1314);
219 assertUidLastUpdateTime(51, 5859);
220}
Connor O'Brien8d866e62021-10-14 14:18:24 -0700221
222TEST(time_in_state, tp_sched_switch_active_cpus) {
223 mock_bpf_set_ktime_ns(1000);
224 mock_bpf_set_current_uid_gid(42);
225
226 initCpuPolicy(0, {0}, {1000, 2000}, true);
227
228 enableTracking();
229
230 mock_bpf_set_smp_processor_id(0);
231
232 noteSchedSwitch(0, 1);
233
234 mock_bpf_set_ktime_ns(1100);
235
236 noteSchedSwitch(0, 1);
237
238 mock_bpf_set_ktime_ns(1200);
239
240 noteSchedSwitch(1, 2);
241
242 assertConcurrentTimes(42, 0, {100}, {100});
243}
Connor O'Brien21cce612022-03-04 12:43:11 -0800244
245TEST(time_in_state, tp_sched_switch_sdk_sandbox) {
246 mock_bpf_set_ktime_ns(1000);
247 mock_bpf_set_current_uid_gid(AID_SDK_SANDBOX_PROCESS_START);
248
249 initCpuPolicy(0, {0}, {1000, 2000}, true);
250
251 enableTracking();
252
253 mock_bpf_set_smp_processor_id(0);
254
255 noteSchedSwitch(0, 1);
256
257 mock_bpf_set_ktime_ns(1100);
258
259 noteSchedSwitch(1, 2);
260
261 assertTimeInState(AID_APP_START, 0, {100, 0});
262 assertTimeInState(AID_SDK_SANDBOX, 0, {100, 0});
263
264 assertConcurrentTimes(AID_APP_START, 0, {100}, {100});
265 assertConcurrentTimes(AID_SDK_SANDBOX, 0, {100}, {100});
266}