• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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