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