xref: /aosp_15_r20/frameworks/native/libs/cputimeinstate/cputimeinstate.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2019 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 #define LOG_TAG "libtimeinstate"
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include "cputimeinstate.h"
20*38e8c45fSAndroid Build Coastguard Worker #include <bpf_timeinstate.h>
21*38e8c45fSAndroid Build Coastguard Worker 
22*38e8c45fSAndroid Build Coastguard Worker #include <dirent.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <errno.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <sys/sysinfo.h>
26*38e8c45fSAndroid Build Coastguard Worker 
27*38e8c45fSAndroid Build Coastguard Worker #include <mutex>
28*38e8c45fSAndroid Build Coastguard Worker #include <numeric>
29*38e8c45fSAndroid Build Coastguard Worker #include <optional>
30*38e8c45fSAndroid Build Coastguard Worker #include <set>
31*38e8c45fSAndroid Build Coastguard Worker #include <string>
32*38e8c45fSAndroid Build Coastguard Worker #include <unordered_map>
33*38e8c45fSAndroid Build Coastguard Worker #include <vector>
34*38e8c45fSAndroid Build Coastguard Worker 
35*38e8c45fSAndroid Build Coastguard Worker #include <android-base/file.h>
36*38e8c45fSAndroid Build Coastguard Worker #include <android-base/parseint.h>
37*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
38*38e8c45fSAndroid Build Coastguard Worker #include <android-base/strings.h>
39*38e8c45fSAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
40*38e8c45fSAndroid Build Coastguard Worker #include <bpf/BpfMap.h>
41*38e8c45fSAndroid Build Coastguard Worker #include <libbpf.h>
42*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
43*38e8c45fSAndroid Build Coastguard Worker 
44*38e8c45fSAndroid Build Coastguard Worker using android::base::StringPrintf;
45*38e8c45fSAndroid Build Coastguard Worker using android::base::unique_fd;
46*38e8c45fSAndroid Build Coastguard Worker 
47*38e8c45fSAndroid Build Coastguard Worker namespace android {
48*38e8c45fSAndroid Build Coastguard Worker namespace bpf {
49*38e8c45fSAndroid Build Coastguard Worker 
50*38e8c45fSAndroid Build Coastguard Worker static std::mutex gInitializedMutex;
51*38e8c45fSAndroid Build Coastguard Worker static bool gInitialized = false;
52*38e8c45fSAndroid Build Coastguard Worker static std::mutex gTrackingMutex;
53*38e8c45fSAndroid Build Coastguard Worker static bool gTracking = false;
54*38e8c45fSAndroid Build Coastguard Worker static uint32_t gNPolicies = 0;
55*38e8c45fSAndroid Build Coastguard Worker static uint32_t gNCpus = 0;
56*38e8c45fSAndroid Build Coastguard Worker static std::vector<std::vector<uint32_t>> gPolicyFreqs;
57*38e8c45fSAndroid Build Coastguard Worker static std::vector<std::vector<uint32_t>> gPolicyCpus;
58*38e8c45fSAndroid Build Coastguard Worker static std::vector<uint32_t> gCpuIndexMap;
59*38e8c45fSAndroid Build Coastguard Worker static std::set<uint32_t> gAllFreqs;
60*38e8c45fSAndroid Build Coastguard Worker static unique_fd gTisTotalMapFd;
61*38e8c45fSAndroid Build Coastguard Worker static unique_fd gTisMapFd;
62*38e8c45fSAndroid Build Coastguard Worker static unique_fd gConcurrentMapFd;
63*38e8c45fSAndroid Build Coastguard Worker static unique_fd gUidLastUpdateMapFd;
64*38e8c45fSAndroid Build Coastguard Worker static unique_fd gPidTisMapFd;
65*38e8c45fSAndroid Build Coastguard Worker 
readNumbersFromFile(const std::string & path)66*38e8c45fSAndroid Build Coastguard Worker static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
67*38e8c45fSAndroid Build Coastguard Worker     std::string data;
68*38e8c45fSAndroid Build Coastguard Worker 
69*38e8c45fSAndroid Build Coastguard Worker     if (!android::base::ReadFileToString(path, &data)) return {};
70*38e8c45fSAndroid Build Coastguard Worker 
71*38e8c45fSAndroid Build Coastguard Worker     auto strings = android::base::Split(data, " \n");
72*38e8c45fSAndroid Build Coastguard Worker     std::vector<uint32_t> ret;
73*38e8c45fSAndroid Build Coastguard Worker     for (const auto &s : strings) {
74*38e8c45fSAndroid Build Coastguard Worker         if (s.empty()) continue;
75*38e8c45fSAndroid Build Coastguard Worker         uint32_t n;
76*38e8c45fSAndroid Build Coastguard Worker         if (!android::base::ParseUint(s, &n)) return {};
77*38e8c45fSAndroid Build Coastguard Worker         ret.emplace_back(n);
78*38e8c45fSAndroid Build Coastguard Worker     }
79*38e8c45fSAndroid Build Coastguard Worker     return ret;
80*38e8c45fSAndroid Build Coastguard Worker }
81*38e8c45fSAndroid Build Coastguard Worker 
isPolicyFile(const struct dirent * d)82*38e8c45fSAndroid Build Coastguard Worker static int isPolicyFile(const struct dirent *d) {
83*38e8c45fSAndroid Build Coastguard Worker     return android::base::StartsWith(d->d_name, "policy");
84*38e8c45fSAndroid Build Coastguard Worker }
85*38e8c45fSAndroid Build Coastguard Worker 
comparePolicyFiles(const struct dirent ** d1,const struct dirent ** d2)86*38e8c45fSAndroid Build Coastguard Worker static int comparePolicyFiles(const struct dirent **d1, const struct dirent **d2) {
87*38e8c45fSAndroid Build Coastguard Worker     uint32_t policyN1, policyN2;
88*38e8c45fSAndroid Build Coastguard Worker     if (sscanf((*d1)->d_name, "policy%" SCNu32 "", &policyN1) != 1 ||
89*38e8c45fSAndroid Build Coastguard Worker         sscanf((*d2)->d_name, "policy%" SCNu32 "", &policyN2) != 1)
90*38e8c45fSAndroid Build Coastguard Worker         return 0;
91*38e8c45fSAndroid Build Coastguard Worker     return policyN1 - policyN2;
92*38e8c45fSAndroid Build Coastguard Worker }
93*38e8c45fSAndroid Build Coastguard Worker 
initGlobals()94*38e8c45fSAndroid Build Coastguard Worker static bool initGlobals() {
95*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> guard(gInitializedMutex);
96*38e8c45fSAndroid Build Coastguard Worker     if (gInitialized) return true;
97*38e8c45fSAndroid Build Coastguard Worker 
98*38e8c45fSAndroid Build Coastguard Worker     gNCpus = get_nprocs_conf();
99*38e8c45fSAndroid Build Coastguard Worker 
100*38e8c45fSAndroid Build Coastguard Worker     struct dirent **dirlist;
101*38e8c45fSAndroid Build Coastguard Worker     const char basepath[] = "/sys/devices/system/cpu/cpufreq";
102*38e8c45fSAndroid Build Coastguard Worker     int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
103*38e8c45fSAndroid Build Coastguard Worker     if (ret == -1 || ret == 0) return false;
104*38e8c45fSAndroid Build Coastguard Worker     gNPolicies = ret;
105*38e8c45fSAndroid Build Coastguard Worker 
106*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::string> policyFileNames;
107*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < gNPolicies; ++i) {
108*38e8c45fSAndroid Build Coastguard Worker         policyFileNames.emplace_back(dirlist[i]->d_name);
109*38e8c45fSAndroid Build Coastguard Worker         free(dirlist[i]);
110*38e8c45fSAndroid Build Coastguard Worker     }
111*38e8c45fSAndroid Build Coastguard Worker     free(dirlist);
112*38e8c45fSAndroid Build Coastguard Worker     uint32_t max_cpu_number = 0;
113*38e8c45fSAndroid Build Coastguard Worker     for (const auto &policy : policyFileNames) {
114*38e8c45fSAndroid Build Coastguard Worker         std::vector<uint32_t> freqs;
115*38e8c45fSAndroid Build Coastguard Worker         for (const auto &name : {"available", "boost"}) {
116*38e8c45fSAndroid Build Coastguard Worker             std::string path =
117*38e8c45fSAndroid Build Coastguard Worker                     StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
118*38e8c45fSAndroid Build Coastguard Worker             auto nums = readNumbersFromFile(path);
119*38e8c45fSAndroid Build Coastguard Worker             if (!nums) continue;
120*38e8c45fSAndroid Build Coastguard Worker             freqs.insert(freqs.end(), nums->begin(), nums->end());
121*38e8c45fSAndroid Build Coastguard Worker         }
122*38e8c45fSAndroid Build Coastguard Worker         if (freqs.empty()) return false;
123*38e8c45fSAndroid Build Coastguard Worker         std::sort(freqs.begin(), freqs.end());
124*38e8c45fSAndroid Build Coastguard Worker         gPolicyFreqs.emplace_back(freqs);
125*38e8c45fSAndroid Build Coastguard Worker 
126*38e8c45fSAndroid Build Coastguard Worker         for (auto freq : freqs) gAllFreqs.insert(freq);
127*38e8c45fSAndroid Build Coastguard Worker 
128*38e8c45fSAndroid Build Coastguard Worker         std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus");
129*38e8c45fSAndroid Build Coastguard Worker         auto cpus = readNumbersFromFile(path);
130*38e8c45fSAndroid Build Coastguard Worker         if (!cpus) return false;
131*38e8c45fSAndroid Build Coastguard Worker         for (auto cpu : *cpus) {
132*38e8c45fSAndroid Build Coastguard Worker             if(cpu > max_cpu_number)
133*38e8c45fSAndroid Build Coastguard Worker                 max_cpu_number = cpu;
134*38e8c45fSAndroid Build Coastguard Worker         }
135*38e8c45fSAndroid Build Coastguard Worker         gPolicyCpus.emplace_back(*cpus);
136*38e8c45fSAndroid Build Coastguard Worker     }
137*38e8c45fSAndroid Build Coastguard Worker     gCpuIndexMap = std::vector<uint32_t>(max_cpu_number+1, -1);
138*38e8c45fSAndroid Build Coastguard Worker     uint32_t cpuorder = 0;
139*38e8c45fSAndroid Build Coastguard Worker     for (const auto &cpuList : gPolicyCpus) {
140*38e8c45fSAndroid Build Coastguard Worker         for (auto cpu : cpuList) {
141*38e8c45fSAndroid Build Coastguard Worker             gCpuIndexMap[cpu] = cpuorder++;
142*38e8c45fSAndroid Build Coastguard Worker         }
143*38e8c45fSAndroid Build Coastguard Worker     }
144*38e8c45fSAndroid Build Coastguard Worker 
145*38e8c45fSAndroid Build Coastguard Worker     gTisTotalMapFd =
146*38e8c45fSAndroid Build Coastguard Worker             unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_total_time_in_state_map")};
147*38e8c45fSAndroid Build Coastguard Worker     if (gTisTotalMapFd < 0) return false;
148*38e8c45fSAndroid Build Coastguard Worker 
149*38e8c45fSAndroid Build Coastguard Worker     gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_time_in_state_map")};
150*38e8c45fSAndroid Build Coastguard Worker     if (gTisMapFd < 0) return false;
151*38e8c45fSAndroid Build Coastguard Worker 
152*38e8c45fSAndroid Build Coastguard Worker     gConcurrentMapFd =
153*38e8c45fSAndroid Build Coastguard Worker             unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
154*38e8c45fSAndroid Build Coastguard Worker     if (gConcurrentMapFd < 0) return false;
155*38e8c45fSAndroid Build Coastguard Worker 
156*38e8c45fSAndroid Build Coastguard Worker     gUidLastUpdateMapFd =
157*38e8c45fSAndroid Build Coastguard Worker             unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_last_update_map")};
158*38e8c45fSAndroid Build Coastguard Worker     if (gUidLastUpdateMapFd < 0) return false;
159*38e8c45fSAndroid Build Coastguard Worker 
160*38e8c45fSAndroid Build Coastguard Worker     gPidTisMapFd = unique_fd{mapRetrieveRO(BPF_FS_PATH "map_timeInState_pid_time_in_state_map")};
161*38e8c45fSAndroid Build Coastguard Worker     if (gPidTisMapFd < 0) return false;
162*38e8c45fSAndroid Build Coastguard Worker 
163*38e8c45fSAndroid Build Coastguard Worker     unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_map"));
164*38e8c45fSAndroid Build Coastguard Worker     if (trackedPidMapFd < 0) return false;
165*38e8c45fSAndroid Build Coastguard Worker 
166*38e8c45fSAndroid Build Coastguard Worker     gInitialized = true;
167*38e8c45fSAndroid Build Coastguard Worker     return true;
168*38e8c45fSAndroid Build Coastguard Worker }
169*38e8c45fSAndroid Build Coastguard Worker 
retrieveProgramFd(const std::string & eventType,const std::string & eventName)170*38e8c45fSAndroid Build Coastguard Worker static int retrieveProgramFd(const std::string &eventType, const std::string &eventName) {
171*38e8c45fSAndroid Build Coastguard Worker     std::string path = StringPrintf(BPF_FS_PATH "prog_timeInState_tracepoint_%s_%s",
172*38e8c45fSAndroid Build Coastguard Worker                                     eventType.c_str(), eventName.c_str());
173*38e8c45fSAndroid Build Coastguard Worker     return retrieveProgram(path.c_str());
174*38e8c45fSAndroid Build Coastguard Worker }
175*38e8c45fSAndroid Build Coastguard Worker 
attachTracepointProgram(const std::string & eventType,const std::string & eventName)176*38e8c45fSAndroid Build Coastguard Worker static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
177*38e8c45fSAndroid Build Coastguard Worker     int prog_fd = retrieveProgramFd(eventType, eventName);
178*38e8c45fSAndroid Build Coastguard Worker     if (prog_fd < 0) return false;
179*38e8c45fSAndroid Build Coastguard Worker     return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
180*38e8c45fSAndroid Build Coastguard Worker }
181*38e8c45fSAndroid Build Coastguard Worker 
getPolicyFreqIdx(uint32_t policy)182*38e8c45fSAndroid Build Coastguard Worker static std::optional<uint32_t> getPolicyFreqIdx(uint32_t policy) {
183*38e8c45fSAndroid Build Coastguard Worker     auto path = StringPrintf("/sys/devices/system/cpu/cpufreq/policy%u/scaling_cur_freq",
184*38e8c45fSAndroid Build Coastguard Worker                              gPolicyCpus[policy][0]);
185*38e8c45fSAndroid Build Coastguard Worker     auto freqVec = readNumbersFromFile(path);
186*38e8c45fSAndroid Build Coastguard Worker     if (!freqVec.has_value() || freqVec->size() != 1) return {};
187*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t idx = 0; idx < gPolicyFreqs[policy].size(); ++idx) {
188*38e8c45fSAndroid Build Coastguard Worker         if ((*freqVec)[0] == gPolicyFreqs[policy][idx]) return idx + 1;
189*38e8c45fSAndroid Build Coastguard Worker     }
190*38e8c45fSAndroid Build Coastguard Worker     return {};
191*38e8c45fSAndroid Build Coastguard Worker }
192*38e8c45fSAndroid Build Coastguard Worker 
193*38e8c45fSAndroid Build Coastguard Worker // Check if tracking is expected to work without activating it.
isTrackingUidTimesSupported()194*38e8c45fSAndroid Build Coastguard Worker bool isTrackingUidTimesSupported() {
195*38e8c45fSAndroid Build Coastguard Worker     auto freqs = getCpuFreqs();
196*38e8c45fSAndroid Build Coastguard Worker     if (!freqs || freqs->empty()) return false;
197*38e8c45fSAndroid Build Coastguard Worker     if (gTracking) return true;
198*38e8c45fSAndroid Build Coastguard Worker     if (retrieveProgramFd("sched", "sched_switch") < 0) return false;
199*38e8c45fSAndroid Build Coastguard Worker     if (retrieveProgramFd("power", "cpu_frequency") < 0) return false;
200*38e8c45fSAndroid Build Coastguard Worker     if (retrieveProgramFd("sched", "sched_process_free") < 0) return false;
201*38e8c45fSAndroid Build Coastguard Worker     return true;
202*38e8c45fSAndroid Build Coastguard Worker }
203*38e8c45fSAndroid Build Coastguard Worker 
204*38e8c45fSAndroid Build Coastguard Worker // Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
205*38e8c45fSAndroid Build Coastguard Worker // Returns true on success, false otherwise.
206*38e8c45fSAndroid Build Coastguard Worker // Tracking is active only once a live process has successfully called this function; if the calling
207*38e8c45fSAndroid Build Coastguard Worker // process dies then it must be called again to resume tracking.
208*38e8c45fSAndroid Build Coastguard Worker // This function should *not* be called while tracking is already active; doing so is unnecessary
209*38e8c45fSAndroid Build Coastguard Worker // and can lead to accounting errors.
startTrackingUidTimes()210*38e8c45fSAndroid Build Coastguard Worker bool startTrackingUidTimes() {
211*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard<std::mutex> guard(gTrackingMutex);
212*38e8c45fSAndroid Build Coastguard Worker     if (!initGlobals()) return false;
213*38e8c45fSAndroid Build Coastguard Worker     if (gTracking) return true;
214*38e8c45fSAndroid Build Coastguard Worker 
215*38e8c45fSAndroid Build Coastguard Worker     unique_fd cpuPolicyFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_cpu_policy_map"));
216*38e8c45fSAndroid Build Coastguard Worker     if (cpuPolicyFd < 0) return false;
217*38e8c45fSAndroid Build Coastguard Worker 
218*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
219*38e8c45fSAndroid Build Coastguard Worker         for (auto &cpu : gPolicyCpus[i]) {
220*38e8c45fSAndroid Build Coastguard Worker             if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false;
221*38e8c45fSAndroid Build Coastguard Worker         }
222*38e8c45fSAndroid Build Coastguard Worker     }
223*38e8c45fSAndroid Build Coastguard Worker 
224*38e8c45fSAndroid Build Coastguard Worker     unique_fd freqToIdxFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_freq_to_idx_map"));
225*38e8c45fSAndroid Build Coastguard Worker     if (freqToIdxFd < 0) return false;
226*38e8c45fSAndroid Build Coastguard Worker     freq_idx_key_t key;
227*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < gNPolicies; ++i) {
228*38e8c45fSAndroid Build Coastguard Worker         key.policy = i;
229*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t j = 0; j < gPolicyFreqs[i].size(); ++j) {
230*38e8c45fSAndroid Build Coastguard Worker             key.freq = gPolicyFreqs[i][j];
231*38e8c45fSAndroid Build Coastguard Worker             // Start indexes at 1 so that uninitialized state is distinguishable from lowest freq.
232*38e8c45fSAndroid Build Coastguard Worker             // The uid_times map still uses 0-based indexes, and the sched_switch program handles
233*38e8c45fSAndroid Build Coastguard Worker             // conversion between them, so this does not affect our map reading code.
234*38e8c45fSAndroid Build Coastguard Worker             uint32_t idx = j + 1;
235*38e8c45fSAndroid Build Coastguard Worker             if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false;
236*38e8c45fSAndroid Build Coastguard Worker         }
237*38e8c45fSAndroid Build Coastguard Worker     }
238*38e8c45fSAndroid Build Coastguard Worker 
239*38e8c45fSAndroid Build Coastguard Worker     unique_fd cpuLastUpdateFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_cpu_last_update_map"));
240*38e8c45fSAndroid Build Coastguard Worker     if (cpuLastUpdateFd < 0) return false;
241*38e8c45fSAndroid Build Coastguard Worker     std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
242*38e8c45fSAndroid Build Coastguard Worker     uint32_t zero = 0;
243*38e8c45fSAndroid Build Coastguard Worker     if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
244*38e8c45fSAndroid Build Coastguard Worker 
245*38e8c45fSAndroid Build Coastguard Worker     unique_fd nrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_nr_active_map"));
246*38e8c45fSAndroid Build Coastguard Worker     if (nrActiveFd < 0) return false;
247*38e8c45fSAndroid Build Coastguard Worker     if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
248*38e8c45fSAndroid Build Coastguard Worker 
249*38e8c45fSAndroid Build Coastguard Worker     unique_fd policyNrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_policy_nr_active_map"));
250*38e8c45fSAndroid Build Coastguard Worker     if (policyNrActiveFd < 0) return false;
251*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < gNPolicies; ++i) {
252*38e8c45fSAndroid Build Coastguard Worker         if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
253*38e8c45fSAndroid Build Coastguard Worker     }
254*38e8c45fSAndroid Build Coastguard Worker 
255*38e8c45fSAndroid Build Coastguard Worker     unique_fd policyFreqIdxFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_policy_freq_idx_map"));
256*38e8c45fSAndroid Build Coastguard Worker     if (policyFreqIdxFd < 0) return false;
257*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i < gNPolicies; ++i) {
258*38e8c45fSAndroid Build Coastguard Worker         auto freqIdx = getPolicyFreqIdx(i);
259*38e8c45fSAndroid Build Coastguard Worker         if (!freqIdx.has_value()) return false;
260*38e8c45fSAndroid Build Coastguard Worker         if (writeToMapEntry(policyFreqIdxFd, &i, &(*freqIdx), BPF_ANY)) return false;
261*38e8c45fSAndroid Build Coastguard Worker     }
262*38e8c45fSAndroid Build Coastguard Worker 
263*38e8c45fSAndroid Build Coastguard Worker     gTracking = attachTracepointProgram("sched", "sched_switch") &&
264*38e8c45fSAndroid Build Coastguard Worker             attachTracepointProgram("power", "cpu_frequency") &&
265*38e8c45fSAndroid Build Coastguard Worker             attachTracepointProgram("sched", "sched_process_free");
266*38e8c45fSAndroid Build Coastguard Worker     return gTracking;
267*38e8c45fSAndroid Build Coastguard Worker }
268*38e8c45fSAndroid Build Coastguard Worker 
getCpuFreqs()269*38e8c45fSAndroid Build Coastguard Worker std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() {
270*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return {};
271*38e8c45fSAndroid Build Coastguard Worker     return gPolicyFreqs;
272*38e8c45fSAndroid Build Coastguard Worker }
273*38e8c45fSAndroid Build Coastguard Worker 
getTotalCpuFreqTimes()274*38e8c45fSAndroid Build Coastguard Worker std::optional<std::vector<std::vector<uint64_t>>> getTotalCpuFreqTimes() {
275*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return {};
276*38e8c45fSAndroid Build Coastguard Worker 
277*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::vector<uint64_t>> out;
278*38e8c45fSAndroid Build Coastguard Worker     uint32_t maxFreqCount = 0;
279*38e8c45fSAndroid Build Coastguard Worker     for (const auto &freqList : gPolicyFreqs) {
280*38e8c45fSAndroid Build Coastguard Worker         if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
281*38e8c45fSAndroid Build Coastguard Worker         out.emplace_back(freqList.size(), 0);
282*38e8c45fSAndroid Build Coastguard Worker     }
283*38e8c45fSAndroid Build Coastguard Worker 
284*38e8c45fSAndroid Build Coastguard Worker     std::vector<uint64_t> vals(gNCpus);
285*38e8c45fSAndroid Build Coastguard Worker     const uint32_t freqCount = maxFreqCount <= MAX_FREQS_FOR_TOTAL ? maxFreqCount :
286*38e8c45fSAndroid Build Coastguard Worker             MAX_FREQS_FOR_TOTAL;
287*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t freqIdx = 0; freqIdx < freqCount; ++freqIdx) {
288*38e8c45fSAndroid Build Coastguard Worker         if (findMapEntry(gTisTotalMapFd, &freqIdx, vals.data())) return {};
289*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t policyIdx = 0; policyIdx < gNPolicies; ++policyIdx) {
290*38e8c45fSAndroid Build Coastguard Worker             if (freqIdx >= gPolicyFreqs[policyIdx].size()) continue;
291*38e8c45fSAndroid Build Coastguard Worker             for (const auto &cpu : gPolicyCpus[policyIdx]) {
292*38e8c45fSAndroid Build Coastguard Worker                 out[policyIdx][freqIdx] += vals[gCpuIndexMap[cpu]];
293*38e8c45fSAndroid Build Coastguard Worker             }
294*38e8c45fSAndroid Build Coastguard Worker         }
295*38e8c45fSAndroid Build Coastguard Worker     }
296*38e8c45fSAndroid Build Coastguard Worker 
297*38e8c45fSAndroid Build Coastguard Worker     return out;
298*38e8c45fSAndroid Build Coastguard Worker }
299*38e8c45fSAndroid Build Coastguard Worker // Retrieve the times in ns that uid spent running at each CPU frequency.
300*38e8c45fSAndroid Build Coastguard Worker // Return contains no value on error, otherwise it contains a vector of vectors using the format:
301*38e8c45fSAndroid Build Coastguard Worker // [[t0_0, t0_1, ...],
302*38e8c45fSAndroid Build Coastguard Worker //  [t1_0, t1_1, ...], ...]
303*38e8c45fSAndroid Build Coastguard Worker // where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
getUidCpuFreqTimes(uint32_t uid)304*38e8c45fSAndroid Build Coastguard Worker std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) {
305*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return {};
306*38e8c45fSAndroid Build Coastguard Worker 
307*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::vector<uint64_t>> out;
308*38e8c45fSAndroid Build Coastguard Worker     uint32_t maxFreqCount = 0;
309*38e8c45fSAndroid Build Coastguard Worker     for (const auto &freqList : gPolicyFreqs) {
310*38e8c45fSAndroid Build Coastguard Worker         if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
311*38e8c45fSAndroid Build Coastguard Worker         out.emplace_back(freqList.size(), 0);
312*38e8c45fSAndroid Build Coastguard Worker     }
313*38e8c45fSAndroid Build Coastguard Worker 
314*38e8c45fSAndroid Build Coastguard Worker     std::vector<tis_val_t> vals(gNCpus);
315*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
316*38e8c45fSAndroid Build Coastguard Worker         const time_key_t key = {.uid = uid, .bucket = i};
317*38e8c45fSAndroid Build Coastguard Worker         if (findMapEntry(gTisMapFd, &key, vals.data())) {
318*38e8c45fSAndroid Build Coastguard Worker             time_key_t tmpKey;
319*38e8c45fSAndroid Build Coastguard Worker             if (errno != ENOENT || getFirstMapKey(gTisMapFd, &tmpKey)) return {};
320*38e8c45fSAndroid Build Coastguard Worker             continue;
321*38e8c45fSAndroid Build Coastguard Worker         }
322*38e8c45fSAndroid Build Coastguard Worker 
323*38e8c45fSAndroid Build Coastguard Worker         auto offset = i * FREQS_PER_ENTRY;
324*38e8c45fSAndroid Build Coastguard Worker         auto nextOffset = (i + 1) * FREQS_PER_ENTRY;
325*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t j = 0; j < gNPolicies; ++j) {
326*38e8c45fSAndroid Build Coastguard Worker             if (offset >= gPolicyFreqs[j].size()) continue;
327*38e8c45fSAndroid Build Coastguard Worker             auto begin = out[j].begin() + offset;
328*38e8c45fSAndroid Build Coastguard Worker             auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end();
329*38e8c45fSAndroid Build Coastguard Worker 
330*38e8c45fSAndroid Build Coastguard Worker             for (const auto &cpu : gPolicyCpus[j]) {
331*38e8c45fSAndroid Build Coastguard Worker                 std::transform(begin, end, std::begin(vals[gCpuIndexMap[cpu]].ar), begin,
332*38e8c45fSAndroid Build Coastguard Worker                                std::plus<uint64_t>());
333*38e8c45fSAndroid Build Coastguard Worker             }
334*38e8c45fSAndroid Build Coastguard Worker         }
335*38e8c45fSAndroid Build Coastguard Worker     }
336*38e8c45fSAndroid Build Coastguard Worker 
337*38e8c45fSAndroid Build Coastguard Worker     return out;
338*38e8c45fSAndroid Build Coastguard Worker }
339*38e8c45fSAndroid Build Coastguard Worker 
uidUpdatedSince(uint32_t uid,uint64_t lastUpdate,uint64_t * newLastUpdate)340*38e8c45fSAndroid Build Coastguard Worker static std::optional<bool> uidUpdatedSince(uint32_t uid, uint64_t lastUpdate,
341*38e8c45fSAndroid Build Coastguard Worker                                            uint64_t *newLastUpdate) {
342*38e8c45fSAndroid Build Coastguard Worker     uint64_t uidLastUpdate;
343*38e8c45fSAndroid Build Coastguard Worker     if (findMapEntry(gUidLastUpdateMapFd, &uid, &uidLastUpdate)) return {};
344*38e8c45fSAndroid Build Coastguard Worker     // Updates that occurred during the previous read may have been missed. To mitigate
345*38e8c45fSAndroid Build Coastguard Worker     // this, don't ignore entries updated up to 1s before *lastUpdate
346*38e8c45fSAndroid Build Coastguard Worker     constexpr uint64_t NSEC_PER_SEC = 1000000000;
347*38e8c45fSAndroid Build Coastguard Worker     if (uidLastUpdate + NSEC_PER_SEC < lastUpdate) return false;
348*38e8c45fSAndroid Build Coastguard Worker     if (uidLastUpdate > *newLastUpdate) *newLastUpdate = uidLastUpdate;
349*38e8c45fSAndroid Build Coastguard Worker     return true;
350*38e8c45fSAndroid Build Coastguard Worker }
351*38e8c45fSAndroid Build Coastguard Worker 
352*38e8c45fSAndroid Build Coastguard Worker // Retrieve the times in ns that each uid spent running at each CPU freq.
353*38e8c45fSAndroid Build Coastguard Worker // Return contains no value on error, otherwise it contains a map from uids to vectors of vectors
354*38e8c45fSAndroid Build Coastguard Worker // using the format:
355*38e8c45fSAndroid Build Coastguard Worker // { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
356*38e8c45fSAndroid Build Coastguard Worker //   uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
357*38e8c45fSAndroid Build Coastguard Worker // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
358*38e8c45fSAndroid Build Coastguard Worker std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsCpuFreqTimes()359*38e8c45fSAndroid Build Coastguard Worker getUidsCpuFreqTimes() {
360*38e8c45fSAndroid Build Coastguard Worker     return getUidsUpdatedCpuFreqTimes(nullptr);
361*38e8c45fSAndroid Build Coastguard Worker }
362*38e8c45fSAndroid Build Coastguard Worker 
363*38e8c45fSAndroid Build Coastguard Worker // Retrieve the times in ns that each uid spent running at each CPU freq, excluding UIDs that have
364*38e8c45fSAndroid Build Coastguard Worker // not run since before lastUpdate.
365*38e8c45fSAndroid Build Coastguard Worker // Return format is the same as getUidsCpuFreqTimes()
366*38e8c45fSAndroid Build Coastguard Worker std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsUpdatedCpuFreqTimes(uint64_t * lastUpdate)367*38e8c45fSAndroid Build Coastguard Worker getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate) {
368*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return {};
369*38e8c45fSAndroid Build Coastguard Worker     time_key_t key, prevKey;
370*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
371*38e8c45fSAndroid Build Coastguard Worker     if (getFirstMapKey(gTisMapFd, &key)) {
372*38e8c45fSAndroid Build Coastguard Worker         if (errno == ENOENT) return map;
373*38e8c45fSAndroid Build Coastguard Worker         return std::nullopt;
374*38e8c45fSAndroid Build Coastguard Worker     }
375*38e8c45fSAndroid Build Coastguard Worker 
376*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::vector<uint64_t>> mapFormat;
377*38e8c45fSAndroid Build Coastguard Worker     for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0);
378*38e8c45fSAndroid Build Coastguard Worker 
379*38e8c45fSAndroid Build Coastguard Worker     uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
380*38e8c45fSAndroid Build Coastguard Worker     std::vector<tis_val_t> vals(gNCpus);
381*38e8c45fSAndroid Build Coastguard Worker     do {
382*38e8c45fSAndroid Build Coastguard Worker         if (lastUpdate) {
383*38e8c45fSAndroid Build Coastguard Worker             auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
384*38e8c45fSAndroid Build Coastguard Worker             if (!uidUpdated.has_value()) return {};
385*38e8c45fSAndroid Build Coastguard Worker             if (!*uidUpdated) continue;
386*38e8c45fSAndroid Build Coastguard Worker         }
387*38e8c45fSAndroid Build Coastguard Worker         if (findMapEntry(gTisMapFd, &key, vals.data())) return {};
388*38e8c45fSAndroid Build Coastguard Worker         if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat);
389*38e8c45fSAndroid Build Coastguard Worker 
390*38e8c45fSAndroid Build Coastguard Worker         auto offset = key.bucket * FREQS_PER_ENTRY;
391*38e8c45fSAndroid Build Coastguard Worker         auto nextOffset = (key.bucket + 1) * FREQS_PER_ENTRY;
392*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t i = 0; i < gNPolicies; ++i) {
393*38e8c45fSAndroid Build Coastguard Worker             if (offset >= gPolicyFreqs[i].size()) continue;
394*38e8c45fSAndroid Build Coastguard Worker             auto begin = map[key.uid][i].begin() + offset;
395*38e8c45fSAndroid Build Coastguard Worker             auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY :
396*38e8c45fSAndroid Build Coastguard Worker                 map[key.uid][i].end();
397*38e8c45fSAndroid Build Coastguard Worker             for (const auto &cpu : gPolicyCpus[i]) {
398*38e8c45fSAndroid Build Coastguard Worker                 std::transform(begin, end, std::begin(vals[gCpuIndexMap[cpu]].ar), begin,
399*38e8c45fSAndroid Build Coastguard Worker                                std::plus<uint64_t>());
400*38e8c45fSAndroid Build Coastguard Worker             }
401*38e8c45fSAndroid Build Coastguard Worker         }
402*38e8c45fSAndroid Build Coastguard Worker         prevKey = key;
403*38e8c45fSAndroid Build Coastguard Worker     } while (prevKey = key, !getNextMapKey(gTisMapFd, &prevKey, &key));
404*38e8c45fSAndroid Build Coastguard Worker     if (errno != ENOENT) return {};
405*38e8c45fSAndroid Build Coastguard Worker     if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate;
406*38e8c45fSAndroid Build Coastguard Worker     return map;
407*38e8c45fSAndroid Build Coastguard Worker }
408*38e8c45fSAndroid Build Coastguard Worker 
verifyConcurrentTimes(const concurrent_time_t & ct)409*38e8c45fSAndroid Build Coastguard Worker static bool verifyConcurrentTimes(const concurrent_time_t &ct) {
410*38e8c45fSAndroid Build Coastguard Worker     uint64_t activeSum = std::accumulate(ct.active.begin(), ct.active.end(), (uint64_t)0);
411*38e8c45fSAndroid Build Coastguard Worker     uint64_t policySum = 0;
412*38e8c45fSAndroid Build Coastguard Worker     for (const auto &vec : ct.policy) {
413*38e8c45fSAndroid Build Coastguard Worker         policySum += std::accumulate(vec.begin(), vec.end(), (uint64_t)0);
414*38e8c45fSAndroid Build Coastguard Worker     }
415*38e8c45fSAndroid Build Coastguard Worker     return activeSum == policySum;
416*38e8c45fSAndroid Build Coastguard Worker }
417*38e8c45fSAndroid Build Coastguard Worker 
418*38e8c45fSAndroid Build Coastguard Worker // Retrieve the times in ns that uid spent running concurrently with each possible number of other
419*38e8c45fSAndroid Build Coastguard Worker // tasks on each cluster (policy times) and overall (active times).
420*38e8c45fSAndroid Build Coastguard Worker // Return contains no value on error, otherwise it contains a concurrent_time_t with the format:
421*38e8c45fSAndroid Build Coastguard Worker // {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...]}
422*38e8c45fSAndroid Build Coastguard Worker // where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent
423*38e8c45fSAndroid Build Coastguard Worker // running on the ith cluster, concurrently with tasks on j other cpus in the same cluster
getUidConcurrentTimes(uint32_t uid,bool retry)424*38e8c45fSAndroid Build Coastguard Worker std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry) {
425*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return {};
426*38e8c45fSAndroid Build Coastguard Worker     concurrent_time_t ret = {.active = std::vector<uint64_t>(gNCpus, 0)};
427*38e8c45fSAndroid Build Coastguard Worker     for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0);
428*38e8c45fSAndroid Build Coastguard Worker     std::vector<concurrent_val_t> vals(gNCpus);
429*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t i = 0; i <= (gNCpus - 1) / CPUS_PER_ENTRY; ++i) {
430*38e8c45fSAndroid Build Coastguard Worker         const time_key_t key = {.uid = uid, .bucket = i};
431*38e8c45fSAndroid Build Coastguard Worker         if (findMapEntry(gConcurrentMapFd, &key, vals.data())) {
432*38e8c45fSAndroid Build Coastguard Worker             time_key_t tmpKey;
433*38e8c45fSAndroid Build Coastguard Worker             if (errno != ENOENT || getFirstMapKey(gConcurrentMapFd, &tmpKey)) return {};
434*38e8c45fSAndroid Build Coastguard Worker             continue;
435*38e8c45fSAndroid Build Coastguard Worker         }
436*38e8c45fSAndroid Build Coastguard Worker         auto offset = key.bucket * CPUS_PER_ENTRY;
437*38e8c45fSAndroid Build Coastguard Worker         auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY;
438*38e8c45fSAndroid Build Coastguard Worker 
439*38e8c45fSAndroid Build Coastguard Worker         auto activeBegin = ret.active.begin() + offset;
440*38e8c45fSAndroid Build Coastguard Worker         auto activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret.active.end();
441*38e8c45fSAndroid Build Coastguard Worker 
442*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) {
443*38e8c45fSAndroid Build Coastguard Worker             std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin,
444*38e8c45fSAndroid Build Coastguard Worker                            std::plus<uint64_t>());
445*38e8c45fSAndroid Build Coastguard Worker         }
446*38e8c45fSAndroid Build Coastguard Worker 
447*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t policy = 0; policy < gNPolicies; ++policy) {
448*38e8c45fSAndroid Build Coastguard Worker             if (offset >= gPolicyCpus[policy].size()) continue;
449*38e8c45fSAndroid Build Coastguard Worker             auto policyBegin = ret.policy[policy].begin() + offset;
450*38e8c45fSAndroid Build Coastguard Worker             auto policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY
451*38e8c45fSAndroid Build Coastguard Worker                                                                      : ret.policy[policy].end();
452*38e8c45fSAndroid Build Coastguard Worker 
453*38e8c45fSAndroid Build Coastguard Worker             for (const auto &cpu : gPolicyCpus[policy]) {
454*38e8c45fSAndroid Build Coastguard Worker                 std::transform(policyBegin, policyEnd, std::begin(vals[gCpuIndexMap[cpu]].policy),
455*38e8c45fSAndroid Build Coastguard Worker                                policyBegin, std::plus<uint64_t>());
456*38e8c45fSAndroid Build Coastguard Worker             }
457*38e8c45fSAndroid Build Coastguard Worker         }
458*38e8c45fSAndroid Build Coastguard Worker     }
459*38e8c45fSAndroid Build Coastguard Worker     if (!verifyConcurrentTimes(ret) && retry)  return getUidConcurrentTimes(uid, false);
460*38e8c45fSAndroid Build Coastguard Worker     return ret;
461*38e8c45fSAndroid Build Coastguard Worker }
462*38e8c45fSAndroid Build Coastguard Worker 
463*38e8c45fSAndroid Build Coastguard Worker // Retrieve the times in ns that each uid spent running concurrently with each possible number of
464*38e8c45fSAndroid Build Coastguard Worker // other tasks on each cluster (policy times) and overall (active times).
465*38e8c45fSAndroid Build Coastguard Worker // Return contains no value on error, otherwise it contains a map from uids to concurrent_time_t's
466*38e8c45fSAndroid Build Coastguard Worker // using the format:
467*38e8c45fSAndroid Build Coastguard Worker // { uid0 -> {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...] }, ...}
468*38e8c45fSAndroid Build Coastguard Worker // where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent
469*38e8c45fSAndroid Build Coastguard Worker // running on the ith cluster, concurrently with tasks on j other cpus in the same cluster.
getUidsConcurrentTimes()470*38e8c45fSAndroid Build Coastguard Worker std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() {
471*38e8c45fSAndroid Build Coastguard Worker     return getUidsUpdatedConcurrentTimes(nullptr);
472*38e8c45fSAndroid Build Coastguard Worker }
473*38e8c45fSAndroid Build Coastguard Worker 
474*38e8c45fSAndroid Build Coastguard Worker // Retrieve the times in ns that each uid spent running concurrently with each possible number of
475*38e8c45fSAndroid Build Coastguard Worker // other tasks on each cluster (policy times) and overall (active times), excluding UIDs that have
476*38e8c45fSAndroid Build Coastguard Worker // not run since before lastUpdate.
477*38e8c45fSAndroid Build Coastguard Worker // Return format is the same as getUidsConcurrentTimes()
getUidsUpdatedConcurrentTimes(uint64_t * lastUpdate)478*38e8c45fSAndroid Build Coastguard Worker std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsUpdatedConcurrentTimes(
479*38e8c45fSAndroid Build Coastguard Worker         uint64_t *lastUpdate) {
480*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return {};
481*38e8c45fSAndroid Build Coastguard Worker     time_key_t key, prevKey;
482*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<uint32_t, concurrent_time_t> ret;
483*38e8c45fSAndroid Build Coastguard Worker     if (getFirstMapKey(gConcurrentMapFd, &key)) {
484*38e8c45fSAndroid Build Coastguard Worker         if (errno == ENOENT) return ret;
485*38e8c45fSAndroid Build Coastguard Worker         return {};
486*38e8c45fSAndroid Build Coastguard Worker     }
487*38e8c45fSAndroid Build Coastguard Worker 
488*38e8c45fSAndroid Build Coastguard Worker     concurrent_time_t retFormat = {.active = std::vector<uint64_t>(gNCpus, 0)};
489*38e8c45fSAndroid Build Coastguard Worker     for (const auto &cpuList : gPolicyCpus) retFormat.policy.emplace_back(cpuList.size(), 0);
490*38e8c45fSAndroid Build Coastguard Worker 
491*38e8c45fSAndroid Build Coastguard Worker     std::vector<concurrent_val_t> vals(gNCpus);
492*38e8c45fSAndroid Build Coastguard Worker     std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd;
493*38e8c45fSAndroid Build Coastguard Worker 
494*38e8c45fSAndroid Build Coastguard Worker     uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
495*38e8c45fSAndroid Build Coastguard Worker     do {
496*38e8c45fSAndroid Build Coastguard Worker         if (key.bucket > (gNCpus - 1) / CPUS_PER_ENTRY) return {};
497*38e8c45fSAndroid Build Coastguard Worker         if (lastUpdate) {
498*38e8c45fSAndroid Build Coastguard Worker             auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
499*38e8c45fSAndroid Build Coastguard Worker             if (!uidUpdated.has_value()) return {};
500*38e8c45fSAndroid Build Coastguard Worker             if (!*uidUpdated) continue;
501*38e8c45fSAndroid Build Coastguard Worker         }
502*38e8c45fSAndroid Build Coastguard Worker         if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {};
503*38e8c45fSAndroid Build Coastguard Worker         if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat);
504*38e8c45fSAndroid Build Coastguard Worker 
505*38e8c45fSAndroid Build Coastguard Worker         auto offset = key.bucket * CPUS_PER_ENTRY;
506*38e8c45fSAndroid Build Coastguard Worker         auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY;
507*38e8c45fSAndroid Build Coastguard Worker 
508*38e8c45fSAndroid Build Coastguard Worker         activeBegin = ret[key.uid].active.begin();
509*38e8c45fSAndroid Build Coastguard Worker         activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret[key.uid].active.end();
510*38e8c45fSAndroid Build Coastguard Worker 
511*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) {
512*38e8c45fSAndroid Build Coastguard Worker             std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin,
513*38e8c45fSAndroid Build Coastguard Worker                            std::plus<uint64_t>());
514*38e8c45fSAndroid Build Coastguard Worker         }
515*38e8c45fSAndroid Build Coastguard Worker 
516*38e8c45fSAndroid Build Coastguard Worker         for (uint32_t policy = 0; policy < gNPolicies; ++policy) {
517*38e8c45fSAndroid Build Coastguard Worker             if (offset >= gPolicyCpus[policy].size()) continue;
518*38e8c45fSAndroid Build Coastguard Worker             policyBegin = ret[key.uid].policy[policy].begin() + offset;
519*38e8c45fSAndroid Build Coastguard Worker             policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY
520*38e8c45fSAndroid Build Coastguard Worker                                                                 : ret[key.uid].policy[policy].end();
521*38e8c45fSAndroid Build Coastguard Worker 
522*38e8c45fSAndroid Build Coastguard Worker             for (const auto &cpu : gPolicyCpus[policy]) {
523*38e8c45fSAndroid Build Coastguard Worker                 std::transform(policyBegin, policyEnd, std::begin(vals[gCpuIndexMap[cpu]].policy),
524*38e8c45fSAndroid Build Coastguard Worker                                policyBegin, std::plus<uint64_t>());
525*38e8c45fSAndroid Build Coastguard Worker             }
526*38e8c45fSAndroid Build Coastguard Worker         }
527*38e8c45fSAndroid Build Coastguard Worker     } while (prevKey = key, !getNextMapKey(gConcurrentMapFd, &prevKey, &key));
528*38e8c45fSAndroid Build Coastguard Worker     if (errno != ENOENT) return {};
529*38e8c45fSAndroid Build Coastguard Worker     for (const auto &[key, value] : ret) {
530*38e8c45fSAndroid Build Coastguard Worker         if (!verifyConcurrentTimes(value)) {
531*38e8c45fSAndroid Build Coastguard Worker             auto val = getUidConcurrentTimes(key, false);
532*38e8c45fSAndroid Build Coastguard Worker             if (val.has_value()) ret[key] = val.value();
533*38e8c45fSAndroid Build Coastguard Worker         }
534*38e8c45fSAndroid Build Coastguard Worker     }
535*38e8c45fSAndroid Build Coastguard Worker     if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate;
536*38e8c45fSAndroid Build Coastguard Worker     return ret;
537*38e8c45fSAndroid Build Coastguard Worker }
538*38e8c45fSAndroid Build Coastguard Worker 
539*38e8c45fSAndroid Build Coastguard Worker // Clear all time in state data for a given uid. Returns false on error, true otherwise.
540*38e8c45fSAndroid Build Coastguard Worker // This is only suitable for clearing data when an app is uninstalled; if called on a UID with
541*38e8c45fSAndroid Build Coastguard Worker // running tasks it will cause time in state vs. concurrent time totals to be inconsistent for that
542*38e8c45fSAndroid Build Coastguard Worker // UID.
clearUidTimes(uint32_t uid)543*38e8c45fSAndroid Build Coastguard Worker bool clearUidTimes(uint32_t uid) {
544*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return false;
545*38e8c45fSAndroid Build Coastguard Worker 
546*38e8c45fSAndroid Build Coastguard Worker     time_key_t key = {.uid = uid};
547*38e8c45fSAndroid Build Coastguard Worker 
548*38e8c45fSAndroid Build Coastguard Worker     uint32_t maxFreqCount = 0;
549*38e8c45fSAndroid Build Coastguard Worker     for (const auto &freqList : gPolicyFreqs) {
550*38e8c45fSAndroid Build Coastguard Worker         if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
551*38e8c45fSAndroid Build Coastguard Worker     }
552*38e8c45fSAndroid Build Coastguard Worker 
553*38e8c45fSAndroid Build Coastguard Worker     tis_val_t zeros = {0};
554*38e8c45fSAndroid Build Coastguard Worker     std::vector<tis_val_t> vals(gNCpus, zeros);
555*38e8c45fSAndroid Build Coastguard Worker     for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
556*38e8c45fSAndroid Build Coastguard Worker         if (writeToMapEntry(gTisMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT)
557*38e8c45fSAndroid Build Coastguard Worker             return false;
558*38e8c45fSAndroid Build Coastguard Worker         if (deleteMapEntry(gTisMapFd, &key) && errno != ENOENT) return false;
559*38e8c45fSAndroid Build Coastguard Worker     }
560*38e8c45fSAndroid Build Coastguard Worker 
561*38e8c45fSAndroid Build Coastguard Worker     concurrent_val_t czeros = { .active = {0}, .policy = {0}, };
562*38e8c45fSAndroid Build Coastguard Worker     std::vector<concurrent_val_t> cvals(gNCpus, czeros);
563*38e8c45fSAndroid Build Coastguard Worker     for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
564*38e8c45fSAndroid Build Coastguard Worker         if (writeToMapEntry(gConcurrentMapFd, &key, cvals.data(), BPF_EXIST) && errno != ENOENT)
565*38e8c45fSAndroid Build Coastguard Worker             return false;
566*38e8c45fSAndroid Build Coastguard Worker         if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false;
567*38e8c45fSAndroid Build Coastguard Worker     }
568*38e8c45fSAndroid Build Coastguard Worker 
569*38e8c45fSAndroid Build Coastguard Worker     if (deleteMapEntry(gUidLastUpdateMapFd, &uid) && errno != ENOENT) return false;
570*38e8c45fSAndroid Build Coastguard Worker     return true;
571*38e8c45fSAndroid Build Coastguard Worker }
572*38e8c45fSAndroid Build Coastguard Worker 
startTrackingProcessCpuTimes(pid_t pid)573*38e8c45fSAndroid Build Coastguard Worker bool startTrackingProcessCpuTimes(pid_t pid) {
574*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return false;
575*38e8c45fSAndroid Build Coastguard Worker 
576*38e8c45fSAndroid Build Coastguard Worker     unique_fd trackedPidHashMapFd(
577*38e8c45fSAndroid Build Coastguard Worker             mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_hash_map"));
578*38e8c45fSAndroid Build Coastguard Worker     if (trackedPidHashMapFd < 0) return false;
579*38e8c45fSAndroid Build Coastguard Worker 
580*38e8c45fSAndroid Build Coastguard Worker     unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_map"));
581*38e8c45fSAndroid Build Coastguard Worker     if (trackedPidMapFd < 0) return false;
582*38e8c45fSAndroid Build Coastguard Worker 
583*38e8c45fSAndroid Build Coastguard Worker     for (uint32_t index = 0; index < MAX_TRACKED_PIDS; index++) {
584*38e8c45fSAndroid Build Coastguard Worker         // Find first available [index, pid] entry in the pid_tracked_hash_map map
585*38e8c45fSAndroid Build Coastguard Worker         if (writeToMapEntry(trackedPidHashMapFd, &index, &pid, BPF_NOEXIST) != 0) {
586*38e8c45fSAndroid Build Coastguard Worker             if (errno != EEXIST) {
587*38e8c45fSAndroid Build Coastguard Worker                 return false;
588*38e8c45fSAndroid Build Coastguard Worker             }
589*38e8c45fSAndroid Build Coastguard Worker             continue; // This index is already taken
590*38e8c45fSAndroid Build Coastguard Worker         }
591*38e8c45fSAndroid Build Coastguard Worker 
592*38e8c45fSAndroid Build Coastguard Worker         tracked_pid_t tracked_pid = {.pid = pid, .state = TRACKED_PID_STATE_ACTIVE};
593*38e8c45fSAndroid Build Coastguard Worker         if (writeToMapEntry(trackedPidMapFd, &index, &tracked_pid, BPF_ANY) != 0) {
594*38e8c45fSAndroid Build Coastguard Worker             return false;
595*38e8c45fSAndroid Build Coastguard Worker         }
596*38e8c45fSAndroid Build Coastguard Worker         return true;
597*38e8c45fSAndroid Build Coastguard Worker     }
598*38e8c45fSAndroid Build Coastguard Worker     return false;
599*38e8c45fSAndroid Build Coastguard Worker }
600*38e8c45fSAndroid Build Coastguard Worker 
601*38e8c45fSAndroid Build Coastguard Worker // Marks the specified task identified by its PID (aka TID) for CPU time-in-state tracking
602*38e8c45fSAndroid Build Coastguard Worker // aggregated with other tasks sharing the same TGID and aggregation key.
startAggregatingTaskCpuTimes(pid_t pid,uint16_t aggregationKey)603*38e8c45fSAndroid Build Coastguard Worker bool startAggregatingTaskCpuTimes(pid_t pid, uint16_t aggregationKey) {
604*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return false;
605*38e8c45fSAndroid Build Coastguard Worker 
606*38e8c45fSAndroid Build Coastguard Worker     unique_fd taskAggregationMapFd(
607*38e8c45fSAndroid Build Coastguard Worker             mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_task_aggregation_map"));
608*38e8c45fSAndroid Build Coastguard Worker     if (taskAggregationMapFd < 0) return false;
609*38e8c45fSAndroid Build Coastguard Worker 
610*38e8c45fSAndroid Build Coastguard Worker     return writeToMapEntry(taskAggregationMapFd, &pid, &aggregationKey, BPF_ANY) == 0;
611*38e8c45fSAndroid Build Coastguard Worker }
612*38e8c45fSAndroid Build Coastguard Worker 
613*38e8c45fSAndroid Build Coastguard Worker // Retrieves the times in ns that each thread spent running at each CPU freq, aggregated by
614*38e8c45fSAndroid Build Coastguard Worker // aggregation key.
615*38e8c45fSAndroid Build Coastguard Worker // Return contains no value on error, otherwise it contains a map from aggregation keys
616*38e8c45fSAndroid Build Coastguard Worker // to vectors of vectors using the format:
617*38e8c45fSAndroid Build Coastguard Worker // { aggKey0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
618*38e8c45fSAndroid Build Coastguard Worker //   aggKey1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
619*38e8c45fSAndroid Build Coastguard Worker // where ti_j_k is the ns tid i spent running on the jth cluster at the cluster's kth lowest freq.
620*38e8c45fSAndroid Build Coastguard Worker std::optional<std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>>>
getAggregatedTaskCpuFreqTimes(pid_t tgid,const std::vector<uint16_t> & aggregationKeys)621*38e8c45fSAndroid Build Coastguard Worker getAggregatedTaskCpuFreqTimes(pid_t tgid, const std::vector<uint16_t> &aggregationKeys) {
622*38e8c45fSAndroid Build Coastguard Worker     if (!gInitialized && !initGlobals()) return {};
623*38e8c45fSAndroid Build Coastguard Worker 
624*38e8c45fSAndroid Build Coastguard Worker     uint32_t maxFreqCount = 0;
625*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::vector<uint64_t>> mapFormat;
626*38e8c45fSAndroid Build Coastguard Worker     for (const auto &freqList : gPolicyFreqs) {
627*38e8c45fSAndroid Build Coastguard Worker         if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
628*38e8c45fSAndroid Build Coastguard Worker         mapFormat.emplace_back(freqList.size(), 0);
629*38e8c45fSAndroid Build Coastguard Worker     }
630*38e8c45fSAndroid Build Coastguard Worker 
631*38e8c45fSAndroid Build Coastguard Worker     bool dataCollected = false;
632*38e8c45fSAndroid Build Coastguard Worker     std::unordered_map<uint16_t, std::vector<std::vector<uint64_t>>> map;
633*38e8c45fSAndroid Build Coastguard Worker     std::vector<tis_val_t> vals(gNCpus);
634*38e8c45fSAndroid Build Coastguard Worker     for (uint16_t aggregationKey : aggregationKeys) {
635*38e8c45fSAndroid Build Coastguard Worker         map.emplace(aggregationKey, mapFormat);
636*38e8c45fSAndroid Build Coastguard Worker 
637*38e8c45fSAndroid Build Coastguard Worker         aggregated_task_tis_key_t key{.tgid = tgid, .aggregation_key = aggregationKey};
638*38e8c45fSAndroid Build Coastguard Worker         for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
639*38e8c45fSAndroid Build Coastguard Worker             if (findMapEntry(gPidTisMapFd, &key, vals.data()) != 0) {
640*38e8c45fSAndroid Build Coastguard Worker                 if (errno != ENOENT) {
641*38e8c45fSAndroid Build Coastguard Worker                     return {};
642*38e8c45fSAndroid Build Coastguard Worker                 }
643*38e8c45fSAndroid Build Coastguard Worker                 continue;
644*38e8c45fSAndroid Build Coastguard Worker             } else {
645*38e8c45fSAndroid Build Coastguard Worker                 dataCollected = true;
646*38e8c45fSAndroid Build Coastguard Worker             }
647*38e8c45fSAndroid Build Coastguard Worker 
648*38e8c45fSAndroid Build Coastguard Worker             // Combine data by aggregating time-in-state data grouped by CPU cluster aka policy.
649*38e8c45fSAndroid Build Coastguard Worker             uint32_t offset = key.bucket * FREQS_PER_ENTRY;
650*38e8c45fSAndroid Build Coastguard Worker             uint32_t nextOffset = offset + FREQS_PER_ENTRY;
651*38e8c45fSAndroid Build Coastguard Worker             for (uint32_t j = 0; j < gNPolicies; ++j) {
652*38e8c45fSAndroid Build Coastguard Worker                 if (offset >= gPolicyFreqs[j].size()) continue;
653*38e8c45fSAndroid Build Coastguard Worker                 auto begin = map[key.aggregation_key][j].begin() + offset;
654*38e8c45fSAndroid Build Coastguard Worker                 auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY
655*38e8c45fSAndroid Build Coastguard Worker                                                                : map[key.aggregation_key][j].end();
656*38e8c45fSAndroid Build Coastguard Worker                 for (const auto &cpu : gPolicyCpus[j]) {
657*38e8c45fSAndroid Build Coastguard Worker                     std::transform(begin, end, std::begin(vals[gCpuIndexMap[cpu]].ar), begin,
658*38e8c45fSAndroid Build Coastguard Worker                                    std::plus<uint64_t>());
659*38e8c45fSAndroid Build Coastguard Worker                 }
660*38e8c45fSAndroid Build Coastguard Worker             }
661*38e8c45fSAndroid Build Coastguard Worker         }
662*38e8c45fSAndroid Build Coastguard Worker     }
663*38e8c45fSAndroid Build Coastguard Worker 
664*38e8c45fSAndroid Build Coastguard Worker     if (!dataCollected) {
665*38e8c45fSAndroid Build Coastguard Worker         // Check if eBPF is supported on this device. If it is, gTisMap should not be empty.
666*38e8c45fSAndroid Build Coastguard Worker         time_key_t key;
667*38e8c45fSAndroid Build Coastguard Worker         if (getFirstMapKey(gTisMapFd, &key) != 0) {
668*38e8c45fSAndroid Build Coastguard Worker             return {};
669*38e8c45fSAndroid Build Coastguard Worker         }
670*38e8c45fSAndroid Build Coastguard Worker     }
671*38e8c45fSAndroid Build Coastguard Worker     return map;
672*38e8c45fSAndroid Build Coastguard Worker }
673*38e8c45fSAndroid Build Coastguard Worker 
674*38e8c45fSAndroid Build Coastguard Worker } // namespace bpf
675*38e8c45fSAndroid Build Coastguard Worker } // namespace android
676