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