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
17 #include <dataproviders/PowerStatsEnergyConsumer.h>
18
19 #include <android-base/logging.h>
20
21 namespace aidl {
22 namespace android {
23 namespace hardware {
24 namespace power {
25 namespace stats {
26
PowerStatsEnergyConsumer(std::shared_ptr<PowerStats> p,EnergyConsumerType type,std::string name,bool attr)27 PowerStatsEnergyConsumer::PowerStatsEnergyConsumer(std::shared_ptr<PowerStats> p,
28 EnergyConsumerType type, std::string name,
29 bool attr)
30 : kType(type), kName(name), mPowerStats(p), mWithAttribution(attr) {}
31
createMeterConsumer(std::shared_ptr<PowerStats> p,EnergyConsumerType type,std::string name,std::set<std::string> channelNames)32 std::unique_ptr<PowerStatsEnergyConsumer> PowerStatsEnergyConsumer::createMeterConsumer(
33 std::shared_ptr<PowerStats> p, EnergyConsumerType type, std::string name,
34 std::set<std::string> channelNames) {
35 return createMeterAndEntityConsumer(p, type, name, channelNames, "", {});
36 }
37
createEntityConsumer(std::shared_ptr<PowerStats> p,EnergyConsumerType type,std::string name,std::string powerEntityName,std::map<std::string,int32_t> stateCoeffs)38 std::unique_ptr<PowerStatsEnergyConsumer> PowerStatsEnergyConsumer::createEntityConsumer(
39 std::shared_ptr<PowerStats> p, EnergyConsumerType type, std::string name,
40 std::string powerEntityName, std::map<std::string, int32_t> stateCoeffs) {
41 return createMeterAndEntityConsumer(p, type, name, {}, powerEntityName, stateCoeffs);
42 }
43
createMeterAndEntityConsumer(std::shared_ptr<PowerStats> p,EnergyConsumerType type,std::string name,std::set<std::string> channelNames,std::string powerEntityName,std::map<std::string,int32_t> stateCoeffs)44 std::unique_ptr<PowerStatsEnergyConsumer> PowerStatsEnergyConsumer::createMeterAndEntityConsumer(
45 std::shared_ptr<PowerStats> p, EnergyConsumerType type, std::string name,
46 std::set<std::string> channelNames, std::string powerEntityName,
47 std::map<std::string, int32_t> stateCoeffs) {
48 auto ret =
49 std::unique_ptr<PowerStatsEnergyConsumer>(new PowerStatsEnergyConsumer(p, type, name));
50
51 if (ret->addEnergyMeter(channelNames) && ret->addPowerEntity(powerEntityName, stateCoeffs)) {
52 return ret;
53 }
54
55 LOG(ERROR) << "Failed to create PowerStatsEnergyConsumer for " << name;
56 return nullptr;
57 }
58
createMeterAndAttrConsumer(std::shared_ptr<PowerStats> p,EnergyConsumerType type,std::string name,std::set<std::string> channelNames,std::unordered_map<int32_t,std::string> paths,std::map<std::string,int32_t> stateCoeffs)59 std::unique_ptr<PowerStatsEnergyConsumer> PowerStatsEnergyConsumer::createMeterAndAttrConsumer(
60 std::shared_ptr<PowerStats> p, EnergyConsumerType type, std::string name,
61 std::set<std::string> channelNames, std::unordered_map<int32_t, std::string> paths,
62 std::map<std::string, int32_t> stateCoeffs) {
63 auto ret = std::unique_ptr<PowerStatsEnergyConsumer>(
64 new PowerStatsEnergyConsumer(p, type, name, true));
65
66 if (ret->addEnergyMeter(channelNames) && ret->addAttribution(paths, stateCoeffs)) {
67 return ret;
68 }
69
70 LOG(ERROR) << "Failed to create PowerStatsEnergyConsumer for " << name;
71 return nullptr;
72 }
73
addEnergyMeter(std::set<std::string> channelNames)74 bool PowerStatsEnergyConsumer::addEnergyMeter(std::set<std::string> channelNames) {
75 if (channelNames.empty()) {
76 return true;
77 }
78
79 std::vector<Channel> channels;
80 mPowerStats->getEnergyMeterInfo(&channels);
81
82 for (const auto &c : channels) {
83 if (channelNames.count(c.name)) {
84 mChannelIds.push_back(c.id);
85 }
86 }
87
88 return (mChannelIds.size() == channelNames.size());
89 }
90
addPowerEntity(std::string powerEntityName,std::map<std::string,int32_t> stateCoeffs)91 bool PowerStatsEnergyConsumer::addPowerEntity(std::string powerEntityName,
92 std::map<std::string, int32_t> stateCoeffs) {
93 if (powerEntityName.empty() || stateCoeffs.empty()) {
94 return true;
95 }
96
97 std::vector<PowerEntity> powerEntities;
98 mPowerStats->getPowerEntityInfo(&powerEntities);
99
100 for (const auto &p : powerEntities) {
101 if (powerEntityName == p.name) {
102 mPowerEntityId = p.id;
103 for (const auto &s : p.states) {
104 if (stateCoeffs.count(s.name)) {
105 mCoefficients.emplace(s.id, stateCoeffs.at(s.name));
106 }
107 }
108 break;
109 }
110 }
111
112 return (mCoefficients.size() == stateCoeffs.size());
113 }
114
addAttribution(std::unordered_map<int32_t,std::string> paths,std::map<std::string,int32_t> stateCoeffs)115 bool PowerStatsEnergyConsumer::addAttribution(std::unordered_map<int32_t, std::string> paths,
116 std::map<std::string, int32_t> stateCoeffs) {
117 mAttrInfoPath = paths;
118
119 if (paths.count(UID_TIME_IN_STATE)) {
120 mEnergyAttribution = PowerStatsEnergyAttribution();
121 AttributionStats attrStats = mEnergyAttribution.getAttributionStats(paths);
122 if (attrStats.uidTimeInStateNames.empty()) {
123 LOG(ERROR) << "Failed to read uid_time_in_state";
124 return false;
125 }
126
127 // stateCoeffs should not blocking energy consumer to return power meter
128 // so just handle this in getEnergyConsumed()
129 if (stateCoeffs.empty()) {
130 return true;
131 }
132
133 int32_t stateId = 0;
134 for (const auto &stateName : attrStats.uidTimeInStateNames) {
135 if (stateCoeffs.count(stateName)) {
136 // When uid_time_in_state is not the only type of attribution,
137 // should condider to separate the coefficients just for attribution.
138 mCoefficients.emplace(stateId, stateCoeffs.at(stateName));
139 }
140 stateId++;
141 }
142 }
143
144 return (mCoefficients.size() == stateCoeffs.size());
145 }
146
getEnergyConsumed()147 std::optional<EnergyConsumerResult> PowerStatsEnergyConsumer::getEnergyConsumed() {
148 int64_t totalEnergyUWs = 0;
149 int64_t timestampMs = 0;
150
151 if (!mChannelIds.empty()) {
152 std::vector<EnergyMeasurement> measurements;
153 if (mPowerStats->readEnergyMeter(mChannelIds, &measurements).isOk()) {
154 for (const auto &m : measurements) {
155 totalEnergyUWs += m.energyUWs;
156 timestampMs = m.timestampMs;
157 }
158 } else {
159 LOG(ERROR) << "Failed to read energy meter";
160 return {};
161 }
162 }
163
164 std::vector<EnergyConsumerAttribution> attribution;
165 if (!mCoefficients.empty()) {
166 if (mWithAttribution) {
167 AttributionStats attrStats = mEnergyAttribution.getAttributionStats(mAttrInfoPath);
168 if (attrStats.uidTimeInStats.empty() || attrStats.uidTimeInStateNames.empty()) {
169 LOG(ERROR) << "Failed to read uid_time_in_state for attribution, return default EnergyConsumer";
170 } else {
171 int64_t totalRelativeEnergyUWs = 0;
172 for (const auto &uidTimeInStat : attrStats.uidTimeInStats) {
173 int64_t uidEnergyUWs = 0;
174 for (int id = 0; id < uidTimeInStat.second.size(); id++) {
175 if (mCoefficients.count(id)) {
176 int64_t d_time_in_state = uidTimeInStat.second.at(id);
177 if (mUidTimeInStateSS.count(uidTimeInStat.first)) {
178 d_time_in_state -= mUidTimeInStateSS.at(uidTimeInStat.first).at(id);
179 }
180 uidEnergyUWs += mCoefficients.at(id) * d_time_in_state;
181 }
182 }
183 totalRelativeEnergyUWs += uidEnergyUWs;
184
185 EnergyConsumerAttribution attr = {
186 .uid = uidTimeInStat.first,
187 .energyUWs = uidEnergyUWs,
188 };
189 attribution.emplace_back(attr);
190 }
191
192 int64_t d_totalEnergyUWs = totalEnergyUWs - mTotalEnergySS;
193 float powerScale = 0;
194 if (totalRelativeEnergyUWs != 0) {
195 powerScale = static_cast<float>(d_totalEnergyUWs) / totalRelativeEnergyUWs;
196 }
197 for (auto &attr : attribution) {
198 attr.energyUWs = (int64_t)(attr.energyUWs * powerScale) +
199 (mUidEnergySS.count(attr.uid) ? mUidEnergySS.at(attr.uid) : 0);
200 mUidEnergySS[attr.uid] = attr.energyUWs;
201 }
202
203 mUidTimeInStateSS = attrStats.uidTimeInStats;
204 mTotalEnergySS = totalEnergyUWs;
205 }
206 } else {
207 std::vector<StateResidencyResult> results;
208 if (mPowerStats->getStateResidency({mPowerEntityId}, &results).isOk()) {
209 for (const auto &s : results[0].stateResidencyData) {
210 if (mCoefficients.count(s.id)) {
211 totalEnergyUWs += mCoefficients.at(s.id) * s.totalTimeInStateMs;
212 }
213 }
214 } else {
215 LOG(ERROR) << "Failed to get state residency";
216 return {};
217 }
218 }
219 }
220
221 return EnergyConsumerResult{.timestampMs = timestampMs,
222 .energyUWs = totalEnergyUWs,
223 .attribution = attribution};
224 }
225
getConsumerName()226 std::string PowerStatsEnergyConsumer::getConsumerName() {
227 return kName;
228 }
229
230 } // namespace stats
231 } // namespace power
232 } // namespace hardware
233 } // namespace android
234 } // namespace aidl
235