summaryrefslogtreecommitdiff
path: root/thermal
diff options
context:
space:
mode:
authorTeYuan Wang <kamewang@google.com>2022-03-28 20:26:06 +0800
committerTeYuan Wang <kamewang@google.com>2022-04-20 19:59:27 +0800
commit708a1dfa926bc2ca1f0c9aaa6543ed95c9f1fc89 (patch)
tree8aeebcf79a58107a98ad8bb24f9b1bcd0f483942 /thermal
parent996a9e16cedb40c0035235e7a81b32742e2a5725 (diff)
thermal: Introduce PID 2.0
Support dynamically power budget distribution base on real power loading Bug: 196478280 Test: run burn8 and manhattan and confirm thermal throttling, Test: Verify thermal powerhint, and thermal event notification with emul_temp Test: adb shell lshal debug android.hardware.thermal@2.0::IThermal/default Change-Id: I9741762375f96e9b7c03db857f0e7d78c31eb5ee
Diffstat (limited to 'thermal')
-rw-r--r--thermal/Android.bp43
-rw-r--r--thermal/Thermal.cpp375
-rw-r--r--thermal/Thermal.h10
-rw-r--r--thermal/device.mk11
-rw-r--r--thermal/pid_1_0/utils/thermal_throttling.cpp451
-rw-r--r--thermal/pid_1_0/utils/thermal_throttling.h121
-rw-r--r--thermal/thermal-helper.cpp459
-rw-r--r--thermal/thermal-helper.h81
-rw-r--r--thermal/utils/power_files.cpp391
-rw-r--r--thermal/utils/power_files.h88
-rw-r--r--thermal/utils/powerhal_helper.cpp134
-rw-r--r--thermal/utils/powerhal_helper.h67
-rw-r--r--thermal/utils/thermal_files.cpp2
-rw-r--r--thermal/utils/thermal_files.h2
-rw-r--r--thermal/utils/thermal_info.cpp (renamed from thermal/utils/config_parser.cpp)66
-rw-r--r--thermal/utils/thermal_info.h (renamed from thermal/utils/config_parser.h)12
-rw-r--r--thermal/utils/thermal_throttling.cpp590
-rw-r--r--thermal/utils/thermal_throttling.h127
18 files changed, 2041 insertions, 989 deletions
diff --git a/thermal/Android.bp b/thermal/Android.bp
index 09722ce..f0d5a6e 100644
--- a/thermal/Android.bp
+++ b/thermal/Android.bp
@@ -1,21 +1,39 @@
-package {
- // See: http://go/android-license-faq
- default_applicable_licenses: [
- "Android-Apache-2.0",
- "hardware_google_pixel_thermal_license",
- ],
+soong_config_module_type {
+ name: "thermal_hal_feature_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "thermal_hal_feature",
+ variables: ["pid"],
+ properties: ["cflags", "srcs"],
}
-license {
- name: "hardware_google_pixel_thermal_license",
- license_kinds: ["SPDX-license-identifier-BSD"],
- license_text: ["LICENSE"],
+soong_config_string_variable {
+ name: "pid",
+ values: ["apply_1_0", "apply_2_0"],
+}
+
+thermal_hal_feature_cc_defaults {
+ name: "thermal_hal_feature_defaults",
+ soong_config_variables: {
+ pid: {
+ apply_1_0: {
+ srcs: [
+ "pid_1_0/utils/thermal_throttling.cpp",
+ ],
+ },
+ apply_2_0: {
+ srcs: [
+ "utils/thermal_throttling.cpp",
+ ],
+ },
+ },
+ },
}
cc_binary {
name: "android.hardware.thermal@2.0-service.pixel",
defaults: [
"hidl_defaults",
+ "thermal_hal_feature_defaults",
],
vendor: true,
relative_install_path: "hw",
@@ -27,10 +45,11 @@ cc_binary {
"service.cpp",
"Thermal.cpp",
"thermal-helper.cpp",
- "utils/config_parser.cpp",
+ "utils/thermal_info.cpp",
"utils/thermal_files.cpp",
- "utils/thermal_watcher.cpp",
"utils/power_files.cpp",
+ "utils/powerhal_helper.cpp",
+ "utils/thermal_watcher.cpp",
],
shared_libs: [
"libbase",
diff --git a/thermal/Thermal.cpp b/thermal/Thermal.cpp
index 8f9f0e2..d0dc078 100644
--- a/thermal/Thermal.cpp
+++ b/thermal/Thermal.cpp
@@ -64,7 +64,7 @@ Return<void> setInitFailureAndCallback(T _hidl_cb, hidl_vec<U> data) {
// Thermal() is killed.
Thermal::Thermal()
: thermal_helper_(
- std::bind(&Thermal::sendThermalChangedCallback, this, std::placeholders::_1)) {}
+ std::bind(&Thermal::sendThermalChangedCallback, this, std::placeholders::_1)) {}
// Methods from ::android::hardware::thermal::V1_0::IThermal.
Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) {
@@ -164,7 +164,7 @@ Return<void> Thermal::getCurrentCoolingDevices(bool filterType, CoolingType type
}
if (!thermal_helper_.fillCurrentCoolingDevices(filterType, type, &cooling_devices)) {
- return setFailureAndCallback(_hidl_cb, cooling_devices, "Failed to read thermal sensors.");
+ return setFailureAndCallback(_hidl_cb, cooling_devices, "Failed to read cooling devices.");
}
_hidl_cb(status, cooling_devices);
@@ -219,7 +219,7 @@ Return<void> Thermal::registerThermalChangedCallback(const sp<IThermalChangedCal
}
Return<void> Thermal::unregisterThermalChangedCallback(
- const sp<IThermalChangedCallback> &callback, unregisterThermalChangedCallback_cb _hidl_cb) {
+ const sp<IThermalChangedCallback> &callback, unregisterThermalChangedCallback_cb _hidl_cb) {
ThermalStatus status;
if (callback == nullptr) {
status.code = ThermalStatusCode::FAILURE;
@@ -233,19 +233,20 @@ Return<void> Thermal::unregisterThermalChangedCallback(
bool removed = false;
std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
callbacks_.erase(
- std::remove_if(callbacks_.begin(), callbacks_.end(),
- [&](const CallbackSetting &c) {
- if (interfacesEqual(c.callback, callback)) {
- LOG(INFO)
- << "a callback has been unregistered to ThermalHAL, isFilter: "
- << c.is_filter_type << " Type: "
- << android::hardware::thermal::V2_0::toString(c.type);
- removed = true;
- return true;
- }
- return false;
- }),
- callbacks_.end());
+ std::remove_if(
+ callbacks_.begin(), callbacks_.end(),
+ [&](const CallbackSetting &c) {
+ if (interfacesEqual(c.callback, callback)) {
+ LOG(INFO)
+ << "a callback has been unregistered to ThermalHAL, isFilter: "
+ << c.is_filter_type << " Type: "
+ << android::hardware::thermal::V2_0::toString(c.type);
+ removed = true;
+ return true;
+ }
+ return false;
+ }),
+ callbacks_.end());
if (!removed) {
status.code = ThermalStatusCode::FAILURE;
status.debugMessage = "The callback was not registered before";
@@ -332,69 +333,88 @@ void Thermal::dumpVirtualSensorInfo(std::ostringstream *dump_buf) {
void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) {
*dump_buf << "Throttling Info:" << std::endl;
const auto &map = thermal_helper_.GetSensorInfoMap();
+ const auto &thermal_throttling_status_map = thermal_helper_.GetThermalThrottlingStatusMap();
for (const auto &name_info_pair : map) {
if (name_info_pair.second.throttling_info->binded_cdev_info_map.size()) {
*dump_buf << " Name: " << name_info_pair.first << std::endl;
- *dump_buf << " PID Info:" << std::endl;
- *dump_buf << " K_po: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->k_po[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " K_pu: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->k_pu[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " K_i: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->k_i[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " K_d: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->k_d[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " i_max: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->i_max[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " max_alloc_power: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->max_alloc_power[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " min_alloc_power: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->min_alloc_power[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " s_power: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->s_power[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " i_cutoff: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << name_info_pair.second.throttling_info->i_cutoff[i] << " ";
+ if (thermal_throttling_status_map.at(name_info_pair.first)
+ .pid_power_budget_map.size()) {
+ *dump_buf << " PID Info:" << std::endl;
+ *dump_buf << " K_po: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->k_po[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " K_pu: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->k_pu[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " K_i: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->k_i[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " K_d: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->k_d[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " i_max: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->i_max[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " max_alloc_power: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->max_alloc_power[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " min_alloc_power: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->min_alloc_power[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " s_power: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->s_power[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " i_cutoff: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << name_info_pair.second.throttling_info->i_cutoff[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
}
- *dump_buf << "]" << std::endl;
*dump_buf << " Binded CDEV Info:" << std::endl;
- if (name_info_pair.second.throttling_info->binded_cdev_info_map.size()) {
- for (const auto &binded_cdev_info_pair :
- name_info_pair.second.throttling_info->binded_cdev_info_map) {
- *dump_buf << " Cooling device name: " << binded_cdev_info_pair.first
- << std::endl;
+ for (const auto &binded_cdev_info_pair :
+ name_info_pair.second.throttling_info->binded_cdev_info_map) {
+ *dump_buf << " Cooling device name: " << binded_cdev_info_pair.first << std::endl;
+ if (thermal_throttling_status_map.at(name_info_pair.first)
+ .pid_power_budget_map.size()) {
*dump_buf << " WeightForPID: [";
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
*dump_buf << binded_cdev_info_pair.second.cdev_weight_for_pid[i] << " ";
}
*dump_buf << "]" << std::endl;
- *dump_buf << " Ceiling: [";
+ }
+ *dump_buf << " Ceiling: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << binded_cdev_info_pair.second.cdev_ceiling[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+ *dump_buf << " Hard limit: [";
+ for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
+ *dump_buf << binded_cdev_info_pair.second.limit_info[i] << " ";
+ }
+ *dump_buf << "]" << std::endl;
+
+ if (!binded_cdev_info_pair.second.power_rail.empty()) {
+ *dump_buf << " Binded power rail: "
+ << binded_cdev_info_pair.second.power_rail << std::endl;
+ *dump_buf << " Power threshold: [";
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << binded_cdev_info_pair.second.cdev_ceiling[i] << " ";
+ *dump_buf << binded_cdev_info_pair.second.power_thresholds[i] << " ";
}
*dump_buf << "]" << std::endl;
*dump_buf << " Floor with PowerLink: [";
@@ -403,45 +423,30 @@ void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) {
<< " ";
}
*dump_buf << "]" << std::endl;
- *dump_buf << " Hard limit: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << binded_cdev_info_pair.second.limit_info[i] << " ";
- }
- *dump_buf << "]" << std::endl;
-
- if (!binded_cdev_info_pair.second.power_rail.empty()) {
- *dump_buf << " Binded power rail: "
- << binded_cdev_info_pair.second.power_rail << std::endl;
- *dump_buf << " Power threshold: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- *dump_buf << binded_cdev_info_pair.second.power_thresholds[i] << " ";
- }
- *dump_buf << "]" << std::endl;
- *dump_buf << " Release logic: ";
- switch (binded_cdev_info_pair.second.release_logic) {
- case ReleaseLogic::INCREASE:
- *dump_buf << "INCREASE";
- break;
- case ReleaseLogic::DECREASE:
- *dump_buf << "DECREASE";
- break;
- case ReleaseLogic::STEPWISE:
- *dump_buf << "STEPWISE";
- break;
- case ReleaseLogic::RELEASE_TO_FLOOR:
- *dump_buf << "RELEASE_TO_FLOOR";
- break;
- default:
- *dump_buf << "NONE";
- break;
- }
- *dump_buf << std::endl;
- *dump_buf << " high_power_check: " << std::boolalpha
- << binded_cdev_info_pair.second.high_power_check << std::endl;
- *dump_buf << " throttling_with_power_link: " << std::boolalpha
- << binded_cdev_info_pair.second.throttling_with_power_link
- << std::endl;
+ *dump_buf << " Release logic: ";
+ switch (binded_cdev_info_pair.second.release_logic) {
+ case ReleaseLogic::INCREASE:
+ *dump_buf << "INCREASE";
+ break;
+ case ReleaseLogic::DECREASE:
+ *dump_buf << "DECREASE";
+ break;
+ case ReleaseLogic::STEPWISE:
+ *dump_buf << "STEPWISE";
+ break;
+ case ReleaseLogic::RELEASE_TO_FLOOR:
+ *dump_buf << "RELEASE_TO_FLOOR";
+ break;
+ default:
+ *dump_buf << "NONE";
+ break;
}
+ *dump_buf << std::endl;
+ *dump_buf << " high_power_check: " << std::boolalpha
+ << binded_cdev_info_pair.second.high_power_check << std::endl;
+ *dump_buf << " throttling_with_power_link: " << std::boolalpha
+ << binded_cdev_info_pair.second.throttling_with_power_link
+ << std::endl;
}
}
}
@@ -449,36 +454,50 @@ void Thermal::dumpThrottlingInfo(std::ostringstream *dump_buf) {
}
void Thermal::dumpThrottlingRequestStatus(std::ostringstream *dump_buf) {
- const auto &sensor_status_map = thermal_helper_.GetSensorStatusMap();
- const auto &cdev_status_map = thermal_helper_.GetCdevStatusMap();
- const auto &release_map = thermal_helper_.GetThrottlingReleaseMap();
+ const auto &thermal_throttling_status_map = thermal_helper_.GetThermalThrottlingStatusMap();
+ if (!thermal_throttling_status_map.size()) {
+ return;
+ }
*dump_buf << "Throttling Request Status " << std::endl;
- for (const auto &cdev_status_pair : cdev_status_map) {
- *dump_buf << " Name: " << cdev_status_pair.first << std::endl;
- for (const auto &request_pair : cdev_status_pair.second) {
- *dump_buf << " Request Sensor: " << request_pair.first << std::endl;
- *dump_buf << " Request Throttling State: " << request_pair.second << std::endl;
- if (sensor_status_map.at(request_pair.first).pid_request_map.size() &&
- sensor_status_map.at(request_pair.first)
- .pid_request_map.count(cdev_status_pair.first)) {
- *dump_buf << " PID Request State: "
- << sensor_status_map.at(request_pair.first)
- .pid_request_map.at(cdev_status_pair.first)
+ for (const auto &thermal_throttling_status_pair : thermal_throttling_status_map) {
+ *dump_buf << " Name: " << thermal_throttling_status_pair.first << std::endl;
+ if (thermal_throttling_status_pair.second.pid_power_budget_map.size()) {
+ *dump_buf << " power budget request state" << std::endl;
+ for (const auto &request_pair :
+ thermal_throttling_status_pair.second.pid_power_budget_map) {
+ *dump_buf << " " << request_pair.first << ": " << request_pair.second
<< std::endl;
}
- if (sensor_status_map.at(request_pair.first).hard_limit_request_map.size() &&
- sensor_status_map.at(request_pair.first)
- .hard_limit_request_map.count(cdev_status_pair.first)) {
- *dump_buf << " Hard Limit Request State: "
- << sensor_status_map.at(request_pair.first)
- .hard_limit_request_map.at(cdev_status_pair.first)
+ }
+ if (thermal_throttling_status_pair.second.pid_cdev_request_map.size()) {
+ *dump_buf << " pid cdev request state" << std::endl;
+ for (const auto &request_pair :
+ thermal_throttling_status_pair.second.pid_cdev_request_map) {
+ *dump_buf << " " << request_pair.first << ": " << request_pair.second
<< std::endl;
}
- if (release_map.count(request_pair.first) &&
- release_map.at(request_pair.first).count(cdev_status_pair.first)) {
- const auto &cdev_release_info =
- release_map.at(request_pair.first).at(cdev_status_pair.first);
- *dump_buf << " Release Step: " << cdev_release_info.release_step << std::endl;
+ }
+ if (thermal_throttling_status_pair.second.hardlimit_cdev_request_map.size()) {
+ *dump_buf << " hard limit cdev request state" << std::endl;
+ for (const auto &request_pair :
+ thermal_throttling_status_pair.second.hardlimit_cdev_request_map) {
+ *dump_buf << " " << request_pair.first << ": " << request_pair.second
+ << std::endl;
+ }
+ }
+ if (thermal_throttling_status_pair.second.throttling_release_map.size()) {
+ *dump_buf << " cdev release state" << std::endl;
+ for (const auto &request_pair :
+ thermal_throttling_status_pair.second.throttling_release_map) {
+ *dump_buf << " " << request_pair.first << ": " << request_pair.second
+ << std::endl;
+ }
+ }
+ if (thermal_throttling_status_pair.second.cdev_status_map.size()) {
+ *dump_buf << " cdev request state" << std::endl;
+ for (const auto &request_pair : thermal_throttling_status_pair.second.cdev_status_map) {
+ *dump_buf << " " << request_pair.first << ": " << request_pair.second
+ << std::endl;
}
}
}
@@ -495,57 +514,52 @@ void Thermal::dumpPowerRailInfo(std::ostringstream *dump_buf) {
<< std::endl;
*dump_buf << " Power Sample Delay: " << power_rail_pair.second.power_sample_delay.count()
<< std::endl;
- for (const auto &power_status_pair : power_status_map) {
- if (power_status_pair.second.count(power_rail_pair.first)) {
- auto power_history =
- power_status_pair.second.at(power_rail_pair.first).power_history;
- *dump_buf << " Request Sensor: " << power_status_pair.first << std::endl;
- *dump_buf
- << " Last Updated AVG Power: "
- << power_status_pair.second.at(power_rail_pair.first).last_updated_avg_power
- << " mW" << std::endl;
+ if (power_status_map.count(power_rail_pair.first)) {
+ auto power_history = power_status_map.at(power_rail_pair.first).power_history;
+ *dump_buf << " Last Updated AVG Power: "
+ << power_status_map.at(power_rail_pair.first).last_updated_avg_power << " mW"
+ << std::endl;
+ if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
+ *dump_buf << " Formula=";
+ switch (power_rail_pair.second.virtual_power_rail_info->formula) {
+ case FormulaOption::COUNT_THRESHOLD:
+ *dump_buf << "COUNT_THRESHOLD";
+ break;
+ case FormulaOption::WEIGHTED_AVG:
+ *dump_buf << "WEIGHTED_AVG";
+ break;
+ case FormulaOption::MAXIMUM:
+ *dump_buf << "MAXIMUM";
+ break;
+ case FormulaOption::MINIMUM:
+ *dump_buf << "MINIMUM";
+ break;
+ default:
+ *dump_buf << "NONE";
+ break;
+ }
+ *dump_buf << std::endl;
+ }
+ for (size_t i = 0; i < power_history.size(); ++i) {
if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
- *dump_buf << " Formula=";
- switch (power_rail_pair.second.virtual_power_rail_info->formula) {
- case FormulaOption::COUNT_THRESHOLD:
- *dump_buf << "COUNT_THRESHOLD";
- break;
- case FormulaOption::WEIGHTED_AVG:
- *dump_buf << "WEIGHTED_AVG";
- break;
- case FormulaOption::MAXIMUM:
- *dump_buf << "MAXIMUM";
- break;
- case FormulaOption::MINIMUM:
- *dump_buf << "MINIMUM";
- break;
- default:
- *dump_buf << "NONE";
- break;
- }
- *dump_buf << std::endl;
+ *dump_buf
+ << " Linked power rail "
+ << power_rail_pair.second.virtual_power_rail_info->linked_power_rails[i]
+ << std::endl;
+ *dump_buf << " Coefficient="
+ << power_rail_pair.second.virtual_power_rail_info->coefficients[i]
+ << std::endl;
+ *dump_buf << " Power Samples: ";
+ } else {
+ *dump_buf << " Power Samples: ";
}
- for (size_t i = 0; i < power_history.size(); ++i) {
- if (power_rail_pair.second.virtual_power_rail_info != nullptr) {
- *dump_buf << " Linked power rail "
- << power_rail_pair.second.virtual_power_rail_info
- ->linked_power_rails[i]
- << std::endl;
- *dump_buf << " Coefficient="
- << power_rail_pair.second.virtual_power_rail_info->coefficients[i]
- << std::endl;
- *dump_buf << " Power Samples: ";
- } else {
- *dump_buf << " Power Samples: ";
- }
- while (power_history[i].size() > 0) {
- const auto power_sample = power_history[i].front();
- power_history[i].pop();
- *dump_buf << "(T=" << power_sample.duration
- << ", uWs=" << power_sample.energy_counter << ") ";
- }
- *dump_buf << std::endl;
+ while (power_history[i].size() > 0) {
+ const auto power_sample = power_history[i].front();
+ power_history[i].pop();
+ *dump_buf << "(T=" << power_sample.duration
+ << ", uWs=" << power_sample.energy_counter << ") ";
}
+ *dump_buf << std::endl;
}
}
}
@@ -660,6 +674,9 @@ Return<void> Thermal::debug(const hidl_handle &handle, const hidl_vec<hidl_strin
dump_buf << "getHysteresis:" << std::endl;
const auto &map = thermal_helper_.GetSensorInfoMap();
for (const auto &name_info_pair : map) {
+ if (!name_info_pair.second.is_watch) {
+ continue;
+ }
dump_buf << " Name: " << name_info_pair.first;
dump_buf << " hotHysteresis: [";
for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
diff --git a/thermal/Thermal.h b/thermal/Thermal.h
index d33e77d..36e079e 100644
--- a/thermal/Thermal.h
+++ b/thermal/Thermal.h
@@ -16,13 +16,13 @@
#pragma once
-#include <mutex>
-#include <thread>
-
#include <android/hardware/thermal/2.0/IThermal.h>
#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
#include <hidl/Status.h>
+#include <mutex>
+#include <thread>
+
#include "thermal-helper.h"
namespace android {
@@ -69,8 +69,8 @@ class Thermal : public IThermal {
const sp<IThermalChangedCallback> &callback, bool filterType, TemperatureType_2_0 type,
registerThermalChangedCallback_cb _hidl_cb) override;
Return<void> unregisterThermalChangedCallback(
- const sp<IThermalChangedCallback> &callback,
- unregisterThermalChangedCallback_cb _hidl_cb) override;
+ const sp<IThermalChangedCallback> &callback,
+ unregisterThermalChangedCallback_cb _hidl_cb) override;
Return<void> getCurrentCoolingDevices(bool filterType, CoolingType type,
getCurrentCoolingDevices_cb _hidl_cb) override;
diff --git a/thermal/device.mk b/thermal/device.mk
index d316633..bf150cd 100644
--- a/thermal/device.mk
+++ b/thermal/device.mk
@@ -1,6 +1,15 @@
# Thermal HAL
+SOONG_CONFIG_NAMESPACES += thermal_hal_feature
+SOONG_CONFIG_thermal_hal_feature += \
+ pid \
+
+SOONG_CONFIG_thermal_hal_feature_pid ?= apply_1_0
+
+PRODUCT_PACKAGES += \
+ android.hardware.thermal@2.0-service.pixel
+
+# Thermal utils
PRODUCT_PACKAGES += \
- android.hardware.thermal@2.0-service.pixel \
thermal_symlinks
ifneq (,$(filter userdebug eng, $(TARGET_BUILD_VARIANT)))
diff --git a/thermal/pid_1_0/utils/thermal_throttling.cpp b/thermal/pid_1_0/utils/thermal_throttling.cpp
new file mode 100644
index 0000000..f158b6c
--- /dev/null
+++ b/thermal/pid_1_0/utils/thermal_throttling.cpp
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thermal_throttling.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <utils/Trace.h>
+
+#include <iterator>
+#include <set>
+#include <sstream>
+#include <thread>
+#include <vector>
+
+#include "../../utils/power_files.h"
+#include "../../utils/thermal_info.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V2_0 {
+namespace implementation {
+
+// To find the next PID target state according to the current thermal severity
+size_t getTargetStateOfPID(const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity) {
+ size_t target_state = 0;
+
+ for (const auto &severity : hidl_enum_range<ThrottlingSeverity>()) {
+ size_t state = static_cast<size_t>(severity);
+ if (std::isnan(sensor_info.throttling_info->s_power[state])) {
+ continue;
+ }
+ target_state = state;
+ if (severity > curr_severity) {
+ break;
+ }
+ }
+ LOG(VERBOSE) << "PID target state = " << target_state;
+ return target_state;
+}
+
+void ThermalThrottling::clearThrottlingData(std::string_view sensor_name,
+ const SensorInfo &sensor_info) {
+ if (!thermal_throttling_status_map_.count(sensor_name.data())) {
+ return;
+ }
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+
+ for (auto &pid_power_budget_pair :
+ thermal_throttling_status_map_.at(sensor_name.data()).pid_power_budget_map) {
+ pid_power_budget_pair.second = std::numeric_limits<int>::max();
+ }
+
+ for (auto &pid_cdev_request_pair :
+ thermal_throttling_status_map_.at(sensor_name.data()).pid_cdev_request_map) {
+ pid_cdev_request_pair.second = 0;
+ }
+
+ for (auto &hardlimit_cdev_request_pair :
+ thermal_throttling_status_map_.at(sensor_name.data()).hardlimit_cdev_request_map) {
+ hardlimit_cdev_request_pair.second = 0;
+ }
+
+ for (auto &throttling_release_pair :
+ thermal_throttling_status_map_.at(sensor_name.data()).throttling_release_map) {
+ throttling_release_pair.second = 0;
+ }
+
+ thermal_throttling_status_map_[sensor_name.data()].err_integral =
+ sensor_info.throttling_info->err_integral_default;
+ thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
+ return;
+}
+
+bool ThermalThrottling::registerThermalThrottling(
+ std::string_view sensor_name, const std::shared_ptr<ThrottlingInfo> &throttling_info,
+ const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
+ if (thermal_throttling_status_map_.count(sensor_name.data())) {
+ LOG(ERROR) << "Sensor " << sensor_name.data() << " throttling map has been registered";
+ return false;
+ }
+
+ if (throttling_info == nullptr) {
+ LOG(ERROR) << "Sensor " << sensor_name.data() << " has no throttling info";
+ return false;
+ }
+ thermal_throttling_status_map_[sensor_name.data()].err_integral =
+ throttling_info->err_integral_default;
+ thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
+
+ for (auto &binded_cdev_pair : throttling_info->binded_cdev_info_map) {
+ if (!cooling_device_info_map.count(binded_cdev_pair.first)) {
+ LOG(ERROR) << "Could not find " << sensor_name.data() << "'s binded CDEV "
+ << binded_cdev_pair.first;
+ return false;
+ }
+ // Register PID throttling map
+ for (const auto &cdev_weight : binded_cdev_pair.second.cdev_weight_for_pid) {
+ if (!std::isnan(cdev_weight)) {
+ thermal_throttling_status_map_[sensor_name.data()]
+ .pid_power_budget_map[binded_cdev_pair.first] =
+ std::numeric_limits<int>::max();
+ thermal_throttling_status_map_[sensor_name.data()]
+ .pid_cdev_request_map[binded_cdev_pair.first] = 0;
+ thermal_throttling_status_map_[sensor_name.data()]
+ .cdev_status_map[binded_cdev_pair.first] = 0;
+ break;
+ }
+ }
+ // Register hard limit throttling map
+ for (const auto &limit_info : binded_cdev_pair.second.limit_info) {
+ if (limit_info > 0) {
+ thermal_throttling_status_map_[sensor_name.data()]
+ .hardlimit_cdev_request_map[binded_cdev_pair.first] = 0;
+ thermal_throttling_status_map_[sensor_name.data()]
+ .cdev_status_map[binded_cdev_pair.first] = 0;
+ break;
+ }
+ }
+ // Register throttling release map if power threshold is exist
+ if (!binded_cdev_pair.second.power_rail.empty()) {
+ for (const auto &power_threshold : binded_cdev_pair.second.power_thresholds) {
+ if (!std::isnan(power_threshold)) {
+ thermal_throttling_status_map_[sensor_name.data()]
+ .throttling_release_map[binded_cdev_pair.first] = 0;
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// return power budget based on PID algo
+float ThermalThrottling::updatePowerBudget(const Temperature_2_0 &temp,
+ const SensorInfo &sensor_info,
+ std::chrono::milliseconds time_elapsed_ms,
+ ThrottlingSeverity curr_severity) {
+ float p = 0, i = 0, d = 0;
+ float power_budget = std::numeric_limits<float>::max();
+
+ if (curr_severity == ThrottlingSeverity::NONE) {
+ return power_budget;
+ }
+
+ const auto target_state = getTargetStateOfPID(sensor_info, curr_severity);
+
+ // Compute PID
+ float err = sensor_info.hot_thresholds[target_state] - temp.value;
+ p = err * (err < 0 ? sensor_info.throttling_info->k_po[target_state]
+ : sensor_info.throttling_info->k_pu[target_state]);
+ i = thermal_throttling_status_map_[temp.name].err_integral *
+ sensor_info.throttling_info->k_i[target_state];
+ if (err < sensor_info.throttling_info->i_cutoff[target_state]) {
+ float i_next = i + err * sensor_info.throttling_info->k_i[target_state];
+ if (abs(i_next) < sensor_info.throttling_info->i_max[target_state]) {
+ i = i_next;
+ thermal_throttling_status_map_[temp.name].err_integral += err;
+ }
+ }
+
+ if (!std::isnan(thermal_throttling_status_map_[temp.name].prev_err) &&
+ time_elapsed_ms != std::chrono::milliseconds::zero()) {
+ d = sensor_info.throttling_info->k_d[target_state] *
+ (err - thermal_throttling_status_map_[temp.name].prev_err) / time_elapsed_ms.count();
+ }
+
+ thermal_throttling_status_map_[temp.name].prev_err = err;
+ // Calculate power budget
+ power_budget = sensor_info.throttling_info->s_power[target_state] + p + i + d;
+ if (power_budget < sensor_info.throttling_info->min_alloc_power[target_state]) {
+ power_budget = sensor_info.throttling_info->min_alloc_power[target_state];
+ }
+ if (power_budget > sensor_info.throttling_info->max_alloc_power[target_state]) {
+ power_budget = sensor_info.throttling_info->max_alloc_power[target_state];
+ }
+
+ LOG(INFO) << temp.name << " power_budget=" << power_budget << " err=" << err
+ << " err_integral=" << thermal_throttling_status_map_[temp.name].err_integral
+ << " s_power=" << sensor_info.throttling_info->s_power[target_state]
+ << " time_elapsed_ms=" << time_elapsed_ms.count() << " p=" << p << " i=" << i
+ << " d=" << d << " control target=" << target_state;
+
+ return power_budget;
+}
+
+bool ThermalThrottling::updateCdevRequestByPower(
+ 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, CdevInfo> &cooling_device_info_map) {
+ float total_weight = 0, cdev_power_budget;
+ size_t j;
+
+ const auto target_state = getTargetStateOfPID(sensor_info, curr_severity);
+ auto total_power_budget = updatePowerBudget(temp, sensor_info, time_elapsed_ms, curr_severity);
+
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ // Compute total cdev weight
+ for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
+ const auto cdev_weight = binded_cdev_info_pair.second
+ .cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
+ if (std::isnan(cdev_weight)) {
+ continue;
+ }
+ total_weight += cdev_weight;
+ }
+
+ // Map cdev state by power
+ for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
+ const auto cdev_weight = binded_cdev_info_pair.second.cdev_weight_for_pid[target_state];
+ if (!std::isnan(cdev_weight)) {
+ cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
+
+ const CdevInfo &cdev_info_pair =
+ cooling_device_info_map.at(binded_cdev_info_pair.first);
+ for (j = 0; j < cdev_info_pair.state2power.size() - 1; ++j) {
+ if (cdev_power_budget > cdev_info_pair.state2power[j]) {
+ break;
+ }
+ }
+
+ thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
+ binded_cdev_info_pair.first) = static_cast<int>(j);
+ LOG(VERBOSE) << "Power allocator: Sensor " << temp.name << " allocate "
+ << cdev_power_budget << "mW to " << binded_cdev_info_pair.first
+ << "(cdev_weight=" << cdev_weight << ") update state to " << j;
+ }
+ }
+ return true;
+}
+
+void ThermalThrottling::updateCdevRequestBySeverity(std::string_view sensor_name,
+ const SensorInfo &sensor_info,
+ ThrottlingSeverity curr_severity) {
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ for (auto const &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
+ thermal_throttling_status_map_[sensor_name.data()].hardlimit_cdev_request_map.at(
+ binded_cdev_info_pair.first) =
+ binded_cdev_info_pair.second.limit_info[static_cast<size_t>(curr_severity)];
+ LOG(VERBOSE) << "Hard Limit: Sensor " << sensor_name.data() << " update cdev "
+ << binded_cdev_info_pair.first << " to "
+ << thermal_throttling_status_map_[sensor_name.data()]
+ .hardlimit_cdev_request_map.at(binded_cdev_info_pair.first);
+ }
+}
+
+bool ThermalThrottling::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) {
+ ATRACE_CALL();
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ if (!thermal_throttling_status_map_.count(sensor_name.data())) {
+ return false;
+ }
+ auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
+ for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
+ float avg_power = -1;
+
+ if (!thermal_throttling_status.throttling_release_map.count(binded_cdev_info_pair.first) ||
+ !power_status_map.count(binded_cdev_info_pair.second.power_rail)) {
+ return false;
+ }
+
+ const auto max_state = cooling_device_info_map.at(binded_cdev_info_pair.first).max_state;
+
+ auto &release_step =
+ thermal_throttling_status.throttling_release_map.at(binded_cdev_info_pair.first);
+ avg_power =
+ power_status_map.at(binded_cdev_info_pair.second.power_rail).last_updated_avg_power;
+
+ // Return false if we cannot get the AVG power
+ if (std::isnan(avg_power) || avg_power < 0) {
+ release_step = binded_cdev_info_pair.second.throttling_with_power_link ? max_state : 0;
+ continue;
+ }
+
+ bool is_over_budget = true;
+ if (!binded_cdev_info_pair.second.high_power_check) {
+ if (avg_power <
+ binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
+ is_over_budget = false;
+ }
+ } else {
+ if (avg_power >
+ binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
+ is_over_budget = false;
+ }
+ }
+ LOG(INFO) << sensor_name.data() << "'s " << binded_cdev_info_pair.first
+ << " binded power rail " << binded_cdev_info_pair.second.power_rail
+ << ": power threshold = "
+ << binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]
+ << ", avg power = " << avg_power;
+
+ switch (binded_cdev_info_pair.second.release_logic) {
+ case ReleaseLogic::INCREASE:
+ if (!is_over_budget) {
+ if (std::abs(release_step) < static_cast<int>(max_state)) {
+ release_step--;
+ }
+ } else {
+ release_step = 0;
+ }
+ break;
+ case ReleaseLogic::DECREASE:
+ if (!is_over_budget) {
+ if (release_step < static_cast<int>(max_state)) {
+ release_step++;
+ }
+ } else {
+ release_step = 0;
+ }
+ break;
+ case ReleaseLogic::STEPWISE:
+ if (!is_over_budget) {
+ if (release_step < static_cast<int>(max_state)) {
+ release_step++;
+ }
+ } else {
+ if (std::abs(release_step) < static_cast<int>(max_state)) {
+ release_step--;
+ }
+ }
+ break;
+ case ReleaseLogic::RELEASE_TO_FLOOR:
+ release_step = is_over_budget ? 0 : max_state;
+ break;
+ case ReleaseLogic::NONE:
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+void ThermalThrottling::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) {
+ if (!thermal_throttling_status_map_.count(temp.name)) {
+ return;
+ }
+
+ if (thermal_throttling_status_map_[temp.name].pid_power_budget_map.size()) {
+ updateCdevRequestByPower(temp, sensor_info, curr_severity, time_elapsed_ms,
+ cooling_device_info_map);
+ }
+
+ if (thermal_throttling_status_map_[temp.name].hardlimit_cdev_request_map.size()) {
+ updateCdevRequestBySeverity(temp.name.c_str(), sensor_info, curr_severity);
+ }
+
+ if (thermal_throttling_status_map_[temp.name].throttling_release_map.size()) {
+ throttlingReleaseUpdate(temp.name.c_str(), cooling_device_info_map, power_status_map,
+ curr_severity, sensor_info);
+ }
+}
+
+void ThermalThrottling::computeCoolingDevicesRequest(
+ std::string_view sensor_name, const SensorInfo &sensor_info,
+ const ThrottlingSeverity curr_severity,
+ std::vector<std::string> *cooling_devices_to_update) {
+ int release_step = 0;
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+
+ if (!thermal_throttling_status_map_.count(sensor_name.data())) {
+ return;
+ }
+
+ auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
+ const auto &cdev_release_map = thermal_throttling_status.throttling_release_map;
+
+ for (auto &cdev_request_pair : thermal_throttling_status.cdev_status_map) {
+ int pid_cdev_request = 0;
+ int hardlimit_cdev_request = 0;
+ const auto &binded_cdev_info =
+ sensor_info.throttling_info->binded_cdev_info_map.at(cdev_request_pair.first);
+ const auto cdev_ceiling = binded_cdev_info.cdev_ceiling[static_cast<size_t>(curr_severity)];
+ const auto cdev_floor =
+ binded_cdev_info.cdev_floor_with_power_link[static_cast<size_t>(curr_severity)];
+ release_step = 0;
+
+ if (thermal_throttling_status.pid_cdev_request_map.count(cdev_request_pair.first)) {
+ pid_cdev_request =
+ thermal_throttling_status.pid_cdev_request_map.at(cdev_request_pair.first);
+ }
+
+ if (thermal_throttling_status.hardlimit_cdev_request_map.count(cdev_request_pair.first)) {
+ hardlimit_cdev_request = thermal_throttling_status.hardlimit_cdev_request_map.at(
+ cdev_request_pair.first);
+ }
+
+ if (cdev_release_map.count(cdev_request_pair.first)) {
+ release_step = cdev_release_map.at(cdev_request_pair.first);
+ }
+
+ LOG(VERBOSE) << sensor_name.data() << " binded cooling device " << cdev_request_pair.first
+ << "'s pid_request=" << pid_cdev_request
+ << " hardlimit_cdev_request=" << hardlimit_cdev_request
+ << " release_step=" << release_step
+ << " cdev_floor_with_power_link=" << cdev_floor
+ << " cdev_ceiling=" << cdev_ceiling;
+
+ auto request_state = std::max(pid_cdev_request, hardlimit_cdev_request);
+ if (release_step) {
+ if (release_step >= request_state) {
+ request_state = 0;
+ } else {
+ request_state = request_state - release_step;
+ }
+ // Only check the cdev_floor when release step is non zero
+ if (request_state < cdev_floor) {
+ request_state = cdev_floor;
+ }
+ }
+ if (request_state > cdev_ceiling) {
+ request_state = cdev_ceiling;
+ }
+
+ if (cdev_request_pair.second != request_state) {
+ cdev_request_pair.second = request_state;
+ cooling_devices_to_update->emplace_back(cdev_request_pair.first);
+ }
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
diff --git a/thermal/pid_1_0/utils/thermal_throttling.h b/thermal/pid_1_0/utils/thermal_throttling.h
new file mode 100644
index 0000000..e94f25d
--- /dev/null
+++ b/thermal/pid_1_0/utils/thermal_throttling.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/thermal/2.0/IThermal.h>
+
+#include <queue>
+#include <shared_mutex>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "../../utils/power_files.h"
+#include "../../utils/thermal_info.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::thermal::V2_0::IThermal;
+using Temperature_2_0 = ::android::hardware::thermal::V2_0::Temperature;
+using ::android::hardware::thermal::V2_0::TemperatureThreshold;
+using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
+
+struct ThermalThrottlingStatus {
+ std::unordered_map<std::string, int> pid_power_budget_map;
+ std::unordered_map<std::string, int> pid_cdev_request_map;
+ std::unordered_map<std::string, int> hardlimit_cdev_request_map;
+ std::unordered_map<std::string, int> throttling_release_map;
+ std::unordered_map<std::string, int> cdev_status_map;
+ float err_integral;
+ float prev_err;
+};
+
+// Return the target state of PID algorithm
+size_t getTargetStateOfPID(const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity);
+
+// A helper class for conducting thermal throttling
+class ThermalThrottling {
+ public:
+ ThermalThrottling() = default;
+ ~ThermalThrottling() = default;
+ // Disallow copy and assign.
+ ThermalThrottling(const ThermalThrottling &) = delete;
+ void operator=(const ThermalThrottling &) = delete;
+
+ // Clear throttling data
+ void clearThrottlingData(std::string_view sensor_name, const SensorInfo &sensor_info);
+ // Register map for throttling algo
+ bool registerThermalThrottling(
+ std::string_view sensor_name, const std::shared_ptr<ThrottlingInfo> &throttling_info,
+ const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map);
+ // Register map for throttling release algo
+ bool registerThrottlingReleaseToWatch(std::string_view sensor_name, std::string_view cdev_name,
+ const BindedCdevInfo &binded_cdev_info);
+ // Get throttling status map
+ const std::unordered_map<std::string, ThermalThrottlingStatus> &GetThermalThrottlingStatusMap()
+ const {
+ std::shared_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ return thermal_throttling_status_map_;
+ }
+ // update thermal throttling request for the specific sensor
+ void 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);
+
+ // Compute the throttling target from all the sensors' request
+ void computeCoolingDevicesRequest(std::string_view sensor_name, const SensorInfo &sensor_info,
+ const ThrottlingSeverity curr_severity,
+ std::vector<std::string> *cooling_devices_to_update);
+
+ private:
+ // PID algo - get the total power budget
+ float updatePowerBudget(const Temperature_2_0 &temp, const SensorInfo &sensor_info,
+ std::chrono::milliseconds time_elapsed_ms,
+ ThrottlingSeverity curr_severity);
+ // PID algo - map the target throttling state according to the power budget
+ bool updateCdevRequestByPower(
+ 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, CdevInfo> &cooling_device_info_map);
+ // Hard limit algo - assign the throttling state according to the severity
+ void updateCdevRequestBySeverity(std::string_view sensor_name, const SensorInfo &sensor_info,
+ ThrottlingSeverity curr_severity);
+ // Throttling release algo according to predefined power threshold
+ bool 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);
+
+ mutable std::shared_mutex thermal_throttling_status_map_mutex_;
+ // Thermal throttling status from each sensor
+ std::unordered_map<std::string, ThermalThrottlingStatus> thermal_throttling_status_map_;
+ std::vector<std::string> cooling_devices_to_update;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
diff --git a/thermal/thermal-helper.cpp b/thermal/thermal-helper.cpp
index 41b2b27..9b23560 100644
--- a/thermal/thermal-helper.cpp
+++ b/thermal/thermal-helper.cpp
@@ -22,8 +22,6 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <android/binder_manager.h>
-#include <hidl/HidlTransportSupport.h>
#include <utils/Trace.h>
#include <iterator>
@@ -61,7 +59,6 @@ constexpr std::string_view kThermalDisabledProperty("vendor.disable.thermal.cont
namespace {
using android::base::StringPrintf;
-using android::hardware::thermal::V2_0::toString;
/*
* Pixel don't offline CPU, so std::thread::hardware_concurrency(); should work.
@@ -75,18 +72,18 @@ using android::hardware::thermal::V2_0::toString;
static int getNumberOfCores() {
std::string file;
if (!android::base::ReadFileToString(kCpuPresentFile.data(), &file)) {
- LOG(ERROR) << "Error reading Cpu present file: " << kCpuPresentFile;
+ LOG(ERROR) << "Error reading CPU present file: " << kCpuPresentFile;
return 0;
}
std::vector<std::string> pieces = android::base::Split(file, "-");
if (pieces.size() != 2) {
- LOG(ERROR) << "Error parsing Cpu present file content: " << file;
+ LOG(ERROR) << "Error parsing CPU present file content: " << file;
return 0;
}
auto min_core = std::stoul(pieces[0]);
auto max_core = std::stoul(pieces[1]);
if (max_core < min_core) {
- LOG(ERROR) << "Error parsing Cpu present min and max: " << min_core << " - " << max_core;
+ LOG(ERROR) << "Error parsing CPU present min and max: " << min_core << " - " << max_core;
return 0;
}
return static_cast<std::size_t>(max_core - min_core + 1);
@@ -96,7 +93,7 @@ const int kMaxCpus = getNumberOfCores();
void parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> *cpu_usages) {
std::string data;
if (!android::base::ReadFileToString(kCpuUsageFile.data(), &data)) {
- LOG(ERROR) << "Error reading cpu usage file: " << kCpuUsageFile;
+ LOG(ERROR) << "Error reading CPU usage file: " << kCpuUsageFile;
return;
}
@@ -121,7 +118,7 @@ void parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> *cpu_usages) {
kCpuOnlineFileSuffix.data());
std::string is_online;
if (!android::base::ReadFileToString(cpu_online_path, &is_online)) {
- LOG(ERROR) << "Could not open Cpu online file: " << cpu_online_path;
+ LOG(ERROR) << "Could not open CPU online file: " << cpu_online_path;
if (cpu_num != 0) {
return;
}
@@ -134,7 +131,7 @@ void parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> *cpu_usages) {
(*cpu_usages)[cpu_num].total = user + nice + system + idle;
(*cpu_usages)[cpu_num].isOnline = (is_online == "1") ? true : false;
} else {
- LOG(ERROR) << "Unexpected cpu number: " << words[0];
+ LOG(ERROR) << "Unexpected CPU number: " << words[0];
return;
}
}
@@ -176,91 +173,6 @@ std::unordered_map<std::string, std::string> parseThermalPathMap(std::string_vie
}
} // namespace
-PowerHalService::PowerHalService()
- : power_hal_aidl_exist_(true), power_hal_aidl_(nullptr), power_hal_ext_aidl_(nullptr) {
- connect();
-}
-
-bool PowerHalService::connect() {
- std::lock_guard<std::mutex> lock(lock_);
- if (!power_hal_aidl_exist_)
- return false;
-
- if (power_hal_aidl_ != nullptr)
- return true;
-
- const std::string kInstance = std::string(IPower::descriptor) + "/default";
- ndk::SpAIBinder power_binder = ndk::SpAIBinder(AServiceManager_getService(kInstance.c_str()));
- ndk::SpAIBinder ext_power_binder;
-
- if (power_binder.get() == nullptr) {
- LOG(ERROR) << "Cannot get Power Hal Binder";
- power_hal_aidl_exist_ = false;
- return false;
- }
-
- power_hal_aidl_ = IPower::fromBinder(power_binder);
-
- if (power_hal_aidl_ == nullptr) {
- power_hal_aidl_exist_ = false;
- LOG(ERROR) << "Cannot get Power Hal AIDL" << kInstance.c_str();
- return false;
- }
-
- if (STATUS_OK != AIBinder_getExtension(power_binder.get(), ext_power_binder.getR()) ||
- ext_power_binder.get() == nullptr) {
- LOG(ERROR) << "Cannot get Power Hal Extension Binder";
- power_hal_aidl_exist_ = false;
- return false;
- }
-
- power_hal_ext_aidl_ = IPowerExt::fromBinder(ext_power_binder);
- if (power_hal_ext_aidl_ == nullptr) {
- LOG(ERROR) << "Cannot get Power Hal Extension AIDL";
- power_hal_aidl_exist_ = false;
- }
-
- return true;
-}
-
-bool PowerHalService::isModeSupported(const std::string &type, const ThrottlingSeverity &t) {
- bool isSupported = false;
- if (!isPowerHalConnected()) {
- return false;
- }
- std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
- lock_.lock();
- if (!power_hal_ext_aidl_->isModeSupported(power_hint, &isSupported).isOk()) {
- LOG(ERROR) << "Fail to check supported mode, Hint: " << power_hint;
- power_hal_aidl_exist_ = false;
- power_hal_ext_aidl_ = nullptr;
- power_hal_aidl_ = nullptr;
- lock_.unlock();
- return false;
- }
- lock_.unlock();
- return isSupported;
-}
-
-void PowerHalService::setMode(const std::string &type, const ThrottlingSeverity &t,
- const bool &enable) {
- if (!isPowerHalConnected()) {
- return;
- }
-
- std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
- LOG(INFO) << "Send Hint " << power_hint << " Enable: " << std::boolalpha << enable;
- lock_.lock();
- if (!power_hal_ext_aidl_->setMode(power_hint, enable).isOk()) {
- LOG(ERROR) << "Fail to set mode, Hint: " << power_hint;
- power_hal_aidl_exist_ = false;
- power_hal_ext_aidl_ = nullptr;
- power_hal_aidl_ = nullptr;
- lock_.unlock();
- return;
- }
- lock_.unlock();
-}
/*
* Populate the sensor_name_to_file_map_ map by walking through the file tree,
@@ -278,8 +190,7 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb)
android::base::GetBoolProperty(kThermalDisabledProperty.data(), false);
is_initialized_ = ParseCoolingDevice(config_path, &cooling_device_info_map_) &&
- ParseSensorInfo(config_path, &sensor_info_map_) &&
- ParsePowerRailInfo(config_path, &power_rail_info_map_);
+ ParseSensorInfo(config_path, &sensor_info_map_);
if (thermal_throttling_disabled) {
return;
@@ -298,6 +209,10 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb)
LOG(FATAL) << "ThermalHAL could not be initialized properly.";
}
+ if (!power_files_.registerPowerRailsToWatch(config_path)) {
+ LOG(FATAL) << "Failed to register power rails";
+ }
+
for (auto const &name_status_pair : sensor_info_map_) {
sensor_status_map_[name_status_pair.first] = {
.severity = ThrottlingSeverity::NONE,
@@ -306,33 +221,19 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb)
.prev_hint_severity = ThrottlingSeverity::NONE,
.last_update_time = boot_clock::time_point::min(),
.thermal_cached = {NAN, boot_clock::time_point::min()},
- .err_integral = 0.0,
- .prev_err = NAN,
};
- for (auto &binded_cdev_pair :
- name_status_pair.second.throttling_info->binded_cdev_info_map) {
- if (!cooling_device_info_map_.count(binded_cdev_pair.first)) {
- LOG(FATAL) << "Could not find " << binded_cdev_pair.first
- << " in cooling device info map";
- }
-
- for (const auto &cdev_weight : binded_cdev_pair.second.cdev_weight_for_pid) {
- if (!std::isnan(cdev_weight)) {
- sensor_status_map_[name_status_pair.first]
- .pid_request_map[binded_cdev_pair.first] = 0;
- cdev_status_map_[binded_cdev_pair.first][name_status_pair.first] = 0;
- break;
- }
+ if (name_status_pair.second.throttling_info != nullptr) {
+ if (!thermal_throttling_.registerThermalThrottling(
+ name_status_pair.first, name_status_pair.second.throttling_info,
+ cooling_device_info_map_)) {
+ LOG(FATAL) << name_status_pair.first << " failed to register thermal throttling";
}
+ }
- for (const auto &limit_info : binded_cdev_pair.second.limit_info) {
- if (limit_info > 0) {
- sensor_status_map_[name_status_pair.first]
- .hard_limit_request_map[binded_cdev_pair.first] = 0;
- cdev_status_map_[binded_cdev_pair.first][name_status_pair.first] = 0;
- }
- }
+ // Update cooling device max state
+ for (auto &binded_cdev_pair :
+ name_status_pair.second.throttling_info->binded_cdev_info_map) {
const auto &cdev_info = cooling_device_info_map_.at(binded_cdev_pair.first);
for (auto &cdev_ceiling : binded_cdev_pair.second.cdev_ceiling) {
@@ -345,19 +246,6 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb)
cdev_ceiling = cdev_info.max_state;
}
}
-
- if (power_rail_info_map_.count(binded_cdev_pair.second.power_rail) &&
- power_rail_info_map_.at(binded_cdev_pair.second.power_rail).power_sample_count &&
- power_files_.findEnergySourceToWatch()) {
- const auto &power_rail_info =
- power_rail_info_map_.at(binded_cdev_pair.second.power_rail);
- if (!power_files_.registerPowerRailsToWatch(
- name_status_pair.first, binded_cdev_pair.first, binded_cdev_pair.second,
- cdev_info, power_rail_info)) {
- LOG(FATAL) << "Could not register " << binded_cdev_pair.first
- << "'s power energy source: " << binded_cdev_pair.second.power_rail;
- }
- }
}
if (name_status_pair.second.virtual_sensor_info != nullptr &&
@@ -368,8 +256,9 @@ ThermalHelper::ThermalHelper(const NotificationCallback &cb)
sensor_info_map_[name_status_pair.second.virtual_sensor_info->trigger_sensor]
.is_watch = true;
} else {
- LOG(FATAL) << "Could not find " << name_status_pair.first << "'s trigger sensor: "
- << name_status_pair.second.virtual_sensor_info->trigger_sensor;
+ LOG(FATAL) << name_status_pair.first << "'s trigger sensor: "
+ << name_status_pair.second.virtual_sensor_info->trigger_sensor
+ << " is invalid";
}
}
}
@@ -446,16 +335,16 @@ bool ThermalHelper::readTemperature(std::string_view sensor_name, Temperature_1_
const SensorInfo &sensor_info = sensor_info_map_.at(sensor_name.data());
TemperatureType_1_0 type =
- (static_cast<int>(sensor_info.type) > static_cast<int>(TemperatureType_1_0::SKIN))
- ? TemperatureType_1_0::UNKNOWN
- : static_cast<TemperatureType_1_0>(sensor_info.type);
+ (static_cast<int>(sensor_info.type) > static_cast<int>(TemperatureType_1_0::SKIN))
+ ? TemperatureType_1_0::UNKNOWN
+ : static_cast<TemperatureType_1_0>(sensor_info.type);
out->type = type;
out->name = sensor_name.data();
out->currentValue = temp * sensor_info.multiplier;
out->throttlingThreshold =
- sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
+ sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
out->shutdownThreshold =
- sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
+ sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
out->vrThrottlingThreshold = sensor_info.vr_threshold;
return true;
@@ -479,7 +368,7 @@ bool ThermalHelper::readTemperature(
out->value = temp * sensor_info.multiplier;
std::pair<ThrottlingSeverity, ThrottlingSeverity> status =
- std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
+ std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
// Only update status if the thermal sensor is being monitored
if (sensor_info.is_watch) {
ThrottlingSeverity prev_hot_severity, prev_cold_severity;
@@ -498,8 +387,8 @@ bool ThermalHelper::readTemperature(
}
out->throttlingStatus = static_cast<size_t>(status.first) > static_cast<size_t>(status.second)
- ? status.first
- : status.second;
+ ? status.first
+ : status.second;
return true;
}
@@ -525,216 +414,34 @@ bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name,
return true;
}
-// To find the next PID target state according to the current thermal severity
-size_t ThermalHelper::getTargetStateOfPID(const SensorInfo &sensor_info,
- const SensorStatus &sensor_status) {
- size_t target_state = 0;
-
- for (const auto &severity : hidl_enum_range<ThrottlingSeverity>()) {
- size_t state = static_cast<size_t>(severity);
- if (std::isnan(sensor_info.throttling_info->s_power[state])) {
- continue;
- }
- target_state = state;
- if (severity > sensor_status.severity) {
- break;
- }
- }
- return target_state;
-}
-
-// Return the power budget which is computed by PID algorithm
-float ThermalHelper::pidPowerCalculator(const Temperature_2_0 &temp, const SensorInfo &sensor_info,
- SensorStatus *sensor_status,
- std::chrono::milliseconds time_elapsed_ms,
- size_t target_state) {
- float p = 0, i = 0, d = 0;
- float power_budget = std::numeric_limits<float>::max();
-
- ATRACE_CALL();
- LOG(VERBOSE) << "PID target state=" << target_state;
- if (!target_state || (sensor_status->severity == ThrottlingSeverity::NONE)) {
- sensor_status->err_integral = 0;
- sensor_status->prev_err = NAN;
- return power_budget;
- }
-
- // Compute PID
- float err = sensor_info.hot_thresholds[target_state] - temp.value;
- p = err * (err < 0 ? sensor_info.throttling_info->k_po[target_state]
- : sensor_info.throttling_info->k_pu[target_state]);
- i = sensor_status->err_integral * sensor_info.throttling_info->k_i[target_state];
- if (err < sensor_info.throttling_info->i_cutoff[target_state]) {
- float i_next = i + err * sensor_info.throttling_info->k_i[target_state];
- if (abs(i_next) < sensor_info.throttling_info->i_max[target_state]) {
- i = i_next;
- sensor_status->err_integral += err;
- }
- }
-
- if (!std::isnan(sensor_status->prev_err) &&
- time_elapsed_ms != std::chrono::milliseconds::zero()) {
- d = sensor_info.throttling_info->k_d[target_state] * (err - sensor_status->prev_err) /
- time_elapsed_ms.count();
- }
-
- sensor_status->prev_err = err;
- // Calculate power budget
- power_budget = sensor_info.throttling_info->s_power[target_state] + p + i + d;
- if (power_budget < sensor_info.throttling_info->min_alloc_power[target_state]) {
- power_budget = sensor_info.throttling_info->min_alloc_power[target_state];
- }
- if (power_budget > sensor_info.throttling_info->max_alloc_power[target_state]) {
- power_budget = sensor_info.throttling_info->max_alloc_power[target_state];
- }
-
- LOG(VERBOSE) << "power_budget=" << power_budget << " err=" << err
- << " err_integral=" << sensor_status->err_integral
- << " s_power=" << sensor_info.throttling_info->s_power[target_state]
- << " time_elpased_ms=" << time_elapsed_ms.count() << " p=" << p << " i=" << i
- << " d=" << d;
-
- return power_budget;
-}
-
-bool ThermalHelper::requestCdevByPower(std::string_view sensor_name, SensorStatus *sensor_status,
- const SensorInfo &sensor_info, float total_power_budget,
- size_t target_state) {
- float total_weight = 0, cdev_power_budget;
- size_t j;
-
- ATRACE_CALL();
- for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
- if (!std::isnan(binded_cdev_info_pair.second.cdev_weight_for_pid[target_state])) {
- total_weight += binded_cdev_info_pair.second.cdev_weight_for_pid[target_state];
- }
- }
-
- if (!total_weight) {
- LOG(ERROR) << "Sensor: " << sensor_name.data() << " total weight value is zero";
- return false;
- }
-
- // Map cdev state by power
- for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
- const auto cdev_weight = binded_cdev_info_pair.second.cdev_weight_for_pid[target_state];
- if (!std::isnan(cdev_weight)) {
- cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
-
- const CdevInfo &cdev_info_pair =
- cooling_device_info_map_.at(binded_cdev_info_pair.first);
- for (j = 0; j < cdev_info_pair.state2power.size() - 1; ++j) {
- if (cdev_power_budget > cdev_info_pair.state2power[j]) {
- break;
- }
- }
- sensor_status->pid_request_map.at(binded_cdev_info_pair.first) = static_cast<int>(j);
- LOG(VERBOSE) << "Power allocator: Sensor " << sensor_name.data() << " allocate "
- << cdev_power_budget << "mW to " << binded_cdev_info_pair.first
- << "(cdev_weight=" << cdev_weight << ") update state to " << j;
- }
- }
- return true;
-}
-
-void ThermalHelper::requestCdevBySeverity(std::string_view sensor_name, SensorStatus *sensor_status,
- const SensorInfo &sensor_info) {
- ATRACE_CALL();
- for (auto const &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
- sensor_status->hard_limit_request_map.at(binded_cdev_info_pair.first) =
- binded_cdev_info_pair.second
- .limit_info[static_cast<size_t>(sensor_status->severity)];
- LOG(VERBOSE) << "Hard Limit: Sensor " << sensor_name.data() << " update cdev "
- << binded_cdev_info_pair.first << " to "
- << sensor_status->hard_limit_request_map.at(binded_cdev_info_pair.first);
- }
-}
-
-void ThermalHelper::computeCoolingDevicesRequest(
- std::string_view sensor_name, const SensorInfo &sensor_info,
- const SensorStatus &sensor_status, std::vector<std::string> *cooling_devices_to_update) {
- int release_step = 0;
-
- ATRACE_CALL();
- std::unique_lock<std::shared_mutex> _lock(cdev_status_map_mutex_);
- for (auto &cdev_request_pair : cdev_status_map_) {
- if (!cdev_request_pair.second.count(sensor_name.data())) {
- continue;
- }
- int pid_request = 0;
- int hard_limit_request = 0;
- const auto &binded_cdev_info =
- sensor_info.throttling_info->binded_cdev_info_map.at(cdev_request_pair.first);
- const auto cdev_ceiling =
- binded_cdev_info.cdev_ceiling[static_cast<size_t>(sensor_status.severity)];
- const auto cdev_floor =
- binded_cdev_info
- .cdev_floor_with_power_link[static_cast<size_t>(sensor_status.severity)];
- release_step = 0;
-
- if (sensor_status.pid_request_map.count(cdev_request_pair.first)) {
- pid_request = sensor_status.pid_request_map.at(cdev_request_pair.first);
- }
-
- if (sensor_status.hard_limit_request_map.count(cdev_request_pair.first)) {
- hard_limit_request = sensor_status.hard_limit_request_map.at(cdev_request_pair.first);
- }
-
- release_step = power_files_.getReleaseStep(sensor_name, cdev_request_pair.first);
- LOG(VERBOSE) << "Sensor: " << sensor_name.data() << " binded cooling device "
- << cdev_request_pair.first << "'s pid_request=" << pid_request
- << " hard_limit_request=" << hard_limit_request
- << " release_step=" << release_step
- << " cdev_floor_with_power_link=" << cdev_floor
- << " cdev_ceiling=" << cdev_ceiling;
-
- auto request_state = std::max(pid_request, hard_limit_request);
- if (release_step) {
- if (release_step >= request_state) {
- request_state = 0;
- } else {
- request_state = request_state - release_step;
- }
- // Only check the cdev_floor when release step is non zero
- if (request_state < cdev_floor) {
- request_state = cdev_floor;
- }
- }
-
- if (request_state > cdev_ceiling) {
- request_state = cdev_ceiling;
- }
- if (cdev_request_pair.second.at(sensor_name.data()) != request_state) {
- cdev_request_pair.second.at(sensor_name.data()) = request_state;
- cooling_devices_to_update->emplace_back(cdev_request_pair.first);
- LOG(INFO) << "Sensor: " << sensor_name.data() << " request " << cdev_request_pair.first
- << " to " << request_state;
- }
- }
-}
-
void ThermalHelper::updateCoolingDevices(const std::vector<std::string> &updated_cdev) {
int max_state;
+ const auto &thermal_throttling_status_map = thermal_throttling_.GetThermalThrottlingStatusMap();
+
for (const auto &target_cdev : updated_cdev) {
max_state = 0;
- const CdevRequestStatus &cdev_status = cdev_status_map_.at(target_cdev);
- for (auto &sensor_request_pair : cdev_status) {
- if (sensor_request_pair.second > max_state) {
- max_state = sensor_request_pair.second;
+ for (const auto &thermal_throttling_status_pair : thermal_throttling_status_map) {
+ if (!thermal_throttling_status_pair.second.cdev_status_map.count(target_cdev)) {
+ continue;
+ }
+ const auto state =
+ thermal_throttling_status_pair.second.cdev_status_map.at(target_cdev);
+ if (state > max_state) {
+ max_state = state;
}
}
if (cooling_devices_.writeCdevFile(target_cdev, std::to_string(max_state))) {
- LOG(VERBOSE) << "Successfully update cdev " << target_cdev << " sysfs to " << max_state;
+ LOG(INFO) << "Successfully update cdev " << target_cdev << " sysfs to " << max_state;
}
}
}
std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::getSeverityFromThresholds(
- const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
- const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
- ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
- float value) const {
+ const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
+ const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
+ ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
+ float value) const {
ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
ThrottlingSeverity ret_hot_hysteresis = ThrottlingSeverity::NONE;
ThrottlingSeverity ret_cold = ThrottlingSeverity::NONE;
@@ -981,10 +688,10 @@ bool ThermalHelper::fillTemperatures(hidl_vec<Temperature_1_0> *temperatures) {
} else {
LOG(ERROR) << __func__
<< ": error reading temperature for sensor: " << name_info_pair.first;
+ return false;
}
}
*temperatures = ret;
-
return ret.size() > 0;
}
@@ -994,11 +701,9 @@ bool ThermalHelper::fillCurrentTemperatures(bool filterType, bool filterCallback
std::vector<Temperature_2_0> ret;
for (const auto &name_info_pair : sensor_info_map_) {
Temperature_2_0 temp;
-
if (name_info_pair.second.is_hidden) {
continue;
}
-
if (filterType && name_info_pair.second.type != type) {
continue;
}
@@ -1021,11 +726,9 @@ bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType_2
std::vector<TemperatureThreshold> ret;
for (const auto &name_info_pair : sensor_info_map_) {
TemperatureThreshold temp;
-
if (name_info_pair.second.is_hidden) {
continue;
}
-
if (filterType && name_info_pair.second.type != type) {
continue;
}
@@ -1168,15 +871,14 @@ std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc(
const std::set<std::string> &uevent_sensors) {
std::vector<Temperature_2_0> temps;
std::vector<std::string> cooling_devices_to_update;
- std::set<std::string> updated_power_rails;
boot_clock::time_point now = boot_clock::now();
auto min_sleep_ms = std::chrono::milliseconds::max();
+ bool power_data_is_updated = false;
ATRACE_CALL();
for (auto &name_status_pair : sensor_status_map_) {
bool force_update = false;
bool force_sysfs = false;
- bool severity_changed = false;
Temperature_2_0 temp;
TemperatureThreshold threshold;
SensorStatus &sensor_status = name_status_pair.second;
@@ -1264,7 +966,6 @@ std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc(
}
if (temp.throttlingStatus != sensor_status.severity) {
temps.push_back(temp);
- severity_changed = true;
sensor_status.severity = temp.throttlingStatus;
sleep_ms = (sensor_status.severity != ThrottlingSeverity::NONE)
? sensor_info.passive_delay
@@ -1272,58 +973,29 @@ std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc(
}
}
- if (sensor_status.severity != ThrottlingSeverity::NONE) {
- LOG(INFO) << temp.name << ": " << temp.value;
- } else {
- LOG(VERBOSE) << temp.name << ": " << temp.value;
- }
-
- // Start PID computation
- if (sensor_status.pid_request_map.size()) {
- size_t target_state = getTargetStateOfPID(sensor_info, sensor_status);
- float power_budget = pidPowerCalculator(temp, sensor_info, &sensor_status,
- time_elapsed_ms, target_state);
- if (!requestCdevByPower(name_status_pair.first, &sensor_status, sensor_info,
- power_budget, target_state)) {
- LOG(ERROR) << "Sensor " << temp.name << " PID request cdev failed";
- }
- }
-
- if (sensor_status.hard_limit_request_map.size()) {
- // Start hard limit computation
- requestCdevBySeverity(name_status_pair.first, &sensor_status, sensor_info);
+ if (!power_data_is_updated) {
+ power_files_.refreshPowerStatus();
+ power_data_is_updated = true;
}
- // Aggregate cooling device request
- if (sensor_status.pid_request_map.size() || sensor_status.hard_limit_request_map.size()) {
- if (sensor_status.severity == ThrottlingSeverity::NONE) {
- power_files_.setPowerDataToDefault(name_status_pair.first);
- } else {
- for (const auto &binded_cdev_info_pair :
- sensor_info.throttling_info->binded_cdev_info_map) {
- if (binded_cdev_info_pair.second.power_rail != "") {
- const auto &power_rail_info =
- power_rail_info_map_.at(binded_cdev_info_pair.second.power_rail);
-
- if (power_files_.throttlingReleaseUpdate(
- name_status_pair.first, binded_cdev_info_pair.first,
- sensor_status.severity, time_elapsed_ms,
- binded_cdev_info_pair.second, power_rail_info,
- !updated_power_rails.count(
- binded_cdev_info_pair.second.power_rail),
- severity_changed)) {
- updated_power_rails.insert(binded_cdev_info_pair.second.power_rail);
- }
- }
- }
- }
- computeCoolingDevicesRequest(name_status_pair.first, sensor_info, sensor_status,
- &cooling_devices_to_update);
+ if (sensor_status.severity == ThrottlingSeverity::NONE) {
+ LOG(VERBOSE) << temp.name << ": " << temp.value;
+ thermal_throttling_.clearThrottlingData(name_status_pair.first, sensor_info);
+ } else {
+ LOG(INFO) << temp.name << ": " << temp.value;
+ // update thermal throttling request
+ thermal_throttling_.thermalThrottlingUpdate(
+ temp, sensor_info, sensor_status.severity, time_elapsed_ms,
+ power_files_.GetPowerStatusMap(), cooling_device_info_map_);
}
+ thermal_throttling_.computeCoolingDevicesRequest(name_status_pair.first, sensor_info,
+ sensor_status.severity,
+ &cooling_devices_to_update);
if (min_sleep_ms > sleep_ms) {
min_sleep_ms = sleep_ms;
}
+
LOG(VERBOSE) << "Sensor " << name_status_pair.first << ": sleep_ms=" << sleep_ms.count()
<< ", min_sleep_ms voting result=" << min_sleep_ms.count();
sensor_status.last_update_time = now;
@@ -1345,8 +1017,7 @@ std::chrono::milliseconds ThermalHelper::thermalWatcherCallbackFunc(
}
}
- power_files_.clearEnergyInfoMap();
- return min_sleep_ms < kMinPollIntervalMs ? kMinPollIntervalMs : min_sleep_ms;
+ return min_sleep_ms;
}
bool ThermalHelper::connectToPowerHal() {
diff --git a/thermal/thermal-helper.h b/thermal/thermal-helper.h
index c9d0e49..8e047f1 100644
--- a/thermal/thermal-helper.h
+++ b/thermal/thermal-helper.h
@@ -26,13 +26,11 @@
#include <unordered_map>
#include <vector>
-#include <aidl/android/hardware/power/IPower.h>
-#include <aidl/google/hardware/power/extension/pixel/IPowerExt.h>
-#include <android/hardware/thermal/2.0/IThermal.h>
-
-#include "utils/config_parser.h"
#include "utils/power_files.h"
+#include "utils/powerhal_helper.h"
#include "utils/thermal_files.h"
+#include "utils/thermal_info.h"
+#include "utils/thermal_throttling.h"
#include "utils/thermal_watcher.h"
namespace android {
@@ -41,8 +39,6 @@ namespace thermal {
namespace V2_0 {
namespace implementation {
-using ::aidl::android::hardware::power::IPower;
-using ::aidl::google::hardware::power::extension::pixel::IPowerExt;
using ::android::hardware::hidl_vec;
using ::android::hardware::thermal::V1_0::CpuUsage;
using ::android::hardware::thermal::V2_0::CoolingType;
@@ -58,7 +54,6 @@ using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
using NotificationCallback = std::function<void(const Temperature_2_0 &t)>;
using NotificationTime = std::chrono::time_point<std::chrono::steady_clock>;
-using CdevRequestStatus = std::unordered_map<std::string, int>;
// Get thermal_zone type
bool getThermalZoneTypeById(int tz_id, std::string *);
@@ -74,29 +69,7 @@ struct SensorStatus {
ThrottlingSeverity prev_cold_severity;
ThrottlingSeverity prev_hint_severity;
boot_clock::time_point last_update_time;
- std::unordered_map<std::string, int> pid_request_map;
- std::unordered_map<std::string, int> hard_limit_request_map;
ThermalSample thermal_cached;
- float err_integral;
- float prev_err;
-};
-
-class PowerHalService {
- public:
- PowerHalService();
- ~PowerHalService() = default;
- bool connect();
- bool isAidlPowerHalExist() { return power_hal_aidl_exist_; }
- bool isModeSupported(const std::string &type, const ThrottlingSeverity &t);
- bool isPowerHalConnected() { return power_hal_aidl_ != nullptr; }
- bool isPowerHalExtConnected() { return power_hal_ext_aidl_ != nullptr; }
- void setMode(const std::string &type, const ThrottlingSeverity &t, const bool &enable);
-
- private:
- bool power_hal_aidl_exist_;
- std::shared_ptr<IPower> power_hal_aidl_;
- std::shared_ptr<IPowerExt> power_hal_ext_aidl_;
- std::mutex lock_;
};
class ThermalHelper {
@@ -136,30 +109,26 @@ class ThermalHelper {
const std::unordered_map<std::string, CdevInfo> &GetCdevInfoMap() const {
return cooling_device_info_map_;
}
- // Get PowerRailInfo Map
- const std::unordered_map<std::string, PowerRailInfo> &GetPowerRailInfoMap() const {
- return power_rail_info_map_;
- }
// Get SensorStatus Map
const std::unordered_map<std::string, SensorStatus> &GetSensorStatusMap() const {
std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
return sensor_status_map_;
}
- // Get CdevStatus Map
- const std::unordered_map<std::string, CdevRequestStatus> &GetCdevStatusMap() const {
- std::shared_lock<std::shared_mutex> _lock(cdev_status_map_mutex_);
- return cdev_status_map_;
+ // Get Thermal Throttling Map
+ const std::unordered_map<std::string, ThermalThrottlingStatus> &GetThermalThrottlingStatusMap()
+ const {
+ return thermal_throttling_.GetThermalThrottlingStatusMap();
}
- // Get ThrottlingRelease Map
- const std::unordered_map<std::string, CdevReleaseStatus> &GetThrottlingReleaseMap() const {
- return power_files_.GetThrottlingReleaseMap();
+
+ // Get PowerRailInfo Map
+ const std::unordered_map<std::string, PowerRailInfo> &GetPowerRailInfoMap() const {
+ return power_files_.GetPowerRailInfoMap();
}
// Get PowerStatus Map
- const std::unordered_map<std::string, PowerStatusMap> &GetPowerStatusMap() const {
+ const std::unordered_map<std::string, PowerStatus> &GetPowerStatusMap() const {
return power_files_.GetPowerStatusMap();
}
-
void sendPowerExtHint(const Temperature_2_0 &t);
bool isAidlPowerHalExist() { return power_hal_service_.isAidlPowerHalExist(); }
bool isPowerHalConnected() { return power_hal_service_.isPowerHalConnected(); }
@@ -177,46 +146,30 @@ class ThermalHelper {
const std::set<std::string> &uevent_sensors);
// Return hot and cold severity status as std::pair
std::pair<ThrottlingSeverity, ThrottlingSeverity> getSeverityFromThresholds(
- const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
- const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
- ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
- float value) const;
+ const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
+ const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
+ ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
+ float value) const;
// Read temperature data according to thermal sensor's info
bool readThermalSensor(std::string_view sensor_name, float *temp, const bool force_sysfs);
- // Return the target state of PID algorithm
- size_t getTargetStateOfPID(const SensorInfo &sensor_info, const SensorStatus &sensor_status);
- // Return the power budget which is computed by PID algorithm
- float pidPowerCalculator(const Temperature_2_0 &temp, const SensorInfo &sensor_info,
- SensorStatus *sensor_status,
- const std::chrono::milliseconds time_elapsed_ms, size_t target_state);
bool connectToPowerHal();
void updateSupportedPowerHints();
- bool requestCdevByPower(std::string_view sensor_name, SensorStatus *sensor_status,
- const SensorInfo &sensor_info, float total_power_budget,
- size_t target_state);
- void requestCdevBySeverity(std::string_view sensor_name, SensorStatus *sensor_status,
- const SensorInfo &sensor_info);
- void computeCoolingDevicesRequest(std::string_view sensor_name, const SensorInfo &sensor_info,
- const SensorStatus &sensor_status,
- std::vector<std::string> *cooling_devices_to_update);
void updateCoolingDevices(const std::vector<std::string> &cooling_devices_to_update);
sp<ThermalWatcher> thermal_watcher_;
PowerFiles power_files_;
ThermalFiles thermal_sensors_;
ThermalFiles cooling_devices_;
+ ThermalThrottling thermal_throttling_;
bool is_initialized_;
const NotificationCallback cb_;
std::unordered_map<std::string, CdevInfo> cooling_device_info_map_;
std::unordered_map<std::string, SensorInfo> sensor_info_map_;
- std::unordered_map<std::string, PowerRailInfo> power_rail_info_map_;
std::unordered_map<std::string, std::map<ThrottlingSeverity, ThrottlingSeverity>>
supported_powerhint_map_;
PowerHalService power_hal_service_;
mutable std::shared_mutex sensor_status_map_mutex_;
std::unordered_map<std::string, SensorStatus> sensor_status_map_;
- mutable std::shared_mutex cdev_status_map_mutex_;
- std::unordered_map<std::string, CdevRequestStatus> cdev_status_map_;
};
} // namespace implementation
diff --git a/thermal/utils/power_files.cpp b/thermal/utils/power_files.cpp
index a559454..3561e84 100644
--- a/thermal/utils/power_files.cpp
+++ b/thermal/utils/power_files.cpp
@@ -39,56 +39,20 @@ constexpr std::string_view kEnergyValueNode("energy_value");
using android::base::ReadFileToString;
using android::base::StringPrintf;
-void PowerFiles::setPowerDataToDefault(std::string_view sensor_name) {
- std::unique_lock<std::shared_mutex> _lock(throttling_release_map_mutex_);
- if (!throttling_release_map_.count(sensor_name.data()) ||
- !power_status_map_.count(sensor_name.data())) {
- return;
- }
-
- auto &cdev_release_map = throttling_release_map_.at(sensor_name.data());
- PowerSample power_sample = {};
-
- for (auto &power_status_pair : power_status_map_.at(sensor_name.data())) {
- for (size_t i = 0; i < power_status_pair.second.power_history.size(); ++i) {
- for (size_t j = 0; j < power_status_pair.second.power_history[i].size(); ++j) {
- power_status_pair.second.power_history[i].pop();
- power_status_pair.second.power_history[i].emplace(power_sample);
- }
- }
- power_status_pair.second.last_updated_avg_power = NAN;
- }
-
- for (auto &cdev_release_pair : cdev_release_map) {
- cdev_release_pair.second.release_step = 0;
+bool PowerFiles::registerPowerRailsToWatch(std::string_view config_path) {
+ if (!ParsePowerRailInfo(config_path, &power_rail_info_map_)) {
+ LOG(ERROR) << "Failed to parse power rail info config";
+ return false;
}
-}
-int PowerFiles::getReleaseStep(std::string_view sensor_name, std::string_view cdev_name) {
- int release_step = 0;
- std::shared_lock<std::shared_mutex> _lock(throttling_release_map_mutex_);
-
- if (throttling_release_map_.count(sensor_name.data()) &&
- throttling_release_map_[sensor_name.data()].count(cdev_name.data())) {
- release_step = throttling_release_map_[sensor_name.data()][cdev_name.data()].release_step;
+ if (!power_rail_info_map_.size()) {
+ LOG(INFO) << " No power rail info config found";
+ return true;
}
- return release_step;
-}
-
-bool PowerFiles::registerPowerRailsToWatch(std::string_view sensor_name, std::string_view cdev_name,
- const BindedCdevInfo &binded_cdev_info,
- const CdevInfo &cdev_info,
- const PowerRailInfo &power_rail_info) {
- std::vector<std::queue<PowerSample>> power_history;
- PowerSample power_sample = {
- .energy_counter = 0,
- .duration = 0,
- };
-
- if (throttling_release_map_.count(sensor_name.data()) &&
- throttling_release_map_[sensor_name.data()].count(binded_cdev_info.power_rail)) {
- return true;
+ if (!findEnergySourceToWatch()) {
+ LOG(ERROR) << "Cannot find energy source";
+ return false;
}
if (!energy_info_map_.size() && !updateEnergyValues()) {
@@ -96,50 +60,59 @@ bool PowerFiles::registerPowerRailsToWatch(std::string_view sensor_name, std::st
return false;
}
- if (power_rail_info.virtual_power_rail_info != nullptr &&
- power_rail_info.virtual_power_rail_info->linked_power_rails.size()) {
- for (size_t i = 0; i < power_rail_info.virtual_power_rail_info->linked_power_rails.size();
- ++i) {
- if (energy_info_map_.count(
- power_rail_info.virtual_power_rail_info->linked_power_rails[i])) {
+ for (const auto &power_rail_info_pair : power_rail_info_map_) {
+ std::vector<std::queue<PowerSample>> power_history;
+ if (!power_rail_info_pair.second.power_sample_count ||
+ power_rail_info_pair.second.power_sample_delay == std::chrono::milliseconds::max()) {
+ continue;
+ }
+
+ PowerSample power_sample = {
+ .energy_counter = 0,
+ .duration = 0,
+ };
+
+ if (power_rail_info_pair.second.virtual_power_rail_info != nullptr &&
+ power_rail_info_pair.second.virtual_power_rail_info->linked_power_rails.size()) {
+ for (size_t i = 0;
+ i < power_rail_info_pair.second.virtual_power_rail_info->linked_power_rails.size();
+ ++i) {
+ if (!energy_info_map_.count(power_rail_info_pair.second.virtual_power_rail_info
+ ->linked_power_rails[i])) {
+ LOG(ERROR) << " Could not find energy source "
+ << power_rail_info_pair.second.virtual_power_rail_info
+ ->linked_power_rails[i];
+ return false;
+ }
power_history.emplace_back(std::queue<PowerSample>());
- for (int j = 0; j < power_rail_info.power_sample_count; j++) {
+ for (int j = 0; j < power_rail_info_pair.second.power_sample_count; j++) {
power_history[i].emplace(power_sample);
}
+ }
+ } else {
+ if (energy_info_map_.count(power_rail_info_pair.first)) {
+ power_history.emplace_back(std::queue<PowerSample>());
+ for (int j = 0; j < power_rail_info_pair.second.power_sample_count; j++) {
+ power_history[0].emplace(power_sample);
+ }
} else {
- LOG(ERROR) << "Could not find power rail "
- << power_rail_info.virtual_power_rail_info->linked_power_rails[i];
+ LOG(ERROR) << "Could not find energy source " << power_rail_info_pair.first;
return false;
}
}
- } else {
- if (energy_info_map_.count(power_rail_info.rail)) {
- power_history.emplace_back(std::queue<PowerSample>());
- for (int j = 0; j < power_rail_info.power_sample_count; j++) {
- power_history[0].emplace(power_sample);
- }
+
+ if (power_history.size()) {
+ power_status_map_[power_rail_info_pair.first] = {
+ .power_history = power_history,
+ .last_update_time = boot_clock::time_point::min(),
+ .last_updated_avg_power = NAN,
+ };
} else {
- LOG(ERROR) << "Could not find power rail " << power_rail_info.rail;
+ LOG(ERROR) << "power history size is zero";
return false;
}
+ LOG(INFO) << "Successfully to register power rail " << power_rail_info_pair.first;
}
-
- if (power_history.size()) {
- throttling_release_map_[sensor_name.data()][cdev_name.data()] = {
- .release_step = 0,
- .max_release_step = cdev_info.max_state,
- };
- power_status_map_[sensor_name.data()][binded_cdev_info.power_rail] = {
- .power_history = power_history,
- .time_remaining = power_rail_info.power_sample_delay,
- .last_updated_avg_power = NAN,
- };
- } else {
- return false;
- }
-
- LOG(INFO) << "Sensor " << sensor_name.data() << " successfully registers power rail "
- << binded_cdev_info.power_rail << " for cooling device " << cdev_name.data();
return true;
}
@@ -179,10 +152,6 @@ bool PowerFiles::findEnergySourceToWatch(void) {
return true;
}
-void PowerFiles::clearEnergyInfoMap(void) {
- energy_info_map_.clear();
-}
-
bool PowerFiles::updateEnergyValues(void) {
std::string deviceEnergyContent;
std::string deviceEnergyContents;
@@ -200,7 +169,6 @@ bool PowerFiles::updateEnergyValues(void) {
std::istringstream energyData(deviceEnergyContents);
- clearEnergyInfoMap();
while (std::getline(energyData, line)) {
/* Read rail energy */
uint64_t energy_counter = 0;
@@ -241,215 +209,128 @@ bool PowerFiles::updateEnergyValues(void) {
return true;
}
-bool PowerFiles::getAveragePower(std::string_view power_rail,
- std::queue<PowerSample> *power_history, bool power_sample_update,
- float *avg_power) {
- bool ret = true;
- const auto last_sample = power_history->front();
+float PowerFiles::updateAveragePower(std::string_view power_rail,
+ std::queue<PowerSample> *power_history) {
+ float avg_power = NAN;
if (!energy_info_map_.count(power_rail.data())) {
LOG(ERROR) << " Could not find power rail " << power_rail.data();
- return false;
+ return avg_power;
}
+ const auto last_sample = power_history->front();
const auto curr_sample = energy_info_map_.at(power_rail.data());
const auto duration = curr_sample.duration - last_sample.duration;
const auto deltaEnergy = curr_sample.energy_counter - last_sample.energy_counter;
if (!last_sample.duration) {
- LOG(VERBOSE) << "Power rail " << power_rail.data() << ": the last energy timestamp is zero";
+ LOG(VERBOSE) << "Power rail " << power_rail.data()
+ << ": all power samples have not been collected yet";
} else if (duration <= 0 || deltaEnergy < 0) {
LOG(ERROR) << "Power rail " << power_rail.data() << " is invalid: duration = " << duration
<< ", deltaEnergy = " << deltaEnergy;
- ret = false;
+ return avg_power;
} else {
- *avg_power = static_cast<float>(deltaEnergy) / static_cast<float>(duration);
- LOG(VERBOSE) << "Power rail " << power_rail.data() << ", avg power = " << *avg_power
+ avg_power = static_cast<float>(deltaEnergy) / static_cast<float>(duration);
+ LOG(VERBOSE) << "Power rail " << power_rail.data() << ", avg power = " << avg_power
<< ", duration = " << duration << ", deltaEnergy = " << deltaEnergy;
}
- if (power_sample_update) {
- power_history->pop();
- power_history->push(curr_sample);
- }
+ power_history->pop();
+ power_history->push(curr_sample);
- return ret;
+ return avg_power;
}
-bool PowerFiles::computeAveragePower(const PowerRailInfo &power_rail_info,
- PowerStatus *power_status, bool power_sample_update,
- float *avg_power) {
- bool ret = true;
-
- float avg_power_val = -1;
- float offset = power_rail_info.virtual_power_rail_info->offset;
- for (size_t i = 0; i < power_rail_info.virtual_power_rail_info->linked_power_rails.size();
- i++) {
- float coefficient = power_rail_info.virtual_power_rail_info->coefficients[i];
- float avg_power_number = -1;
- if (!getAveragePower(power_rail_info.virtual_power_rail_info->linked_power_rails[i],
- &power_status->power_history[i], power_sample_update,
- &avg_power_number)) {
- ret = false;
- continue;
- } else if (avg_power_number < 0) {
- continue;
- }
- switch (power_rail_info.virtual_power_rail_info->formula) {
- case FormulaOption::COUNT_THRESHOLD:
- if ((coefficient < 0 && avg_power_number < -coefficient) ||
- (coefficient >= 0 && avg_power_number >= coefficient))
- avg_power_val += 1;
- break;
- case FormulaOption::WEIGHTED_AVG:
- avg_power_val += avg_power_number * coefficient;
- break;
- case FormulaOption::MAXIMUM:
- if (i == 0)
- avg_power_val = std::numeric_limits<float>::lowest();
- if (avg_power_number * coefficient > avg_power_val)
- avg_power_val = avg_power_number * coefficient;
- break;
- case FormulaOption::MINIMUM:
- if (i == 0)
- avg_power_val = std::numeric_limits<float>::max();
- if (avg_power_number * coefficient < avg_power_val)
- avg_power_val = avg_power_number * coefficient;
- break;
- default:
- break;
- }
- }
- if (avg_power_val >= 0) {
- avg_power_val = avg_power_val + offset;
- }
+float PowerFiles::updatePowerRail(std::string_view power_rail) {
+ float avg_power = NAN;
- *avg_power = avg_power_val;
- return ret;
-}
-
-bool PowerFiles::throttlingReleaseUpdate(std::string_view sensor_name, std::string_view cdev_name,
- const ThrottlingSeverity severity,
- const std::chrono::milliseconds time_elapsed_ms,
- const BindedCdevInfo &binded_cdev_info,
- const PowerRailInfo &power_rail_info,
- bool power_sample_update, bool severity_changed) {
- std::unique_lock<std::shared_mutex> _lock(throttling_release_map_mutex_);
- float avg_power = -1;
+ if (!power_rail_info_map_.count(power_rail.data())) {
+ return avg_power;
+ }
- ATRACE_CALL();
- if (!throttling_release_map_.count(sensor_name.data()) ||
- !throttling_release_map_[sensor_name.data()].count(cdev_name.data()) ||
- !power_status_map_.count(sensor_name.data()) ||
- !power_status_map_[sensor_name.data()].count(binded_cdev_info.power_rail)) {
- return false;
+ if (!power_status_map_.count(power_rail.data())) {
+ return avg_power;
}
- auto &release_status = throttling_release_map_[sensor_name.data()].at(cdev_name.data());
- auto &power_status = power_status_map_[sensor_name.data()].at(binded_cdev_info.power_rail);
+ const auto &power_rail_info = power_rail_info_map_.at(power_rail.data());
+ auto &power_status = power_status_map_.at(power_rail.data());
- if (power_sample_update) {
- if (time_elapsed_ms > power_status.time_remaining) {
- power_status.time_remaining = power_rail_info.power_sample_delay;
- } else {
- power_status.time_remaining = power_status.time_remaining - time_elapsed_ms;
- LOG(VERBOSE) << "Power rail " << binded_cdev_info.power_rail
- << " : timeout remaining = " << power_status.time_remaining.count();
- if (!severity_changed) {
- return true;
- } else {
- // get the cached average power when thermal severity is changed
- power_sample_update = false;
- }
- }
- } else if (!severity_changed &&
- power_status.time_remaining != power_rail_info.power_sample_delay) {
- return false;
+ boot_clock::time_point now = boot_clock::now();
+ auto time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
+ now - power_status.last_update_time);
+
+ if (power_status.last_update_time != boot_clock::time_point::min() &&
+ time_elapsed_ms < power_rail_info.power_sample_delay) {
+ return power_status.last_updated_avg_power;
}
if (!energy_info_map_.size() && !updateEnergyValues()) {
LOG(ERROR) << "Failed to update energy values";
- release_status.release_step = 0;
- return false;
+ return avg_power;
}
- if (!power_sample_update && !std::isnan(power_status.last_updated_avg_power)) {
- avg_power = power_status.last_updated_avg_power;
+ if (power_rail_info.virtual_power_rail_info == nullptr) {
+ avg_power = updateAveragePower(power_rail, &power_status.power_history[0]);
} else {
- // Return false if we cannot get the average power of the target power rail
- if (!((power_rail_info.virtual_power_rail_info == nullptr)
- ? getAveragePower(binded_cdev_info.power_rail, &power_status.power_history[0],
- power_sample_update, &avg_power)
- : computeAveragePower(power_rail_info, &power_status, power_sample_update,
- &avg_power))) {
- release_status.release_step = 0;
- if (binded_cdev_info.throttling_with_power_link) {
- release_status.release_step = release_status.max_release_step;
- }
- return false;
- } else if (avg_power < 0) {
- if (binded_cdev_info.throttling_with_power_link) {
- release_status.release_step = release_status.max_release_step;
+ const auto offset = power_rail_info.virtual_power_rail_info->offset;
+ float avg_power_val = 0.0;
+ for (size_t i = 0; i < power_rail_info.virtual_power_rail_info->linked_power_rails.size();
+ i++) {
+ float coefficient = power_rail_info.virtual_power_rail_info->coefficients[i];
+ float avg_power_number = updateAveragePower(
+ power_rail_info.virtual_power_rail_info->linked_power_rails[i],
+ &power_status.power_history[i]);
+
+ switch (power_rail_info.virtual_power_rail_info->formula) {
+ case FormulaOption::COUNT_THRESHOLD:
+ if ((coefficient < 0 && avg_power_number < -coefficient) ||
+ (coefficient >= 0 && avg_power_number >= coefficient))
+ avg_power_val += 1;
+ break;
+ case FormulaOption::WEIGHTED_AVG:
+ avg_power_val += avg_power_number * coefficient;
+ break;
+ case FormulaOption::MAXIMUM:
+ if (i == 0)
+ avg_power_val = std::numeric_limits<float>::lowest();
+ if (avg_power_number * coefficient > avg_power_val)
+ avg_power_val = avg_power_number * coefficient;
+ break;
+ case FormulaOption::MINIMUM:
+ if (i == 0)
+ avg_power_val = std::numeric_limits<float>::max();
+ if (avg_power_number * coefficient < avg_power_val)
+ avg_power_val = avg_power_number * coefficient;
+ break;
+ default:
+ break;
}
- return true;
}
+ if (avg_power_val >= 0) {
+ avg_power_val = avg_power_val + offset;
+ }
+
+ avg_power = avg_power_val;
+ }
+
+ if (avg_power < 0) {
+ avg_power = NAN;
}
power_status.last_updated_avg_power = avg_power;
- bool is_over_budget = true;
- if (!binded_cdev_info.high_power_check) {
- if (avg_power < binded_cdev_info.power_thresholds[static_cast<int>(severity)]) {
- is_over_budget = false;
- }
- } else {
- if (avg_power > binded_cdev_info.power_thresholds[static_cast<int>(severity)]) {
- is_over_budget = false;
- }
+ power_status.last_update_time = now;
+ return avg_power;
+}
+
+bool PowerFiles::refreshPowerStatus(void) {
+ if (!updateEnergyValues()) {
+ LOG(ERROR) << "Failed to update energy values";
+ return false;
}
- LOG(INFO) << "Power rail " << binded_cdev_info.power_rail << ": power threshold = "
- << binded_cdev_info.power_thresholds[static_cast<int>(severity)]
- << ", avg power = " << avg_power;
-
- switch (binded_cdev_info.release_logic) {
- case ReleaseLogic::INCREASE:
- if (!is_over_budget) {
- if (std::abs(release_status.release_step) <
- static_cast<int>(release_status.max_release_step)) {
- release_status.release_step--;
- }
- } else {
- release_status.release_step = 0;
- }
- break;
- case ReleaseLogic::DECREASE:
- if (!is_over_budget) {
- if (release_status.release_step <
- static_cast<int>(release_status.max_release_step)) {
- release_status.release_step++;
- }
- } else {
- release_status.release_step = 0;
- }
- break;
- case ReleaseLogic::STEPWISE:
- if (!is_over_budget) {
- if (release_status.release_step <
- static_cast<int>(release_status.max_release_step)) {
- release_status.release_step++;
- }
- } else {
- if (std::abs(release_status.release_step) <
- static_cast<int>(release_status.max_release_step)) {
- release_status.release_step--;
- }
- }
- break;
- case ReleaseLogic::RELEASE_TO_FLOOR:
- release_status.release_step = is_over_budget ? 0 : release_status.max_release_step;
- break;
- case ReleaseLogic::NONE:
- default:
- break;
+
+ for (const auto &power_status_pair : power_status_map_) {
+ updatePowerRail(power_status_pair.first);
}
return true;
}
diff --git a/thermal/utils/power_files.h b/thermal/utils/power_files.h
index 6207ba5..65c6758 100644
--- a/thermal/utils/power_files.h
+++ b/thermal/utils/power_files.h
@@ -16,13 +16,16 @@
#pragma once
+#include <android-base/chrono_utils.h>
+
+#include <chrono>
#include <queue>
#include <shared_mutex>
#include <string>
#include <unordered_map>
#include <unordered_set>
-#include "config_parser.h"
+#include "thermal_info.h"
namespace android {
namespace hardware {
@@ -30,26 +33,20 @@ namespace thermal {
namespace V2_0 {
namespace implementation {
+using android::base::boot_clock;
+
struct PowerSample {
uint64_t energy_counter;
uint64_t duration;
};
-struct ReleaseStatus {
- int release_step;
- int max_release_step;
-};
-
struct PowerStatus {
- std::chrono::milliseconds time_remaining;
+ boot_clock::time_point last_update_time;
// A vector to record the queues of power sample history.
std::vector<std::queue<PowerSample>> power_history;
float last_updated_avg_power;
};
-using CdevReleaseStatus = std::unordered_map<std::string, ReleaseStatus>;
-using PowerStatusMap = std::unordered_map<std::string, PowerStatus>;
-
// A helper class for monitoring power rails.
class PowerFiles {
public:
@@ -58,64 +55,35 @@ class PowerFiles {
// Disallow copy and assign.
PowerFiles(const PowerFiles &) = delete;
void operator=(const PowerFiles &) = delete;
-
- // Register a map for the throttling release decision of target power rail
- // Return false if the power_rail is not supported.
- bool registerPowerRailsToWatch(std::string_view sensor_name, std::string_view cdev_name,
- const BindedCdevInfo &binded_cdev_info,
- const CdevInfo &cdev_info, const PowerRailInfo &power_rail_info);
-
- // Find the energy source path, return false if no energy source found.
- bool findEnergySourceToWatch(void);
-
- // Clear the data of energy_info_map_.
- void clearEnergyInfoMap(void);
-
- // Update energy value to energy_info_map_, return false if the value is failed to update.
- bool updateEnergyValues(void);
-
- bool getAveragePower(std::string_view power_rail, std::queue<PowerSample> *power_history,
- bool power_sample_update, float *avg_power);
- bool computeAveragePower(const PowerRailInfo &power_rail_info, PowerStatus *power_status,
- bool power_sample_update, float *avg_power);
-
- // Update the throttling release status according to the average power, return true if power
- // rail is updated.
- bool throttlingReleaseUpdate(std::string_view sensor_name, std::string_view cdev_name,
- const ThrottlingSeverity severity,
- const std::chrono::milliseconds time_elapsed_ms,
- const BindedCdevInfo &binded_cdev_info,
- const PowerRailInfo &power_rail_info, bool power_sample_update,
- bool severity_changed);
-
- // Get the throttling release status for the targer power rail which is binded in specific
- // sensor.
- int getReleaseStep(std::string_view sensor_name, std::string_view cdev_name);
-
- // Clear the data of throttling_release_map_.
- void setPowerDataToDefault(std::string_view sensor_name);
-
- // Get throttling release status map
- const std::unordered_map<std::string, CdevReleaseStatus> &GetThrottlingReleaseMap() const {
- std::shared_lock<std::shared_mutex> _lock(throttling_release_map_mutex_);
- return throttling_release_map_;
- }
-
- // Get Power status map
- const std::unordered_map<std::string, PowerStatusMap> &GetPowerStatusMap() const {
+ bool registerPowerRailsToWatch(std::string_view config_path);
+ // Update the power data from ODPM sysfs
+ bool refreshPowerStatus(void);
+ // Get power status map
+ const std::unordered_map<std::string, PowerStatus> &GetPowerStatusMap() const {
std::shared_lock<std::shared_mutex> _lock(power_status_map_mutex_);
return power_status_map_;
}
+ // Get power rail info map
+ const std::unordered_map<std::string, PowerRailInfo> &GetPowerRailInfoMap() const {
+ return power_rail_info_map_;
+ }
private:
- // The map to record the energy info for each power rail.
+ // Update energy value to energy_info_map_, return false if the value is failed to update.
+ bool updateEnergyValues(void);
+ // Compute the average power for physical power rail.
+ float updateAveragePower(std::string_view power_rail, std::queue<PowerSample> *power_history);
+ // Update the power data for the target power rail.
+ float updatePowerRail(std::string_view power_rail);
+ // Find the energy source path, return false if no energy source found.
+ bool findEnergySourceToWatch(void);
+ // The map to record the energy counter for each power rail.
std::unordered_map<std::string, PowerSample> energy_info_map_;
- // The map to record the throttling release status for each thermal sensor.
- std::unordered_map<std::string, CdevReleaseStatus> throttling_release_map_;
- mutable std::shared_mutex throttling_release_map_mutex_;
// The map to record the power data for each thermal sensor.
- std::unordered_map<std::string, PowerStatusMap> power_status_map_;
+ std::unordered_map<std::string, PowerStatus> power_status_map_;
mutable std::shared_mutex power_status_map_mutex_;
+ // The map to record the power rail information from thermal config
+ std::unordered_map<std::string, PowerRailInfo> power_rail_info_map_;
// The set to store the energy source paths
std::unordered_set<std::string> energy_path_set_;
};
diff --git a/thermal/utils/powerhal_helper.cpp b/thermal/utils/powerhal_helper.cpp
new file mode 100644
index 0000000..515fa2d
--- /dev/null
+++ b/thermal/utils/powerhal_helper.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "powerhal_helper.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android/binder_manager.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <iterator>
+#include <set>
+#include <sstream>
+#include <thread>
+#include <vector>
+
+#include "thermal_info.h"
+#include "thermal_throttling.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V2_0 {
+namespace implementation {
+
+using android::base::StringPrintf;
+
+PowerHalService::PowerHalService()
+ : power_hal_aidl_exist_(true), power_hal_aidl_(nullptr), power_hal_ext_aidl_(nullptr) {
+ connect();
+}
+
+bool PowerHalService::connect() {
+ std::lock_guard<std::mutex> lock(lock_);
+ if (!power_hal_aidl_exist_)
+ return false;
+
+ if (power_hal_aidl_ != nullptr)
+ return true;
+
+ const std::string kInstance = std::string(IPower::descriptor) + "/default";
+ ndk::SpAIBinder power_binder = ndk::SpAIBinder(AServiceManager_getService(kInstance.c_str()));
+ ndk::SpAIBinder ext_power_binder;
+
+ if (power_binder.get() == nullptr) {
+ LOG(ERROR) << "Cannot get Power Hal Binder";
+ power_hal_aidl_exist_ = false;
+ return false;
+ }
+
+ power_hal_aidl_ = IPower::fromBinder(power_binder);
+
+ if (power_hal_aidl_ == nullptr) {
+ power_hal_aidl_exist_ = false;
+ LOG(ERROR) << "Cannot get Power Hal AIDL" << kInstance.c_str();
+ return false;
+ }
+
+ if (STATUS_OK != AIBinder_getExtension(power_binder.get(), ext_power_binder.getR()) ||
+ ext_power_binder.get() == nullptr) {
+ LOG(ERROR) << "Cannot get Power Hal Extension Binder";
+ power_hal_aidl_exist_ = false;
+ return false;
+ }
+
+ power_hal_ext_aidl_ = IPowerExt::fromBinder(ext_power_binder);
+ if (power_hal_ext_aidl_ == nullptr) {
+ LOG(ERROR) << "Cannot get Power Hal Extension AIDL";
+ power_hal_aidl_exist_ = false;
+ }
+
+ return true;
+}
+
+bool PowerHalService::isModeSupported(const std::string &type, const ThrottlingSeverity &t) {
+ bool isSupported = false;
+ if (!isPowerHalConnected()) {
+ return false;
+ }
+ std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
+ lock_.lock();
+ if (!power_hal_ext_aidl_->isModeSupported(power_hint, &isSupported).isOk()) {
+ LOG(ERROR) << "Fail to check supported mode, Hint: " << power_hint;
+ power_hal_aidl_exist_ = false;
+ power_hal_ext_aidl_ = nullptr;
+ power_hal_aidl_ = nullptr;
+ lock_.unlock();
+ return false;
+ }
+ lock_.unlock();
+ return isSupported;
+}
+
+void PowerHalService::setMode(const std::string &type, const ThrottlingSeverity &t,
+ const bool &enable) {
+ if (!isPowerHalConnected()) {
+ return;
+ }
+
+ std::string power_hint = StringPrintf("THERMAL_%s_%s", type.c_str(), toString(t).c_str());
+ LOG(INFO) << "Send Hint " << power_hint << " Enable: " << std::boolalpha << enable;
+ lock_.lock();
+ if (!power_hal_ext_aidl_->setMode(power_hint, enable).isOk()) {
+ LOG(ERROR) << "Fail to set mode, Hint: " << power_hint;
+ power_hal_aidl_exist_ = false;
+ power_hal_ext_aidl_ = nullptr;
+ power_hal_aidl_ = nullptr;
+ lock_.unlock();
+ return;
+ }
+ lock_.unlock();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
diff --git a/thermal/utils/powerhal_helper.h b/thermal/utils/powerhal_helper.h
new file mode 100644
index 0000000..761e315
--- /dev/null
+++ b/thermal/utils/powerhal_helper.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/power/IPower.h>
+#include <aidl/google/hardware/power/extension/pixel/IPowerExt.h>
+#include <android/hardware/thermal/2.0/IThermal.h>
+
+#include <queue>
+#include <shared_mutex>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V2_0 {
+namespace implementation {
+
+using ::aidl::android::hardware::power::IPower;
+using ::aidl::google::hardware::power::extension::pixel::IPowerExt;
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::thermal::V2_0::IThermal;
+using Temperature_2_0 = ::android::hardware::thermal::V2_0::Temperature;
+using ::android::hardware::thermal::V2_0::TemperatureThreshold;
+using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
+using CdevRequestStatus = std::unordered_map<std::string, int>;
+
+class PowerHalService {
+ public:
+ PowerHalService();
+ ~PowerHalService() = default;
+ bool connect();
+ bool isAidlPowerHalExist() { return power_hal_aidl_exist_; }
+ bool isModeSupported(const std::string &type, const ThrottlingSeverity &t);
+ bool isPowerHalConnected() { return power_hal_aidl_ != nullptr; }
+ bool isPowerHalExtConnected() { return power_hal_ext_aidl_ != nullptr; }
+ void setMode(const std::string &type, const ThrottlingSeverity &t, const bool &enable);
+
+ private:
+ bool power_hal_aidl_exist_;
+ std::shared_ptr<IPower> power_hal_aidl_;
+ std::shared_ptr<IPowerExt> power_hal_ext_aidl_;
+ std::mutex lock_;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
diff --git a/thermal/utils/thermal_files.cpp b/thermal/utils/thermal_files.cpp
index d98f16a..ff10d8b 100644
--- a/thermal/utils/thermal_files.cpp
+++ b/thermal/utils/thermal_files.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/thermal/utils/thermal_files.h b/thermal/utils/thermal_files.h
index 0c0a852..59afba6 100644
--- a/thermal/utils/thermal_files.h
+++ b/thermal/utils/thermal_files.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/thermal/utils/config_parser.cpp b/thermal/utils/thermal_info.cpp
index 2c2bbf1..7ed63c3 100644
--- a/thermal/utils/config_parser.cpp
+++ b/thermal/utils/thermal_info.cpp
@@ -13,17 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "thermal_info.h"
+
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <cmath>
-#include <unordered_set>
-
#include <json/reader.h>
#include <json/value.h>
-#include "config_parser.h"
+#include <cmath>
+#include <unordered_set>
namespace android {
namespace hardware {
@@ -429,9 +429,10 @@ bool ParseSensorInfo(std::string_view config_path,
}
float vr_threshold = NAN;
- vr_threshold = getFloatFromValue(sensors[i]["VrThreshold"]);
- LOG(INFO) << "Sensor[" << name << "]'s VrThreshold: " << vr_threshold;
-
+ if (!sensors[i]["VrThreshold"].empty()) {
+ vr_threshold = getFloatFromValue(sensors[i]["VrThreshold"]);
+ LOG(INFO) << "Sensor[" << name << "]'s VrThreshold: " << vr_threshold;
+ }
float multiplier = sensors[i]["Multiplier"].asFloat();
LOG(INFO) << "Sensor[" << name << "]'s Multiplier: " << multiplier;
@@ -479,6 +480,7 @@ bool ParseSensorInfo(std::string_view config_path,
s_power.fill(NAN);
std::array<float, kThrottlingSeverityCount> i_cutoff;
i_cutoff.fill(NAN);
+ float err_integral_default = 0.0;
// Parse PID parameters
if (!sensors[i]["PIDInfo"].empty()) {
@@ -557,6 +559,10 @@ bool ParseSensorInfo(std::string_view config_path,
sensors_parsed->clear();
return false;
}
+ LOG(INFO) << "Start to parse"
+ << " Sensor[" << name << "]'s E_Integral_Default";
+ err_integral_default = getFloatFromValue(sensors[i]["PIDInfo"]["E_Integral_Default"]);
+ LOG(INFO) << "Sensor[" << name << "]'s E_Integral_Default: " << err_integral_default;
// Confirm we have at least one valid PID combination
bool valid_pid_combination = false;
for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
@@ -592,6 +598,8 @@ bool ParseSensorInfo(std::string_view config_path,
cdev_weight_for_pid.fill(NAN);
CdevArray cdev_ceiling;
cdev_ceiling.fill(std::numeric_limits<int>::max());
+ int max_release_step = std::numeric_limits<int>::max();
+ int max_throttle_step = std::numeric_limits<int>::max();
if (support_pid) {
if (!values[j]["CdevWeightForPID"].empty()) {
LOG(INFO) << "Sensor[" << name << "]: Star to parse " << cdev_name
@@ -613,6 +621,30 @@ bool ParseSensorInfo(std::string_view config_path,
return false;
}
}
+ if (!values[j]["MaxReleaseStep"].empty()) {
+ max_release_step = getIntFromValue(values[j]["MaxReleaseStep"]);
+ if (max_release_step < 0) {
+ LOG(ERROR) << "Sensor[" << name << "]'s " << cdev_name
+ << " MaxReleaseStep: " << max_release_step;
+ sensors_parsed->clear();
+ return false;
+ } else {
+ LOG(INFO) << "Sensor[" << name << "]'s " << cdev_name
+ << " MaxReleaseStep: " << max_release_step;
+ }
+ }
+ if (!values[j]["MaxThrottleStep"].empty()) {
+ max_throttle_step = getIntFromValue(values[j]["MaxThrottleStep"]);
+ if (max_throttle_step < 0) {
+ LOG(ERROR) << "Sensor[" << name << "]'s " << cdev_name
+ << " MaxThrottleStep: " << max_throttle_step;
+ sensors_parsed->clear();
+ return false;
+ } else {
+ LOG(INFO) << "Sensor[" << name << "]'s " << cdev_name
+ << " MaxThrottleStep: " << max_throttle_step;
+ }
+ }
}
CdevArray limit_info;
limit_info.fill(0);
@@ -675,7 +707,6 @@ bool ParseSensorInfo(std::string_view config_path,
sensors_parsed->clear();
return false;
}
-
if (values[j]["ReleaseLogic"].asString() == "INCREASE") {
release_logic = ReleaseLogic::INCREASE;
LOG(INFO) << "Release logic: INCREASE";
@@ -704,6 +735,8 @@ bool ParseSensorInfo(std::string_view config_path,
.throttling_with_power_link = throttling_with_power_link,
.cdev_weight_for_pid = cdev_weight_for_pid,
.cdev_ceiling = cdev_ceiling,
+ .max_release_step = max_release_step,
+ .max_throttle_step = max_throttle_step,
.cdev_floor_with_power_link = cdev_floor_with_power_link,
.power_rail = power_rail,
};
@@ -724,9 +757,9 @@ bool ParseSensorInfo(std::string_view config_path,
trigger_sensor, formula});
}
- std::unique_ptr<ThrottlingInfo> throttling_info(
+ std::shared_ptr<ThrottlingInfo> throttling_info(
new ThrottlingInfo{k_po, k_pu, k_i, k_d, i_max, max_alloc_power, min_alloc_power,
- s_power, i_cutoff, binded_cdev_info_map});
+ s_power, i_cutoff, err_integral_default, binded_cdev_info_map});
(*sensors_parsed)[name] = {
.type = sensor_type,
@@ -767,7 +800,7 @@ bool ParseCoolingDevice(std::string_view config_path,
std::string errorMessage;
if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
- LOG(ERROR) << "Failed to parse JSON config";
+ LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
return false;
}
@@ -820,7 +853,7 @@ bool ParseCoolingDevice(std::string_view config_path,
}
} else {
LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name
- << " does not support Power2State";
+ << " does not support State2Power";
}
const std::string &power_rail = cooling_devices[i]["PowerRail"].asString();
@@ -851,7 +884,7 @@ bool ParsePowerRailInfo(std::string_view config_path,
std::string errorMessage;
if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
- LOG(ERROR) << "Failed to parse JSON config";
+ LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
return false;
}
@@ -920,6 +953,13 @@ bool ParsePowerRailInfo(std::string_view config_path,
return false;
}
+ if (linked_power_rails.size() != coefficients.size()) {
+ LOG(ERROR) << "PowerRails[" << name
+ << "]'s combination size is not matched with coefficient size";
+ power_rails_parsed->clear();
+ return false;
+ }
+
if (!power_rails[i]["Offset"].empty()) {
offset = power_rails[i]["Offset"].asFloat();
}
diff --git a/thermal/utils/config_parser.h b/thermal/utils/thermal_info.h
index 12bdf24..84d0402 100644
--- a/thermal/utils/config_parser.h
+++ b/thermal/utils/thermal_info.h
@@ -16,11 +16,11 @@
#pragma once
+#include <android/hardware/thermal/2.0/IThermal.h>
+
#include <string>
#include <unordered_map>
-#include <android/hardware/thermal/2.0/IThermal.h>
-
namespace android {
namespace hardware {
namespace thermal {
@@ -32,7 +32,7 @@ using CoolingType_2_0 = ::android::hardware::thermal::V2_0::CoolingType;
using TemperatureType_2_0 = ::android::hardware::thermal::V2_0::TemperatureType;
using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
constexpr size_t kThrottlingSeverityCount = std::distance(
- hidl_enum_range<ThrottlingSeverity>().begin(), hidl_enum_range<ThrottlingSeverity>().end());
+ hidl_enum_range<ThrottlingSeverity>().begin(), hidl_enum_range<ThrottlingSeverity>().end());
using ThrottlingArray = std::array<float, static_cast<size_t>(kThrottlingSeverityCount)>;
using CdevArray = std::array<int, static_cast<size_t>(kThrottlingSeverityCount)>;
constexpr std::chrono::milliseconds kMinPollIntervalMs = std::chrono::milliseconds(2000);
@@ -75,6 +75,8 @@ struct BindedCdevInfo {
ReleaseLogic release_logic;
ThrottlingArray cdev_weight_for_pid;
CdevArray cdev_ceiling;
+ int max_release_step;
+ int max_throttle_step;
CdevArray cdev_floor_with_power_link;
std::string power_rail;
// The flag for activate release logic when power is higher than power threshold
@@ -93,6 +95,7 @@ struct ThrottlingInfo {
ThrottlingArray min_alloc_power;
ThrottlingArray s_power;
ThrottlingArray i_cutoff;
+ float err_integral_default;
std::unordered_map<std::string, BindedCdevInfo> binded_cdev_info_map;
};
@@ -113,7 +116,7 @@ struct SensorInfo {
bool is_watch;
bool is_hidden;
std::unique_ptr<VirtualSensorInfo> virtual_sensor_info;
- std::unique_ptr<ThrottlingInfo> throttling_info;
+ std::shared_ptr<ThrottlingInfo> throttling_info;
};
struct CdevInfo {
@@ -123,6 +126,7 @@ struct CdevInfo {
std::vector<float> state2power;
int max_state;
};
+
struct PowerRailInfo {
std::string rail;
int power_sample_count;
diff --git a/thermal/utils/thermal_throttling.cpp b/thermal/utils/thermal_throttling.cpp
new file mode 100644
index 0000000..be1c39e
--- /dev/null
+++ b/thermal/utils/thermal_throttling.cpp
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "thermal_throttling.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <utils/Trace.h>
+
+#include <iterator>
+#include <set>
+#include <sstream>
+#include <thread>
+#include <vector>
+
+#include "power_files.h"
+#include "thermal_info.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V2_0 {
+namespace implementation {
+
+// To find the next PID target state according to the current thermal severity
+size_t getTargetStateOfPID(const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity) {
+ size_t target_state = 0;
+
+ for (const auto &severity : hidl_enum_range<ThrottlingSeverity>()) {
+ size_t state = static_cast<size_t>(severity);
+ if (std::isnan(sensor_info.throttling_info->s_power[state])) {
+ continue;
+ }
+ target_state = state;
+ if (severity > curr_severity) {
+ break;
+ }
+ }
+ LOG(VERBOSE) << "PID target state = " << target_state;
+ return target_state;
+}
+
+void ThermalThrottling::clearThrottlingData(std::string_view sensor_name,
+ const SensorInfo &sensor_info) {
+ if (!thermal_throttling_status_map_.count(sensor_name.data())) {
+ return;
+ }
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+
+ for (auto &pid_power_budget_pair :
+ thermal_throttling_status_map_.at(sensor_name.data()).pid_power_budget_map) {
+ pid_power_budget_pair.second = std::numeric_limits<int>::max();
+ }
+
+ for (auto &pid_cdev_request_pair :
+ thermal_throttling_status_map_.at(sensor_name.data()).pid_cdev_request_map) {
+ pid_cdev_request_pair.second = 0;
+ }
+
+ for (auto &hardlimit_cdev_request_pair :
+ thermal_throttling_status_map_.at(sensor_name.data()).hardlimit_cdev_request_map) {
+ hardlimit_cdev_request_pair.second = 0;
+ }
+
+ for (auto &throttling_release_pair :
+ thermal_throttling_status_map_.at(sensor_name.data()).throttling_release_map) {
+ throttling_release_pair.second = 0;
+ }
+
+ thermal_throttling_status_map_[sensor_name.data()].err_integral =
+ sensor_info.throttling_info->err_integral_default;
+ thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
+ return;
+}
+
+bool ThermalThrottling::registerThermalThrottling(
+ std::string_view sensor_name, const std::shared_ptr<ThrottlingInfo> &throttling_info,
+ const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
+ if (thermal_throttling_status_map_.count(sensor_name.data())) {
+ LOG(ERROR) << "Sensor " << sensor_name.data() << " throttling map has been registered";
+ return false;
+ }
+
+ if (throttling_info == nullptr) {
+ LOG(ERROR) << "Sensor " << sensor_name.data() << " has no throttling info";
+ return false;
+ }
+ thermal_throttling_status_map_[sensor_name.data()].err_integral =
+ throttling_info->err_integral_default;
+ thermal_throttling_status_map_[sensor_name.data()].prev_err = NAN;
+
+ for (auto &binded_cdev_pair : throttling_info->binded_cdev_info_map) {
+ if (!cooling_device_info_map.count(binded_cdev_pair.first)) {
+ LOG(ERROR) << "Could not find " << sensor_name.data() << "'s binded CDEV "
+ << binded_cdev_pair.first;
+ return false;
+ }
+ // Register PID throttling map
+ for (const auto &cdev_weight : binded_cdev_pair.second.cdev_weight_for_pid) {
+ if (!std::isnan(cdev_weight)) {
+ thermal_throttling_status_map_[sensor_name.data()]
+ .pid_power_budget_map[binded_cdev_pair.first] =
+ std::numeric_limits<int>::max();
+ thermal_throttling_status_map_[sensor_name.data()]
+ .pid_cdev_request_map[binded_cdev_pair.first] = 0;
+ thermal_throttling_status_map_[sensor_name.data()]
+ .cdev_status_map[binded_cdev_pair.first] = 0;
+ break;
+ }
+ }
+ // Register hard limit throttling map
+ for (const auto &limit_info : binded_cdev_pair.second.limit_info) {
+ if (limit_info > 0) {
+ thermal_throttling_status_map_[sensor_name.data()]
+ .hardlimit_cdev_request_map[binded_cdev_pair.first] = 0;
+ thermal_throttling_status_map_[sensor_name.data()]
+ .cdev_status_map[binded_cdev_pair.first] = 0;
+ break;
+ }
+ }
+ // Register throttling release map if power threshold exists
+ if (!binded_cdev_pair.second.power_rail.empty()) {
+ for (const auto &power_threshold : binded_cdev_pair.second.power_thresholds) {
+ if (!std::isnan(power_threshold)) {
+ thermal_throttling_status_map_[sensor_name.data()]
+ .throttling_release_map[binded_cdev_pair.first] = 0;
+ break;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// return power budget based on PID algo
+float ThermalThrottling::updatePowerBudget(const Temperature_2_0 &temp,
+ const SensorInfo &sensor_info,
+ std::chrono::milliseconds time_elapsed_ms,
+ ThrottlingSeverity curr_severity) {
+ float p = 0, i = 0, d = 0;
+ float power_budget = std::numeric_limits<float>::max();
+
+ if (curr_severity == ThrottlingSeverity::NONE) {
+ return power_budget;
+ }
+
+ const auto target_state = getTargetStateOfPID(sensor_info, curr_severity);
+
+ // Compute PID
+ float err = sensor_info.hot_thresholds[target_state] - temp.value;
+ p = err * (err < 0 ? sensor_info.throttling_info->k_po[target_state]
+ : sensor_info.throttling_info->k_pu[target_state]);
+ i = thermal_throttling_status_map_[temp.name].err_integral *
+ sensor_info.throttling_info->k_i[target_state];
+ if (err < sensor_info.throttling_info->i_cutoff[target_state]) {
+ float i_next = i + err * sensor_info.throttling_info->k_i[target_state];
+ if (abs(i_next) < sensor_info.throttling_info->i_max[target_state]) {
+ i = i_next;
+ thermal_throttling_status_map_[temp.name].err_integral += err;
+ }
+ }
+
+ if (!std::isnan(thermal_throttling_status_map_[temp.name].prev_err) &&
+ time_elapsed_ms != std::chrono::milliseconds::zero()) {
+ d = sensor_info.throttling_info->k_d[target_state] *
+ (err - thermal_throttling_status_map_[temp.name].prev_err) / time_elapsed_ms.count();
+ }
+
+ thermal_throttling_status_map_[temp.name].prev_err = err;
+ // Calculate power budget
+ power_budget = sensor_info.throttling_info->s_power[target_state] + p + i + d;
+ if (power_budget < sensor_info.throttling_info->min_alloc_power[target_state]) {
+ power_budget = sensor_info.throttling_info->min_alloc_power[target_state];
+ }
+ if (power_budget > sensor_info.throttling_info->max_alloc_power[target_state]) {
+ power_budget = sensor_info.throttling_info->max_alloc_power[target_state];
+ }
+
+ LOG(INFO) << temp.name << " power_budget=" << power_budget << " err=" << err
+ << " err_integral=" << thermal_throttling_status_map_[temp.name].err_integral
+ << " s_power=" << sensor_info.throttling_info->s_power[target_state]
+ << " time_elapsed_ms=" << time_elapsed_ms.count() << " p=" << p << " i=" << i
+ << " d=" << d << " control target=" << target_state;
+
+ return power_budget;
+}
+
+// Allocate power budget to binded cooling devices base on the real ODPM power data
+bool ThermalThrottling::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) {
+ float total_weight = 0;
+ float last_updated_avg_power = NAN;
+ float allocated_power = 0;
+ float allocated_weight = 0;
+ bool low_power_device_check = true;
+ bool is_budget_allocated = false;
+ bool power_data_invalid = false;
+ auto total_power_budget = updatePowerBudget(temp, sensor_info, time_elapsed_ms, curr_severity);
+ std::set<std::string> allocated_cdev;
+
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ // Compute total cdev weight
+ for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
+ const auto cdev_weight = binded_cdev_info_pair.second
+ .cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
+ if (std::isnan(cdev_weight) || cdev_weight == 0) {
+ allocated_cdev.insert(binded_cdev_info_pair.first);
+ continue;
+ }
+ total_weight += cdev_weight;
+ }
+
+ while (!is_budget_allocated) {
+ for (const auto &binded_cdev_info_pair :
+ sensor_info.throttling_info->binded_cdev_info_map) {
+ float cdev_power_adjustment = 0;
+ const auto cdev_weight =
+ binded_cdev_info_pair.second
+ .cdev_weight_for_pid[static_cast<size_t>(curr_severity)];
+
+ const CdevInfo &cdev_info = cooling_device_info_map.at(binded_cdev_info_pair.first);
+
+ if (allocated_cdev.count(binded_cdev_info_pair.first)) {
+ continue;
+ }
+ if (std::isnan(cdev_weight) || !cdev_weight) {
+ allocated_cdev.insert(binded_cdev_info_pair.first);
+ continue;
+ }
+
+ // Get the power data
+ if (!power_data_invalid) {
+ if (!binded_cdev_info_pair.second.power_rail.empty()) {
+ last_updated_avg_power =
+ power_status_map.at(binded_cdev_info_pair.second.power_rail)
+ .last_updated_avg_power;
+ if (std::isnan(last_updated_avg_power)) {
+ LOG(VERBOSE) << "power data is under collecting";
+ power_data_invalid = true;
+ break;
+ }
+ } else {
+ power_data_invalid = true;
+ break;
+ }
+ if (binded_cdev_info_pair.second.throttling_with_power_link) {
+ return false;
+ }
+ }
+
+ auto cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
+ cdev_power_adjustment = cdev_power_budget - last_updated_avg_power;
+
+ if (low_power_device_check) {
+ // Share the budget for the CDEV which power is lower than target
+ if (cdev_power_adjustment > 0 &&
+ thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
+ binded_cdev_info_pair.first) == 0) {
+ allocated_power += last_updated_avg_power;
+ allocated_weight += cdev_weight;
+ allocated_cdev.insert(binded_cdev_info_pair.first);
+ }
+ } else {
+ // Ignore the power distribution if the CDEV has no space to reduce power
+ if ((cdev_power_adjustment < 0 &&
+ thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
+ binded_cdev_info_pair.first) == cdev_info.max_state)) {
+ continue;
+ }
+
+ if (!power_data_invalid && binded_cdev_info_pair.second.power_rail != "") {
+ auto cdev_curr_power_budget =
+ thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
+ binded_cdev_info_pair.first);
+
+ if (last_updated_avg_power > cdev_curr_power_budget) {
+ cdev_power_budget = cdev_curr_power_budget +=
+ (cdev_power_adjustment *
+ (cdev_curr_power_budget / last_updated_avg_power));
+ } else {
+ cdev_power_budget = cdev_curr_power_budget += cdev_power_adjustment;
+ }
+ } else {
+ cdev_power_budget = total_power_budget * (cdev_weight / total_weight);
+ }
+
+ if (!std::isnan(cdev_info.state2power[0]) &&
+ cdev_power_budget > cdev_info.state2power[0]) {
+ cdev_power_budget = cdev_info.state2power[0];
+ } else if (cdev_power_budget < 0) {
+ cdev_power_budget = 0;
+ }
+
+ const auto curr_state =
+ thermal_throttling_status_map_[temp.name].pid_cdev_request_map.at(
+ binded_cdev_info_pair.first);
+
+ if (binded_cdev_info_pair.second.max_release_step !=
+ std::numeric_limits<int>::max() &&
+ cdev_power_adjustment > 0) {
+ auto target_state =
+ std::max(curr_state - binded_cdev_info_pair.second.max_release_step, 0);
+ cdev_power_budget =
+ std::min(cdev_power_budget, cdev_info.state2power[target_state]);
+ }
+
+ if (binded_cdev_info_pair.second.max_throttle_step !=
+ std::numeric_limits<int>::max() &&
+ cdev_power_adjustment < 0) {
+ auto target_state =
+ std::min(curr_state + binded_cdev_info_pair.second.max_throttle_step,
+ cdev_info.max_state);
+ cdev_power_budget =
+ std::max(cdev_power_budget, cdev_info.state2power[target_state]);
+ }
+
+ thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
+ binded_cdev_info_pair.first) = cdev_power_budget;
+ LOG(VERBOSE) << temp.name << " allocate "
+ << thermal_throttling_status_map_[temp.name].pid_power_budget_map.at(
+ binded_cdev_info_pair.first)
+ << "mW to " << binded_cdev_info_pair.first
+ << "(cdev_weight=" << cdev_weight << ")";
+ }
+ }
+
+ if (!power_data_invalid) {
+ total_power_budget -= allocated_power;
+ total_weight -= allocated_weight;
+ }
+ allocated_power = 0;
+ allocated_weight = 0;
+
+ if (low_power_device_check) {
+ low_power_device_check = false;
+ } else {
+ is_budget_allocated = true;
+ }
+ }
+
+ return true;
+}
+
+void ThermalThrottling::updateCdevRequestByPower(
+ std::string sensor_name,
+ const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map) {
+ size_t i;
+
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ for (auto &pid_power_budget_pair :
+ thermal_throttling_status_map_[sensor_name.data()].pid_power_budget_map) {
+ const CdevInfo &cdev_info = cooling_device_info_map.at(pid_power_budget_pair.first);
+
+ for (i = 0; i < cdev_info.state2power.size() - 1; ++i) {
+ if (pid_power_budget_pair.second >= cdev_info.state2power[i]) {
+ break;
+ }
+ }
+ thermal_throttling_status_map_[sensor_name.data()].pid_cdev_request_map.at(
+ pid_power_budget_pair.first) = static_cast<int>(i);
+ }
+
+ return;
+}
+
+void ThermalThrottling::updateCdevRequestBySeverity(std::string_view sensor_name,
+ const SensorInfo &sensor_info,
+ ThrottlingSeverity curr_severity) {
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ for (auto const &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
+ thermal_throttling_status_map_[sensor_name.data()].hardlimit_cdev_request_map.at(
+ binded_cdev_info_pair.first) =
+ binded_cdev_info_pair.second.limit_info[static_cast<size_t>(curr_severity)];
+ LOG(VERBOSE) << "Hard Limit: Sensor " << sensor_name.data() << " update cdev "
+ << binded_cdev_info_pair.first << " to "
+ << thermal_throttling_status_map_[sensor_name.data()]
+ .hardlimit_cdev_request_map.at(binded_cdev_info_pair.first);
+ }
+}
+
+bool ThermalThrottling::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) {
+ ATRACE_CALL();
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ if (!thermal_throttling_status_map_.count(sensor_name.data())) {
+ return false;
+ }
+ auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
+ for (const auto &binded_cdev_info_pair : sensor_info.throttling_info->binded_cdev_info_map) {
+ float avg_power = -1;
+
+ if (!thermal_throttling_status.throttling_release_map.count(binded_cdev_info_pair.first) ||
+ !power_status_map.count(binded_cdev_info_pair.second.power_rail)) {
+ return false;
+ }
+
+ const auto max_state = cooling_device_info_map.at(binded_cdev_info_pair.first).max_state;
+
+ auto &release_step =
+ thermal_throttling_status.throttling_release_map.at(binded_cdev_info_pair.first);
+ avg_power =
+ power_status_map.at(binded_cdev_info_pair.second.power_rail).last_updated_avg_power;
+
+ if (std::isnan(avg_power) || avg_power < 0) {
+ release_step = binded_cdev_info_pair.second.throttling_with_power_link ? max_state : 0;
+ continue;
+ }
+
+ bool is_over_budget = true;
+ if (!binded_cdev_info_pair.second.high_power_check) {
+ if (avg_power <
+ binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
+ is_over_budget = false;
+ }
+ } else {
+ if (avg_power >
+ binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]) {
+ is_over_budget = false;
+ }
+ }
+ LOG(INFO) << sensor_name.data() << "'s " << binded_cdev_info_pair.first
+ << " binded power rail " << binded_cdev_info_pair.second.power_rail
+ << ": power threshold = "
+ << binded_cdev_info_pair.second.power_thresholds[static_cast<int>(severity)]
+ << ", avg power = " << avg_power;
+
+ switch (binded_cdev_info_pair.second.release_logic) {
+ case ReleaseLogic::INCREASE:
+ if (!is_over_budget) {
+ if (std::abs(release_step) < static_cast<int>(max_state)) {
+ release_step--;
+ }
+ } else {
+ release_step = 0;
+ }
+ break;
+ case ReleaseLogic::DECREASE:
+ if (!is_over_budget) {
+ if (release_step < static_cast<int>(max_state)) {
+ release_step++;
+ }
+ } else {
+ release_step = 0;
+ }
+ break;
+ case ReleaseLogic::STEPWISE:
+ if (!is_over_budget) {
+ if (release_step < static_cast<int>(max_state)) {
+ release_step++;
+ }
+ } else {
+ if (std::abs(release_step) < static_cast<int>(max_state)) {
+ release_step--;
+ }
+ }
+ break;
+ case ReleaseLogic::RELEASE_TO_FLOOR:
+ release_step = is_over_budget ? 0 : max_state;
+ break;
+ case ReleaseLogic::NONE:
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+void ThermalThrottling::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) {
+ if (!thermal_throttling_status_map_.count(temp.name)) {
+ return;
+ }
+
+ if (thermal_throttling_status_map_[temp.name].pid_power_budget_map.size()) {
+ if (!allocatePowerToCdev(temp, sensor_info, curr_severity, time_elapsed_ms,
+ power_status_map, cooling_device_info_map)) {
+ LOG(ERROR) << "Sensor " << temp.name << " PID request cdev failed";
+ // Clear the CDEV request if the power budget is failed to be allocated
+ for (auto &pid_cdev_request_pair :
+ thermal_throttling_status_map_[temp.name].pid_cdev_request_map) {
+ pid_cdev_request_pair.second = 0;
+ }
+ }
+ updateCdevRequestByPower(temp.name, cooling_device_info_map);
+ }
+
+ if (thermal_throttling_status_map_[temp.name].hardlimit_cdev_request_map.size()) {
+ updateCdevRequestBySeverity(temp.name.c_str(), sensor_info, curr_severity);
+ }
+
+ if (thermal_throttling_status_map_[temp.name].throttling_release_map.size()) {
+ throttlingReleaseUpdate(temp.name.c_str(), cooling_device_info_map, power_status_map,
+ curr_severity, sensor_info);
+ }
+}
+
+void ThermalThrottling::computeCoolingDevicesRequest(
+ std::string_view sensor_name, const SensorInfo &sensor_info,
+ const ThrottlingSeverity curr_severity,
+ std::vector<std::string> *cooling_devices_to_update) {
+ int release_step = 0;
+ std::unique_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+
+ if (!thermal_throttling_status_map_.count(sensor_name.data())) {
+ return;
+ }
+
+ auto &thermal_throttling_status = thermal_throttling_status_map_.at(sensor_name.data());
+ const auto &cdev_release_map = thermal_throttling_status.throttling_release_map;
+
+ for (auto &cdev_request_pair : thermal_throttling_status.cdev_status_map) {
+ int pid_cdev_request = 0;
+ int hardlimit_cdev_request = 0;
+ const auto &binded_cdev_info =
+ sensor_info.throttling_info->binded_cdev_info_map.at(cdev_request_pair.first);
+ const auto cdev_ceiling = binded_cdev_info.cdev_ceiling[static_cast<size_t>(curr_severity)];
+ const auto cdev_floor =
+ binded_cdev_info.cdev_floor_with_power_link[static_cast<size_t>(curr_severity)];
+ release_step = 0;
+
+ if (thermal_throttling_status.pid_cdev_request_map.count(cdev_request_pair.first)) {
+ pid_cdev_request =
+ thermal_throttling_status.pid_cdev_request_map.at(cdev_request_pair.first);
+ }
+
+ if (thermal_throttling_status.hardlimit_cdev_request_map.count(cdev_request_pair.first)) {
+ hardlimit_cdev_request = thermal_throttling_status.hardlimit_cdev_request_map.at(
+ cdev_request_pair.first);
+ }
+
+ if (cdev_release_map.count(cdev_request_pair.first)) {
+ release_step = cdev_release_map.at(cdev_request_pair.first);
+ }
+
+ LOG(VERBOSE) << sensor_name.data() << " binded cooling device " << cdev_request_pair.first
+ << "'s pid_request=" << pid_cdev_request
+ << " hardlimit_cdev_request=" << hardlimit_cdev_request
+ << " release_step=" << release_step
+ << " cdev_floor_with_power_link=" << cdev_floor
+ << " cdev_ceiling=" << cdev_ceiling;
+
+ auto request_state = std::max(pid_cdev_request, hardlimit_cdev_request);
+ if (release_step) {
+ if (release_step >= request_state) {
+ request_state = 0;
+ } else {
+ request_state = request_state - release_step;
+ }
+ // Only check the cdev_floor when release step is non zero
+ request_state = std::max(request_state, cdev_floor);
+ }
+ request_state = std::min(request_state, cdev_ceiling);
+
+ if (cdev_request_pair.second != request_state) {
+ cdev_request_pair.second = request_state;
+ cooling_devices_to_update->emplace_back(cdev_request_pair.first);
+ }
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android
diff --git a/thermal/utils/thermal_throttling.h b/thermal/utils/thermal_throttling.h
new file mode 100644
index 0000000..a1c9f6c
--- /dev/null
+++ b/thermal/utils/thermal_throttling.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/thermal/2.0/IThermal.h>
+
+#include <queue>
+#include <shared_mutex>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "power_files.h"
+#include "thermal_info.h"
+
+namespace android {
+namespace hardware {
+namespace thermal {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::thermal::V2_0::IThermal;
+using Temperature_2_0 = ::android::hardware::thermal::V2_0::Temperature;
+using ::android::hardware::thermal::V2_0::TemperatureThreshold;
+using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
+
+struct ThermalThrottlingStatus {
+ std::unordered_map<std::string, int> pid_power_budget_map;
+ std::unordered_map<std::string, int> pid_cdev_request_map;
+ std::unordered_map<std::string, int> hardlimit_cdev_request_map;
+ std::unordered_map<std::string, int> throttling_release_map;
+ std::unordered_map<std::string, int> cdev_status_map;
+ float err_integral;
+ float prev_err;
+};
+
+// Return the control temp target of PID algorithm
+size_t getTargetStateOfPID(const SensorInfo &sensor_info, const ThrottlingSeverity curr_severity);
+
+// A helper class for conducting thermal throttling
+class ThermalThrottling {
+ public:
+ ThermalThrottling() = default;
+ ~ThermalThrottling() = default;
+ // Disallow copy and assign.
+ ThermalThrottling(const ThermalThrottling &) = delete;
+ void operator=(const ThermalThrottling &) = delete;
+
+ // Clear throttling data
+ void clearThrottlingData(std::string_view sensor_name, const SensorInfo &sensor_info);
+ // Register map for throttling algo
+ bool registerThermalThrottling(
+ std::string_view sensor_name, const std::shared_ptr<ThrottlingInfo> &throttling_info,
+ const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map);
+ // Register map for throttling release algo
+ bool registerThrottlingReleaseToWatch(std::string_view sensor_name, std::string_view cdev_name,
+ const BindedCdevInfo &binded_cdev_info);
+ // Get throttling status map
+ const std::unordered_map<std::string, ThermalThrottlingStatus> &GetThermalThrottlingStatusMap()
+ const {
+ std::shared_lock<std::shared_mutex> _lock(thermal_throttling_status_map_mutex_);
+ return thermal_throttling_status_map_;
+ }
+ // Update thermal throttling request for the specific sensor
+ void 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);
+
+ // Compute the throttling target from all the sensors' request
+ void computeCoolingDevicesRequest(std::string_view sensor_name, const SensorInfo &sensor_info,
+ const ThrottlingSeverity curr_severity,
+ std::vector<std::string> *cooling_devices_to_update);
+
+ private:
+ // PID algo - get the total power budget
+ float updatePowerBudget(const Temperature_2_0 &temp, const SensorInfo &sensor_info,
+ std::chrono::milliseconds time_elapsed_ms,
+ ThrottlingSeverity curr_severity);
+ // PID algo - allocate the power to target CDEV according to the ODPM
+ bool 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);
+ // PID algo - map the target throttling state according to the power budget
+ void updateCdevRequestByPower(
+ std::string sensor_name,
+ const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map);
+ // Hard limit algo - assign the throttling state according to the severity
+ void updateCdevRequestBySeverity(std::string_view sensor_name, const SensorInfo &sensor_info,
+ ThrottlingSeverity curr_severity);
+ // Throttling release algo - decide release step according to the predefined power threshold,
+ // return false if the throttling release is not registered in thermal config
+ bool 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);
+
+ mutable std::shared_mutex thermal_throttling_status_map_mutex_;
+ // Thermal throttling status from each sensor
+ std::unordered_map<std::string, ThermalThrottlingStatus> thermal_throttling_status_map_;
+ std::vector<std::string> cooling_devices_to_update;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace thermal
+} // namespace hardware
+} // namespace android