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