• 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 android {
37 namespace hardware {
38 namespace thermal {
39 namespace V2_0 {
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 : hidl_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 
clearThrottlingData(std::string_view sensor_name,const SensorInfo & sensor_info)61 void ThermalThrottling::clearThrottlingData(std::string_view sensor_name,
62                                             const SensorInfo &sensor_info) {
63     if (!thermal_throttling_status_map_.count(sensor_name.data())) {
64         return;
65     }
66     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
67 
68     for (auto &pid_power_budget_pair :
69          thermal_throttling_status_map_.at(sensor_name.data()).pid_power_budget_map) {
70         pid_power_budget_pair.second = std::numeric_limits<int>::max();
71     }
72 
73     for (auto &pid_cdev_request_pair :
74          thermal_throttling_status_map_.at(sensor_name.data()).pid_cdev_request_map) {
75         pid_cdev_request_pair.second = 0;
76     }
77 
78     for (auto &hardlimit_cdev_request_pair :
79          thermal_throttling_status_map_.at(sensor_name.data()).hardlimit_cdev_request_map) {
80         hardlimit_cdev_request_pair.second = 0;
81     }
82 
83     for (auto &throttling_release_pair :
84          thermal_throttling_status_map_.at(sensor_name.data()).throttling_release_map) {
85         throttling_release_pair.second = 0;
86     }
87 
88     thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
89     thermal_throttling_status_map_[sensor_name.data()].i_budget =
90             sensor_info.throttling_info->i_default;
91     thermal_throttling_status_map_[sensor_name.data()].prev_target =
92             static_cast<size_t>(ThrottlingSeverity::NONE);
93     thermal_throttling_status_map_[sensor_name.data()].prev_power_budget = NAN;
94     thermal_throttling_status_map_[sensor_name.data()].tran_cycle = 0;
95 
96     return;
97 }
98 
registerThermalThrottling(std::string_view sensor_name,const std::shared_ptr<ThrottlingInfo> & throttling_info,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map)99 bool ThermalThrottling::registerThermalThrottling(
100         std::string_view sensor_name, const std::shared_ptr<ThrottlingInfo> &throttling_info,
101         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
102     if (thermal_throttling_status_map_.count(sensor_name.data())) {
103         LOG(ERROR) << "Sensor " << sensor_name.data() << " throttling map has been registered";
104         return false;
105     }
106 
107     if (throttling_info == nullptr) {
108         LOG(ERROR) << "Sensor " << sensor_name.data() << " has no throttling info";
109         return false;
110     }
111 
112     thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
113     thermal_throttling_status_map_[sensor_name.data()].i_budget = throttling_info->i_default;
114     thermal_throttling_status_map_[sensor_name.data()].prev_target =
115             static_cast<size_t>(ThrottlingSeverity::NONE);
116     thermal_throttling_status_map_[sensor_name.data()].prev_power_budget = NAN;
117     thermal_throttling_status_map_[sensor_name.data()].tran_cycle = 0;
118 
119     for (auto &binded_cdev_pair : throttling_info->binded_cdev_info_map) {
120         if (!cooling_device_info_map.count(binded_cdev_pair.first)) {
121             LOG(ERROR) << "Could not find " << sensor_name.data() << "'s binded CDEV "
122                        << binded_cdev_pair.first;
123             return false;
124         }
125         // Register PID throttling map
126         for (const auto &cdev_weight : binded_cdev_pair.second.cdev_weight_for_pid) {
127             if (!std::isnan(cdev_weight)) {
128                 thermal_throttling_status_map_[sensor_name.data()]
129                         .pid_power_budget_map[binded_cdev_pair.first] =
130                         std::numeric_limits<int>::max();
131                 thermal_throttling_status_map_[sensor_name.data()]
132                         .pid_cdev_request_map[binded_cdev_pair.first] = 0;
133                 thermal_throttling_status_map_[sensor_name.data()]
134                         .cdev_status_map[binded_cdev_pair.first] = 0;
135                 break;
136             }
137         }
138         // Register hard limit throttling map
139         for (const auto &limit_info : binded_cdev_pair.second.limit_info) {
140             if (limit_info > 0) {
141                 thermal_throttling_status_map_[sensor_name.data()]
142                         .hardlimit_cdev_request_map[binded_cdev_pair.first] = 0;
143                 thermal_throttling_status_map_[sensor_name.data()]
144                         .cdev_status_map[binded_cdev_pair.first] = 0;
145                 break;
146             }
147         }
148         // Register throttling release map if power threshold exists
149         if (!binded_cdev_pair.second.power_rail.empty()) {
150             for (const auto &power_threshold : binded_cdev_pair.second.power_thresholds) {
151                 if (!std::isnan(power_threshold)) {
152                     thermal_throttling_status_map_[sensor_name.data()]
153                             .throttling_release_map[binded_cdev_pair.first] = 0;
154                     break;
155                 }
156             }
157         }
158     }
159     return true;
160 }
161 
162 // return power budget based on PID algo
updatePowerBudget(const Temperature_2_0 & temp,const SensorInfo & sensor_info,std::chrono::milliseconds time_elapsed_ms,ThrottlingSeverity curr_severity)163 float ThermalThrottling::updatePowerBudget(const Temperature_2_0 &temp,
164                                            const SensorInfo &sensor_info,
165                                            std::chrono::milliseconds time_elapsed_ms,
166                                            ThrottlingSeverity curr_severity) {
167     float p = 0, d = 0;
168     float power_budget = std::numeric_limits<float>::max();
169     bool target_changed = false;
170     float budget_transient = 0.0;
171     auto &throttling_status = thermal_throttling_status_map_.at(temp.name);
172     std::string sensor_name = temp.name;
173 
174     if (curr_severity == ThrottlingSeverity::NONE) {
175         return power_budget;
176     }
177 
178     const auto target_state = getTargetStateOfPID(sensor_info, curr_severity);
179     if (throttling_status.prev_target != static_cast<size_t>(ThrottlingSeverity::NONE) &&
180         target_state != throttling_status.prev_target &&
181         sensor_info.throttling_info->tran_cycle > 0) {
182         throttling_status.tran_cycle = sensor_info.throttling_info->tran_cycle - 1;
183         target_changed = true;
184     }
185     throttling_status.prev_target = target_state;
186 
187     // Compute PID
188     float err = sensor_info.hot_thresholds[target_state] - temp.value;
189     p = err * (err < 0 ? sensor_info.throttling_info->k_po[target_state]
190                        : sensor_info.throttling_info->k_pu[target_state]);
191 
192     if (err < sensor_info.throttling_info->i_cutoff[target_state]) {
193         throttling_status.i_budget += err * sensor_info.throttling_info->k_i[target_state];
194     }
195 
196     if (fabsf(throttling_status.i_budget) > sensor_info.throttling_info->i_max[target_state]) {
197         throttling_status.i_budget = sensor_info.throttling_info->i_max[target_state] *
198                                      (throttling_status.i_budget > 0 ? 1 : -1);
199     }
200 
201     if (!std::isnan(throttling_status.prev_err) &&
202         time_elapsed_ms != std::chrono::milliseconds::zero()) {
203         d = sensor_info.throttling_info->k_d[target_state] * (err - throttling_status.prev_err) /
204             time_elapsed_ms.count();
205     }
206 
207     throttling_status.prev_err = err;
208     // Calculate power budget
209     power_budget =
210             sensor_info.throttling_info->s_power[target_state] + p + throttling_status.i_budget + d;
211     if (power_budget < sensor_info.throttling_info->min_alloc_power[target_state]) {
212         power_budget = sensor_info.throttling_info->min_alloc_power[target_state];
213     }
214     if (power_budget > sensor_info.throttling_info->max_alloc_power[target_state]) {
215         power_budget = sensor_info.throttling_info->max_alloc_power[target_state];
216     }
217 
218     if (target_changed) {
219         throttling_status.budget_transient = throttling_status.prev_power_budget - power_budget;
220     }
221 
222     if (throttling_status.tran_cycle) {
223         budget_transient = throttling_status.budget_transient *
224                            ((static_cast<float>(throttling_status.tran_cycle) /
225                              static_cast<float>(sensor_info.throttling_info->tran_cycle)));
226         power_budget += budget_transient;
227         throttling_status.tran_cycle--;
228     }
229 
230     LOG(INFO) << temp.name << " power_budget=" << power_budget << " err=" << err
231               << " s_power=" << sensor_info.throttling_info->s_power[target_state]
232               << " time_elapsed_ms=" << time_elapsed_ms.count() << " p=" << p
233               << " i=" << throttling_status.i_budget << " d=" << d
234               << " budget transient=" << budget_transient << " control target=" << target_state;
235 
236     ATRACE_INT((sensor_name + std::string("-power_budget")).c_str(),
237                static_cast<int>(power_budget));
238     ATRACE_INT((sensor_name + std::string("-s_power")).c_str(),
239                static_cast<int>(sensor_info.throttling_info->s_power[target_state]));
240     ATRACE_INT((sensor_name + std::string("-time_elapsed_ms")).c_str(),
241                static_cast<int>(time_elapsed_ms.count()));
242     ATRACE_INT((sensor_name + std::string("-budget_transient")).c_str(),
243                static_cast<int>(budget_transient));
244     ATRACE_INT((sensor_name + std::string("-i")).c_str(),
245                static_cast<int>(throttling_status.i_budget));
246     ATRACE_INT((sensor_name + std::string("-target_state")).c_str(),
247                static_cast<int>(target_state));
248 
249     ATRACE_INT((sensor_name + std::string("-err")).c_str(), static_cast<int>(err));
250     ATRACE_INT((sensor_name + std::string("-p")).c_str(), static_cast<int>(p));
251     ATRACE_INT((sensor_name + std::string("-temp")).c_str(), static_cast<int>(temp.value));
252 
253     throttling_status.prev_power_budget = power_budget;
254 
255     return power_budget;
256 }
257 
computeExcludedPower(const SensorInfo & sensor_info,const ThrottlingSeverity curr_severity,const std::unordered_map<std::string,PowerStatus> & power_status_map,std::string * log_buf)258 float ThermalThrottling::computeExcludedPower(
259         const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity,
260         const std::unordered_map<std::string, PowerStatus> &power_status_map,
261         std::string *log_buf) {
262     float excluded_power = 0.0;
263 
264     for (const auto &excluded_power_info_pair :
265          sensor_info.throttling_info->excluded_power_info_map) {
266         const auto last_updated_avg_power =
267                 power_status_map.at(excluded_power_info_pair.first).last_updated_avg_power;
268         if (!std::isnan(last_updated_avg_power)) {
269             excluded_power += last_updated_avg_power *
270                               excluded_power_info_pair.second[static_cast<size_t>(curr_severity)];
271             log_buf->append(StringPrintf(
272                     "(%s: %0.2f mW, cdev_weight: %f)", excluded_power_info_pair.first.c_str(),
273                     last_updated_avg_power,
274                     excluded_power_info_pair.second[static_cast<size_t>(curr_severity)]));
275 
276             ATRACE_INT((excluded_power_info_pair.first + std::string("-avg_power")).c_str(),
277                        static_cast<int>(last_updated_avg_power));
278         }
279     }
280 
281     ATRACE_INT("excluded_power", static_cast<int>(excluded_power));
282     return excluded_power;
283 }
284 
285 // Allocate power budget to binded cooling devices base on the real ODPM power data
allocatePowerToCdev(const Temperature_2_0 & 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)286 bool ThermalThrottling::allocatePowerToCdev(
287         const Temperature_2_0 &temp, const SensorInfo &sensor_info,
288         const ThrottlingSeverity curr_severity, const std::chrono::milliseconds time_elapsed_ms,
289         const std::unordered_map<std::string, PowerStatus> &power_status_map,
290         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
291     float total_weight = 0;
292     float last_updated_avg_power = NAN;
293     float allocated_power = 0;
294     float allocated_weight = 0;
295     bool low_power_device_check = true;
296     bool is_budget_allocated = false;
297     bool power_data_invalid = false;
298     std::set<std::string> allocated_cdev;
299     std::string log_buf;
300 
301     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
302     auto total_power_budget = updatePowerBudget(temp, sensor_info, time_elapsed_ms, curr_severity);
303 
304     if (sensor_info.throttling_info->excluded_power_info_map.size()) {
305         std::string log_buf;
306         total_power_budget -=
307                 computeExcludedPower(sensor_info, curr_severity, power_status_map, &log_buf);
308         total_power_budget = std::max(total_power_budget, 0.0f);
309         if (!log_buf.empty()) {
310             LOG(INFO) << temp.name << " power budget=" << total_power_budget << " after " << log_buf
311                       << " is excluded";
312         }
313     }
314 
315     // Compute total cdev weight
316     for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
317         const auto cdev_weight = binded_cdev_info_pair.second
318                                          .cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
319         if (std::isnan(cdev_weight) || cdev_weight == 0) {
320             allocated_cdev.insert(binded_cdev_info_pair.first);
321             continue;
322         }
323         total_weight += cdev_weight;
324     }
325 
326     while (!is_budget_allocated) {
327         for (const auto &binded_cdev_info_pair :
328              sensor_info.throttling_info->binded_cdev_info_map) {
329             float cdev_power_adjustment = 0;
330             const auto cdev_weight =
331                     binded_cdev_info_pair.second
332                             .cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
333 
334             if (allocated_cdev.count(binded_cdev_info_pair.first)) {
335                 continue;
336             }
337             if (std::isnan(cdev_weight) || !cdev_weight) {
338                 allocated_cdev.insert(binded_cdev_info_pair.first);
339                 continue;
340             }
341 
342             // Get the power data
343             if (!power_data_invalid) {
344                 if (!binded_cdev_info_pair.second.power_rail.empty()) {
345                     last_updated_avg_power =
346                             power_status_map.at(binded_cdev_info_pair.second.power_rail)
347                                     .last_updated_avg_power;
348                     if (std::isnan(last_updated_avg_power)) {
349                         LOG(VERBOSE) << "power data is under collecting";
350                         power_data_invalid = true;
351                         break;
352                     }
353 
354                     ATRACE_INT((binded_cdev_info_pair.second.power_rail + std::string("-avg_power"))
355                                        .c_str(),
356                                static_cast<int>(last_updated_avg_power));
357                 } else {
358                     power_data_invalid = true;
359                     break;
360                 }
361                 if (binded_cdev_info_pair.second.throttling_with_power_link) {
362                     return false;
363                 }
364             }
365 
366             auto cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
367             cdev_power_adjustment = cdev_power_budget - last_updated_avg_power;
368 
369             if (low_power_device_check) {
370                 // Share the budget for the CDEV which power is lower than target
371                 if (cdev_power_adjustment > 0 &&
372                     thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
373                             binded_cdev_info_pair.first) == 0) {
374                     allocated_power += last_updated_avg_power;
375                     allocated_weight += cdev_weight;
376                     allocated_cdev.insert(binded_cdev_info_pair.first);
377                     if (!binded_cdev_info_pair.second.power_rail.empty()) {
378                         log_buf.append(StringPrintf("(%s: %0.2f mW)",
379                                                     binded_cdev_info_pair.second.power_rail.c_str(),
380                                                     last_updated_avg_power));
381                     }
382                     LOG(VERBOSE) << temp.name << " binded " << binded_cdev_info_pair.first
383                                  << " has been already at min state 0";
384                 }
385             } else {
386                 const CdevInfo &cdev_info = cooling_device_info_map.at(binded_cdev_info_pair.first);
387                 if (!binded_cdev_info_pair.second.power_rail.empty()) {
388                     log_buf.append(StringPrintf("(%s: %0.2f mW)",
389                                                 binded_cdev_info_pair.second.power_rail.c_str(),
390                                                 last_updated_avg_power));
391                 }
392                 // Ignore the power distribution if the CDEV has no space to reduce power
393                 if ((cdev_power_adjustment < 0 &&
394                      thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
395                              binded_cdev_info_pair.first) == cdev_info.max_state)) {
396                     LOG(VERBOSE) << temp.name << " binded " << binded_cdev_info_pair.first
397                                  << " has been already at max state " << cdev_info.max_state;
398                     continue;
399                 }
400 
401                 if (!power_data_invalid && binded_cdev_info_pair.second.power_rail != "") {
402                     auto cdev_curr_power_budget =
403                             thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
404                                     binded_cdev_info_pair.first);
405 
406                     if (last_updated_avg_power > cdev_curr_power_budget) {
407                         cdev_power_budget = cdev_curr_power_budget +=
408                                 (cdev_power_adjustment *
409                                  (cdev_curr_power_budget / last_updated_avg_power));
410                     } else {
411                         cdev_power_budget = cdev_curr_power_budget += cdev_power_adjustment;
412                     }
413                 } else {
414                     cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
415                 }
416 
417                 if (!std::isnan(cdev_info.state2power[0]) &&
418                     cdev_power_budget > cdev_info.state2power[0]) {
419                     cdev_power_budget = cdev_info.state2power[0];
420                 } else if (cdev_power_budget < 0) {
421                     cdev_power_budget = 0;
422                 }
423 
424                 const auto curr_state =
425                         thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
426                                 binded_cdev_info_pair.first);
427 
428                 if (binded_cdev_info_pair.second.max_release_step !=
429                             std::numeric_limits<int>::max() &&
430                     (power_data_invalid || cdev_power_adjustment > 0)) {
431                     auto target_state =
432                             std::max(curr_state - binded_cdev_info_pair.second.max_release_step, 0);
433                     cdev_power_budget =
434                             std::min(cdev_power_budget, cdev_info.state2power[target_state]);
435                 }
436 
437                 if (binded_cdev_info_pair.second.max_throttle_step !=
438                             std::numeric_limits<int>::max() &&
439                     (power_data_invalid || cdev_power_adjustment < 0)) {
440                     auto target_state =
441                             std::min(curr_state + binded_cdev_info_pair.second.max_throttle_step,
442                                      cdev_info.max_state);
443                     cdev_power_budget =
444                             std::max(cdev_power_budget, cdev_info.state2power[target_state]);
445                 }
446 
447                 thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
448                         binded_cdev_info_pair.first) = cdev_power_budget;
449                 LOG(VERBOSE) << temp.name << " allocate "
450                              << thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
451                                         binded_cdev_info_pair.first)
452                              << "mW to " << binded_cdev_info_pair.first
453                              << "(cdev_weight=" << cdev_weight << ")";
454             }
455         }
456 
457         if (!power_data_invalid) {
458             total_power_budget -= allocated_power;
459             total_weight -= allocated_weight;
460         }
461         allocated_power = 0;
462         allocated_weight = 0;
463 
464         if (low_power_device_check) {
465             low_power_device_check = false;
466         } else {
467             is_budget_allocated = true;
468         }
469     }
470     if (log_buf.size()) {
471         LOG(INFO) << temp.name << " binded power rails: " << log_buf;
472     }
473     return true;
474 }
475 
updateCdevRequestByPower(std::string sensor_name,const std::unordered_map<std::string,CdevInfo> & cooling_device_info_map)476 void ThermalThrottling::updateCdevRequestByPower(
477         std::string sensor_name,
478         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
479     size_t i;
480 
481     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
482     for (auto &pid_power_budget_pair :
483          thermal_throttling_status_map_[sensor_name.data()].pid_power_budget_map) {
484         const CdevInfo &cdev_info = cooling_device_info_map.at(pid_power_budget_pair.first);
485 
486         for (i = 0; i < cdev_info.state2power.size() - 1; ++i) {
487             if (pid_power_budget_pair.second >= cdev_info.state2power[i]) {
488                 break;
489             }
490         }
491         thermal_throttling_status_map_[sensor_name.data()].pid_cdev_request_map.at(
492                 pid_power_budget_pair.first) = static_cast<int>(i);
493     }
494 
495     return;
496 }
497 
updateCdevRequestBySeverity(std::string_view sensor_name,const SensorInfo & sensor_info,ThrottlingSeverity curr_severity)498 void ThermalThrottling::updateCdevRequestBySeverity(std::string_view sensor_name,
499                                                     const SensorInfo &sensor_info,
500                                                     ThrottlingSeverity curr_severity) {
501     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
502     for (auto const &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
503         thermal_throttling_status_map_[sensor_name.data()].hardlimit_cdev_request_map.at(
504                 binded_cdev_info_pair.first) =
505                 binded_cdev_info_pair.second.limit_info[static_cast<size_t>(curr_severity)];
506         LOG(VERBOSE) << "Hard Limit: Sensor " << sensor_name.data() << " update cdev "
507                      << binded_cdev_info_pair.first << " to "
508                      << thermal_throttling_status_map_[sensor_name.data()]
509                                 .hardlimit_cdev_request_map.at(binded_cdev_info_pair.first);
510     }
511 }
512 
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)513 bool ThermalThrottling::throttlingReleaseUpdate(
514         std::string_view sensor_name,
515         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map,
516         const std::unordered_map<std::string, PowerStatus> &power_status_map,
517         const ThrottlingSeverity severity, const SensorInfo &sensor_info) {
518     ATRACE_CALL();
519     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
520     if (!thermal_throttling_status_map_.count(sensor_name.data())) {
521         return false;
522     }
523     auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
524     for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
525         float avg_power = -1;
526 
527         if (!thermal_throttling_status.throttling_release_map.count(binded_cdev_info_pair.first) ||
528             !power_status_map.count(binded_cdev_info_pair.second.power_rail)) {
529             return false;
530         }
531 
532         const auto max_state = cooling_device_info_map.at(binded_cdev_info_pair.first).max_state;
533 
534         auto &release_step =
535                 thermal_throttling_status.throttling_release_map.at(binded_cdev_info_pair.first);
536         avg_power =
537                 power_status_map.at(binded_cdev_info_pair.second.power_rail).last_updated_avg_power;
538 
539         if (std::isnan(avg_power) || avg_power < 0) {
540             release_step = binded_cdev_info_pair.second.throttling_with_power_link ? max_state : 0;
541             continue;
542         }
543 
544         bool is_over_budget = true;
545         if (!binded_cdev_info_pair.second.high_power_check) {
546             if (avg_power <
547                 binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
548                 is_over_budget = false;
549             }
550         } else {
551             if (avg_power >
552                 binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
553                 is_over_budget = false;
554             }
555         }
556         LOG(INFO) << sensor_name.data() << "'s " << binded_cdev_info_pair.first
557                   << " binded power rail " << binded_cdev_info_pair.second.power_rail
558                   << ": power threshold = "
559                   << binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]
560                   << ", avg power = " << avg_power;
561 
562         ATRACE_INT(
563                 (binded_cdev_info_pair.second.power_rail + std::string("-power_threshold")).c_str(),
564                 static_cast<int>(
565                         binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]));
566         ATRACE_INT((binded_cdev_info_pair.second.power_rail + std::string("-avg_power")).c_str(),
567                    avg_power);
568 
569         switch (binded_cdev_info_pair.second.release_logic) {
570             case ReleaseLogic::INCREASE:
571                 if (!is_over_budget) {
572                     if (std::abs(release_step) < static_cast<int>(max_state)) {
573                         release_step--;
574                     }
575                 } else {
576                     release_step = 0;
577                 }
578                 break;
579             case ReleaseLogic::DECREASE:
580                 if (!is_over_budget) {
581                     if (release_step < static_cast<int>(max_state)) {
582                         release_step++;
583                     }
584                 } else {
585                     release_step = 0;
586                 }
587                 break;
588             case ReleaseLogic::STEPWISE:
589                 if (!is_over_budget) {
590                     if (release_step < static_cast<int>(max_state)) {
591                         release_step++;
592                     }
593                 } else {
594                     if (std::abs(release_step) < static_cast<int>(max_state)) {
595                         release_step--;
596                     }
597                 }
598                 break;
599             case ReleaseLogic::RELEASE_TO_FLOOR:
600                 release_step = is_over_budget ? 0 : max_state;
601                 break;
602             case ReleaseLogic::NONE:
603             default:
604                 break;
605         }
606     }
607     return true;
608 }
609 
thermalThrottlingUpdate(const Temperature_2_0 & 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)610 void ThermalThrottling::thermalThrottlingUpdate(
611         const Temperature_2_0 &temp, const SensorInfo &sensor_info,
612         const ThrottlingSeverity curr_severity, const std::chrono::milliseconds time_elapsed_ms,
613         const std::unordered_map<std::string, PowerStatus> &power_status_map,
614         const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
615     if (!thermal_throttling_status_map_.count(temp.name)) {
616         return;
617     }
618 
619     if (thermal_throttling_status_map_[temp.name].pid_power_budget_map.size()) {
620         if (!allocatePowerToCdev(temp, sensor_info, curr_severity, time_elapsed_ms,
621                                  power_status_map, cooling_device_info_map)) {
622             LOG(ERROR) << "Sensor " << temp.name << " PID request cdev failed";
623             // Clear the CDEV request if the power budget is failed to be allocated
624             for (auto &pid_cdev_request_pair :
625                  thermal_throttling_status_map_[temp.name].pid_cdev_request_map) {
626                 pid_cdev_request_pair.second = 0;
627             }
628         }
629         updateCdevRequestByPower(temp.name, cooling_device_info_map);
630     }
631 
632     if (thermal_throttling_status_map_[temp.name].hardlimit_cdev_request_map.size()) {
633         updateCdevRequestBySeverity(temp.name.c_str(), sensor_info, curr_severity);
634     }
635 
636     if (thermal_throttling_status_map_[temp.name].throttling_release_map.size()) {
637         throttlingReleaseUpdate(temp.name.c_str(), cooling_device_info_map, power_status_map,
638                                 curr_severity, sensor_info);
639     }
640 }
641 
computeCoolingDevicesRequest(std::string_view sensor_name,const SensorInfo & sensor_info,const ThrottlingSeverity curr_severity,std::vector<std::string> * cooling_devices_to_update)642 void ThermalThrottling::computeCoolingDevicesRequest(
643         std::string_view sensor_name, const SensorInfo &sensor_info,
644         const ThrottlingSeverity curr_severity,
645         std::vector<std::string> *cooling_devices_to_update) {
646     int release_step = 0;
647     std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
648 
649     if (!thermal_throttling_status_map_.count(sensor_name.data())) {
650         return;
651     }
652 
653     auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
654     const auto &cdev_release_map = thermal_throttling_status.throttling_release_map;
655 
656     for (auto &cdev_request_pair : thermal_throttling_status.cdev_status_map) {
657         int pid_cdev_request = 0;
658         int hardlimit_cdev_request = 0;
659         const auto &binded_cdev_info =
660                 sensor_info.throttling_info->binded_cdev_info_map.at(cdev_request_pair.first);
661         const auto cdev_ceiling = binded_cdev_info.cdev_ceiling[static_cast<size_t>(curr_severity)];
662         const auto cdev_floor =
663                 binded_cdev_info.cdev_floor_with_power_link[static_cast<size_t>(curr_severity)];
664         release_step = 0;
665 
666         if (thermal_throttling_status.pid_cdev_request_map.count(cdev_request_pair.first)) {
667             pid_cdev_request =
668                     thermal_throttling_status.pid_cdev_request_map.at(cdev_request_pair.first);
669         }
670 
671         if (thermal_throttling_status.hardlimit_cdev_request_map.count(cdev_request_pair.first)) {
672             hardlimit_cdev_request = thermal_throttling_status.hardlimit_cdev_request_map.at(
673                     cdev_request_pair.first);
674         }
675 
676         if (cdev_release_map.count(cdev_request_pair.first)) {
677             release_step = cdev_release_map.at(cdev_request_pair.first);
678         }
679 
680         LOG(VERBOSE) << sensor_name.data() << " binded cooling device " << cdev_request_pair.first
681                      << "'s pid_request=" << pid_cdev_request
682                      << " hardlimit_cdev_request=" << hardlimit_cdev_request
683                      << " release_step=" << release_step
684                      << " cdev_floor_with_power_link=" << cdev_floor
685                      << " cdev_ceiling=" << cdev_ceiling;
686 
687         ATRACE_INT((cdev_request_pair.first + std::string("-pid_request")).c_str(),
688                    pid_cdev_request);
689         ATRACE_INT((cdev_request_pair.first + std::string("-hardlimit_request")).c_str(),
690                    hardlimit_cdev_request);
691         ATRACE_INT((cdev_request_pair.first + std::string("-release_step")).c_str(), release_step);
692         ATRACE_INT((cdev_request_pair.first + std::string("-cdev_floor")).c_str(), cdev_floor);
693         ATRACE_INT((cdev_request_pair.first + std::string("-cdev_ceiling")).c_str(), cdev_ceiling);
694 
695         auto request_state = std::max(pid_cdev_request, hardlimit_cdev_request);
696         if (release_step) {
697             if (release_step >= request_state) {
698                 request_state = 0;
699             } else {
700                 request_state = request_state - release_step;
701             }
702             // Only check the cdev_floor when release step is non zero
703             request_state = std::max(request_state, cdev_floor);
704         }
705         request_state = std::min(request_state, cdev_ceiling);
706 
707         if (cdev_request_pair.second != request_state) {
708             cdev_request_pair.second = request_state;
709             cooling_devices_to_update->emplace_back(cdev_request_pair.first);
710         }
711     }
712 }
713 
714 }  // namespace implementation
715 }  // namespace V2_0
716 }  // namespace thermal
717 }  // namespace hardware
718 }  // namespace android
719