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