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