1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "DvfsStateResidencyDataProvider.h"
17
18 #include <android-base/logging.h>
19 #include <android-base/parseint.h>
20 #include <android-base/strings.h>
21
22 #include <string>
23 #include <utility>
24
25 using android::base::ParseUint;
26 using android::base::Split;
27 using android::base::StartsWith;
28 using android::base::Trim;
29
30 static const std::string nameSuffix = "-DVFS";
31
32 namespace aidl {
33 namespace android {
34 namespace hardware {
35 namespace power {
36 namespace stats {
37
DvfsStateResidencyDataProvider(std::string path,uint64_t clockRate,std::vector<Config> cfgs)38 DvfsStateResidencyDataProvider::DvfsStateResidencyDataProvider(std::string path, uint64_t clockRate,
39 std::vector<Config> cfgs)
40 : mPowerEntities(std::move(cfgs)), mPath(std::move(path)), mClockRate(clockRate) {}
41
matchEntity(char const * line)42 int32_t DvfsStateResidencyDataProvider::matchEntity(char const *line) {
43 for (int32_t i = 0; i < mPowerEntities.size(); i++) {
44 if (mPowerEntities[i].powerEntityName == Trim(std::string(line))) {
45 return i;
46 }
47 }
48 return -1;
49 }
50
matchState(char const * line,const Config & powerEntity)51 int32_t DvfsStateResidencyDataProvider::matchState(char const *line, const Config& powerEntity) {
52 for (int32_t i = 0; i < powerEntity.states.size(); i++) {
53 if (StartsWith(Trim(std::string(line)), powerEntity.states[i].second)) {
54 return i;
55 }
56 }
57 return -1;
58 }
59
parseState(char const * line,uint64_t * duration,uint64_t * count)60 bool DvfsStateResidencyDataProvider::parseState(char const *line, uint64_t *duration,
61 uint64_t *count) {
62 std::vector<std::string> parts = Split(line, " ");
63 if (parts.size() != 7) {
64 return false;
65 }
66 if (!ParseUint(Trim(parts[3]), count)) {
67 return false;
68 }
69 if (!ParseUint(Trim(parts[6]), duration)) {
70 return false;
71 }
72 return true;
73 }
74
getStateResidencies(std::unordered_map<std::string,std::vector<StateResidency>> * residencies)75 bool DvfsStateResidencyDataProvider::getStateResidencies(
76 std::unordered_map<std::string, std::vector<StateResidency>> *residencies) {
77 std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(mPath.c_str(), "r"), fclose);
78 if (!fp) {
79 PLOG(ERROR) << __func__ << ":Failed to open file " << mPath;
80 return false;
81 }
82
83 for (const Config &powerEntity : mPowerEntities) {
84 std::vector<StateResidency> stateResidency(powerEntity.states.size());
85 for (int32_t i = 0; i < stateResidency.size(); i++) {
86 stateResidency[i].id = i;
87 }
88 residencies->emplace(powerEntity.powerEntityName + nameSuffix, stateResidency);
89 }
90
91 size_t len = 0;
92 char *line = nullptr;
93
94 int32_t temp, powerEntityIndex, stateId = -1;
95 uint64_t duration, count;
96 auto it = residencies->end();
97
98 while (getline(&line, &len, fp.get()) != -1) {
99 temp = matchEntity(line);
100 // Assign new index only when a new valid entity is encountered.
101 if (temp >= 0) {
102 powerEntityIndex = temp;
103 it = residencies->find(mPowerEntities[powerEntityIndex].powerEntityName + nameSuffix);
104 }
105
106 // The given string is last state for each entity.
107 if (StartsWith(Trim(std::string(line)), "last_freq_change_time_ns:"))
108 it = residencies->end();
109
110 if (it != residencies->end()) {
111 stateId = matchState(line, mPowerEntities[powerEntityIndex]);
112
113 if (stateId >= 0) {
114 if (parseState(line, &duration, &count)) {
115 it->second[stateId].totalTimeInStateMs =
116 duration / mClockRate;
117 it->second[stateId].totalStateEntryCount = count;
118 } else {
119 LOG(ERROR) << "Failed to parse duration and count from [" << std::string(line)
120 << "]";
121 return false;
122 }
123 }
124 }
125 }
126
127 free(line);
128
129 return true;
130 }
131
getInfo()132 std::unordered_map<std::string, std::vector<State>> DvfsStateResidencyDataProvider::getInfo() {
133 std::unordered_map<std::string, std::vector<State>> info;
134 for (auto const &entity : mPowerEntities) {
135 std::vector<State> stateInfo(entity.states.size());
136 int32_t stateId = 0;
137 for (auto const &state : entity.states) {
138 stateInfo[stateId] = State{
139 .id = stateId,
140 .name = state.first
141 };
142 stateId++;
143 }
144 info.emplace(entity.powerEntityName + nameSuffix, stateInfo);
145 }
146 return info;
147 }
148
149 } // namespace stats
150 } // namespace power
151 } // namespace hardware
152 } // namespace android
153 } // namespace aidl
154