Loading libs/cputimeinstate/cputimeinstate.cpp +52 −3 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ static std::vector<std::vector<uint32_t>> gPolicyCpus; static std::set<uint32_t> gAllFreqs; static unique_fd gTisMapFd; static unique_fd gConcurrentMapFd; static unique_fd gUidLastUpdateMapFd; static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) { std::string data; Loading Loading @@ -144,6 +145,10 @@ static bool initGlobals() { unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; if (gConcurrentMapFd < 0) return false; gUidLastUpdateMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")}; if (gUidLastUpdateMapFd < 0) return false; gInitialized = true; return true; } Loading Loading @@ -263,6 +268,18 @@ std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t ui return out; } static std::optional<bool> uidUpdatedSince(uint32_t uid, uint64_t lastUpdate, uint64_t *newLastUpdate) { uint64_t uidLastUpdate; if (findMapEntry(gUidLastUpdateMapFd, &uid, &uidLastUpdate)) return {}; // Updates that occurred during the previous read may have been missed. To mitigate // this, don't ignore entries updated up to 1s before *lastUpdate constexpr uint64_t NSEC_PER_SEC = 1000000000; if (uidLastUpdate + NSEC_PER_SEC < lastUpdate) return false; if (uidLastUpdate > *newLastUpdate) *newLastUpdate = uidLastUpdate; return true; } // Retrieve the times in ns that each uid spent running at each CPU freq. // Return contains no value on error, otherwise it contains a map from uids to vectors of vectors // using the format: Loading @@ -271,6 +288,14 @@ std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t ui // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq. std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsCpuFreqTimes() { return getUidsUpdatedCpuFreqTimes(nullptr); } // Retrieve the times in ns that each uid spent running at each CPU freq, excluding UIDs that have // not run since before lastUpdate. // Return format is the same as getUidsCpuFreqTimes() std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate) { if (!gInitialized && !initGlobals()) return {}; time_key_t key, prevKey; std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map; Loading @@ -282,8 +307,14 @@ getUidsCpuFreqTimes() { std::vector<std::vector<uint64_t>> mapFormat; for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0); uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0; std::vector<tis_val_t> vals(gNCpus); do { if (lastUpdate) { auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate); if (!uidUpdated.has_value()) return {}; if (!*uidUpdated) continue; } if (findMapEntry(gTisMapFd, &key, vals.data())) return {}; if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat); Loading @@ -299,8 +330,9 @@ getUidsCpuFreqTimes() { } } prevKey = key; } while (!getNextMapKey(gTisMapFd, &prevKey, &key)); } while (prevKey = key, !getNextMapKey(gTisMapFd, &prevKey, &key)); if (errno != ENOENT) return {}; if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate; return map; } Loading Loading @@ -365,6 +397,15 @@ std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry) // where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent // running on the ith cluster, concurrently with tasks on j other cpus in the same cluster. std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() { return getUidsUpdatedConcurrentTimes(nullptr); } // Retrieve the times in ns that each uid spent running concurrently with each possible number of // other tasks on each cluster (policy times) and overall (active times), excluding UIDs that have // not run since before lastUpdate. // Return format is the same as getUidsConcurrentTimes() std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsUpdatedConcurrentTimes( uint64_t *lastUpdate) { if (!gInitialized && !initGlobals()) return {}; time_key_t key, prevKey; std::unordered_map<uint32_t, concurrent_time_t> ret; Loading @@ -379,7 +420,13 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent std::vector<concurrent_val_t> vals(gNCpus); std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd; uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0; do { if (lastUpdate) { auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate); if (!uidUpdated.has_value()) return {}; if (!*uidUpdated) continue; } if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {}; if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat); Loading @@ -405,8 +452,7 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent std::plus<uint64_t>()); } } prevKey = key; } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key)); } while (prevKey = key, !getNextMapKey(gConcurrentMapFd, &prevKey, &key)); if (errno != ENOENT) return {}; for (const auto &[key, value] : ret) { if (!verifyConcurrentTimes(value)) { Loading @@ -414,6 +460,7 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent if (val.has_value()) ret[key] = val.value(); } } if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate; return ret; } Loading Loading @@ -446,6 +493,8 @@ bool clearUidTimes(uint32_t uid) { return false; if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false; } if (deleteMapEntry(gUidLastUpdateMapFd, &uid) && errno != ENOENT) return false; return true; } Loading libs/cputimeinstate/cputimeinstate.h +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ 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::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate); std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs(); struct concurrent_time_t { Loading @@ -35,6 +37,8 @@ struct concurrent_time_t { std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry = true); std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes(); std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsUpdatedConcurrentTimes(uint64_t *lastUpdate); bool clearUidTimes(unsigned int uid); } // namespace bpf Loading libs/cputimeinstate/testtimeinstate.cpp +180 −76 Original line number Diff line number Diff line Loading @@ -115,12 +115,14 @@ TEST(TimeInStateTest, SingleUidTimesConsistent) { } TEST(TimeInStateTest, AllUidTimeInState) { vector<size_t> sizes; auto map = getUidsCpuFreqTimes(); uint64_t zero = 0; auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); ASSERT_FALSE(map->empty()); vector<size_t> sizes; auto firstEntry = map->begin()->second; for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); Loading @@ -129,9 +131,63 @@ TEST(TimeInStateTest, AllUidTimeInState) { for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); } } } void TestCheckUpdate(const std::vector<std::vector<uint64_t>> &before, const std::vector<std::vector<uint64_t>> &after) { ASSERT_EQ(before.size(), after.size()); uint64_t sumBefore = 0, sumAfter = 0; for (size_t i = 0; i < before.size(); ++i) { ASSERT_EQ(before[i].size(), after[i].size()); for (size_t j = 0; j < before[i].size(); ++j) { // Times should never decrease ASSERT_LE(before[i][j], after[i][j]); } sumBefore += std::accumulate(before[i].begin(), before[i].end(), (uint64_t)0); sumAfter += std::accumulate(after[i].begin(), after[i].end(), (uint64_t)0); } ASSERT_LE(sumBefore, sumAfter); ASSERT_LE(sumAfter - sumBefore, NSEC_PER_SEC); } TEST(TimeInStateTest, AllUidUpdatedTimeInState) { uint64_t lastUpdate = 0; auto map1 = getUidsUpdatedCpuFreqTimes(&lastUpdate); ASSERT_TRUE(map1.has_value()); ASSERT_FALSE(map1->empty()); ASSERT_NE(lastUpdate, (uint64_t)0); uint64_t oldLastUpdate = lastUpdate; // Sleep briefly to trigger a context switch, ensuring we see at least one update. struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 1000000; nanosleep (&ts, NULL); auto map2 = getUidsUpdatedCpuFreqTimes(&lastUpdate); ASSERT_TRUE(map2.has_value()); ASSERT_FALSE(map2->empty()); ASSERT_NE(lastUpdate, oldLastUpdate); bool someUidsExcluded = false; for (const auto &[uid, v] : *map1) { if (map2->find(uid) == map2->end()) { someUidsExcluded = true; break; } } ASSERT_TRUE(someUidsExcluded); for (const auto &[uid, newTimes] : *map2) { ASSERT_NE(map1->find(uid), map1->end()); ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid], newTimes)); } } TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { auto map = getUidsCpuFreqTimes(); uint64_t zero = 0; auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); ASSERT_FALSE(map->empty()); Loading @@ -150,9 +206,12 @@ TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { } } } } TEST(TimeInStateTest, AllUidConcurrentTimes) { auto map = getUidsConcurrentTimes(); uint64_t zero = 0; auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); ASSERT_FALSE(map->empty()); Loading @@ -165,9 +224,47 @@ TEST(TimeInStateTest, AllUidConcurrentTimes) { } } } } TEST(TimeInStateTest, AllUidUpdatedConcurrentTimes) { uint64_t lastUpdate = 0; auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate); ASSERT_TRUE(map1.has_value()); ASSERT_FALSE(map1->empty()); ASSERT_NE(lastUpdate, (uint64_t)0); // Sleep briefly to trigger a context switch, ensuring we see at least one update. struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 1000000; nanosleep (&ts, NULL); uint64_t oldLastUpdate = lastUpdate; auto map2 = getUidsUpdatedConcurrentTimes(&lastUpdate); ASSERT_TRUE(map2.has_value()); ASSERT_FALSE(map2->empty()); ASSERT_NE(lastUpdate, oldLastUpdate); bool someUidsExcluded = false; for (const auto &[uid, v] : *map1) { if (map2->find(uid) == map2->end()) { someUidsExcluded = true; break; } } ASSERT_TRUE(someUidsExcluded); for (const auto &[uid, newTimes] : *map2) { ASSERT_NE(map1->find(uid), map1->end()); ASSERT_NO_FATAL_FAILURE(TestCheckUpdate({(*map1)[uid].active},{newTimes.active})); ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid].policy, newTimes.policy)); } } TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { auto map = getUidsConcurrentTimes(); uint64_t zero = 0; auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); for (const auto &kv : *map) { uint32_t uid = kv.first; Loading @@ -184,6 +281,7 @@ TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { } } } } void TestCheckDelta(uint64_t before, uint64_t after) { // Times should never decrease Loading Loading @@ -242,7 +340,9 @@ TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) { } TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) { auto map = getUidsCpuFreqTimes(); uint64_t zero = 0; auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); bool foundLargeValue = false; Loading @@ -258,9 +358,12 @@ TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) { // uint64_t as expected, we should have some times higher than that. ASSERT_TRUE(foundLargeValue); } } TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) { auto concurrentMap = getUidsConcurrentTimes(); uint64_t zero = 0; auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; for (const auto &concurrentMap : maps) { ASSERT_TRUE(concurrentMap); bool activeFoundLargeValue = false; Loading @@ -282,6 +385,7 @@ TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) { ASSERT_TRUE(activeFoundLargeValue); ASSERT_TRUE(policyFoundLargeValue); } } TEST(TimeInStateTest, AllUidTimesConsistent) { auto tisMap = getUidsCpuFreqTimes(); Loading Loading
libs/cputimeinstate/cputimeinstate.cpp +52 −3 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ static std::vector<std::vector<uint32_t>> gPolicyCpus; static std::set<uint32_t> gAllFreqs; static unique_fd gTisMapFd; static unique_fd gConcurrentMapFd; static unique_fd gUidLastUpdateMapFd; static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) { std::string data; Loading Loading @@ -144,6 +145,10 @@ static bool initGlobals() { unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")}; if (gConcurrentMapFd < 0) return false; gUidLastUpdateMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")}; if (gUidLastUpdateMapFd < 0) return false; gInitialized = true; return true; } Loading Loading @@ -263,6 +268,18 @@ std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t ui return out; } static std::optional<bool> uidUpdatedSince(uint32_t uid, uint64_t lastUpdate, uint64_t *newLastUpdate) { uint64_t uidLastUpdate; if (findMapEntry(gUidLastUpdateMapFd, &uid, &uidLastUpdate)) return {}; // Updates that occurred during the previous read may have been missed. To mitigate // this, don't ignore entries updated up to 1s before *lastUpdate constexpr uint64_t NSEC_PER_SEC = 1000000000; if (uidLastUpdate + NSEC_PER_SEC < lastUpdate) return false; if (uidLastUpdate > *newLastUpdate) *newLastUpdate = uidLastUpdate; return true; } // Retrieve the times in ns that each uid spent running at each CPU freq. // Return contains no value on error, otherwise it contains a map from uids to vectors of vectors // using the format: Loading @@ -271,6 +288,14 @@ std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t ui // where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq. std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsCpuFreqTimes() { return getUidsUpdatedCpuFreqTimes(nullptr); } // Retrieve the times in ns that each uid spent running at each CPU freq, excluding UIDs that have // not run since before lastUpdate. // Return format is the same as getUidsCpuFreqTimes() std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate) { if (!gInitialized && !initGlobals()) return {}; time_key_t key, prevKey; std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map; Loading @@ -282,8 +307,14 @@ getUidsCpuFreqTimes() { std::vector<std::vector<uint64_t>> mapFormat; for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0); uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0; std::vector<tis_val_t> vals(gNCpus); do { if (lastUpdate) { auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate); if (!uidUpdated.has_value()) return {}; if (!*uidUpdated) continue; } if (findMapEntry(gTisMapFd, &key, vals.data())) return {}; if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat); Loading @@ -299,8 +330,9 @@ getUidsCpuFreqTimes() { } } prevKey = key; } while (!getNextMapKey(gTisMapFd, &prevKey, &key)); } while (prevKey = key, !getNextMapKey(gTisMapFd, &prevKey, &key)); if (errno != ENOENT) return {}; if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate; return map; } Loading Loading @@ -365,6 +397,15 @@ std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry) // where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent // running on the ith cluster, concurrently with tasks on j other cpus in the same cluster. std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() { return getUidsUpdatedConcurrentTimes(nullptr); } // Retrieve the times in ns that each uid spent running concurrently with each possible number of // other tasks on each cluster (policy times) and overall (active times), excluding UIDs that have // not run since before lastUpdate. // Return format is the same as getUidsConcurrentTimes() std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsUpdatedConcurrentTimes( uint64_t *lastUpdate) { if (!gInitialized && !initGlobals()) return {}; time_key_t key, prevKey; std::unordered_map<uint32_t, concurrent_time_t> ret; Loading @@ -379,7 +420,13 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent std::vector<concurrent_val_t> vals(gNCpus); std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd; uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0; do { if (lastUpdate) { auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate); if (!uidUpdated.has_value()) return {}; if (!*uidUpdated) continue; } if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {}; if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat); Loading @@ -405,8 +452,7 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent std::plus<uint64_t>()); } } prevKey = key; } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key)); } while (prevKey = key, !getNextMapKey(gConcurrentMapFd, &prevKey, &key)); if (errno != ENOENT) return {}; for (const auto &[key, value] : ret) { if (!verifyConcurrentTimes(value)) { Loading @@ -414,6 +460,7 @@ std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrent if (val.has_value()) ret[key] = val.value(); } } if (lastUpdate && newLastUpdate > *lastUpdate) *lastUpdate = newLastUpdate; return ret; } Loading Loading @@ -446,6 +493,8 @@ bool clearUidTimes(uint32_t uid) { return false; if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false; } if (deleteMapEntry(gUidLastUpdateMapFd, &uid) && errno != ENOENT) return false; return true; } Loading
libs/cputimeinstate/cputimeinstate.h +4 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ 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::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>> getUidsUpdatedCpuFreqTimes(uint64_t *lastUpdate); std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs(); struct concurrent_time_t { Loading @@ -35,6 +37,8 @@ struct concurrent_time_t { std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry = true); std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes(); std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsUpdatedConcurrentTimes(uint64_t *lastUpdate); bool clearUidTimes(unsigned int uid); } // namespace bpf Loading
libs/cputimeinstate/testtimeinstate.cpp +180 −76 Original line number Diff line number Diff line Loading @@ -115,12 +115,14 @@ TEST(TimeInStateTest, SingleUidTimesConsistent) { } TEST(TimeInStateTest, AllUidTimeInState) { vector<size_t> sizes; auto map = getUidsCpuFreqTimes(); uint64_t zero = 0; auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); ASSERT_FALSE(map->empty()); vector<size_t> sizes; auto firstEntry = map->begin()->second; for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size()); Loading @@ -129,9 +131,63 @@ TEST(TimeInStateTest, AllUidTimeInState) { for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]); } } } void TestCheckUpdate(const std::vector<std::vector<uint64_t>> &before, const std::vector<std::vector<uint64_t>> &after) { ASSERT_EQ(before.size(), after.size()); uint64_t sumBefore = 0, sumAfter = 0; for (size_t i = 0; i < before.size(); ++i) { ASSERT_EQ(before[i].size(), after[i].size()); for (size_t j = 0; j < before[i].size(); ++j) { // Times should never decrease ASSERT_LE(before[i][j], after[i][j]); } sumBefore += std::accumulate(before[i].begin(), before[i].end(), (uint64_t)0); sumAfter += std::accumulate(after[i].begin(), after[i].end(), (uint64_t)0); } ASSERT_LE(sumBefore, sumAfter); ASSERT_LE(sumAfter - sumBefore, NSEC_PER_SEC); } TEST(TimeInStateTest, AllUidUpdatedTimeInState) { uint64_t lastUpdate = 0; auto map1 = getUidsUpdatedCpuFreqTimes(&lastUpdate); ASSERT_TRUE(map1.has_value()); ASSERT_FALSE(map1->empty()); ASSERT_NE(lastUpdate, (uint64_t)0); uint64_t oldLastUpdate = lastUpdate; // Sleep briefly to trigger a context switch, ensuring we see at least one update. struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 1000000; nanosleep (&ts, NULL); auto map2 = getUidsUpdatedCpuFreqTimes(&lastUpdate); ASSERT_TRUE(map2.has_value()); ASSERT_FALSE(map2->empty()); ASSERT_NE(lastUpdate, oldLastUpdate); bool someUidsExcluded = false; for (const auto &[uid, v] : *map1) { if (map2->find(uid) == map2->end()) { someUidsExcluded = true; break; } } ASSERT_TRUE(someUidsExcluded); for (const auto &[uid, newTimes] : *map2) { ASSERT_NE(map1->find(uid), map1->end()); ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid], newTimes)); } } TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { auto map = getUidsCpuFreqTimes(); uint64_t zero = 0; auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); ASSERT_FALSE(map->empty()); Loading @@ -150,9 +206,12 @@ TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) { } } } } TEST(TimeInStateTest, AllUidConcurrentTimes) { auto map = getUidsConcurrentTimes(); uint64_t zero = 0; auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); ASSERT_FALSE(map->empty()); Loading @@ -165,9 +224,47 @@ TEST(TimeInStateTest, AllUidConcurrentTimes) { } } } } TEST(TimeInStateTest, AllUidUpdatedConcurrentTimes) { uint64_t lastUpdate = 0; auto map1 = getUidsUpdatedConcurrentTimes(&lastUpdate); ASSERT_TRUE(map1.has_value()); ASSERT_FALSE(map1->empty()); ASSERT_NE(lastUpdate, (uint64_t)0); // Sleep briefly to trigger a context switch, ensuring we see at least one update. struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 1000000; nanosleep (&ts, NULL); uint64_t oldLastUpdate = lastUpdate; auto map2 = getUidsUpdatedConcurrentTimes(&lastUpdate); ASSERT_TRUE(map2.has_value()); ASSERT_FALSE(map2->empty()); ASSERT_NE(lastUpdate, oldLastUpdate); bool someUidsExcluded = false; for (const auto &[uid, v] : *map1) { if (map2->find(uid) == map2->end()) { someUidsExcluded = true; break; } } ASSERT_TRUE(someUidsExcluded); for (const auto &[uid, newTimes] : *map2) { ASSERT_NE(map1->find(uid), map1->end()); ASSERT_NO_FATAL_FAILURE(TestCheckUpdate({(*map1)[uid].active},{newTimes.active})); ASSERT_NO_FATAL_FAILURE(TestCheckUpdate((*map1)[uid].policy, newTimes.policy)); } } TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { auto map = getUidsConcurrentTimes(); uint64_t zero = 0; auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); for (const auto &kv : *map) { uint32_t uid = kv.first; Loading @@ -184,6 +281,7 @@ TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) { } } } } void TestCheckDelta(uint64_t before, uint64_t after) { // Times should never decrease Loading Loading @@ -242,7 +340,9 @@ TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) { } TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) { auto map = getUidsCpuFreqTimes(); uint64_t zero = 0; auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)}; for (const auto &map : maps) { ASSERT_TRUE(map.has_value()); bool foundLargeValue = false; Loading @@ -258,9 +358,12 @@ TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) { // uint64_t as expected, we should have some times higher than that. ASSERT_TRUE(foundLargeValue); } } TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) { auto concurrentMap = getUidsConcurrentTimes(); uint64_t zero = 0; auto maps = {getUidsConcurrentTimes(), getUidsUpdatedConcurrentTimes(&zero)}; for (const auto &concurrentMap : maps) { ASSERT_TRUE(concurrentMap); bool activeFoundLargeValue = false; Loading @@ -282,6 +385,7 @@ TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) { ASSERT_TRUE(activeFoundLargeValue); ASSERT_TRUE(policyFoundLargeValue); } } TEST(TimeInStateTest, AllUidTimesConsistent) { auto tisMap = getUidsCpuFreqTimes(); Loading