1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker *
4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker *
8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker *
10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker */
16*38e8c45fSAndroid Build Coastguard Worker
17*38e8c45fSAndroid Build Coastguard Worker
18*38e8c45fSAndroid Build Coastguard Worker #include <bpf_timeinstate.h>
19*38e8c45fSAndroid Build Coastguard Worker
20*38e8c45fSAndroid Build Coastguard Worker #include <sys/sysinfo.h>
21*38e8c45fSAndroid Build Coastguard Worker
22*38e8c45fSAndroid Build Coastguard Worker #include <pthread.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <semaphore.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <numeric>
25*38e8c45fSAndroid Build Coastguard Worker #include <unordered_map>
26*38e8c45fSAndroid Build Coastguard Worker #include <vector>
27*38e8c45fSAndroid Build Coastguard Worker
28*38e8c45fSAndroid Build Coastguard Worker #include <gtest/gtest.h>
29*38e8c45fSAndroid Build Coastguard Worker
30*38e8c45fSAndroid Build Coastguard Worker #include <android-base/properties.h>
31*38e8c45fSAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
32*38e8c45fSAndroid Build Coastguard Worker #include <bpf/BpfMap.h>
33*38e8c45fSAndroid Build Coastguard Worker #include <cputimeinstate.h>
34*38e8c45fSAndroid Build Coastguard Worker #include <cutils/android_filesystem_config.h>
35*38e8c45fSAndroid Build Coastguard Worker #include <libbpf.h>
36*38e8c45fSAndroid Build Coastguard Worker
37*38e8c45fSAndroid Build Coastguard Worker namespace android {
38*38e8c45fSAndroid Build Coastguard Worker namespace bpf {
39*38e8c45fSAndroid Build Coastguard Worker
40*38e8c45fSAndroid Build Coastguard Worker static constexpr uint64_t NSEC_PER_SEC = 1000000000;
41*38e8c45fSAndroid Build Coastguard Worker static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365;
42*38e8c45fSAndroid Build Coastguard Worker
43*38e8c45fSAndroid Build Coastguard Worker // Declare busy loop variable globally to prevent removal during optimization
44*38e8c45fSAndroid Build Coastguard Worker static volatile long sum __attribute__((used)) = 1;
45*38e8c45fSAndroid Build Coastguard Worker
46*38e8c45fSAndroid Build Coastguard Worker using std::vector;
47*38e8c45fSAndroid Build Coastguard Worker
48*38e8c45fSAndroid Build Coastguard Worker class TimeInStateTest : public testing::Test {
49*38e8c45fSAndroid Build Coastguard Worker protected:
TimeInStateTest()50*38e8c45fSAndroid Build Coastguard Worker TimeInStateTest() {};
51*38e8c45fSAndroid Build Coastguard Worker
SetUp()52*38e8c45fSAndroid Build Coastguard Worker void SetUp() {
53*38e8c45fSAndroid Build Coastguard Worker if (!isTrackingUidTimesSupported() ||
54*38e8c45fSAndroid Build Coastguard Worker !android::base::GetBoolProperty("sys.init.perf_lsm_hooks", false)) {
55*38e8c45fSAndroid Build Coastguard Worker GTEST_SKIP();
56*38e8c45fSAndroid Build Coastguard Worker }
57*38e8c45fSAndroid Build Coastguard Worker }
58*38e8c45fSAndroid Build Coastguard Worker };
59*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,TotalTimeInState)60*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, TotalTimeInState) {
61*38e8c45fSAndroid Build Coastguard Worker auto times = getTotalCpuFreqTimes();
62*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times.has_value());
63*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(times->empty());
64*38e8c45fSAndroid Build Coastguard Worker }
65*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,SingleUidTimeInState)66*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, SingleUidTimeInState) {
67*38e8c45fSAndroid Build Coastguard Worker auto times = getUidCpuFreqTimes(0);
68*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times.has_value());
69*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(times->empty());
70*38e8c45fSAndroid Build Coastguard Worker }
71*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,SingleUidConcurrentTimes)72*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, SingleUidConcurrentTimes) {
73*38e8c45fSAndroid Build Coastguard Worker auto concurrentTimes = getUidConcurrentTimes(0);
74*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(concurrentTimes.has_value());
75*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(concurrentTimes->active.empty());
76*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(concurrentTimes->policy.empty());
77*38e8c45fSAndroid Build Coastguard Worker
78*38e8c45fSAndroid Build Coastguard Worker uint64_t policyEntries = 0;
79*38e8c45fSAndroid Build Coastguard Worker for (const auto &policyTimeVec : concurrentTimes->policy) policyEntries += policyTimeVec.size();
80*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(concurrentTimes->active.size(), policyEntries);
81*38e8c45fSAndroid Build Coastguard Worker }
82*38e8c45fSAndroid Build Coastguard Worker
TestConcurrentTimesConsistent(const struct concurrent_time_t & concurrentTime)83*38e8c45fSAndroid Build Coastguard Worker static void TestConcurrentTimesConsistent(const struct concurrent_time_t &concurrentTime) {
84*38e8c45fSAndroid Build Coastguard Worker size_t maxPolicyCpus = 0;
85*38e8c45fSAndroid Build Coastguard Worker for (const auto &vec : concurrentTime.policy) {
86*38e8c45fSAndroid Build Coastguard Worker maxPolicyCpus = std::max(maxPolicyCpus, vec.size());
87*38e8c45fSAndroid Build Coastguard Worker }
88*38e8c45fSAndroid Build Coastguard Worker uint64_t policySum = 0;
89*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < maxPolicyCpus; ++i) {
90*38e8c45fSAndroid Build Coastguard Worker for (const auto &vec : concurrentTime.policy) {
91*38e8c45fSAndroid Build Coastguard Worker if (i < vec.size()) policySum += vec[i];
92*38e8c45fSAndroid Build Coastguard Worker }
93*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(concurrentTime.active[i], policySum);
94*38e8c45fSAndroid Build Coastguard Worker policySum -= concurrentTime.active[i];
95*38e8c45fSAndroid Build Coastguard Worker }
96*38e8c45fSAndroid Build Coastguard Worker policySum = 0;
97*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < concurrentTime.active.size(); ++i) {
98*38e8c45fSAndroid Build Coastguard Worker for (const auto &vec : concurrentTime.policy) {
99*38e8c45fSAndroid Build Coastguard Worker if (i < vec.size()) policySum += vec[vec.size() - 1 - i];
100*38e8c45fSAndroid Build Coastguard Worker }
101*38e8c45fSAndroid Build Coastguard Worker auto activeSum = concurrentTime.active[concurrentTime.active.size() - 1 - i];
102*38e8c45fSAndroid Build Coastguard Worker // This check is slightly flaky because we may read a map entry in the middle of an update
103*38e8c45fSAndroid Build Coastguard Worker // when active times have been updated but policy times have not. This happens infrequently
104*38e8c45fSAndroid Build Coastguard Worker // and can be distinguished from more serious bugs by re-running the test: if the underlying
105*38e8c45fSAndroid Build Coastguard Worker // data itself is inconsistent, the test will fail every time.
106*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(activeSum, policySum);
107*38e8c45fSAndroid Build Coastguard Worker policySum -= activeSum;
108*38e8c45fSAndroid Build Coastguard Worker }
109*38e8c45fSAndroid Build Coastguard Worker }
110*38e8c45fSAndroid Build Coastguard Worker
TestUidTimesConsistent(const std::vector<std::vector<uint64_t>> & timeInState,const struct concurrent_time_t & concurrentTime)111*38e8c45fSAndroid Build Coastguard Worker static void TestUidTimesConsistent(const std::vector<std::vector<uint64_t>> &timeInState,
112*38e8c45fSAndroid Build Coastguard Worker const struct concurrent_time_t &concurrentTime) {
113*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestConcurrentTimesConsistent(concurrentTime));
114*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(timeInState.size(), concurrentTime.policy.size());
115*38e8c45fSAndroid Build Coastguard Worker uint64_t policySum = 0;
116*38e8c45fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < timeInState.size(); ++i) {
117*38e8c45fSAndroid Build Coastguard Worker uint64_t tisSum =
118*38e8c45fSAndroid Build Coastguard Worker std::accumulate(timeInState[i].begin(), timeInState[i].end(), (uint64_t)0);
119*38e8c45fSAndroid Build Coastguard Worker uint64_t concurrentSum = std::accumulate(concurrentTime.policy[i].begin(),
120*38e8c45fSAndroid Build Coastguard Worker concurrentTime.policy[i].end(), (uint64_t)0);
121*38e8c45fSAndroid Build Coastguard Worker if (tisSum < concurrentSum)
122*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(concurrentSum - tisSum, NSEC_PER_SEC);
123*38e8c45fSAndroid Build Coastguard Worker else
124*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(tisSum - concurrentSum, NSEC_PER_SEC);
125*38e8c45fSAndroid Build Coastguard Worker policySum += concurrentSum;
126*38e8c45fSAndroid Build Coastguard Worker }
127*38e8c45fSAndroid Build Coastguard Worker uint64_t activeSum = std::accumulate(concurrentTime.active.begin(), concurrentTime.active.end(),
128*38e8c45fSAndroid Build Coastguard Worker (uint64_t)0);
129*38e8c45fSAndroid Build Coastguard Worker EXPECT_EQ(activeSum, policySum);
130*38e8c45fSAndroid Build Coastguard Worker }
131*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,SingleUidTimesConsistent)132*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, SingleUidTimesConsistent) {
133*38e8c45fSAndroid Build Coastguard Worker auto times = getUidCpuFreqTimes(0);
134*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times.has_value());
135*38e8c45fSAndroid Build Coastguard Worker
136*38e8c45fSAndroid Build Coastguard Worker auto concurrentTimes = getUidConcurrentTimes(0);
137*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(concurrentTimes.has_value());
138*38e8c45fSAndroid Build Coastguard Worker
139*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(*times, *concurrentTimes));
140*38e8c45fSAndroid Build Coastguard Worker }
141*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidTimeInState)142*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidTimeInState) {
143*38e8c45fSAndroid Build Coastguard Worker uint64_t zero = 0;
144*38e8c45fSAndroid Build Coastguard Worker auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
145*38e8c45fSAndroid Build Coastguard Worker for (const auto &map : maps) {
146*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map.has_value());
147*38e8c45fSAndroid Build Coastguard Worker
148*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map->empty());
149*38e8c45fSAndroid Build Coastguard Worker
150*38e8c45fSAndroid Build Coastguard Worker vector<size_t> sizes;
151*38e8c45fSAndroid Build Coastguard Worker auto firstEntry = map->begin()->second;
152*38e8c45fSAndroid Build Coastguard Worker for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
153*38e8c45fSAndroid Build Coastguard Worker
154*38e8c45fSAndroid Build Coastguard Worker for (const auto &vec : *map) {
155*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(vec.second.size(), sizes.size());
156*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
157*38e8c45fSAndroid Build Coastguard Worker }
158*38e8c45fSAndroid Build Coastguard Worker }
159*38e8c45fSAndroid Build Coastguard Worker }
160*38e8c45fSAndroid Build Coastguard Worker
TestCheckUpdate(const std::vector<std::vector<uint64_t>> & before,const std::vector<std::vector<uint64_t>> & after)161*38e8c45fSAndroid Build Coastguard Worker void TestCheckUpdate(const std::vector<std::vector<uint64_t>> &before,
162*38e8c45fSAndroid Build Coastguard Worker const std::vector<std::vector<uint64_t>> &after) {
163*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(before.size(), after.size());
164*38e8c45fSAndroid Build Coastguard Worker uint64_t sumBefore = 0, sumAfter = 0;
165*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < before.size(); ++i) {
166*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(before[i].size(), after[i].size());
167*38e8c45fSAndroid Build Coastguard Worker for (size_t j = 0; j < before[i].size(); ++j) {
168*38e8c45fSAndroid Build Coastguard Worker // Times should never decrease
169*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(before[i][j], after[i][j]);
170*38e8c45fSAndroid Build Coastguard Worker }
171*38e8c45fSAndroid Build Coastguard Worker sumBefore += std::accumulate(before[i].begin(), before[i].end(), (uint64_t)0);
172*38e8c45fSAndroid Build Coastguard Worker sumAfter += std::accumulate(after[i].begin(), after[i].end(), (uint64_t)0);
173*38e8c45fSAndroid Build Coastguard Worker }
174*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(sumBefore, sumAfter);
175*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(sumAfter - sumBefore, NSEC_PER_SEC);
176*38e8c45fSAndroid Build Coastguard Worker }
177*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidUpdatedTimeInState)178*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidUpdatedTimeInState) {
179*38e8c45fSAndroid Build Coastguard Worker uint64_t lastUpdate = 0;
180*38e8c45fSAndroid Build Coastguard Worker auto map1 = getUidsUpdatedCpuFreqTimes(&lastUpdate);
181*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map1.has_value());
182*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map1->empty());
183*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(lastUpdate, (uint64_t)0);
184*38e8c45fSAndroid Build Coastguard Worker uint64_t oldLastUpdate = lastUpdate;
185*38e8c45fSAndroid Build Coastguard Worker
186*38e8c45fSAndroid Build Coastguard Worker // Sleep briefly to trigger a context switch, ensuring we see at least one update.
187*38e8c45fSAndroid Build Coastguard Worker struct timespec ts;
188*38e8c45fSAndroid Build Coastguard Worker ts.tv_sec = 0;
189*38e8c45fSAndroid Build Coastguard Worker ts.tv_nsec = 1000000;
190*38e8c45fSAndroid Build Coastguard Worker nanosleep (&ts, NULL);
191*38e8c45fSAndroid Build Coastguard Worker
192*38e8c45fSAndroid Build Coastguard Worker auto map2 = getUidsUpdatedCpuFreqTimes(&lastUpdate);
193*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map2.has_value());
194*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map2->empty());
195*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(lastUpdate, oldLastUpdate);
196*38e8c45fSAndroid Build Coastguard Worker
197*38e8c45fSAndroid Build Coastguard Worker bool someUidsExcluded = false;
198*38e8c45fSAndroid Build Coastguard Worker for (const auto &[uid, v] : *map1) {
199*38e8c45fSAndroid Build Coastguard Worker if (map2->find(uid) == map2->end()) {
200*38e8c45fSAndroid Build Coastguard Worker someUidsExcluded = true;
201*38e8c45fSAndroid Build Coastguard Worker break;
202*38e8c45fSAndroid Build Coastguard Worker }
203*38e8c45fSAndroid Build Coastguard Worker }
204*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(someUidsExcluded);
205*38e8c45fSAndroid Build Coastguard Worker
206*38e8c45fSAndroid Build Coastguard Worker for (const auto &[uid, newTimes] : *map2) {
207*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(map1->find(uid), map1->end());
208*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid], newTimes));
209*38e8c45fSAndroid Build Coastguard Worker }
210*38e8c45fSAndroid Build Coastguard Worker }
211*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,TotalAndAllUidTimeInStateConsistent)212*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
213*38e8c45fSAndroid Build Coastguard Worker auto allUid = getUidsCpuFreqTimes();
214*38e8c45fSAndroid Build Coastguard Worker auto total = getTotalCpuFreqTimes();
215*38e8c45fSAndroid Build Coastguard Worker
216*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(allUid.has_value() && total.has_value());
217*38e8c45fSAndroid Build Coastguard Worker
218*38e8c45fSAndroid Build Coastguard Worker // Check the number of policies.
219*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(allUid->at(0).size(), total->size());
220*38e8c45fSAndroid Build Coastguard Worker
221*38e8c45fSAndroid Build Coastguard Worker for (uint32_t policyIdx = 0; policyIdx < total->size(); ++policyIdx) {
222*38e8c45fSAndroid Build Coastguard Worker std::vector<uint64_t> totalTimes = total->at(policyIdx);
223*38e8c45fSAndroid Build Coastguard Worker uint32_t totalFreqsCount = totalTimes.size();
224*38e8c45fSAndroid Build Coastguard Worker std::vector<uint64_t> allUidTimes(totalFreqsCount, 0);
225*38e8c45fSAndroid Build Coastguard Worker for (auto const &[uid, uidTimes]: *allUid) {
226*38e8c45fSAndroid Build Coastguard Worker if (uid == AID_SDK_SANDBOX) continue;
227*38e8c45fSAndroid Build Coastguard Worker for (uint32_t freqIdx = 0; freqIdx < uidTimes[policyIdx].size(); ++freqIdx) {
228*38e8c45fSAndroid Build Coastguard Worker allUidTimes[std::min(freqIdx, totalFreqsCount - 1)] += uidTimes[policyIdx][freqIdx];
229*38e8c45fSAndroid Build Coastguard Worker }
230*38e8c45fSAndroid Build Coastguard Worker }
231*38e8c45fSAndroid Build Coastguard Worker
232*38e8c45fSAndroid Build Coastguard Worker for (uint32_t freqIdx = 0; freqIdx < totalFreqsCount; ++freqIdx) {
233*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(allUidTimes[freqIdx], totalTimes[freqIdx]);
234*38e8c45fSAndroid Build Coastguard Worker }
235*38e8c45fSAndroid Build Coastguard Worker }
236*38e8c45fSAndroid Build Coastguard Worker }
237*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,SingleAndAllUidTimeInStateConsistent)238*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
239*38e8c45fSAndroid Build Coastguard Worker uint64_t zero = 0;
240*38e8c45fSAndroid Build Coastguard Worker auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
241*38e8c45fSAndroid Build Coastguard Worker for (const auto &map : maps) {
242*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map.has_value());
243*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map->empty());
244*38e8c45fSAndroid Build Coastguard Worker
245*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *map) {
246*38e8c45fSAndroid Build Coastguard Worker uint32_t uid = kv.first;
247*38e8c45fSAndroid Build Coastguard Worker auto times1 = kv.second;
248*38e8c45fSAndroid Build Coastguard Worker auto times2 = getUidCpuFreqTimes(uid);
249*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times2.has_value());
250*38e8c45fSAndroid Build Coastguard Worker
251*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(times1.size(), times2->size());
252*38e8c45fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < times1.size(); ++i) {
253*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(times1[i].size(), (*times2)[i].size());
254*38e8c45fSAndroid Build Coastguard Worker for (uint32_t j = 0; j < times1[i].size(); ++j) {
255*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
256*38e8c45fSAndroid Build Coastguard Worker }
257*38e8c45fSAndroid Build Coastguard Worker }
258*38e8c45fSAndroid Build Coastguard Worker }
259*38e8c45fSAndroid Build Coastguard Worker }
260*38e8c45fSAndroid Build Coastguard Worker }
261*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidConcurrentTimes)262*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidConcurrentTimes) {
263*38e8c45fSAndroid Build Coastguard Worker uint64_t zero = 0;
264*38e8c45fSAndroid Build Coastguard Worker auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
265*38e8c45fSAndroid Build Coastguard Worker for (const auto &map : maps) {
266*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map.has_value());
267*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map->empty());
268*38e8c45fSAndroid Build Coastguard Worker
269*38e8c45fSAndroid Build Coastguard Worker auto firstEntry = map->begin()->second;
270*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *map) {
271*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(kv.second.active.size(), firstEntry.active.size());
272*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size());
273*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < kv.second.policy.size(); ++i) {
274*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size());
275*38e8c45fSAndroid Build Coastguard Worker }
276*38e8c45fSAndroid Build Coastguard Worker }
277*38e8c45fSAndroid Build Coastguard Worker }
278*38e8c45fSAndroid Build Coastguard Worker }
279*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidUpdatedConcurrentTimes)280*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidUpdatedConcurrentTimes) {
281*38e8c45fSAndroid Build Coastguard Worker uint64_t lastUpdate = 0;
282*38e8c45fSAndroid Build Coastguard Worker auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate);
283*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map1.has_value());
284*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map1->empty());
285*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(lastUpdate, (uint64_t)0);
286*38e8c45fSAndroid Build Coastguard Worker
287*38e8c45fSAndroid Build Coastguard Worker // Sleep briefly to trigger a context switch, ensuring we see at least one update.
288*38e8c45fSAndroid Build Coastguard Worker struct timespec ts;
289*38e8c45fSAndroid Build Coastguard Worker ts.tv_sec = 0;
290*38e8c45fSAndroid Build Coastguard Worker ts.tv_nsec = 1000000;
291*38e8c45fSAndroid Build Coastguard Worker nanosleep (&ts, NULL);
292*38e8c45fSAndroid Build Coastguard Worker
293*38e8c45fSAndroid Build Coastguard Worker uint64_t oldLastUpdate = lastUpdate;
294*38e8c45fSAndroid Build Coastguard Worker auto map2 = getUidsUpdatedConcurrentTimes(&lastUpdate);
295*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map2.has_value());
296*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map2->empty());
297*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(lastUpdate, oldLastUpdate);
298*38e8c45fSAndroid Build Coastguard Worker
299*38e8c45fSAndroid Build Coastguard Worker bool someUidsExcluded = false;
300*38e8c45fSAndroid Build Coastguard Worker for (const auto &[uid, v] : *map1) {
301*38e8c45fSAndroid Build Coastguard Worker if (map2->find(uid) == map2->end()) {
302*38e8c45fSAndroid Build Coastguard Worker someUidsExcluded = true;
303*38e8c45fSAndroid Build Coastguard Worker break;
304*38e8c45fSAndroid Build Coastguard Worker }
305*38e8c45fSAndroid Build Coastguard Worker }
306*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(someUidsExcluded);
307*38e8c45fSAndroid Build Coastguard Worker
308*38e8c45fSAndroid Build Coastguard Worker for (const auto &[uid, newTimes] : *map2) {
309*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(map1->find(uid), map1->end());
310*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestCheckUpdate({(*map1)[uid].active},{newTimes.active}));
311*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid].policy, newTimes.policy));
312*38e8c45fSAndroid Build Coastguard Worker }
313*38e8c45fSAndroid Build Coastguard Worker }
314*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,SingleAndAllUidConcurrentTimesConsistent)315*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
316*38e8c45fSAndroid Build Coastguard Worker uint64_t zero = 0;
317*38e8c45fSAndroid Build Coastguard Worker auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
318*38e8c45fSAndroid Build Coastguard Worker for (const auto &map : maps) {
319*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map.has_value());
320*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *map) {
321*38e8c45fSAndroid Build Coastguard Worker uint32_t uid = kv.first;
322*38e8c45fSAndroid Build Coastguard Worker auto times1 = kv.second;
323*38e8c45fSAndroid Build Coastguard Worker auto times2 = getUidConcurrentTimes(uid);
324*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times2.has_value());
325*38e8c45fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < times1.active.size(); ++i) {
326*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC);
327*38e8c45fSAndroid Build Coastguard Worker }
328*38e8c45fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < times1.policy.size(); ++i) {
329*38e8c45fSAndroid Build Coastguard Worker for (uint32_t j = 0; j < times1.policy[i].size(); ++j) {
330*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC);
331*38e8c45fSAndroid Build Coastguard Worker }
332*38e8c45fSAndroid Build Coastguard Worker }
333*38e8c45fSAndroid Build Coastguard Worker }
334*38e8c45fSAndroid Build Coastguard Worker }
335*38e8c45fSAndroid Build Coastguard Worker }
336*38e8c45fSAndroid Build Coastguard Worker
TestCheckDelta(uint64_t before,uint64_t after)337*38e8c45fSAndroid Build Coastguard Worker void TestCheckDelta(uint64_t before, uint64_t after) {
338*38e8c45fSAndroid Build Coastguard Worker // Times should never decrease
339*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(before, after);
340*38e8c45fSAndroid Build Coastguard Worker // UID can't have run for more than ~1s on each CPU
341*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
342*38e8c45fSAndroid Build Coastguard Worker }
343*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,TotalTimeInStateMonotonic)344*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, TotalTimeInStateMonotonic) {
345*38e8c45fSAndroid Build Coastguard Worker auto before = getTotalCpuFreqTimes();
346*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(before.has_value());
347*38e8c45fSAndroid Build Coastguard Worker sleep(1);
348*38e8c45fSAndroid Build Coastguard Worker auto after = getTotalCpuFreqTimes();
349*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(after.has_value());
350*38e8c45fSAndroid Build Coastguard Worker
351*38e8c45fSAndroid Build Coastguard Worker for (uint32_t policyIdx = 0; policyIdx < after->size(); ++policyIdx) {
352*38e8c45fSAndroid Build Coastguard Worker auto timesBefore = before->at(policyIdx);
353*38e8c45fSAndroid Build Coastguard Worker auto timesAfter = after->at(policyIdx);
354*38e8c45fSAndroid Build Coastguard Worker for (uint32_t freqIdx = 0; freqIdx < timesAfter.size(); ++freqIdx) {
355*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestCheckDelta(timesBefore[freqIdx], timesAfter[freqIdx]));
356*38e8c45fSAndroid Build Coastguard Worker }
357*38e8c45fSAndroid Build Coastguard Worker }
358*38e8c45fSAndroid Build Coastguard Worker }
359*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidTimeInStateMonotonic)360*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidTimeInStateMonotonic) {
361*38e8c45fSAndroid Build Coastguard Worker auto map1 = getUidsCpuFreqTimes();
362*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map1.has_value());
363*38e8c45fSAndroid Build Coastguard Worker sleep(1);
364*38e8c45fSAndroid Build Coastguard Worker auto map2 = getUidsCpuFreqTimes();
365*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map2.has_value());
366*38e8c45fSAndroid Build Coastguard Worker
367*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *map1) {
368*38e8c45fSAndroid Build Coastguard Worker uint32_t uid = kv.first;
369*38e8c45fSAndroid Build Coastguard Worker auto times = kv.second;
370*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(map2->find(uid), map2->end());
371*38e8c45fSAndroid Build Coastguard Worker for (uint32_t policy = 0; policy < times.size(); ++policy) {
372*38e8c45fSAndroid Build Coastguard Worker for (uint32_t freqIdx = 0; freqIdx < times[policy].size(); ++freqIdx) {
373*38e8c45fSAndroid Build Coastguard Worker auto before = times[policy][freqIdx];
374*38e8c45fSAndroid Build Coastguard Worker auto after = (*map2)[uid][policy][freqIdx];
375*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
376*38e8c45fSAndroid Build Coastguard Worker }
377*38e8c45fSAndroid Build Coastguard Worker }
378*38e8c45fSAndroid Build Coastguard Worker }
379*38e8c45fSAndroid Build Coastguard Worker }
380*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidConcurrentTimesMonotonic)381*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
382*38e8c45fSAndroid Build Coastguard Worker auto map1 = getUidsConcurrentTimes();
383*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map1.has_value());
384*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map1->empty());
385*38e8c45fSAndroid Build Coastguard Worker sleep(1);
386*38e8c45fSAndroid Build Coastguard Worker auto map2 = getUidsConcurrentTimes();
387*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map2.has_value());
388*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map2->empty());
389*38e8c45fSAndroid Build Coastguard Worker
390*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *map1) {
391*38e8c45fSAndroid Build Coastguard Worker uint32_t uid = kv.first;
392*38e8c45fSAndroid Build Coastguard Worker auto times = kv.second;
393*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(map2->find(uid), map2->end());
394*38e8c45fSAndroid Build Coastguard Worker for (uint32_t i = 0; i < times.active.size(); ++i) {
395*38e8c45fSAndroid Build Coastguard Worker auto before = times.active[i];
396*38e8c45fSAndroid Build Coastguard Worker auto after = (*map2)[uid].active[i];
397*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
398*38e8c45fSAndroid Build Coastguard Worker }
399*38e8c45fSAndroid Build Coastguard Worker for (uint32_t policy = 0; policy < times.policy.size(); ++policy) {
400*38e8c45fSAndroid Build Coastguard Worker for (uint32_t idx = 0; idx < times.policy[policy].size(); ++idx) {
401*38e8c45fSAndroid Build Coastguard Worker auto before = times.policy[policy][idx];
402*38e8c45fSAndroid Build Coastguard Worker auto after = (*map2)[uid].policy[policy][idx];
403*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
404*38e8c45fSAndroid Build Coastguard Worker }
405*38e8c45fSAndroid Build Coastguard Worker }
406*38e8c45fSAndroid Build Coastguard Worker }
407*38e8c45fSAndroid Build Coastguard Worker }
408*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidTimeInStateSanityCheck)409*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidTimeInStateSanityCheck) {
410*38e8c45fSAndroid Build Coastguard Worker uint64_t zero = 0;
411*38e8c45fSAndroid Build Coastguard Worker auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
412*38e8c45fSAndroid Build Coastguard Worker for (const auto &map : maps) {
413*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map.has_value());
414*38e8c45fSAndroid Build Coastguard Worker
415*38e8c45fSAndroid Build Coastguard Worker bool foundLargeValue = false;
416*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *map) {
417*38e8c45fSAndroid Build Coastguard Worker for (const auto &timeVec : kv.second) {
418*38e8c45fSAndroid Build Coastguard Worker for (const auto &time : timeVec) {
419*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(time, NSEC_PER_YEAR);
420*38e8c45fSAndroid Build Coastguard Worker if (time > UINT32_MAX) foundLargeValue = true;
421*38e8c45fSAndroid Build Coastguard Worker }
422*38e8c45fSAndroid Build Coastguard Worker }
423*38e8c45fSAndroid Build Coastguard Worker }
424*38e8c45fSAndroid Build Coastguard Worker // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
425*38e8c45fSAndroid Build Coastguard Worker // uint64_t as expected, we should have some times higher than that.
426*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(foundLargeValue);
427*38e8c45fSAndroid Build Coastguard Worker }
428*38e8c45fSAndroid Build Coastguard Worker }
429*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidConcurrentTimesSanityCheck)430*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
431*38e8c45fSAndroid Build Coastguard Worker uint64_t zero = 0;
432*38e8c45fSAndroid Build Coastguard Worker auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)};
433*38e8c45fSAndroid Build Coastguard Worker for (const auto &concurrentMap : maps) {
434*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(concurrentMap);
435*38e8c45fSAndroid Build Coastguard Worker
436*38e8c45fSAndroid Build Coastguard Worker bool activeFoundLargeValue = false;
437*38e8c45fSAndroid Build Coastguard Worker bool policyFoundLargeValue = false;
438*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *concurrentMap) {
439*38e8c45fSAndroid Build Coastguard Worker for (const auto &time : kv.second.active) {
440*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(time, NSEC_PER_YEAR);
441*38e8c45fSAndroid Build Coastguard Worker if (time > UINT32_MAX) activeFoundLargeValue = true;
442*38e8c45fSAndroid Build Coastguard Worker }
443*38e8c45fSAndroid Build Coastguard Worker for (const auto &policyTimeVec : kv.second.policy) {
444*38e8c45fSAndroid Build Coastguard Worker for (const auto &time : policyTimeVec) {
445*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(time, NSEC_PER_YEAR);
446*38e8c45fSAndroid Build Coastguard Worker if (time > UINT32_MAX) policyFoundLargeValue = true;
447*38e8c45fSAndroid Build Coastguard Worker }
448*38e8c45fSAndroid Build Coastguard Worker }
449*38e8c45fSAndroid Build Coastguard Worker }
450*38e8c45fSAndroid Build Coastguard Worker // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
451*38e8c45fSAndroid Build Coastguard Worker // uint64_t as expected, we should have some times higher than that.
452*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(activeFoundLargeValue);
453*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(policyFoundLargeValue);
454*38e8c45fSAndroid Build Coastguard Worker }
455*38e8c45fSAndroid Build Coastguard Worker }
456*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidConcurrentTimesFailsOnInvalidBucket)457*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
458*38e8c45fSAndroid Build Coastguard Worker uint32_t uid = 0;
459*38e8c45fSAndroid Build Coastguard Worker {
460*38e8c45fSAndroid Build Coastguard Worker // Find an unused UID
461*38e8c45fSAndroid Build Coastguard Worker auto map = getUidsConcurrentTimes();
462*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(map.has_value());
463*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(map->empty());
464*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *map) uid = std::max(uid, kv.first);
465*38e8c45fSAndroid Build Coastguard Worker ++uid;
466*38e8c45fSAndroid Build Coastguard Worker }
467*38e8c45fSAndroid Build Coastguard Worker android::base::unique_fd fd{
468*38e8c45fSAndroid Build Coastguard Worker bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
469*38e8c45fSAndroid Build Coastguard Worker ASSERT_GE(fd, 0);
470*38e8c45fSAndroid Build Coastguard Worker uint32_t nCpus = get_nprocs_conf();
471*38e8c45fSAndroid Build Coastguard Worker uint32_t maxBucket = (nCpus - 1) / CPUS_PER_ENTRY;
472*38e8c45fSAndroid Build Coastguard Worker time_key_t key = {.uid = uid, .bucket = maxBucket + 1};
473*38e8c45fSAndroid Build Coastguard Worker std::vector<concurrent_val_t> vals(nCpus);
474*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(writeToMapEntry(fd, &key, vals.data(), BPF_NOEXIST));
475*38e8c45fSAndroid Build Coastguard Worker EXPECT_FALSE(getUidsConcurrentTimes().has_value());
476*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(deleteMapEntry(fd, &key));
477*38e8c45fSAndroid Build Coastguard Worker }
478*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,AllUidTimesConsistent)479*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, AllUidTimesConsistent) {
480*38e8c45fSAndroid Build Coastguard Worker auto tisMap = getUidsCpuFreqTimes();
481*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(tisMap.has_value());
482*38e8c45fSAndroid Build Coastguard Worker
483*38e8c45fSAndroid Build Coastguard Worker auto concurrentMap = getUidsConcurrentTimes();
484*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(concurrentMap.has_value());
485*38e8c45fSAndroid Build Coastguard Worker
486*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(tisMap->size(), concurrentMap->size());
487*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *tisMap) {
488*38e8c45fSAndroid Build Coastguard Worker uint32_t uid = kv.first;
489*38e8c45fSAndroid Build Coastguard Worker auto times = kv.second;
490*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(concurrentMap->find(uid), concurrentMap->end());
491*38e8c45fSAndroid Build Coastguard Worker
492*38e8c45fSAndroid Build Coastguard Worker auto concurrentTimes = (*concurrentMap)[uid];
493*38e8c45fSAndroid Build Coastguard Worker ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(times, concurrentTimes));
494*38e8c45fSAndroid Build Coastguard Worker }
495*38e8c45fSAndroid Build Coastguard Worker }
496*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,RemoveUid)497*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, RemoveUid) {
498*38e8c45fSAndroid Build Coastguard Worker uint32_t uid = 0;
499*38e8c45fSAndroid Build Coastguard Worker {
500*38e8c45fSAndroid Build Coastguard Worker // Find an unused UID
501*38e8c45fSAndroid Build Coastguard Worker auto times = getUidsCpuFreqTimes();
502*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times.has_value());
503*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(times->empty());
504*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *times) uid = std::max(uid, kv.first);
505*38e8c45fSAndroid Build Coastguard Worker ++uid;
506*38e8c45fSAndroid Build Coastguard Worker }
507*38e8c45fSAndroid Build Coastguard Worker {
508*38e8c45fSAndroid Build Coastguard Worker // Add a map entry for our fake UID by copying a real map entry
509*38e8c45fSAndroid Build Coastguard Worker android::base::unique_fd fd{
510*38e8c45fSAndroid Build Coastguard Worker bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_time_in_state_map")};
511*38e8c45fSAndroid Build Coastguard Worker ASSERT_GE(fd, 0);
512*38e8c45fSAndroid Build Coastguard Worker time_key_t k;
513*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(getFirstMapKey(fd, &k));
514*38e8c45fSAndroid Build Coastguard Worker std::vector<tis_val_t> vals(get_nprocs_conf());
515*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(findMapEntry(fd, &k, vals.data()));
516*38e8c45fSAndroid Build Coastguard Worker uint32_t copiedUid = k.uid;
517*38e8c45fSAndroid Build Coastguard Worker k.uid = uid;
518*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST));
519*38e8c45fSAndroid Build Coastguard Worker
520*38e8c45fSAndroid Build Coastguard Worker android::base::unique_fd fd2{
521*38e8c45fSAndroid Build Coastguard Worker bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
522*38e8c45fSAndroid Build Coastguard Worker k.uid = copiedUid;
523*38e8c45fSAndroid Build Coastguard Worker k.bucket = 0;
524*38e8c45fSAndroid Build Coastguard Worker std::vector<concurrent_val_t> cvals(get_nprocs_conf());
525*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(findMapEntry(fd2, &k, cvals.data()));
526*38e8c45fSAndroid Build Coastguard Worker k.uid = uid;
527*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(writeToMapEntry(fd2, &k, cvals.data(), BPF_NOEXIST));
528*38e8c45fSAndroid Build Coastguard Worker }
529*38e8c45fSAndroid Build Coastguard Worker auto times = getUidCpuFreqTimes(uid);
530*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times.has_value());
531*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(times->empty());
532*38e8c45fSAndroid Build Coastguard Worker
533*38e8c45fSAndroid Build Coastguard Worker auto concurrentTimes = getUidConcurrentTimes(0);
534*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(concurrentTimes.has_value());
535*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(concurrentTimes->active.empty());
536*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(concurrentTimes->policy.empty());
537*38e8c45fSAndroid Build Coastguard Worker
538*38e8c45fSAndroid Build Coastguard Worker uint64_t sum = 0;
539*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < times->size(); ++i) {
540*38e8c45fSAndroid Build Coastguard Worker for (auto x : (*times)[i]) sum += x;
541*38e8c45fSAndroid Build Coastguard Worker }
542*38e8c45fSAndroid Build Coastguard Worker ASSERT_GT(sum, (uint64_t)0);
543*38e8c45fSAndroid Build Coastguard Worker
544*38e8c45fSAndroid Build Coastguard Worker uint64_t activeSum = 0;
545*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < concurrentTimes->active.size(); ++i) {
546*38e8c45fSAndroid Build Coastguard Worker activeSum += concurrentTimes->active[i];
547*38e8c45fSAndroid Build Coastguard Worker }
548*38e8c45fSAndroid Build Coastguard Worker ASSERT_GT(activeSum, (uint64_t)0);
549*38e8c45fSAndroid Build Coastguard Worker
550*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(clearUidTimes(uid));
551*38e8c45fSAndroid Build Coastguard Worker
552*38e8c45fSAndroid Build Coastguard Worker auto allTimes = getUidsCpuFreqTimes();
553*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(allTimes.has_value());
554*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(allTimes->empty());
555*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(allTimes->find(uid), allTimes->end());
556*38e8c45fSAndroid Build Coastguard Worker
557*38e8c45fSAndroid Build Coastguard Worker auto allConcurrentTimes = getUidsConcurrentTimes();
558*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(allConcurrentTimes.has_value());
559*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(allConcurrentTimes->empty());
560*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
561*38e8c45fSAndroid Build Coastguard Worker }
562*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,GetCpuFreqs)563*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, GetCpuFreqs) {
564*38e8c45fSAndroid Build Coastguard Worker auto freqs = getCpuFreqs();
565*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(freqs.has_value());
566*38e8c45fSAndroid Build Coastguard Worker
567*38e8c45fSAndroid Build Coastguard Worker auto times = getUidCpuFreqTimes(0);
568*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times.has_value());
569*38e8c45fSAndroid Build Coastguard Worker
570*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(freqs->size(), times->size());
571*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
572*38e8c45fSAndroid Build Coastguard Worker }
573*38e8c45fSAndroid Build Coastguard Worker
timeNanos()574*38e8c45fSAndroid Build Coastguard Worker uint64_t timeNanos() {
575*38e8c45fSAndroid Build Coastguard Worker struct timespec spec;
576*38e8c45fSAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &spec);
577*38e8c45fSAndroid Build Coastguard Worker return spec.tv_sec * 1000000000 + spec.tv_nsec;
578*38e8c45fSAndroid Build Coastguard Worker }
579*38e8c45fSAndroid Build Coastguard Worker
580*38e8c45fSAndroid Build Coastguard Worker // Keeps CPU busy with some number crunching
useCpu()581*38e8c45fSAndroid Build Coastguard Worker void useCpu() {
582*38e8c45fSAndroid Build Coastguard Worker sum = 1;
583*38e8c45fSAndroid Build Coastguard Worker for (int i = 1; i < 100000; i++) {
584*38e8c45fSAndroid Build Coastguard Worker sum *= i;
585*38e8c45fSAndroid Build Coastguard Worker }
586*38e8c45fSAndroid Build Coastguard Worker }
587*38e8c45fSAndroid Build Coastguard Worker
588*38e8c45fSAndroid Build Coastguard Worker sem_t pingsem, pongsem;
589*38e8c45fSAndroid Build Coastguard Worker
testThread(void *)590*38e8c45fSAndroid Build Coastguard Worker void *testThread(void *) {
591*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < 10; i++) {
592*38e8c45fSAndroid Build Coastguard Worker sem_wait(&pingsem);
593*38e8c45fSAndroid Build Coastguard Worker useCpu();
594*38e8c45fSAndroid Build Coastguard Worker sem_post(&pongsem);
595*38e8c45fSAndroid Build Coastguard Worker }
596*38e8c45fSAndroid Build Coastguard Worker return nullptr;
597*38e8c45fSAndroid Build Coastguard Worker }
598*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,GetAggregatedTaskCpuFreqTimes)599*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, GetAggregatedTaskCpuFreqTimes) {
600*38e8c45fSAndroid Build Coastguard Worker uint64_t startTimeNs = timeNanos();
601*38e8c45fSAndroid Build Coastguard Worker
602*38e8c45fSAndroid Build Coastguard Worker sem_init(&pingsem, 0, 1);
603*38e8c45fSAndroid Build Coastguard Worker sem_init(&pongsem, 0, 0);
604*38e8c45fSAndroid Build Coastguard Worker
605*38e8c45fSAndroid Build Coastguard Worker pthread_t thread;
606*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(pthread_create(&thread, NULL, &testThread, NULL), 0);
607*38e8c45fSAndroid Build Coastguard Worker
608*38e8c45fSAndroid Build Coastguard Worker // This process may have been running for some time, so when we start tracking
609*38e8c45fSAndroid Build Coastguard Worker // CPU time, the very first switch may include the accumulated time.
610*38e8c45fSAndroid Build Coastguard Worker // Yield the remainder of this timeslice to the newly created thread.
611*38e8c45fSAndroid Build Coastguard Worker sem_wait(&pongsem);
612*38e8c45fSAndroid Build Coastguard Worker sem_post(&pingsem);
613*38e8c45fSAndroid Build Coastguard Worker
614*38e8c45fSAndroid Build Coastguard Worker pid_t tgid = getpid();
615*38e8c45fSAndroid Build Coastguard Worker startTrackingProcessCpuTimes(tgid);
616*38e8c45fSAndroid Build Coastguard Worker
617*38e8c45fSAndroid Build Coastguard Worker pid_t tid = pthread_gettid_np(thread);
618*38e8c45fSAndroid Build Coastguard Worker startAggregatingTaskCpuTimes(tid, 42);
619*38e8c45fSAndroid Build Coastguard Worker
620*38e8c45fSAndroid Build Coastguard Worker // Play ping-pong with the other thread to ensure that both threads get
621*38e8c45fSAndroid Build Coastguard Worker // some CPU time.
622*38e8c45fSAndroid Build Coastguard Worker for (int i = 0; i < 9; i++) {
623*38e8c45fSAndroid Build Coastguard Worker sem_wait(&pongsem);
624*38e8c45fSAndroid Build Coastguard Worker useCpu();
625*38e8c45fSAndroid Build Coastguard Worker sem_post(&pingsem);
626*38e8c45fSAndroid Build Coastguard Worker }
627*38e8c45fSAndroid Build Coastguard Worker
628*38e8c45fSAndroid Build Coastguard Worker pthread_join(thread, NULL);
629*38e8c45fSAndroid Build Coastguard Worker
630*38e8c45fSAndroid Build Coastguard Worker std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>> optionalMap =
631*38e8c45fSAndroid Build Coastguard Worker getAggregatedTaskCpuFreqTimes(tgid, {0, 42});
632*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(optionalMap);
633*38e8c45fSAndroid Build Coastguard Worker
634*38e8c45fSAndroid Build Coastguard Worker std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map = *optionalMap;
635*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(map.size(), 2u);
636*38e8c45fSAndroid Build Coastguard Worker
637*38e8c45fSAndroid Build Coastguard Worker uint64_t testDurationNs = timeNanos() - startTimeNs;
638*38e8c45fSAndroid Build Coastguard Worker for (auto pair : map) {
639*38e8c45fSAndroid Build Coastguard Worker uint16_t aggregationKey = pair.first;
640*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(aggregationKey == 0 || aggregationKey == 42);
641*38e8c45fSAndroid Build Coastguard Worker
642*38e8c45fSAndroid Build Coastguard Worker std::vector<std::vector<uint64_t>> timesInState = pair.second;
643*38e8c45fSAndroid Build Coastguard Worker uint64_t totalCpuTime = 0;
644*38e8c45fSAndroid Build Coastguard Worker for (size_t i = 0; i < timesInState.size(); i++) {
645*38e8c45fSAndroid Build Coastguard Worker for (size_t j = 0; j < timesInState[i].size(); j++) {
646*38e8c45fSAndroid Build Coastguard Worker totalCpuTime += timesInState[i][j];
647*38e8c45fSAndroid Build Coastguard Worker }
648*38e8c45fSAndroid Build Coastguard Worker }
649*38e8c45fSAndroid Build Coastguard Worker ASSERT_GT(totalCpuTime, 0ul);
650*38e8c45fSAndroid Build Coastguard Worker ASSERT_LE(totalCpuTime, testDurationNs);
651*38e8c45fSAndroid Build Coastguard Worker }
652*38e8c45fSAndroid Build Coastguard Worker }
653*38e8c45fSAndroid Build Coastguard Worker
forceSwitchWithUid(void * uidPtr)654*38e8c45fSAndroid Build Coastguard Worker void *forceSwitchWithUid(void *uidPtr) {
655*38e8c45fSAndroid Build Coastguard Worker if (!uidPtr) return nullptr;
656*38e8c45fSAndroid Build Coastguard Worker setuid(*(uint32_t *)uidPtr);
657*38e8c45fSAndroid Build Coastguard Worker
658*38e8c45fSAndroid Build Coastguard Worker // Sleep briefly to trigger a context switch, ensuring we see at least one update.
659*38e8c45fSAndroid Build Coastguard Worker struct timespec ts;
660*38e8c45fSAndroid Build Coastguard Worker ts.tv_sec = 0;
661*38e8c45fSAndroid Build Coastguard Worker ts.tv_nsec = 1000000;
662*38e8c45fSAndroid Build Coastguard Worker nanosleep(&ts, NULL);
663*38e8c45fSAndroid Build Coastguard Worker return nullptr;
664*38e8c45fSAndroid Build Coastguard Worker }
665*38e8c45fSAndroid Build Coastguard Worker
TEST_F(TimeInStateTest,SdkSandboxUid)666*38e8c45fSAndroid Build Coastguard Worker TEST_F(TimeInStateTest, SdkSandboxUid) {
667*38e8c45fSAndroid Build Coastguard Worker // Find an unused app UID and its corresponding SDK sandbox uid.
668*38e8c45fSAndroid Build Coastguard Worker uint32_t appUid = AID_APP_START, sandboxUid;
669*38e8c45fSAndroid Build Coastguard Worker {
670*38e8c45fSAndroid Build Coastguard Worker auto times = getUidsCpuFreqTimes();
671*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(times.has_value());
672*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(times->empty());
673*38e8c45fSAndroid Build Coastguard Worker for (const auto &kv : *times) {
674*38e8c45fSAndroid Build Coastguard Worker if (kv.first > AID_APP_END) break;
675*38e8c45fSAndroid Build Coastguard Worker appUid = std::max(appUid, kv.first);
676*38e8c45fSAndroid Build Coastguard Worker }
677*38e8c45fSAndroid Build Coastguard Worker appUid++;
678*38e8c45fSAndroid Build Coastguard Worker sandboxUid = appUid + (AID_SDK_SANDBOX_PROCESS_START - AID_APP_START);
679*38e8c45fSAndroid Build Coastguard Worker }
680*38e8c45fSAndroid Build Coastguard Worker
681*38e8c45fSAndroid Build Coastguard Worker // Create a thread to run with the fake sandbox uid.
682*38e8c45fSAndroid Build Coastguard Worker pthread_t thread;
683*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(pthread_create(&thread, NULL, &forceSwitchWithUid, &sandboxUid), 0);
684*38e8c45fSAndroid Build Coastguard Worker pthread_join(thread, NULL);
685*38e8c45fSAndroid Build Coastguard Worker
686*38e8c45fSAndroid Build Coastguard Worker // Confirm we recorded stats for appUid and AID_SDK_SANDBOX but not sandboxUid
687*38e8c45fSAndroid Build Coastguard Worker auto allTimes = getUidsCpuFreqTimes();
688*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(allTimes.has_value());
689*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(allTimes->empty());
690*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(allTimes->find(appUid), allTimes->end());
691*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(allTimes->find(AID_SDK_SANDBOX), allTimes->end());
692*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(allTimes->find(sandboxUid), allTimes->end());
693*38e8c45fSAndroid Build Coastguard Worker
694*38e8c45fSAndroid Build Coastguard Worker auto allConcurrentTimes = getUidsConcurrentTimes();
695*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(allConcurrentTimes.has_value());
696*38e8c45fSAndroid Build Coastguard Worker ASSERT_FALSE(allConcurrentTimes->empty());
697*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(allConcurrentTimes->find(appUid), allConcurrentTimes->end());
698*38e8c45fSAndroid Build Coastguard Worker ASSERT_NE(allConcurrentTimes->find(AID_SDK_SANDBOX), allConcurrentTimes->end());
699*38e8c45fSAndroid Build Coastguard Worker ASSERT_EQ(allConcurrentTimes->find(sandboxUid), allConcurrentTimes->end());
700*38e8c45fSAndroid Build Coastguard Worker
701*38e8c45fSAndroid Build Coastguard Worker ASSERT_TRUE(clearUidTimes(appUid));
702*38e8c45fSAndroid Build Coastguard Worker }
703*38e8c45fSAndroid Build Coastguard Worker
704*38e8c45fSAndroid Build Coastguard Worker } // namespace bpf
705*38e8c45fSAndroid Build Coastguard Worker } // namespace android
706