Loading libs/cputimeinstate/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ cc_library { "-Wall", "-Wextra", ], export_include_dirs: ["."], } cc_test { Loading libs/cputimeinstate/cputimeinstate.cpp +43 −6 Original line number Diff line number Diff line Loading @@ -85,6 +85,16 @@ static int comparePolicyFiles(const struct dirent **d1, const struct dirent **d2 return policyN1 - policyN2; } static int bpf_obj_get_wronly(const char *pathname) { union bpf_attr attr; memset(&attr, 0, sizeof(attr)); attr.pathname = ptr_to_u64((void *)pathname); attr.file_flags = BPF_F_WRONLY; return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr)); } static bool initGlobals() { std::lock_guard<std::mutex> guard(gInitializedMutex); if (gInitialized) return true; Loading Loading @@ -153,17 +163,17 @@ static bool attachTracepointProgram(const std::string &eventType, const std::str bool startTrackingUidTimes() { if (!initGlobals()) return false; unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); if (fd < 0) return false; unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); if (cpuPolicyFd < 0) return false; for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) { for (auto &cpu : gPolicyCpus[i]) { if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false; if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false; } } unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); if (fd2 < 0) return false; unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); if (freqToIdxFd < 0) return false; freq_idx_key_t key; for (uint32_t i = 0; i < gNPolicies; ++i) { key.policy = i; Loading @@ -173,14 +183,41 @@ bool startTrackingUidTimes() { // The uid_times map still uses 0-based indexes, and the sched_switch program handles // conversion between them, so this does not affect our map reading code. uint32_t idx = j + 1; if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false; if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false; } } unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map")); if (cpuLastUpdateFd < 0) return false; std::vector<uint64_t> zeros(get_nprocs_conf(), 0); uint32_t zero = 0; if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false; unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map")); if (nrActiveFd < 0) return false; if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false; unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map")); if (policyNrActiveFd < 0) return false; for (uint32_t i = 0; i < gNPolicies; ++i) { if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false; } unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map")); if (policyFreqIdxFd < 0) return false; for (uint32_t i = 0; i < gNPolicies; ++i) { if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false; } return attachTracepointProgram("sched", "sched_switch") && attachTracepointProgram("power", "cpu_frequency"); } std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() { if (!gInitialized && !initGlobals()) return {}; return gPolicyFreqs; } // Retrieve the times in ns that uid spent running at each CPU frequency. // Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], Loading libs/cputimeinstate/cputimeinstate.h +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ bool startTrackingUidTimes(); std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid); std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsCpuFreqTimes(); std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs(); struct concurrent_time_t { std::vector<uint64_t> active; Loading libs/cputimeinstate/testtimeinstate.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -367,5 +367,16 @@ TEST(TimeInStateTest, RemoveUid) { ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end()); } TEST(TimeInStateTest, GetCpuFreqs) { auto freqs = getCpuFreqs(); ASSERT_TRUE(freqs.has_value()); auto times = getUidCpuFreqTimes(0); ASSERT_TRUE(times.has_value()); ASSERT_EQ(freqs->size(), times->size()); for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size()); } } // namespace bpf } // namespace android Loading
libs/cputimeinstate/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ cc_library { "-Wall", "-Wextra", ], export_include_dirs: ["."], } cc_test { Loading
libs/cputimeinstate/cputimeinstate.cpp +43 −6 Original line number Diff line number Diff line Loading @@ -85,6 +85,16 @@ static int comparePolicyFiles(const struct dirent **d1, const struct dirent **d2 return policyN1 - policyN2; } static int bpf_obj_get_wronly(const char *pathname) { union bpf_attr attr; memset(&attr, 0, sizeof(attr)); attr.pathname = ptr_to_u64((void *)pathname); attr.file_flags = BPF_F_WRONLY; return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr)); } static bool initGlobals() { std::lock_guard<std::mutex> guard(gInitializedMutex); if (gInitialized) return true; Loading Loading @@ -153,17 +163,17 @@ static bool attachTracepointProgram(const std::string &eventType, const std::str bool startTrackingUidTimes() { if (!initGlobals()) return false; unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); if (fd < 0) return false; unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map")); if (cpuPolicyFd < 0) return false; for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) { for (auto &cpu : gPolicyCpus[i]) { if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false; if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false; } } unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); if (fd2 < 0) return false; unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map")); if (freqToIdxFd < 0) return false; freq_idx_key_t key; for (uint32_t i = 0; i < gNPolicies; ++i) { key.policy = i; Loading @@ -173,14 +183,41 @@ bool startTrackingUidTimes() { // The uid_times map still uses 0-based indexes, and the sched_switch program handles // conversion between them, so this does not affect our map reading code. uint32_t idx = j + 1; if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false; if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false; } } unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map")); if (cpuLastUpdateFd < 0) return false; std::vector<uint64_t> zeros(get_nprocs_conf(), 0); uint32_t zero = 0; if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false; unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map")); if (nrActiveFd < 0) return false; if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false; unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map")); if (policyNrActiveFd < 0) return false; for (uint32_t i = 0; i < gNPolicies; ++i) { if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false; } unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map")); if (policyFreqIdxFd < 0) return false; for (uint32_t i = 0; i < gNPolicies; ++i) { if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false; } return attachTracepointProgram("sched", "sched_switch") && attachTracepointProgram("power", "cpu_frequency"); } std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() { if (!gInitialized && !initGlobals()) return {}; return gPolicyFreqs; } // Retrieve the times in ns that uid spent running at each CPU frequency. // Return contains no value on error, otherwise it contains a vector of vectors using the format: // [[t0_0, t0_1, ...], Loading
libs/cputimeinstate/cputimeinstate.h +1 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ bool startTrackingUidTimes(); std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid); std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsCpuFreqTimes(); std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs(); struct concurrent_time_t { std::vector<uint64_t> active; Loading
libs/cputimeinstate/testtimeinstate.cpp +11 −0 Original line number Diff line number Diff line Loading @@ -367,5 +367,16 @@ TEST(TimeInStateTest, RemoveUid) { ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end()); } TEST(TimeInStateTest, GetCpuFreqs) { auto freqs = getCpuFreqs(); ASSERT_TRUE(freqs.has_value()); auto times = getUidCpuFreqTimes(0); ASSERT_TRUE(times.has_value()); ASSERT_EQ(freqs->size(), times->size()); for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size()); } } // namespace bpf } // namespace android