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