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

Commit ee7e749b authored by Connor O'Brien's avatar Connor O'Brien Committed by Android (Google) Code Review
Browse files

Merge changes I97b697c9,If13df157

* changes:
  libtimeinstate: use std::optional
  libtimeinstate: fix map names
parents 60f24555 4b9c4988
Loading
Loading
Loading
Loading
+36 −33
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <inttypes.h>

#include <mutex>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
@@ -62,19 +63,20 @@ static std::vector<std::vector<uint32_t>> gPolicyCpus;
static std::set<uint32_t> gAllFreqs;
static unique_fd gMapFd;

static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
    std::string data;

    if (!android::base::ReadFileToString(path, &data)) return false;
    if (!android::base::ReadFileToString(path, &data)) return {};

    auto strings = android::base::Split(data, " \n");
    std::vector<uint32_t> ret;
    for (const auto &s : strings) {
        if (s.empty()) continue;
        uint32_t n;
        if (!android::base::ParseUint(s, &n)) return false;
        out->emplace_back(n);
        if (!android::base::ParseUint(s, &n)) return {};
        ret.emplace_back(n);
    }
    return true;
    return ret;
}

static int isPolicyFile(const struct dirent *d) {
@@ -111,20 +113,22 @@ static bool initGlobals() {
        for (const auto &name : {"available", "boost"}) {
            std::string path =
                    StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
            if (!readNumbersFromFile(path, &freqs)) return false;
            auto nums = readNumbersFromFile(path);
            if (!nums) return false;
            freqs.insert(freqs.end(), nums->begin(), nums->end());
        }
        std::sort(freqs.begin(), freqs.end());
        gPolicyFreqs.emplace_back(freqs);

        for (auto freq : freqs) gAllFreqs.insert(freq);

        std::vector<uint32_t> cpus;
        std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus");
        if (!readNumbersFromFile(path, &cpus)) return false;
        gPolicyCpus.emplace_back(cpus);
        auto cpus = readNumbersFromFile(path);
        if (!cpus) return false;
        gPolicyCpus.emplace_back(*cpus);
    }

    gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")};
    gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map")};
    if (gMapFd < 0) return false;

    gInitialized = true;
@@ -151,17 +155,15 @@ bool startTrackingUidCpuFreqTimes() {
}

// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes.
// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors
// using the format:
// Return contains no value on error, otherwise it contains a vector of vectors using the format:
// [[t0_0, t0_1, ...],
//  [t1_0, t1_1, ...], ...]
// where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) {
    if (!gInitialized && !initGlobals()) return false;
std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) {
    if (!gInitialized && !initGlobals()) return {};
    time_key_t key = {.uid = uid, .freq = 0};

    freqTimes->clear();
    freqTimes->resize(gNPolicies);
    std::vector<std::vector<uint64_t>> out(gNPolicies);
    std::vector<uint32_t> idxs(gNPolicies, 0);

    val_t value;
@@ -172,32 +174,32 @@ bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTi
            if (errno == ENOENT)
                memset(&value.ar, 0, sizeof(value.ar));
            else
                return false;
                return {};
        }
        for (uint32_t i = 0; i < gNPolicies; ++i) {
            if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
            uint64_t time = 0;
            for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
            idxs[i] += 1;
            (*freqTimes)[i].emplace_back(time);
            out[i].emplace_back(time);
        }
    }

    return true;
    return out;
}

// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap.
// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to
// vectors of vectors using the format:
// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors
// using the format:
// { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
//   uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
// where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
bool getUidsCpuFreqTimes(
        std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) {
    if (!gInitialized && !initGlobals()) return false;
std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
getUidsCpuFreqTimes() {
    if (!gInitialized && !initGlobals()) return {};

    int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times");
    if (fd < 0) return false;
    int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times_map");
    if (fd < 0) return {};
    BpfMap<time_key_t, val_t> m(fd);

    std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
@@ -206,25 +208,26 @@ bool getUidsCpuFreqTimes(
        for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
        policyFreqIdxs.emplace_back(freqIdxs);
    }

    auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
    std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
    auto fn = [&map, &policyFreqIdxs](const time_key_t &key, const val_t &val,
                                             const BpfMap<time_key_t, val_t> &) {
        if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
            (*freqTimeMap)[key.uid].resize(gNPolicies);
        if (map.find(key.uid) == map.end()) {
            map[key.uid].resize(gNPolicies);
            for (uint32_t i = 0; i < gNPolicies; ++i) {
                (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
                map[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
            }
        }

        for (size_t policy = 0; policy < gNPolicies; ++policy) {
            for (const auto &cpu : gPolicyCpus[policy]) {
                auto freqIdx = policyFreqIdxs[policy][key.freq];
                (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu];
                map[key.uid][policy][freqIdx] += val.ar[cpu];
            }
        }
        return android::netdutils::status::ok;
    };
    return isOk(m.iterateWithValue(fn));
    if (isOk(m.iterateWithValue(fn))) return map;
    return {};
}

// Clear all time in state data for a given uid. Returns false on error, true otherwise.
+3 −2
Original line number Diff line number Diff line
@@ -23,8 +23,9 @@ namespace android {
namespace bpf {

bool startTrackingUidCpuFreqTimes();
bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes);
bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap);
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();
bool clearUidCpuFreqTimes(unsigned int uid);

} // namespace bpf
+19 −18
Original line number Diff line number Diff line
@@ -12,45 +12,46 @@ namespace bpf {
using std::vector;

TEST(TimeInStateTest, SingleUid) {
    vector<vector<uint64_t>> times;
    ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
    EXPECT_FALSE(times.empty());
    auto times = getUidCpuFreqTimes(0);
    ASSERT_TRUE(times.has_value());
    EXPECT_FALSE(times->empty());
}

TEST(TimeInStateTest, AllUid) {
    vector<size_t> sizes;
    std::unordered_map<uint32_t, vector<vector<uint64_t>>> map;
    ASSERT_TRUE(getUidsCpuFreqTimes(&map));
    auto map = getUidsCpuFreqTimes();
    ASSERT_TRUE(map.has_value());

    ASSERT_FALSE(map.empty());
    ASSERT_FALSE(map->empty());

    auto firstEntry = map.begin()->second;
    auto firstEntry = map->begin()->second;
    for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());

    for (const auto &vec : map) {
    for (const auto &vec : *map) {
        ASSERT_EQ(vec.second.size(), sizes.size());
        for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
    }
}

TEST(TimeInStateTest, RemoveUid) {
    vector<vector<uint64_t>> times, times2;
    ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
    ASSERT_FALSE(times.empty());
    auto times = getUidCpuFreqTimes(0);
    ASSERT_TRUE(times.has_value());
    ASSERT_FALSE(times->empty());

    uint64_t sum = 0;
    for (size_t i = 0; i < times.size(); ++i) {
        for (auto x : times[i]) sum += x;
    for (size_t i = 0; i < times->size(); ++i) {
        for (auto x : (*times)[i]) sum += x;
    }
    ASSERT_GT(sum, (uint64_t)0);

    ASSERT_TRUE(clearUidCpuFreqTimes(0));

    ASSERT_TRUE(getUidCpuFreqTimes(0, &times2));
    ASSERT_EQ(times2.size(), times.size());
    for (size_t i = 0; i < times.size(); ++i) {
        ASSERT_EQ(times2[i].size(), times[i].size());
        for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]);
    auto times2 = getUidCpuFreqTimes(0);
    ASSERT_TRUE(times2.has_value());
    ASSERT_EQ(times2->size(), times->size());
    for (size_t i = 0; i < times->size(); ++i) {
        ASSERT_EQ((*times2)[i].size(), (*times)[i].size());
        for (size_t j = 0; j < (*times)[i].size(); ++j) ASSERT_LE((*times2)[i][j], (*times)[i][j]);
    }
}