From a3792b2a2f26a8a11ec530c2ba1d3d52a57b2304 Mon Sep 17 00:00:00 2001 From: Darren Hsu Date: Sat, 7 Jan 2023 13:43:26 +0800 Subject: [PATCH] powerstats: Introduce CpupmStateResidencyDataProvider Bug: 263276734 Bug: 264728626 Test: dumpsys android.hardware.power.stats.IPowerStats/default Change-Id: I0887dde159d6f6ed1f5c470464eaf817ecc7b4eb Signed-off-by: Darren Hsu --- .../CpupmStateResidencyDataProvider.cpp | 146 ++++++++++++++++++ .../include/CpupmStateResidencyDataProvider.h | 70 +++++++++ 2 files changed, 216 insertions(+) create mode 100644 powerstats/CpupmStateResidencyDataProvider.cpp create mode 100644 powerstats/include/CpupmStateResidencyDataProvider.h diff --git a/powerstats/CpupmStateResidencyDataProvider.cpp b/powerstats/CpupmStateResidencyDataProvider.cpp new file mode 100644 index 0000000..bb0e61f --- /dev/null +++ b/powerstats/CpupmStateResidencyDataProvider.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "CpupmStateResidencyDataProvider.h" + +#include +#include +#include + +#include +#include + +using android::base::ParseUint; +using android::base::Split; +using android::base::StartsWith; +using android::base::Trim; + +namespace aidl { +namespace android { +namespace hardware { +namespace power { +namespace stats { + +CpupmStateResidencyDataProvider::CpupmStateResidencyDataProvider( + const std::string &path, const Config &config) + : mPath(std::move(path)), mConfig(std::move(config)) {} + +int32_t CpupmStateResidencyDataProvider::matchState(char const *line) { + for (int32_t i = 0; i < mConfig.states.size(); i++) { + if (mConfig.states[i].second == Trim(std::string(line))) { + return i; + } + } + return -1; +} + +int32_t CpupmStateResidencyDataProvider::matchEntity(char const *line) { + for (int32_t i = 0; i < mConfig.entities.size(); i++) { + if (StartsWith(Trim(std::string(line)), mConfig.entities[i].second)) { + return i; + } + } + return -1; +} + +bool CpupmStateResidencyDataProvider::parseState( + char const *line, uint64_t *duration, uint64_t *count) { + std::vector parts = Split(line, " "); + if (parts.size() != 5) { + return false; + } + if (!ParseUint(Trim(parts[1]), count)) { + return false; + } + if (!ParseUint(Trim(parts[3]), duration)) { + return false; + } + return true; +} + +bool CpupmStateResidencyDataProvider::getStateResidencies( + std::unordered_map> *residencies) { + std::unique_ptr fp(fopen(mPath.c_str(), "r"), fclose); + if (!fp) { + PLOG(ERROR) << __func__ << ":Failed to open file " << mPath; + return false; + } + + for (int32_t i = 0; i < mConfig.entities.size(); i++) { + std::vector stateResidencies(mConfig.states.size()); + for (int32_t j = 0; j < stateResidencies.size(); j++) { + stateResidencies[j].id = j; + } + residencies->emplace(mConfig.entities[i].first, stateResidencies); + } + + size_t len = 0; + char *line = nullptr; + + int32_t temp, entityIndex, stateId = -1; + uint64_t duration, count; + auto it = residencies->end(); + + while (getline(&line, &len, fp.get()) != -1) { + temp = matchState(line); + // Assign new id only when a new valid state is encountered. + if (temp >= 0) { + stateId = temp; + } + + if (stateId >= 0) { + entityIndex = matchEntity(line); + it = residencies->find(mConfig.entities[entityIndex].first); + + if (it != residencies->end()) { + if (parseState(line, &duration, &count)) { + it->second[stateId].totalTimeInStateMs = duration / US_TO_MS; + it->second[stateId].totalStateEntryCount = count; + } else { + LOG(ERROR) << "Failed to parse duration and count from [" << std::string(line) + << "]"; + return false; + } + } + } + } + + free(line); + + return true; +} + +std::unordered_map> CpupmStateResidencyDataProvider::getInfo() { + std::unordered_map> info; + for (auto const &entity : mConfig.entities) { + std::vector stateInfo(mConfig.states.size()); + int32_t stateId = 0; + for (auto const &state : mConfig.states) { + stateInfo[stateId] = State{ + .id = stateId, + .name = state.first + }; + stateId++; + } + info.emplace(entity.first, stateInfo); + } + return info; +} + +} // namespace stats +} // namespace power +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/powerstats/include/CpupmStateResidencyDataProvider.h b/powerstats/include/CpupmStateResidencyDataProvider.h new file mode 100644 index 0000000..c04e11e --- /dev/null +++ b/powerstats/include/CpupmStateResidencyDataProvider.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +namespace aidl { +namespace android { +namespace hardware { +namespace power { +namespace stats { + +class CpupmStateResidencyDataProvider : public PowerStats::IStateResidencyDataProvider { + public: + class Config { + public: + // List of power entity name pairs (name to display, name to parse) + std::vector> entities; + + // List of state pairs (state to display, state to parse). + std::vector> states; + }; + + /* + * path - path to cpupm sysfs node. + */ + CpupmStateResidencyDataProvider(const std::string &path, const Config &config); + ~CpupmStateResidencyDataProvider() = default; + + /* + * See IStateResidencyDataProvider::getStateResidencies + */ + bool getStateResidencies( + std::unordered_map> *residencies) override; + + /* + * See IStateResidencyDataProvider::getInfo + */ + std::unordered_map> getInfo() override; + + private: + int32_t matchEntity(char const *line); + int32_t matchState(char const *line); + bool parseState(char const *line, uint64_t *duration, uint64_t *count); + + // A constant to represent the number of microseconds in one millisecond. + const uint64_t US_TO_MS = 1000; + + const std::string mPath; + const Config mConfig; +}; + +} // namespace stats +} // namespace power +} // namespace hardware +} // namespace android +} // namespace aidl