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.uidTimeInStats.empty() || attrStats.uidTimeInStateNames.empty()) {
123 LOG(ERROR) << "Missing 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) << "Missing uid_time_in_state";
170 return {};
171 }
172
173 int64_t totalRelativeEnergyUWs = 0;
174 for (const auto &uidTimeInStat : attrStats.uidTimeInStats) {
175 int64_t uidEnergyUWs = 0;
176 for (int id = 0; id < uidTimeInStat.second.size(); id++) {
177 if (mCoefficients.count(id)) {
178 int64_t d_time_in_state = uidTimeInStat.second.at(id);
179 if (mUidTimeInStateSS.count(uidTimeInStat.first)) {
180 d_time_in_state -= mUidTimeInStateSS.at(uidTimeInStat.first).at(id);
181 }
182 uidEnergyUWs += mCoefficients.at(id) * d_time_in_state;
183 }
184 }
185 totalRelativeEnergyUWs += uidEnergyUWs;
186
187 EnergyConsumerAttribution attr = {
188 .uid = uidTimeInStat.first,
189 .energyUWs = uidEnergyUWs,
190 };
191 attribution.emplace_back(attr);
192 }
193
194 int64_t d_totalEnergyUWs = totalEnergyUWs - mTotalEnergySS;
195 float powerScale = 0;
196 if (totalRelativeEnergyUWs != 0) {
197 powerScale = static_cast<float>(d_totalEnergyUWs) / totalRelativeEnergyUWs;
198 }
199 for (auto &attr : attribution) {
200 attr.energyUWs = (int64_t)(attr.energyUWs * powerScale) +
201 (mUidEnergySS.count(attr.uid) ? mUidEnergySS.at(attr.uid) : 0);
202 mUidEnergySS[attr.uid] = attr.energyUWs;
203 }
204
205 mUidTimeInStateSS = attrStats.uidTimeInStats;
206 mTotalEnergySS = totalEnergyUWs;
207 } else {
208 std::vector<StateResidencyResult> results;
209 if (mPowerStats->getStateResidency({mPowerEntityId}, &results).isOk()) {
210 for (const auto &s : results[0].stateResidencyData) {
211 if (mCoefficients.count(s.id)) {
212 totalEnergyUWs += mCoefficients.at(s.id) * s.totalTimeInStateMs;
213 }
214 }
215 } else {
216 LOG(ERROR) << "Failed to get state residency";
217 return {};
218 }
219 }
220 }
221
222 return EnergyConsumerResult{.timestampMs = timestampMs,
223 .energyUWs = totalEnergyUWs,
224 .attribution = attribution};
225 }
226
getConsumerName()227 std::string PowerStatsEnergyConsumer::getConsumerName() {
228 return kName;
229 }
230
231 } // namespace stats
232 } // namespace power
233 } // namespace hardware
234 } // namespace android
235 } // namespace aidl
236