xref: /aosp_15_r20/frameworks/av/media/psh_utils/PowerStatsProvider.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #include "PowerStatsProvider.h"
18*ec779b8eSAndroid Build Coastguard Worker #include <android/hardware/power/stats/IPowerStats.h>
19*ec779b8eSAndroid Build Coastguard Worker #include <android-base/logging.h>
20*ec779b8eSAndroid Build Coastguard Worker #include <mediautils/ServiceSingleton.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <unordered_map>
22*ec779b8eSAndroid Build Coastguard Worker 
23*ec779b8eSAndroid Build Coastguard Worker using ::android::hardware::power::stats::IPowerStats;
24*ec779b8eSAndroid Build Coastguard Worker 
25*ec779b8eSAndroid Build Coastguard Worker namespace android::media::psh_utils {
26*ec779b8eSAndroid Build Coastguard Worker 
getPowerStatsService()27*ec779b8eSAndroid Build Coastguard Worker static auto getPowerStatsService() {
28*ec779b8eSAndroid Build Coastguard Worker     return mediautils::getService<IPowerStats>();
29*ec779b8eSAndroid Build Coastguard Worker }
30*ec779b8eSAndroid Build Coastguard Worker 
fill(PowerStats * stat) const31*ec779b8eSAndroid Build Coastguard Worker status_t RailEnergyDataProvider::fill(PowerStats *stat) const {
32*ec779b8eSAndroid Build Coastguard Worker     if (stat == nullptr) return BAD_VALUE;
33*ec779b8eSAndroid Build Coastguard Worker     auto powerStatsService = getPowerStatsService();
34*ec779b8eSAndroid Build Coastguard Worker     if (powerStatsService == nullptr) {
35*ec779b8eSAndroid Build Coastguard Worker         return NO_INIT;
36*ec779b8eSAndroid Build Coastguard Worker     }
37*ec779b8eSAndroid Build Coastguard Worker 
38*ec779b8eSAndroid Build Coastguard Worker     std::unordered_map<int32_t, ::android::hardware::power::stats::Channel> channelMap;
39*ec779b8eSAndroid Build Coastguard Worker     {
40*ec779b8eSAndroid Build Coastguard Worker         std::vector<::android::hardware::power::stats::Channel> channels;
41*ec779b8eSAndroid Build Coastguard Worker         if (!powerStatsService->getEnergyMeterInfo(&channels).isOk()) {
42*ec779b8eSAndroid Build Coastguard Worker             LOG(ERROR) << "unable to get energy meter info";
43*ec779b8eSAndroid Build Coastguard Worker             return INVALID_OPERATION;
44*ec779b8eSAndroid Build Coastguard Worker         }
45*ec779b8eSAndroid Build Coastguard Worker         for (auto& channel : channels) {
46*ec779b8eSAndroid Build Coastguard Worker           channelMap.emplace(channel.id, std::move(channel));
47*ec779b8eSAndroid Build Coastguard Worker         }
48*ec779b8eSAndroid Build Coastguard Worker     }
49*ec779b8eSAndroid Build Coastguard Worker 
50*ec779b8eSAndroid Build Coastguard Worker     std::vector<::android::hardware::power::stats::EnergyMeasurement> measurements;
51*ec779b8eSAndroid Build Coastguard Worker     if (!powerStatsService->readEnergyMeter({}, &measurements).isOk()) {
52*ec779b8eSAndroid Build Coastguard Worker         LOG(ERROR) << "unable to get energy measurements";
53*ec779b8eSAndroid Build Coastguard Worker         return INVALID_OPERATION;
54*ec779b8eSAndroid Build Coastguard Worker     }
55*ec779b8eSAndroid Build Coastguard Worker 
56*ec779b8eSAndroid Build Coastguard Worker     for (const auto& measurement : measurements) {
57*ec779b8eSAndroid Build Coastguard Worker         stat->rail_energy.emplace_back(
58*ec779b8eSAndroid Build Coastguard Worker             channelMap.at(measurement.id).subsystem,
59*ec779b8eSAndroid Build Coastguard Worker             channelMap.at(measurement.id).name,
60*ec779b8eSAndroid Build Coastguard Worker             measurement.energyUWs);
61*ec779b8eSAndroid Build Coastguard Worker     }
62*ec779b8eSAndroid Build Coastguard Worker 
63*ec779b8eSAndroid Build Coastguard Worker     // Sort entries first by subsystem_name, then by rail_name.
64*ec779b8eSAndroid Build Coastguard Worker     // Sorting is needed to make interval processing efficient.
65*ec779b8eSAndroid Build Coastguard Worker     std::sort(stat->rail_energy.begin(), stat->rail_energy.end(),
66*ec779b8eSAndroid Build Coastguard Worker               [](const auto& a, const auto& b) {
67*ec779b8eSAndroid Build Coastguard Worker                   if (a.subsystem_name != b.subsystem_name) {
68*ec779b8eSAndroid Build Coastguard Worker                       return a.subsystem_name < b.subsystem_name;
69*ec779b8eSAndroid Build Coastguard Worker                   }
70*ec779b8eSAndroid Build Coastguard Worker                   return a.rail_name < b.rail_name;
71*ec779b8eSAndroid Build Coastguard Worker               });
72*ec779b8eSAndroid Build Coastguard Worker 
73*ec779b8eSAndroid Build Coastguard Worker     return NO_ERROR;
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker 
fill(PowerStats * stat) const76*ec779b8eSAndroid Build Coastguard Worker status_t PowerEntityResidencyDataProvider::fill(PowerStats* stat) const {
77*ec779b8eSAndroid Build Coastguard Worker     if (stat == nullptr) return BAD_VALUE;
78*ec779b8eSAndroid Build Coastguard Worker     auto powerStatsService = getPowerStatsService();
79*ec779b8eSAndroid Build Coastguard Worker     if (powerStatsService == nullptr) {
80*ec779b8eSAndroid Build Coastguard Worker         return NO_INIT;
81*ec779b8eSAndroid Build Coastguard Worker     }
82*ec779b8eSAndroid Build Coastguard Worker 
83*ec779b8eSAndroid Build Coastguard Worker     // these are based on entityId
84*ec779b8eSAndroid Build Coastguard Worker     std::unordered_map<int32_t, std::string> entityNames;
85*ec779b8eSAndroid Build Coastguard Worker     std::unordered_map<int32_t, std::unordered_map<int32_t, std::string>> stateNames;
86*ec779b8eSAndroid Build Coastguard Worker     std::vector<int32_t> powerEntityIds; // ids to use
87*ec779b8eSAndroid Build Coastguard Worker 
88*ec779b8eSAndroid Build Coastguard Worker     {
89*ec779b8eSAndroid Build Coastguard Worker         std::vector<::android::hardware::power::stats::PowerEntity> entities;
90*ec779b8eSAndroid Build Coastguard Worker         if (!powerStatsService->getPowerEntityInfo(&entities).isOk()) {
91*ec779b8eSAndroid Build Coastguard Worker             LOG(ERROR) << __func__ << ": unable to get entity info";
92*ec779b8eSAndroid Build Coastguard Worker             return INVALID_OPERATION;
93*ec779b8eSAndroid Build Coastguard Worker         }
94*ec779b8eSAndroid Build Coastguard Worker 
95*ec779b8eSAndroid Build Coastguard Worker         std::vector<std::string> powerEntityNames;
96*ec779b8eSAndroid Build Coastguard Worker         for (const auto& entity : entities) {
97*ec779b8eSAndroid Build Coastguard Worker             std::unordered_map<int32_t, std::string> states;
98*ec779b8eSAndroid Build Coastguard Worker             for (const auto& state : entity.states) {
99*ec779b8eSAndroid Build Coastguard Worker                 states.emplace(state.id, state.name);
100*ec779b8eSAndroid Build Coastguard Worker             }
101*ec779b8eSAndroid Build Coastguard Worker 
102*ec779b8eSAndroid Build Coastguard Worker             if (std::find(powerEntityNames.begin(), powerEntityNames.end(), entity.name) !=
103*ec779b8eSAndroid Build Coastguard Worker                 powerEntityNames.end()) {
104*ec779b8eSAndroid Build Coastguard Worker                 powerEntityIds.emplace_back(entity.id);
105*ec779b8eSAndroid Build Coastguard Worker             }
106*ec779b8eSAndroid Build Coastguard Worker             entityNames.emplace(entity.id, std::move(entity.name));
107*ec779b8eSAndroid Build Coastguard Worker             stateNames.emplace(entity.id, std::move(states));
108*ec779b8eSAndroid Build Coastguard Worker         }
109*ec779b8eSAndroid Build Coastguard Worker     }
110*ec779b8eSAndroid Build Coastguard Worker 
111*ec779b8eSAndroid Build Coastguard Worker     std::vector<::android::hardware::power::stats::StateResidencyResult> results;
112*ec779b8eSAndroid Build Coastguard Worker     if (!powerStatsService->getStateResidency(powerEntityIds, &results).isOk()) {
113*ec779b8eSAndroid Build Coastguard Worker         LOG(ERROR) << __func__ << ": Unable to get state residency";
114*ec779b8eSAndroid Build Coastguard Worker         return INVALID_OPERATION;
115*ec779b8eSAndroid Build Coastguard Worker     }
116*ec779b8eSAndroid Build Coastguard Worker 
117*ec779b8eSAndroid Build Coastguard Worker     for (const auto& result : results) {
118*ec779b8eSAndroid Build Coastguard Worker         for (const auto& curStateResidency : result.stateResidencyData) {
119*ec779b8eSAndroid Build Coastguard Worker           stat->power_entity_state_residency.emplace_back(
120*ec779b8eSAndroid Build Coastguard Worker               entityNames.at(result.id),
121*ec779b8eSAndroid Build Coastguard Worker               stateNames.at(result.id).at(curStateResidency.id),
122*ec779b8eSAndroid Build Coastguard Worker               static_cast<uint64_t>(curStateResidency.totalTimeInStateMs),
123*ec779b8eSAndroid Build Coastguard Worker               static_cast<uint64_t>(curStateResidency.totalStateEntryCount));
124*ec779b8eSAndroid Build Coastguard Worker         }
125*ec779b8eSAndroid Build Coastguard Worker     }
126*ec779b8eSAndroid Build Coastguard Worker 
127*ec779b8eSAndroid Build Coastguard Worker     // Sort entries first by entity_name, then by state_name.
128*ec779b8eSAndroid Build Coastguard Worker     // Sorting is needed to make interval processing efficient.
129*ec779b8eSAndroid Build Coastguard Worker     std::sort(stat->power_entity_state_residency.begin(),
130*ec779b8eSAndroid Build Coastguard Worker               stat->power_entity_state_residency.end(),
131*ec779b8eSAndroid Build Coastguard Worker               [](const auto& a, const auto& b) {
132*ec779b8eSAndroid Build Coastguard Worker                   if (a.entity_name != b.entity_name) {
133*ec779b8eSAndroid Build Coastguard Worker                       return a.entity_name < b.entity_name;
134*ec779b8eSAndroid Build Coastguard Worker                   }
135*ec779b8eSAndroid Build Coastguard Worker                   return a.state_name < b.state_name;
136*ec779b8eSAndroid Build Coastguard Worker               });
137*ec779b8eSAndroid Build Coastguard Worker     return NO_ERROR;
138*ec779b8eSAndroid Build Coastguard Worker }
139*ec779b8eSAndroid Build Coastguard Worker 
140*ec779b8eSAndroid Build Coastguard Worker } // namespace android::media::psh_utils
141