xref: /aosp_15_r20/frameworks/av/media/psh_utils/PowerStats.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2024 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 #include <android-base/logging.h>
17 #include <audio_utils/clock.h>
18 #include <psh_utils/PowerStats.h>
19 
20 namespace android::media::psh_utils {
21 
22 // Determine the best start time from a and b, which is
23 // min(a, b) if both exist, otherwise the one that exists.
24 template <typename T>
choose_best_start_time(const T & a,const T & b)25 const T& choose_best_start_time(const T& a, const T& b) {
26     if (a) {
27         return b ? std::min(a, b) : a;
28     } else {
29         return b;
30     }
31 }
32 
33 // subtract two time differences.
34 template <typename T, typename U>
sub_time_diff(const T & diff_a,const T & diff_b,const U & abs_c,const U & abs_d)35 const T sub_time_diff(const T& diff_a, const T& diff_b, const U& abs_c, const U& abs_d) {
36     if (diff_a) {
37         return diff_b ? (diff_a - diff_b) : diff_a;
38     } else if (diff_b) {
39         return diff_b;
40     } else {  // no difference exists, use absolute time.
41         return abs_c - abs_d;
42     }
43 }
44 
toString() const45 std::string PowerStats::Metadata::toString() const {
46     return std::string("start_time_since_boot_ms: ").append(
47                     std::to_string(start_time_since_boot_ms))
48             .append(" start_time_monotonic_ms: ").append(std::to_string(start_time_monotonic_ms))
49             .append(audio_utils_time_string_from_ns(start_time_epoch_ms * 1'000'000).time)
50             .append(" duration_ms: ").append(std::to_string(duration_ms))
51             .append(" duration_monotonic_ms: ").append(std::to_string(duration_monotonic_ms));
52 }
53 
operator +=(const Metadata & other)54 PowerStats::Metadata PowerStats::Metadata::operator+=(const Metadata& other) {
55     start_time_since_boot_ms = choose_best_start_time(
56             start_time_since_boot_ms, other.start_time_since_boot_ms);
57     start_time_epoch_ms = choose_best_start_time(
58             start_time_epoch_ms, other.start_time_epoch_ms);
59     start_time_monotonic_ms = choose_best_start_time(
60             start_time_monotonic_ms, other.start_time_monotonic_ms);
61     duration_ms += other.duration_ms;
62     duration_monotonic_ms += other.duration_monotonic_ms;
63     return *this;
64 }
65 
operator -=(const Metadata & other)66 PowerStats::Metadata PowerStats::Metadata::operator-=(const Metadata& other) {
67     // here we calculate duration, if it makes sense.
68     duration_ms = sub_time_diff(duration_ms, other.duration_ms,
69                                 start_time_since_boot_ms, other.start_time_since_boot_ms);
70     duration_monotonic_ms = sub_time_diff(
71             duration_monotonic_ms, other.duration_monotonic_ms,
72             start_time_monotonic_ms, other.start_time_monotonic_ms);
73     start_time_since_boot_ms = choose_best_start_time(
74             start_time_since_boot_ms, other.start_time_since_boot_ms);
75     start_time_epoch_ms = choose_best_start_time(
76             start_time_epoch_ms, other.start_time_epoch_ms);
77     start_time_monotonic_ms = choose_best_start_time(
78             start_time_monotonic_ms, other.start_time_monotonic_ms);
79     return *this;
80 }
81 
operator +(const Metadata & other) const82 PowerStats::Metadata PowerStats::Metadata::operator+(const Metadata& other) const {
83     Metadata result = *this;
84     result += other;
85     return result;
86 }
87 
operator -(const Metadata & other) const88 PowerStats::Metadata PowerStats::Metadata::operator-(const Metadata& other) const {
89     Metadata result = *this;
90     result -= other;
91     return result;
92 }
93 
toString() const94 std::string PowerStats::StateResidency::toString() const {
95     return std::string(entity_name).append(state_name)
96             .append(" ").append(std::to_string(time_ms))
97             .append(" ").append(std::to_string(entry_count));
98 }
99 
operator +=(const StateResidency & other)100 PowerStats::StateResidency PowerStats::StateResidency::operator+=(const StateResidency& other) {
101     if (entity_name.empty()) entity_name = other.entity_name;
102     if (state_name.empty()) state_name = other.state_name;
103     time_ms += other.time_ms;
104     entry_count += other.entry_count;
105     return *this;
106 }
107 
operator -=(const StateResidency & other)108 PowerStats::StateResidency PowerStats::StateResidency::operator-=(const StateResidency& other) {
109     if (entity_name.empty()) entity_name = other.entity_name;
110     if (state_name.empty()) state_name = other.state_name;
111     time_ms -= other.time_ms;
112     entry_count -= other.entry_count;
113     return *this;
114 }
115 
operator +(const StateResidency & other) const116 PowerStats::StateResidency PowerStats::StateResidency::operator+(
117         const StateResidency& other) const {
118     StateResidency result = *this;
119     result += other;
120     return result;
121 }
122 
operator -(const StateResidency & other) const123 PowerStats::StateResidency PowerStats::StateResidency::operator-(
124         const StateResidency& other) const {
125     StateResidency result = *this;
126     result -= other;
127     return result;
128 }
129 
toString() const130 std::string PowerStats::RailEnergy::toString() const {
131     return std::string(subsystem_name)
132             .append(rail_name)
133             .append(" ")
134             .append(std::to_string(energy_uws));
135 }
136 
operator +=(const RailEnergy & other)137 PowerStats::RailEnergy PowerStats::RailEnergy::operator+=(const RailEnergy& other) {
138     if (subsystem_name.empty()) subsystem_name = other.subsystem_name;
139     if (rail_name.empty()) rail_name = other.rail_name;
140     energy_uws += other.energy_uws;
141     return *this;
142 }
143 
operator -=(const RailEnergy & other)144 PowerStats::RailEnergy PowerStats::RailEnergy::operator-=(const RailEnergy& other) {
145     if (subsystem_name.empty()) subsystem_name = other.subsystem_name;
146     if (rail_name.empty()) rail_name = other.rail_name;
147     energy_uws -= other.energy_uws;
148     return *this;
149 }
150 
operator +(const RailEnergy & other) const151 PowerStats::RailEnergy PowerStats::RailEnergy::operator+(const RailEnergy& other) const {
152     RailEnergy result = *this;
153     result += other;
154     return result;
155 }
156 
operator -(const RailEnergy & other) const157 PowerStats::RailEnergy PowerStats::RailEnergy::operator-(const RailEnergy& other) const {
158     RailEnergy result = *this;
159     result -= other;
160     return result;
161 }
162 
toString(const std::string & prefix) const163 std::string PowerStats::toString(const std::string& prefix) const {
164     std::string result;
165     result.append(prefix).append(metadata.toString()).append("\n");
166     result.append(prefix).append(health_stats.toString()).append("\n");
167     for (const auto &residency: power_entity_state_residency) {
168         result.append(prefix).append(residency.toString()).append("\n");
169     }
170     for (const auto &energy: rail_energy) {
171         result.append(prefix).append(energy.toString()).append("\n");
172     }
173     return result;
174 }
175 
normalizedEnergy(const std::string & prefix) const176 std::string PowerStats::normalizedEnergy(const std::string& prefix) const {
177     if (metadata.duration_ms == 0) return {};
178 
179     std::string result(prefix);
180     result.append(audio_utils_time_string_from_ns(
181             metadata.start_time_epoch_ms * 1'000'000).time);
182     result.append(" duration_boottime: ")
183             .append(std::to_string(metadata.duration_ms * 1e-3f))
184             .append(" duration_monotonic: ")
185             .append(std::to_string(metadata.duration_monotonic_ms * 1e-3f))
186             .append("\n");
187     if (health_stats.isValid()) {
188         result.append(prefix)
189                 .append(health_stats.normalizedEnergy(metadata.duration_ms * 1e-3f)).append("\n");
190     }
191 
192     // energy_uws is converted to ave W using recip time in us.
193     const float recipTime = 1e-3 / metadata.duration_ms;
194     int64_t total_energy = 0;
195     for (const auto& energy: rail_energy) {
196         total_energy += energy.energy_uws;
197         result.append(prefix).append(energy.subsystem_name)
198                 .append(energy.rail_name)
199                 .append(" ")
200                 .append(std::to_string(energy.energy_uws * 1e-6))
201                 .append(" ")
202                 .append(std::to_string(energy.energy_uws * recipTime))
203                 .append("\n");
204     }
205     if (total_energy != 0) {
206         result.append(prefix).append("total J and ave W: ")
207                 .append(std::to_string(total_energy * 1e-6))
208                 .append(" ")
209                 .append(std::to_string(total_energy * recipTime))
210                 .append("\n");
211     }
212     return result;
213 }
214 
215 // seconds, joules, watts
energyFrom(const std::string & railMatcher) const216 std::tuple<float, float, float> PowerStats::energyFrom(const std::string& railMatcher) const {
217     if (metadata.duration_ms == 0) return {};
218 
219     // energy_uws is converted to ave W using recip time in us.
220     const float recipTime = 1e-3 / metadata.duration_ms;
221     int64_t total_energy = 0;
222     for (const auto& energy: rail_energy) {
223         if (energy.subsystem_name.find(railMatcher) != std::string::npos
224                 || energy.rail_name.find(railMatcher) != std::string::npos) {
225             total_energy += energy.energy_uws;
226         }
227     }
228     return {metadata.duration_ms * 1e-3, total_energy * 1e-6, total_energy * recipTime};
229 }
230 
operator +=(const PowerStats & other)231 PowerStats PowerStats::operator+=(const PowerStats& other) {
232     metadata += other.metadata;
233     health_stats += other.health_stats;
234     if (power_entity_state_residency.empty()) {
235         power_entity_state_residency = other.power_entity_state_residency;
236     } else if (power_entity_state_residency.size() == other.power_entity_state_residency.size()) {
237         for (size_t i = 0; i < power_entity_state_residency.size(); ++i) {
238             power_entity_state_residency[i] += other.power_entity_state_residency[i];
239         }
240     }
241     if (rail_energy.empty()) {
242         rail_energy = other.rail_energy;
243     } else if (rail_energy.size() == other.rail_energy.size()) {
244         for (size_t i = 0; i < rail_energy.size(); ++i) {
245             rail_energy[i] += other.rail_energy[i];
246         }
247     }
248     return *this;
249 }
250 
operator -=(const PowerStats & other)251 PowerStats PowerStats::operator-=(const PowerStats& other) {
252     metadata -= other.metadata;
253     health_stats -= other.health_stats;
254     if (power_entity_state_residency.empty()) {
255         power_entity_state_residency = other.power_entity_state_residency;
256     } else if (power_entity_state_residency.size() == other.power_entity_state_residency.size()) {
257         for (size_t i = 0; i < power_entity_state_residency.size(); ++i) {
258             power_entity_state_residency[i] -= other.power_entity_state_residency[i];
259         }
260     }
261     if (rail_energy.empty()) {
262         rail_energy = other.rail_energy;
263     } else if (rail_energy.size() == other.rail_energy.size()) {
264         for (size_t i = 0; i < rail_energy.size(); ++i) {
265             rail_energy[i] -= other.rail_energy[i];
266         }
267     }
268     return *this;
269 }
270 
operator +(const PowerStats & other) const271 PowerStats PowerStats::operator+(const PowerStats& other) const {
272     PowerStats result = *this;
273     result += other;
274     return result;
275 }
276 
operator -(const PowerStats & other) const277 PowerStats PowerStats::operator-(const PowerStats& other) const {
278     PowerStats result = *this;
279     result -= other;
280     return result;
281 }
282 
283 } // namespace android::media::psh_utils
284