diff --git a/powerstats/TpuDvfsStateResidencyDataProvider.cpp b/powerstats/TpuDvfsStateResidencyDataProvider.cpp new file mode 100644 index 0000000..e1ce56c --- /dev/null +++ b/powerstats/TpuDvfsStateResidencyDataProvider.cpp @@ -0,0 +1,105 @@ +/* + * 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 "TpuDvfsStateResidencyDataProvider.h" + +#include + +static const std::string ENTITY_NAME = "TPU-DVFS"; + +namespace aidl { +namespace android { +namespace hardware { +namespace power { +namespace stats { + +TpuDvfsStateResidencyDataProvider::TpuDvfsStateResidencyDataProvider( + const std::string& path, + std::vector frequencies, + uint64_t clockRate) + : mPath(path), mFrequencies(std::move(frequencies)), mClockRate(clockRate) {} + +bool TpuDvfsStateResidencyDataProvider::getStateResidencies( + std::unordered_map> *residencies) { + // Using FILE* instead of std::ifstream for performance reasons + std::unique_ptr fp(fopen(mPath.c_str(), "r"), fclose); + if (!fp) { + PLOG(ERROR) << "Failed to open file " << mPath; + return false; + } + + std::vector stateResidencies; + for (int i = 0; i < mFrequencies.size(); i++) { + StateResidency s = {.id = i, .totalTimeInStateMs = 0}; + stateResidencies.push_back(s); + } + + char *line = nullptr; + size_t len = 0; + std::istringstream ssLine; + std::string split; + int32_t lineIdx = 0; + std::vector stateIdxMap; + int32_t colIdx; + std::vector::const_iterator found; + while (getline(&line, &len, fp.get()) != -1) { + ssLine.clear(); + ssLine.str(line); + colIdx = 0; + for (std::string split; std::getline(ssLine, split, ' ');) { + // Skip first column + if (split.find(':') != std::string::npos) + continue; + + if (lineIdx == 0) { + // Build the state index map by first row + split.erase(split.find_last_not_of(" \n\r\t") + 1); + found = std::find(mFrequencies.begin(), mFrequencies.end(), split); + if (found != mFrequencies.end()) { + stateIdxMap.push_back(found - mFrequencies.begin()); + } else { + PLOG(ERROR) << "TPU frequency " << split << " is not found in " << mPath; + stateIdxMap.push_back(0); + } + } else { + // Add up time in frequency per uid + stateResidencies[stateIdxMap[colIdx]].totalTimeInStateMs += + std::atoll(split.c_str()) / mClockRate; + } + colIdx++; + } + lineIdx++; + } + + residencies->emplace(ENTITY_NAME, stateResidencies); + return true; +} + +std::unordered_map> TpuDvfsStateResidencyDataProvider::getInfo() { + std::vector states; + for (int32_t id = 0; id < mFrequencies.size(); id++) { + State s = + {.id = id, .name = std::to_string(std::atol(mFrequencies[id].c_str()) / 1000) + "MHz"}; + states.push_back(s); + } + + return {{ENTITY_NAME, states}}; +} + +} // namespace stats +} // namespace power +} // namespace hardware +} // namespace android +} // namespace aidl diff --git a/powerstats/include/TpuDvfsStateResidencyDataProvider.h b/powerstats/include/TpuDvfsStateResidencyDataProvider.h new file mode 100644 index 0000000..9ce3bd3 --- /dev/null +++ b/powerstats/include/TpuDvfsStateResidencyDataProvider.h @@ -0,0 +1,53 @@ +/* + * 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 TpuDvfsStateResidencyDataProvider : public PowerStats::IStateResidencyDataProvider { + public: + TpuDvfsStateResidencyDataProvider( + const std::string& path, std::vector frequencies, uint64_t clockRate); + ~TpuDvfsStateResidencyDataProvider() = default; + + /* + * See IStateResidencyDataProvider::getStateResidencies + */ + bool getStateResidencies( + std::unordered_map> *residencies) override; + + /* + * See IStateResidencyDataProvider::getInfo + */ + std::unordered_map> getInfo() override; + + private: + const std::string mPath; + const std::vector mFrequencies; + const uint64_t mClockRate; +}; + +} // namespace stats +} // namespace power +} // namespace hardware +} // namespace android +} // namespace aidl