• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 #define ATRACE_TAG (ATRACE_TAG_THERMAL | ATRACE_TAG_HAL)
17 
18 #include "thermal_throttling.h"
19 
20 #include <android-base/file.h>
21 #include <android-base/logging.h>
22 #include <android-base/properties.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25 #include <utils/Trace.h>
26 
27 #include <iterator>
28 #include <set>
29 #include <sstream>
30 #include <thread>
31 #include <vector>
32 
33 #include "power_files.h"
34 #include "thermal_info.h"
35 
36 namespace aidl {
37 namespace android {
38 namespace hardware {
39 namespace thermal {
40 namespace implementation {
41 using ::android::base::StringPrintf;
42 
43 // To find the next PID target state according to the current thermal severity
getTargetStateOfPID(const SensorInfo & sensor_info,const ThrottlingSeverity curr_severity)44 size_t getTargetStateOfPID(const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity) {
45     size_t target_state = 0;
46 
47     for (const auto &severity : ::ndk::enum_range<ThrottlingSeverity>()) {
48         size_t state = static_cast<size_t>(severity);
49         if (std::isnan(sensor_info.throttling_info->s_power[state])) {
50             continue;
51         }
52         target_state = state;
53         if (severity > curr_severity) {
54             break;
55         }
56     }
57     LOG(VERBOSE) << "PID target state = " << target_state;
58     return target_state;
59 }
60 
parseProfileProperty(std::string_view sensor_name,const SensorInfo & sensor_info)61 void ThermalThrottling::parseProfileProperty(std::string_view sensor_name,
62                                              const SensorInfo &sensor_info) {
63     if (sensor_info.throttling_info == nullptr) {
64         return;
65     }
66 
67     const std::string profile = ::android::base::GetProperty(
68             StringPrintf("vendor.thermal.%s.profile", sensor_name.data()), "");
69 
70     if (profile.empty() || sensor_info.throttling_info->profile_map.count(profile)) {
71         if (profile != thermal_throttling_status_map_[sensor_name.data()].profile) {
72             LOG(INFO) << sensor_name.data() << ": throttling profile change to "
73                       << ((profile.empty()) ? "default" : profile);
74             thermal_throttling_status_map_[sensor_name.data()].profile = profile;
75         }
76     } else {
77         LOG(ERROR) << sensor_name.data() << ": set profile to default because " << profile
78                    << " is invalid";
79         thermal_throttling_status_map_[sensor_name.data()].profile = "";
80     }
81 }
82 
clearThrottlingData(std::string_view sensor_name)83 void ThermalThrottling::clearThrottlingData(std::string_view sensor_name) {
84     if (!thermal_throttling_status_map_.count(sensor_name.data())) {
85         return;
86     }
87     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
88 
89     for (auto &pid_power_budget_pair :
90          thermal_throttling_status_map_.at(sensor_name.data()).pid_power_budget_map) {
91         pid_power_budget_pair.second = std::numeric_limits<int>::max();
92     }
93 
94     for (auto &pid_cdev_request_pair :
95          thermal_throttling_status_map_.at(sensor_name.data()).pid_cdev_request_map) {
96         pid_cdev_request_pair.second = 0;
97     }
98 
99     for (auto &hardlimit_cdev_request_pair :
100          thermal_throttling_status_map_.at(sensor_name.data()).hardlimit_cdev_request_map) {
101         hardlimit_cdev_request_pair.second = 0;
102     }
103 
104     for (auto &throttling_release_pair :
105          thermal_throttling_status_map_.at(sensor_name.data()).throttling_release_map) {
106         throttling_release_pair.second = 0;
107     }
108 
109     thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
110     thermal_throttling_status_map_[sensor_name.data()].i_budget = NAN;
111     thermal_throttling_status_map_[sensor_name.data()].prev_target =
112             static_cast<size_t>(ThrottlingSeverity::NONE);
113     thermal_throttling_status_map_[sensor_name.data()].prev_power_budget = NAN;
114     thermal_throttling_status_map_[sensor_name.data()].tran_cycle = 0;
115 
116     return;
117 }
118 
registerThermalThrottling(std::string_view sensor_name,const std::shared_ptr<ThrottlingInfo> & throttling_info,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map)119 bool ThermalThrottling::registerThermalThrottling(
120         std::string_view sensor_name, const std::shared_ptr<ThrottlingInfo> &throttling_info,
121         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
122     if (thermal_throttling_status_map_.count(sensor_name.data())) {
123         LOG(ERROR) << "Sensor " << sensor_name.data() << " throttling map has been registered";
124         return false;
125     }
126 
127     if (throttling_info == nullptr) {
128         LOG(ERROR) << "Sensor " << sensor_name.data() << " has no throttling info";
129         return false;
130     }
131 
132     thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
133     thermal_throttling_status_map_[sensor_name.data()].i_budget = NAN;
134     thermal_throttling_status_map_[sensor_name.data()].prev_target =
135             static_cast<size_t>(ThrottlingSeverity::NONE);
136     thermal_throttling_status_map_[sensor_name.data()].prev_power_budget = NAN;
137     thermal_throttling_status_map_[sensor_name.data()].tran_cycle = 0;
138     thermal_throttling_status_map_[sensor_name.data()].profile = "";
139 
140     for (auto &binded_cdev_pair : throttling_info->binded_cdev_info_map) {
141         if (!cooling_device_info_map.count(binded_cdev_pair.first)) {
142             LOG(ERROR) << "Could not find " << sensor_name.data() << "'s binded CDEV "
143                        << binded_cdev_pair.first;
144             return false;
145         }
146         // Register PID throttling map
147         for (const auto &cdev_weight : binded_cdev_pair.second.cdev_weight_for_pid) {
148             if (!std::isnan(cdev_weight)) {
149                 thermal_throttling_status_map_[sensor_name.data()]
150                         .pid_power_budget_map[binded_cdev_pair.first] =
151                         std::numeric_limits<int>::max();
152                 thermal_throttling_status_map_[sensor_name.data()]
153                         .pid_cdev_request_map[binded_cdev_pair.first] = 0;
154                 thermal_throttling_status_map_[sensor_name.data()]
155                         .cdev_status_map[binded_cdev_pair.first] = 0;
156                 cdev_all_request_map_[binded_cdev_pair.first].insert(0);
157                 break;
158             }
159         }
160         // Register hard limit throttling map
161         for (const auto &limit_info : binded_cdev_pair.second.limit_info) {
162             if (limit_info > 0) {
163                 thermal_throttling_status_map_[sensor_name.data()]
164                         .hardlimit_cdev_request_map[binded_cdev_pair.first] = 0;
165                 thermal_throttling_status_map_[sensor_name.data()]
166                         .cdev_status_map[binded_cdev_pair.first] = 0;
167                 cdev_all_request_map_[binded_cdev_pair.first].insert(0);
168                 break;
169             }
170         }
171         // Register throttling release map if power threshold exists
172         if (!binded_cdev_pair.second.power_rail.empty()) {
173             for (const auto &power_threshold : binded_cdev_pair.second.power_thresholds) {
174                 if (!std::isnan(power_threshold)) {
175                     thermal_throttling_status_map_[sensor_name.data()]
176                             .throttling_release_map[binded_cdev_pair.first] = 0;
177                     break;
178                 }
179             }
180         }
181     }
182     return true;
183 }
184 
185 // return power budget based on PID algo
updatePowerBudget(const Temperature & temp,const SensorInfo & sensor_info,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map,std::chrono::milliseconds time_elapsed_ms,ThrottlingSeverity curr_severity,const bool max_throttling,const std::unordered_map<std::string,PowerStatus> & power_status_map,const std::vector<float> & sensor_predictions)186 float ThermalThrottling::updatePowerBudget(
187         const Temperature &temp, const SensorInfo &sensor_info,
188         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map,
189         std::chrono::milliseconds time_elapsed_ms, ThrottlingSeverity curr_severity,
190         const bool max_throttling,
191         const std::unordered_map<std::string, PowerStatus> &power_status_map,
192         const std::vector<float> &sensor_predictions) {
193     float p = 0, d = 0;
194     float power_budget = std::numeric_limits<float>::max();
195     bool target_changed = false;
196     bool is_fully_throttle = true;
197     bool is_fully_release = true;
198     float budget_transient = 0.0;
199     auto &throttling_status = thermal_throttling_status_map_.at(temp.name);
200     const auto &profile = throttling_status.profile;
201     std::string sensor_name = temp.name;
202 
203     if (curr_severity == ThrottlingSeverity::NONE) {
204         return power_budget;
205     }
206 
207     // Go through the binded cdev, check current throttle status
208     for (const auto &binded_cdev_info_pair :
209          ((sensor_info.throttling_info->profile_map.empty() ||
210            !sensor_info.throttling_info->profile_map.contains(profile))
211                   ? sensor_info.throttling_info->binded_cdev_info_map
212                   : sensor_info.throttling_info->profile_map.at(profile))) {
213         if (throttling_status.pid_cdev_request_map.at(binded_cdev_info_pair.first) >
214             binded_cdev_info_pair.second.limit_info[static_cast<size_t>(curr_severity)]) {
215             is_fully_release = false;
216         }
217         if (throttling_status.pid_cdev_request_map.at(binded_cdev_info_pair.first) <
218             binded_cdev_info_pair.second.cdev_ceiling[static_cast<size_t>(curr_severity)]) {
219             is_fully_throttle = false;
220         }
221     }
222 
223     const auto target_state = getTargetStateOfPID(sensor_info, curr_severity);
224     if (throttling_status.prev_target != static_cast<size_t>(ThrottlingSeverity::NONE) &&
225         target_state != throttling_status.prev_target &&
226         sensor_info.throttling_info->tran_cycle > 0) {
227         throttling_status.tran_cycle = sensor_info.throttling_info->tran_cycle - 1;
228         target_changed = true;
229     }
230     throttling_status.prev_target = target_state;
231 
232     // Compute PID
233     float target = sensor_info.hot_thresholds[target_state];
234     float err = target - temp.value;
235 
236     if (max_throttling && err <= 0) {
237         return sensor_info.throttling_info->min_alloc_power[target_state];
238     }
239 
240     // Calculate P budget
241     p = err * (err < 0 ? sensor_info.throttling_info->k_po[target_state]
242                        : sensor_info.throttling_info->k_pu[target_state]);
243 
244     // Calculate I budget
245     if (std::isnan(throttling_status.i_budget)) {
246         if (std::isnan(sensor_info.throttling_info->i_default_pct)) {
247             throttling_status.i_budget = sensor_info.throttling_info->i_default;
248         } else {
249             float default_i_budget = 0.0;
250             for (const auto &binded_cdev_info_pair :
251                  sensor_info.throttling_info->binded_cdev_info_map) {
252                 int max_cdev_vote;
253                 const CdevInfo &cdev_info = cooling_device_info_map.at(binded_cdev_info_pair.first);
254                 max_cdev_vote = getCdevMaxRequest(binded_cdev_info_pair.first, &max_cdev_vote);
255                 default_i_budget += cdev_info.state2power[max_cdev_vote];
256             }
257             throttling_status.i_budget =
258                     default_i_budget * sensor_info.throttling_info->i_default_pct / 100;
259         }
260     }
261 
262     if (err < sensor_info.throttling_info->i_cutoff[target_state]) {
263         if (err < 0 &&
264             throttling_status.prev_power_budget >
265                     sensor_info.throttling_info->min_alloc_power[target_state] &&
266             !is_fully_throttle) {
267             throttling_status.i_budget += err * sensor_info.throttling_info->k_io[target_state];
268         } else if (err > 0 &&
269                    throttling_status.prev_power_budget <
270                            sensor_info.throttling_info->max_alloc_power[target_state] &&
271                    !is_fully_release) {
272             throttling_status.i_budget += err * sensor_info.throttling_info->k_iu[target_state];
273         }
274     }
275 
276     if (fabsf(throttling_status.i_budget) > sensor_info.throttling_info->i_max[target_state]) {
277         throttling_status.i_budget = sensor_info.throttling_info->i_max[target_state] *
278                                      (throttling_status.i_budget > 0 ? 1 : -1);
279     }
280 
281     // Calculate D budget
282     if (!std::isnan(throttling_status.prev_err) &&
283         time_elapsed_ms != std::chrono::milliseconds::zero()) {
284         d = sensor_info.throttling_info->k_d[target_state] * (err - throttling_status.prev_err) /
285             time_elapsed_ms.count();
286     }
287 
288     // Compute Compensation
289     float compensation = 0;
290     if (sensor_info.predictor_info != nullptr &&
291         sensor_info.predictor_info->support_pid_compensation) {
292         const std::vector<float> &prediction_weights =
293                 sensor_info.predictor_info->prediction_weights;
294         for (size_t i = 0; i < sensor_predictions.size(); ++i) {
295             float prediction_err = target - (sensor_predictions[i] * sensor_info.multiplier);
296             compensation += prediction_weights[i] * prediction_err;
297         }
298         // apply weight based on current severity level
299         compensation *= sensor_info.predictor_info->k_p_compensate[target_state];
300     }
301 
302     // Compute Exclude Powerbudget
303     std::string log_buf;
304     float excludepower = 0;
305     if (sensor_info.throttling_info->excluded_power_info_map.size()) {
306         excludepower = computeExcludedPower(sensor_info, curr_severity, power_status_map, &log_buf,
307                                             sensor_name);
308     }
309 
310     throttling_status.prev_err = err;
311     // Calculate power budget
312     power_budget = sensor_info.throttling_info->s_power[target_state] + p +
313                    throttling_status.i_budget + d + compensation - excludepower;
314 
315     power_budget =
316             std::clamp(power_budget, sensor_info.throttling_info->min_alloc_power[target_state],
317                        sensor_info.throttling_info->max_alloc_power[target_state]);
318 
319     if (target_changed) {
320         throttling_status.budget_transient = throttling_status.prev_power_budget - power_budget;
321     }
322 
323     if (throttling_status.tran_cycle) {
324         budget_transient = throttling_status.budget_transient *
325                            ((static_cast<float>(throttling_status.tran_cycle) /
326                              static_cast<float>(sensor_info.throttling_info->tran_cycle)));
327         power_budget += budget_transient;
328         throttling_status.tran_cycle--;
329     }
330 
331     LOG(INFO) << temp.name << " power_budget=" << power_budget << " err=" << err
332               << " s_power=" << sensor_info.throttling_info->s_power[target_state]
333               << " time_elapsed_ms=" << time_elapsed_ms.count() << " p=" << p
334               << " i=" << throttling_status.i_budget << " d=" << d
335               << " compensation=" << compensation << " budget transient=" << budget_transient
336               << " control target=" << target_state << " excluded power budget=" << excludepower
337               << log_buf;
338 
339     ATRACE_INT((sensor_name + std::string("-power_budget")).c_str(),
340                static_cast<int>(power_budget));
341     ATRACE_INT((sensor_name + std::string("-s_power")).c_str(),
342                static_cast<int>(sensor_info.throttling_info->s_power[target_state]));
343     ATRACE_INT((sensor_name + std::string("-time_elapsed_ms")).c_str(),
344                static_cast<int>(time_elapsed_ms.count()));
345     ATRACE_INT((sensor_name + std::string("-budget_transient")).c_str(),
346                static_cast<int>(budget_transient));
347     ATRACE_INT((sensor_name + std::string("-i")).c_str(),
348                static_cast<int>(throttling_status.i_budget));
349     ATRACE_INT((sensor_name + std::string("-target_state")).c_str(),
350                static_cast<int>(target_state));
351 
352     ATRACE_INT((sensor_name + std::string("-err")).c_str(),
353                static_cast<int>(err / sensor_info.multiplier));
354     ATRACE_INT((sensor_name + std::string("-p")).c_str(), static_cast<int>(p));
355     ATRACE_INT((sensor_name + std::string("-d")).c_str(), static_cast<int>(d));
356     ATRACE_INT((sensor_name + std::string("-predict_compensation")).c_str(),
357                static_cast<int>(compensation));
358     ATRACE_INT((sensor_name + std::string("-excluded_power_budget")).c_str(),
359                static_cast<int>(excludepower));
360     ATRACE_INT((sensor_name + std::string("-temp")).c_str(),
361                static_cast<int>(temp.value / sensor_info.multiplier));
362 
363     throttling_status.prev_power_budget = power_budget;
364 
365     return power_budget;
366 }
367 
computeExcludedPower(const SensorInfo & sensor_info,const ThrottlingSeverity curr_severity,const std::unordered_map<std::string,PowerStatus> & power_status_map,std::string * log_buf,std::string_view sensor_name)368 float ThermalThrottling::computeExcludedPower(
369         const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity,
370         const std::unordered_map<std::string, PowerStatus> &power_status_map, std::string *log_buf,
371         std::string_view sensor_name) {
372     float excluded_power = 0.0;
373 
374     for (const auto &excluded_power_info_pair :
375          sensor_info.throttling_info->excluded_power_info_map) {
376         const auto last_updated_avg_power =
377                 power_status_map.at(excluded_power_info_pair.first).last_updated_avg_power;
378         if (!std::isnan(last_updated_avg_power)) {
379             excluded_power += last_updated_avg_power *
380                               excluded_power_info_pair.second[static_cast<size_t>(curr_severity)];
381             log_buf->append(StringPrintf(
382                     " (%s: %0.2f mW, cdev_weight: %f)", excluded_power_info_pair.first.c_str(),
383                     last_updated_avg_power,
384                     excluded_power_info_pair.second[static_cast<size_t>(curr_severity)]));
385 
386             ATRACE_INT((std::string(sensor_name) + std::string("-") +
387                         excluded_power_info_pair.first + std::string("-avg_power"))
388                                .c_str(),
389                        static_cast<int>(last_updated_avg_power));
390         }
391     }
392 
393     ATRACE_INT((std::string(sensor_name) + std::string("-excluded_power")).c_str(),
394                static_cast<int>(excluded_power));
395     return excluded_power;
396 }
397 
398 // Allocate power budget to binded cooling devices base on the real ODPM power data
allocatePowerToCdev(const Temperature & temp,const SensorInfo & sensor_info,const ThrottlingSeverity curr_severity,const std::chrono::milliseconds time_elapsed_ms,const std::unordered_map<std::string,PowerStatus> & power_status_map,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map,const bool max_throttling,const std::vector<float> & sensor_predictions)399 bool ThermalThrottling::allocatePowerToCdev(
400         const Temperature &temp, const SensorInfo &sensor_info,
401         const ThrottlingSeverity curr_severity, const std::chrono::milliseconds time_elapsed_ms,
402         const std::unordered_map<std::string, PowerStatus> &power_status_map,
403         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map,
404         const bool max_throttling, const std::vector<float> &sensor_predictions) {
405     float total_weight = 0;
406     float last_updated_avg_power = NAN;
407     float allocated_power = 0;
408     float allocated_weight = 0;
409     bool low_power_device_check = true;
410     bool is_budget_allocated = false;
411     bool power_data_invalid = false;
412     std::set<std::string> allocated_cdev;
413     std::string log_buf;
414 
415     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
416     auto total_power_budget =
417             updatePowerBudget(temp, sensor_info, cooling_device_info_map, time_elapsed_ms,
418                               curr_severity, max_throttling, power_status_map, sensor_predictions);
419     const auto &profile = thermal_throttling_status_map_[temp.name].profile;
420 
421     // Go through binded cdev, compute total cdev weight
422     for (const auto &binded_cdev_info_pair :
423          (sensor_info.throttling_info->profile_map.count(profile)
424                   ? sensor_info.throttling_info->profile_map.at(profile)
425                   : sensor_info.throttling_info->binded_cdev_info_map)) {
426         const auto cdev_weight = binded_cdev_info_pair.second
427                                          .cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
428         if (!binded_cdev_info_pair.second.enabled) {
429             continue;
430         } else if (std::isnan(cdev_weight) || cdev_weight == 0) {
431             allocated_cdev.insert(binded_cdev_info_pair.first);
432             continue;
433         }
434         total_weight += cdev_weight;
435     }
436 
437     while (!is_budget_allocated) {
438         for (const auto &binded_cdev_info_pair :
439              (sensor_info.throttling_info->profile_map.count(profile)
440                       ? sensor_info.throttling_info->profile_map.at(profile)
441                       : sensor_info.throttling_info->binded_cdev_info_map)) {
442             float cdev_power_adjustment = 0;
443             const auto cdev_weight =
444                     binded_cdev_info_pair.second
445                             .cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
446 
447             if (allocated_cdev.count(binded_cdev_info_pair.first)) {
448                 continue;
449             }
450 
451             // Get the power data
452             if (!power_data_invalid) {
453                 if (!binded_cdev_info_pair.second.power_rail.empty()) {
454                     last_updated_avg_power =
455                             power_status_map.at(binded_cdev_info_pair.second.power_rail)
456                                     .last_updated_avg_power;
457                     if (std::isnan(last_updated_avg_power)) {
458                         LOG(VERBOSE) << "power data is under collecting";
459                         power_data_invalid = true;
460                         break;
461                     }
462 
463                     ATRACE_INT((temp.name + std::string("-") +
464                                 binded_cdev_info_pair.second.power_rail + std::string("-avg_power"))
465                                        .c_str(),
466                                static_cast<int>(last_updated_avg_power));
467                 } else {
468                     power_data_invalid = true;
469                     break;
470                 }
471                 if (binded_cdev_info_pair.second.throttling_with_power_link) {
472                     return false;
473                 }
474             }
475 
476             auto cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
477             cdev_power_adjustment = cdev_power_budget - last_updated_avg_power;
478 
479             if (low_power_device_check) {
480                 // Share the budget for the CDEV which power is lower than target
481                 if (cdev_power_adjustment > 0 &&
482                     thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
483                             binded_cdev_info_pair.first) == 0) {
484                     allocated_power += last_updated_avg_power;
485                     allocated_weight += cdev_weight;
486                     allocated_cdev.insert(binded_cdev_info_pair.first);
487                     if (!binded_cdev_info_pair.second.power_rail.empty()) {
488                         log_buf.append(StringPrintf("(%s: %0.2f mW)",
489                                                     binded_cdev_info_pair.second.power_rail.c_str(),
490                                                     last_updated_avg_power));
491                     }
492                     LOG(VERBOSE) << temp.name << " binded " << binded_cdev_info_pair.first
493                                  << " has been already at min state 0";
494                 }
495             } else {
496                 const CdevInfo &cdev_info = cooling_device_info_map.at(binded_cdev_info_pair.first);
497                 if (!binded_cdev_info_pair.second.power_rail.empty()) {
498                     log_buf.append(StringPrintf("(%s: %0.2f mW)",
499                                                 binded_cdev_info_pair.second.power_rail.c_str(),
500                                                 last_updated_avg_power));
501                 }
502                 // Ignore the power distribution if the CDEV has no space to reduce power
503                 if ((cdev_power_adjustment < 0 &&
504                      thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
505                              binded_cdev_info_pair.first) == cdev_info.max_state)) {
506                     LOG(VERBOSE) << temp.name << " binded " << binded_cdev_info_pair.first
507                                  << " has been already at max state " << cdev_info.max_state;
508                     continue;
509                 }
510 
511                 if (!binded_cdev_info_pair.second.enabled) {
512                     cdev_power_budget = cdev_info.state2power[0];
513                 } else if (!power_data_invalid && binded_cdev_info_pair.second.power_rail != "") {
514                     auto cdev_curr_power_budget =
515                             thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
516                                     binded_cdev_info_pair.first);
517 
518                     if (last_updated_avg_power > cdev_curr_power_budget) {
519                         cdev_power_budget = cdev_curr_power_budget +=
520                                 (cdev_power_adjustment *
521                                  (cdev_curr_power_budget / last_updated_avg_power));
522                     } else {
523                         cdev_power_budget = cdev_curr_power_budget += cdev_power_adjustment;
524                     }
525                 } else {
526                     cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
527                 }
528 
529                 if (!std::isnan(cdev_info.state2power[0]) &&
530                     cdev_power_budget > cdev_info.state2power[0]) {
531                     cdev_power_budget = cdev_info.state2power[0];
532                 } else if (cdev_power_budget < 0) {
533                     cdev_power_budget = 0;
534                 }
535 
536                 int max_cdev_vote;
537                 if (!getCdevMaxRequest(binded_cdev_info_pair.first, &max_cdev_vote)) {
538                     return false;
539                 }
540 
541                 const auto curr_cdev_vote =
542                         thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
543                                 binded_cdev_info_pair.first);
544 
545                 if (!max_throttling) {
546                     if (binded_cdev_info_pair.second.max_release_step !=
547                                 std::numeric_limits<int>::max() &&
548                         (power_data_invalid || cdev_power_adjustment > 0)) {
549                         if (!power_data_invalid && curr_cdev_vote < max_cdev_vote) {
550                             cdev_power_budget = cdev_info.state2power[curr_cdev_vote];
551                             LOG(VERBOSE) << temp.name << "'s " << binded_cdev_info_pair.first
552                                          << " vote: " << curr_cdev_vote
553                                          << " is lower than max cdev vote: " << max_cdev_vote;
554                         } else {
555                             int target_release_step = binded_cdev_info_pair.second.max_release_step;
556                             while ((curr_cdev_vote - target_release_step) >
557                                            binded_cdev_info_pair.second
558                                                    .limit_info[static_cast<size_t>(
559                                                            curr_severity)] &&
560                                    cdev_info.state2power[curr_cdev_vote - target_release_step] ==
561                                            cdev_info.state2power[curr_cdev_vote]) {
562                                 target_release_step += 1;
563                             }
564                             const auto target_state =
565                                     std::max(curr_cdev_vote - target_release_step, 0);
566 
567                             cdev_power_budget = std::min(cdev_power_budget,
568                                                          cdev_info.state2power[target_state]);
569                         }
570                     }
571 
572                     if (binded_cdev_info_pair.second.max_throttle_step !=
573                                 std::numeric_limits<int>::max() &&
574                         (power_data_invalid || cdev_power_adjustment < 0)) {
575                         int target_throttle_step = binded_cdev_info_pair.second.max_throttle_step;
576                         while ((curr_cdev_vote + target_throttle_step) <
577                                        binded_cdev_info_pair.second
578                                                .cdev_ceiling[static_cast<size_t>(curr_severity)] &&
579                                cdev_info.state2power[curr_cdev_vote + target_throttle_step] ==
580                                        cdev_info.state2power[curr_cdev_vote]) {
581                             target_throttle_step += 1;
582                         }
583                         const auto target_state =
584                                 std::min(curr_cdev_vote + target_throttle_step,
585                                          binded_cdev_info_pair.second
586                                                  .cdev_ceiling[static_cast<size_t>(curr_severity)]);
587                         cdev_power_budget =
588                                 std::max(cdev_power_budget, cdev_info.state2power[target_state]);
589                     }
590                 }
591 
592                 thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
593                         binded_cdev_info_pair.first) = cdev_power_budget;
594                 LOG(VERBOSE) << temp.name << " allocate "
595                              << thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
596                                         binded_cdev_info_pair.first)
597                              << "mW to " << binded_cdev_info_pair.first
598                              << "(cdev_weight=" << cdev_weight << ")";
599             }
600         }
601 
602         if (!power_data_invalid) {
603             total_power_budget -= allocated_power;
604             total_weight -= allocated_weight;
605         }
606         allocated_power = 0;
607         allocated_weight = 0;
608 
609         if (low_power_device_check) {
610             low_power_device_check = false;
611         } else {
612             is_budget_allocated = true;
613         }
614     }
615     if (log_buf.size()) {
616         LOG(INFO) << temp.name << " binded power rails: " << log_buf;
617     }
618     return true;
619 }
620 
updateCdevRequestByPower(std::string sensor_name,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map)621 void ThermalThrottling::updateCdevRequestByPower(
622         std::string sensor_name,
623         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
624     size_t i;
625 
626     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
627     for (auto &pid_power_budget_pair :
628          thermal_throttling_status_map_[sensor_name.data()].pid_power_budget_map) {
629         const CdevInfo &cdev_info = cooling_device_info_map.at(pid_power_budget_pair.first);
630 
631         for (i = 0; i < cdev_info.state2power.size() - 1; ++i) {
632             if (pid_power_budget_pair.second >= cdev_info.state2power[i]) {
633                 break;
634             }
635         }
636         thermal_throttling_status_map_[sensor_name.data()].pid_cdev_request_map.at(
637                 pid_power_budget_pair.first) = static_cast<int>(i);
638     }
639 
640     return;
641 }
642 
updateCdevRequestBySeverity(std::string_view sensor_name,const SensorInfo & sensor_info,ThrottlingSeverity curr_severity)643 void ThermalThrottling::updateCdevRequestBySeverity(std::string_view sensor_name,
644                                                     const SensorInfo &sensor_info,
645                                                     ThrottlingSeverity curr_severity) {
646     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
647     const auto &profile = thermal_throttling_status_map_[sensor_name.data()].profile;
648 
649     for (const auto &binded_cdev_info_pair :
650          (sensor_info.throttling_info->profile_map.count(profile)
651                   ? sensor_info.throttling_info->profile_map.at(profile)
652                   : sensor_info.throttling_info->binded_cdev_info_map)) {
653         if (!thermal_throttling_status_map_[sensor_name.data()].hardlimit_cdev_request_map.count(
654                     binded_cdev_info_pair.first)) {
655             continue;
656         }
657         thermal_throttling_status_map_[sensor_name.data()].hardlimit_cdev_request_map.at(
658                 binded_cdev_info_pair.first) =
659                 (binded_cdev_info_pair.second.enabled)
660                         ? binded_cdev_info_pair.second
661                                   .limit_info[static_cast<size_t>(curr_severity)]
662                         : 0;
663         LOG(VERBOSE) << "Hard Limit: Sensor " << sensor_name.data() << " update cdev "
664                      << binded_cdev_info_pair.first << " to "
665                      << thermal_throttling_status_map_[sensor_name.data()]
666                                 .hardlimit_cdev_request_map.at(binded_cdev_info_pair.first);
667     }
668 }
669 
throttlingReleaseUpdate(std::string_view sensor_name,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map,const std::unordered_map<std::string,PowerStatus> & power_status_map,const ThrottlingSeverity severity,const SensorInfo & sensor_info)670 bool ThermalThrottling::throttlingReleaseUpdate(
671         std::string_view sensor_name,
672         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map,
673         const std::unordered_map<std::string, PowerStatus> &power_status_map,
674         const ThrottlingSeverity severity, const SensorInfo &sensor_info) {
675     ATRACE_CALL();
676     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
677     if (!thermal_throttling_status_map_.count(sensor_name.data())) {
678         return false;
679     }
680     auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
681     for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
682         float avg_power = -1;
683 
684         if (!thermal_throttling_status.throttling_release_map.count(binded_cdev_info_pair.first) ||
685             !power_status_map.count(binded_cdev_info_pair.second.power_rail)) {
686             return false;
687         }
688 
689         const auto max_state = cooling_device_info_map.at(binded_cdev_info_pair.first).max_state;
690 
691         auto &release_step =
692                 thermal_throttling_status.throttling_release_map.at(binded_cdev_info_pair.first);
693         avg_power =
694                 power_status_map.at(binded_cdev_info_pair.second.power_rail).last_updated_avg_power;
695 
696         if (std::isnan(avg_power) || avg_power < 0) {
697             release_step = binded_cdev_info_pair.second.throttling_with_power_link ? max_state : 0;
698             continue;
699         }
700 
701         bool is_over_budget = true;
702         if (!binded_cdev_info_pair.second.high_power_check) {
703             if (avg_power <
704                 binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
705                 is_over_budget = false;
706             }
707         } else {
708             if (avg_power >
709                 binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
710                 is_over_budget = false;
711             }
712         }
713         LOG(INFO) << sensor_name.data() << "'s " << binded_cdev_info_pair.first
714                   << " binded power rail " << binded_cdev_info_pair.second.power_rail
715                   << ": power threshold = "
716                   << binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]
717                   << ", avg power = " << avg_power;
718         std::string atrace_prefix = ::android::base::StringPrintf(
719                 "%s-%s", sensor_name.data(), binded_cdev_info_pair.second.power_rail.data());
720         ATRACE_INT(
721                 (atrace_prefix + std::string("-power_threshold")).c_str(),
722                 static_cast<int>(
723                         binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]));
724         ATRACE_INT((atrace_prefix + std::string("-avg_power")).c_str(), avg_power);
725 
726         switch (binded_cdev_info_pair.second.release_logic) {
727             case ReleaseLogic::INCREASE:
728                 if (!is_over_budget) {
729                     if (std::abs(release_step) < static_cast<int>(max_state)) {
730                         release_step--;
731                     }
732                 } else {
733                     release_step = 0;
734                 }
735                 break;
736             case ReleaseLogic::DECREASE:
737                 if (!is_over_budget) {
738                     if (release_step < static_cast<int>(max_state)) {
739                         release_step++;
740                     }
741                 } else {
742                     release_step = 0;
743                 }
744                 break;
745             case ReleaseLogic::STEPWISE:
746                 if (!is_over_budget) {
747                     if (release_step < static_cast<int>(max_state)) {
748                         release_step++;
749                     }
750                 } else {
751                     if (std::abs(release_step) < static_cast<int>(max_state)) {
752                         release_step--;
753                     }
754                 }
755                 break;
756             case ReleaseLogic::RELEASE_TO_FLOOR:
757                 release_step = is_over_budget ? 0 : max_state;
758                 break;
759             case ReleaseLogic::NONE:
760             default:
761                 break;
762         }
763     }
764     return true;
765 }
766 
thermalThrottlingUpdate(const Temperature & temp,const SensorInfo & sensor_info,const ThrottlingSeverity curr_severity,const std::chrono::milliseconds time_elapsed_ms,const std::unordered_map<std::string,PowerStatus> & power_status_map,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map,const bool max_throttling,const std::vector<float> & sensor_predictions)767 void ThermalThrottling::thermalThrottlingUpdate(
768         const Temperature &temp, const SensorInfo &sensor_info,
769         const ThrottlingSeverity curr_severity, const std::chrono::milliseconds time_elapsed_ms,
770         const std::unordered_map<std::string, PowerStatus> &power_status_map,
771         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map,
772         const bool max_throttling, const std::vector<float> &sensor_predictions) {
773     if (!thermal_throttling_status_map_.count(temp.name)) {
774         return;
775     }
776 
777     if (sensor_info.throttling_info->profile_map.size()) {
778         parseProfileProperty(temp.name.c_str(), sensor_info);
779     }
780 
781     if (thermal_throttling_status_map_[temp.name].pid_power_budget_map.size()) {
782         if (!allocatePowerToCdev(temp, sensor_info, curr_severity, time_elapsed_ms,
783                                  power_status_map, cooling_device_info_map, max_throttling,
784                                  sensor_predictions)) {
785             LOG(ERROR) << "Sensor " << temp.name << " PID request cdev failed";
786             // Clear the CDEV request if the power budget is failed to be allocated
787             for (auto &pid_cdev_request_pair :
788                  thermal_throttling_status_map_[temp.name].pid_cdev_request_map) {
789                 pid_cdev_request_pair.second = 0;
790             }
791         }
792         updateCdevRequestByPower(temp.name, cooling_device_info_map);
793     }
794 
795     if (thermal_throttling_status_map_[temp.name].hardlimit_cdev_request_map.size()) {
796         updateCdevRequestBySeverity(temp.name.c_str(), sensor_info, curr_severity);
797     }
798 
799     if (thermal_throttling_status_map_[temp.name].throttling_release_map.size()) {
800         throttlingReleaseUpdate(temp.name.c_str(), cooling_device_info_map, power_status_map,
801                                 curr_severity, sensor_info);
802     }
803 }
804 
computeCoolingDevicesRequest(std::string_view sensor_name,const SensorInfo & sensor_info,const ThrottlingSeverity curr_severity,std::vector<std::string> * cooling_devices_to_update,ThermalStatsHelper * thermal_stats_helper)805 void ThermalThrottling::computeCoolingDevicesRequest(
806         std::string_view sensor_name, const SensorInfo &sensor_info,
807         const ThrottlingSeverity curr_severity, std::vector<std::string> *cooling_devices_to_update,
808         ThermalStatsHelper *thermal_stats_helper) {
809     int release_step = 0;
810     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
811 
812     if (!thermal_throttling_status_map_.count(sensor_name.data())) {
813         return;
814     }
815 
816     auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
817     const auto &cdev_release_map = thermal_throttling_status.throttling_release_map;
818 
819     const auto &profile = thermal_throttling_status_map_[sensor_name.data()].profile;
820     const auto &binded_cdev_info_map =
821             sensor_info.throttling_info->profile_map.count(profile)
822                     ? sensor_info.throttling_info->profile_map.at(profile)
823                     : sensor_info.throttling_info->binded_cdev_info_map;
824 
825     for (auto &cdev_request_pair : thermal_throttling_status.cdev_status_map) {
826         int pid_cdev_request = 0;
827         int hardlimit_cdev_request = 0;
828         const auto &cdev_name = cdev_request_pair.first;
829         const auto &binded_cdev_info = binded_cdev_info_map.at(cdev_name);
830         const auto cdev_ceiling = binded_cdev_info.cdev_ceiling[static_cast<size_t>(curr_severity)];
831         const auto cdev_floor =
832                 binded_cdev_info.cdev_floor_with_power_link[static_cast<size_t>(curr_severity)];
833         release_step = 0;
834 
835         if (thermal_throttling_status.pid_cdev_request_map.count(cdev_name)) {
836             pid_cdev_request = thermal_throttling_status.pid_cdev_request_map.at(cdev_name);
837         }
838 
839         if (thermal_throttling_status.hardlimit_cdev_request_map.count(cdev_name)) {
840             hardlimit_cdev_request =
841                     thermal_throttling_status.hardlimit_cdev_request_map.at(cdev_name);
842         }
843 
844         if (cdev_release_map.count(cdev_name)) {
845             release_step = cdev_release_map.at(cdev_name);
846         }
847 
848         LOG(VERBOSE) << sensor_name.data() << " binded cooling device " << cdev_name
849                      << "'s pid_request=" << pid_cdev_request
850                      << " hardlimit_cdev_request=" << hardlimit_cdev_request
851                      << " release_step=" << release_step
852                      << " cdev_floor_with_power_link=" << cdev_floor
853                      << " cdev_ceiling=" << cdev_ceiling;
854         std::string atrace_prefix =
855                 ::android::base::StringPrintf("%s-%s", sensor_name.data(), cdev_name.data());
856         ATRACE_INT((atrace_prefix + std::string("-pid_request")).c_str(), pid_cdev_request);
857         ATRACE_INT((atrace_prefix + std::string("-hardlimit_request")).c_str(),
858                    hardlimit_cdev_request);
859         ATRACE_INT((atrace_prefix + std::string("-release_step")).c_str(), release_step);
860         ATRACE_INT((atrace_prefix + std::string("-cdev_floor")).c_str(), cdev_floor);
861         ATRACE_INT((atrace_prefix + std::string("-cdev_ceiling")).c_str(), cdev_ceiling);
862 
863         auto request_state = std::max(pid_cdev_request, hardlimit_cdev_request);
864         if (release_step) {
865             if (release_step >= request_state) {
866                 request_state = 0;
867             } else {
868                 request_state = request_state - release_step;
869             }
870             // Only check the cdev_floor when release step is non zero
871             request_state = std::max(request_state, cdev_floor);
872         }
873         request_state = std::min(request_state, cdev_ceiling);
874         if (cdev_request_pair.second != request_state) {
875             ATRACE_INT((atrace_prefix + std::string("-final_request")).c_str(), request_state);
876             if (updateCdevMaxRequestAndNotifyIfChange(cdev_name, cdev_request_pair.second,
877                                                       request_state)) {
878                 cooling_devices_to_update->emplace_back(cdev_name);
879             }
880             cdev_request_pair.second = request_state;
881             // Update sensor cdev request time in state
882             thermal_stats_helper->updateSensorCdevRequestStats(sensor_name, cdev_name,
883                                                                cdev_request_pair.second);
884         }
885     }
886 }
887 
updateCdevMaxRequestAndNotifyIfChange(std::string_view cdev_name,int cur_request,int new_request)888 bool ThermalThrottling::updateCdevMaxRequestAndNotifyIfChange(std::string_view cdev_name,
889                                                               int cur_request, int new_request) {
890     std::unique_lock<std::shared_mutex> _lock(cdev_all_request_map_mutex_);
891     auto &request_set = cdev_all_request_map_.at(cdev_name.data());
892     int cur_max_request = (*request_set.begin());
893     // Remove old cdev request and add the new one.
894     request_set.erase(request_set.find(cur_request));
895     request_set.insert(new_request);
896     // Check if there is any change in aggregated max cdev request.
897     int new_max_request = (*request_set.begin());
898     LOG(VERBOSE) << "For cooling device [" << cdev_name.data()
899                  << "] cur_max_request is: " << cur_max_request
900                  << " new_max_request is: " << new_max_request;
901     return new_max_request != cur_max_request;
902 }
903 
getCdevMaxRequest(std::string_view cdev_name,int * max_state)904 bool ThermalThrottling::getCdevMaxRequest(std::string_view cdev_name, int *max_state) {
905     std::shared_lock<std::shared_mutex> _lock(cdev_all_request_map_mutex_);
906     if (!cdev_all_request_map_.count(cdev_name.data())) {
907         LOG(ERROR) << "Cooling device [" << cdev_name.data()
908                    << "] not present in cooling device request map";
909         return false;
910     }
911     *max_state = *cdev_all_request_map_.at(cdev_name.data()).begin();
912     return true;
913 }
914 
915 }  // namespace implementation
916 }  // namespace thermal
917 }  // namespace hardware
918 }  // namespace android
919 }  // namespace aidl
920