Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38effc4f authored by Rafal Slawik's avatar Rafal Slawik Committed by Gerrit Code Review
Browse files

Merge "Measure total time in state"

parents cedb52b4 27c48db1
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ static uint32_t gNCpus = 0;
static std::vector<std::vector<uint32_t>> gPolicyFreqs;
static std::vector<std::vector<uint32_t>> gPolicyCpus;
static std::set<uint32_t> gAllFreqs;
static unique_fd gTisTotalMapFd;
static unique_fd gTisMapFd;
static unique_fd gConcurrentMapFd;
static unique_fd gUidLastUpdateMapFd;
@@ -129,6 +130,10 @@ static bool initGlobals() {
        gPolicyCpus.emplace_back(*cpus);
    }

    gTisTotalMapFd =
            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_total_time_in_state_map")};
    if (gTisTotalMapFd < 0) return false;

    gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
    if (gTisMapFd < 0) return false;

@@ -239,6 +244,31 @@ std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() {
    return gPolicyFreqs;
}

std::optional<std::vector<std::vector<uint64_t>>> getTotalCpuFreqTimes() {
    if (!gInitialized && !initGlobals()) return {};

    std::vector<std::vector<uint64_t>> out;
    uint32_t maxFreqCount = 0;
    for (const auto &freqList : gPolicyFreqs) {
        if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
        out.emplace_back(freqList.size(), 0);
    }

    std::vector<uint64_t> vals(gNCpus);
    const uint32_t freqCount = maxFreqCount <= MAX_FREQS_FOR_TOTAL ? maxFreqCount :
            MAX_FREQS_FOR_TOTAL;
    for (uint32_t freqIdx = 0; freqIdx < freqCount; ++freqIdx) {
        if (findMapEntry(gTisTotalMapFd, &freqIdx, vals.data())) return {};
        for (uint32_t policyIdx = 0; policyIdx < gNPolicies; ++policyIdx) {
            if (freqIdx >= gPolicyFreqs[policyIdx].size()) continue;
            for (const auto &cpu : gPolicyCpus[policyIdx]) {
                out[policyIdx][freqIdx] += vals[cpu];
            }
        }
    }

    return out;
}
// 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, ...],
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ namespace android {
namespace bpf {

bool startTrackingUidTimes();
std::optional<std::vector<std::vector<uint64_t>>> getTotalCpuFreqTimes();
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();
+47 −0
Original line number Diff line number Diff line
@@ -40,6 +40,12 @@ static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365;

using std::vector;

TEST(TimeInStateTest, TotalTimeInState) {
    auto times = getTotalCpuFreqTimes();
    ASSERT_TRUE(times.has_value());
    EXPECT_FALSE(times->empty());
}

TEST(TimeInStateTest, SingleUidTimeInState) {
    auto times = getUidCpuFreqTimes(0);
    ASSERT_TRUE(times.has_value());
@@ -186,6 +192,31 @@ TEST(TimeInStateTest, AllUidUpdatedTimeInState) {
    }
}

TEST(TimeInStateTest, TotalAndAllUidTimeInStateConsistent) {
    auto allUid = getUidsCpuFreqTimes();
    auto total = getTotalCpuFreqTimes();

    ASSERT_TRUE(allUid.has_value() && total.has_value());

    // Check the number of policies.
    ASSERT_EQ(allUid->at(0).size(), total->size());

    for (uint32_t policyIdx = 0; policyIdx < total->size(); ++policyIdx) {
        std::vector<uint64_t> totalTimes = total->at(policyIdx);
        uint32_t totalFreqsCount = totalTimes.size();
        std::vector<uint64_t> allUidTimes(totalFreqsCount, 0);
        for (auto const &[uid, uidTimes]: *allUid) {
            for (uint32_t freqIdx = 0; freqIdx < uidTimes[policyIdx].size(); ++freqIdx) {
                allUidTimes[std::min(freqIdx, totalFreqsCount - 1)] += uidTimes[policyIdx][freqIdx];
            }
        }

        for (uint32_t freqIdx = 0; freqIdx < totalFreqsCount; ++freqIdx) {
            ASSERT_LE(allUidTimes[freqIdx], totalTimes[freqIdx]);
        }
    }
}

TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
    uint64_t zero = 0;
    auto maps = {getUidsCpuFreqTimes(), getUidsUpdatedCpuFreqTimes(&zero)};
@@ -292,6 +323,22 @@ void TestCheckDelta(uint64_t before, uint64_t after) {
    ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
}

TEST(TimeInStateTest, TotalTimeInStateMonotonic) {
    auto before = getTotalCpuFreqTimes();
    ASSERT_TRUE(before.has_value());
    sleep(1);
    auto after = getTotalCpuFreqTimes();
    ASSERT_TRUE(after.has_value());

    for (uint32_t policyIdx = 0; policyIdx < after->size(); ++policyIdx) {
        auto timesBefore = before->at(policyIdx);
        auto timesAfter = after->at(policyIdx);
        for (uint32_t freqIdx = 0; freqIdx < timesAfter.size(); ++freqIdx) {
            ASSERT_NO_FATAL_FAILURE(TestCheckDelta(timesBefore[freqIdx], timesAfter[freqIdx]));
        }
    }
}

TEST(TimeInStateTest, AllUidTimeInStateMonotonic) {
    auto map1 = getUidsCpuFreqTimes();
    ASSERT_TRUE(map1.has_value());