aidl: thermal: Update AIDL Thermal HAL from android-15.0.0_r20

HEAD to 387cefaab6d1e4ac30a859f512387cffa640abc1 ("Merge changes from
topic "p25_thermal_config_checker" into main")

Change-Id: I63223eb7562c6218104b774c0ffaae8e8baeb02c
This commit is contained in:
Giovanni Ricca
2025-03-12 15:14:16 +01:00
committed by Ansh
parent 8070f6290a
commit e3935df351
11 changed files with 512 additions and 109 deletions

View File

@@ -10,6 +10,7 @@ cc_binary {
"utils/power_files.cpp",
"utils/powerhal_helper.cpp",
"utils/thermal_stats_helper.cpp",
"utils/thermal_predictions_helper.cpp",
"utils/thermal_watcher.cpp",
"virtualtemp_estimator/virtualtemp_estimator.cpp",
],
@@ -33,7 +34,7 @@ cc_binary {
"libbinder_ndk",
"android.frameworks.stats-V2-ndk",
"android.hardware.power-V1-ndk",
"android.hardware.thermal-V2-ndk",
"android.hardware.thermal-V3-ndk",
"pixel-power-ext-V1-ndk",
"pixelatoms-cpp",
],

View File

@@ -297,6 +297,10 @@ ndk::ScopedAStatus Thermal::unregisterCoolingDeviceChangedCallback(
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Thermal::forecastSkinTemperature(int32_t, float *) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
void Thermal::dumpVirtualSensorInfo(std::ostringstream *dump_buf) {
*dump_buf << "getVirtualSensorInfo:" << std::endl;
const auto &map = thermal_helper_->GetSensorInfoMap();

View File

@@ -68,6 +68,8 @@ class Thermal : public BnThermal {
CoolingType type) override;
ndk::ScopedAStatus unregisterCoolingDeviceChangedCallback(
const std::shared_ptr<ICoolingDeviceChangedCallback> &callback) override;
ndk::ScopedAStatus forecastSkinTemperature(int32_t forecastSeconds,
float *_aidl_return) override;
binder_status_t dump(int fd, const char **args, uint32_t numArgs) override;

View File

@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.thermal</name>
<version>2</version>
<version>3</version>
<fqname>IThermal/default</fqname>
</hal>
</manifest>

View File

@@ -179,6 +179,11 @@ ThermalHelperImpl::ThermalHelperImpl(const NotificationCallback &cb)
ret = false;
}
if (!thermal_predictions_helper_.initializePredictionSensors(sensor_info_map_)) {
LOG(ERROR) << "Failed to initialize prediction sensors";
ret = false;
}
if (ret) {
if (!thermal_stats_helper_.initializeStats(config, sensor_info_map_,
cooling_device_info_map_, this)) {
@@ -279,7 +284,8 @@ ThermalHelperImpl::ThermalHelperImpl(const NotificationCallback &cb)
}
}
// Check predictor info config
if (name_status_pair.second.predictor_info != nullptr) {
if ((name_status_pair.second.predictor_info != nullptr) &&
name_status_pair.second.predictor_info->support_pid_compensation) {
std::string predict_sensor_name = name_status_pair.second.predictor_info->sensor;
if (!(sensor_info_map_.count(predict_sensor_name))) {
LOG(ERROR) << name_status_pair.first << "'s predictor " << predict_sensor_name
@@ -297,31 +303,29 @@ ThermalHelperImpl::ThermalHelperImpl(const NotificationCallback &cb)
break;
}
if (name_status_pair.second.predictor_info->support_pid_compensation) {
std::vector<float> output_template;
size_t prediction_weight_count =
name_status_pair.second.predictor_info->prediction_weights.size();
// read predictor out to get the size of output vector
::thermal::vtestimator::VtEstimatorStatus predict_check =
predictor_sensor_info.virtual_sensor_info->vt_estimator->GetAllPredictions(
&output_template);
std::vector<float> output_template;
size_t prediction_weight_count =
name_status_pair.second.predictor_info->prediction_weights.size();
// read predictor out to get the size of output vector
::thermal::vtestimator::VtEstimatorStatus predict_check =
predictor_sensor_info.virtual_sensor_info->vt_estimator->GetAllPredictions(
&output_template);
if (predict_check != ::thermal::vtestimator::kVtEstimatorOk) {
LOG(ERROR) << "Failed to get output size of " << name_status_pair.first
<< "'s predictor " << predict_sensor_name
<< " GetAllPredictions ret: " << ret << ")";
ret = false;
break;
}
if (predict_check != ::thermal::vtestimator::kVtEstimatorOk) {
LOG(ERROR) << "Failed to get output size of " << name_status_pair.first
<< "'s predictor " << predict_sensor_name
<< " GetAllPredictions ret: " << ret << ")";
ret = false;
break;
}
if (prediction_weight_count != output_template.size()) {
LOG(ERROR) << "Sensor [" << name_status_pair.first << "]: "
<< "prediction weights size (" << prediction_weight_count
<< ") doesn't match predictor [" << predict_sensor_name
<< "]'s output size (" << output_template.size() << ")";
ret = false;
break;
}
if (prediction_weight_count != output_template.size()) {
LOG(ERROR) << "Sensor [" << name_status_pair.first
<< "]: " << "prediction weights size (" << prediction_weight_count
<< ") doesn't match predictor [" << predict_sensor_name
<< "]'s output size (" << output_template.size() << ")";
ret = false;
break;
}
}
}
@@ -507,23 +511,29 @@ bool ThermalHelperImpl::readCoolingDevice(std::string_view cooling_device,
return true;
}
bool ThermalHelperImpl::readTemperature(std::string_view sensor_name, Temperature *out,
const bool force_no_cache) {
SensorReadStatus ThermalHelperImpl::readTemperature(std::string_view sensor_name, Temperature *out,
const bool force_no_cache) {
// Return fail if the thermal sensor cannot be read.
float temp = NAN;
std::map<std::string, float> sensor_log_map;
auto &sensor_status = sensor_status_map_.at(sensor_name.data());
if (!readThermalSensor(sensor_name, &temp, force_no_cache, &sensor_log_map)) {
const auto ret = readThermalSensor(sensor_name, &temp, force_no_cache, &sensor_log_map);
if (ret == SensorReadStatus::ERROR) {
LOG(ERROR) << "Failed to read thermal sensor " << sensor_name.data();
thermal_stats_helper_.reportThermalAbnormality(
ThermalSensorAbnormalityDetected::TEMP_READ_FAIL, sensor_name, std::nullopt);
return false;
return SensorReadStatus::ERROR;
}
if (ret == SensorReadStatus::UNDER_COLLECTING) {
LOG(INFO) << "Thermal sensor " << sensor_name.data() << " is under collecting";
return SensorReadStatus::UNDER_COLLECTING;
}
if (std::isnan(temp)) {
LOG(INFO) << "Sensor " << sensor_name.data() << " temperature is nan.";
return false;
return SensorReadStatus::ERROR;
}
const auto severity_reference = getSeverityReference(sensor_name.data());
@@ -537,7 +547,7 @@ bool ThermalHelperImpl::readTemperature(std::string_view sensor_name, Temperatur
// Only update status if the thermal sensor is being monitored
if (!sensor_info.is_watch) {
return true;
return SensorReadStatus::OKAY;
}
ThrottlingSeverity prev_hot_severity, prev_cold_severity;
{
@@ -589,7 +599,7 @@ bool ThermalHelperImpl::readTemperature(std::string_view sensor_name, Temperatur
ATRACE_INT((sensor_name.data() + std::string("-severity")).c_str(),
static_cast<int>(out->throttlingStatus));
return true;
return SensorReadStatus::OKAY;
}
bool ThermalHelperImpl::readTemperatureThreshold(std::string_view sensor_name,
@@ -822,7 +832,6 @@ bool ThermalHelperImpl::initializeCoolingDevices(
<< cooling_device_info_pair.second.state2power.size()
<< ", number should be " << cooling_device_info_pair.second.max_state + 1
<< " (max_state + 1)";
return false;
}
}
@@ -941,9 +950,11 @@ bool ThermalHelperImpl::fillCurrentTemperatures(bool filterType, bool filterCall
if (filterCallback && !name_info_pair.second.send_cb) {
continue;
}
if (readTemperature(name_info_pair.first, &temp, false)) {
const auto status = readTemperature(name_info_pair.first, &temp, false);
if (status == SensorReadStatus::OKAY) {
ret.emplace_back(std::move(temp));
} else {
} else if (status == SensorReadStatus::ERROR) {
LOG(ERROR) << __func__
<< ": error reading temperature for sensor: " << name_info_pair.first;
}
@@ -1006,7 +1017,7 @@ ThrottlingSeverity ThermalHelperImpl::getSeverityReference(std::string_view sens
}
Temperature temp;
if (!readTemperature(severity_reference, &temp, false)) {
if (readTemperature(severity_reference, &temp, false) != SensorReadStatus::OKAY) {
return ThrottlingSeverity::NONE;
}
LOG(VERBOSE) << sensor_name << "'s severity reference " << severity_reference
@@ -1019,8 +1030,8 @@ bool ThermalHelperImpl::readDataByType(std::string_view sensor_data, float *read
std::map<std::string, float> *sensor_log_map) {
switch (type) {
case SensorFusionType::SENSOR:
if (!readThermalSensor(sensor_data.data(), reading_value, force_no_cache,
sensor_log_map)) {
if (readThermalSensor(sensor_data.data(), reading_value, force_no_cache,
sensor_log_map) == SensorReadStatus::ERROR) {
LOG(ERROR) << "Failed to get " << sensor_data.data() << " data";
return false;
}
@@ -1096,6 +1107,9 @@ bool ThermalHelperImpl::runVirtualTempEstimator(std::string_view sensor_name,
sensor_info.virtual_sensor_info->vt_estimator->Estimate(model_inputs, &model_outputs);
if (ret == ::thermal::vtestimator::kVtEstimatorOk) {
if (sensor_info.predictor_info && sensor_info.predictor_info->supports_predictions) {
thermal_predictions_helper_.updateSensor(sensor_name, model_outputs);
}
*outputs = model_outputs;
return true;
} else if (ret == ::thermal::vtestimator::kVtEstimatorLowConfidence ||
@@ -1241,16 +1255,16 @@ bool ThermalHelperImpl::readTemperaturePredictions(std::string_view sensor_name,
constexpr int kTranTimeoutParam = 2;
bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *temp,
const bool force_no_cache,
std::map<std::string, float> *sensor_log_map) {
SensorReadStatus ThermalHelperImpl::readThermalSensor(
std::string_view sensor_name, float *temp, const bool force_no_cache,
std::map<std::string, float> *sensor_log_map) {
std::string file_reading;
boot_clock::time_point now = boot_clock::now();
ATRACE_NAME(StringPrintf("ThermalHelper::readThermalSensor - %s", sensor_name.data()).c_str());
if (!(sensor_info_map_.count(sensor_name.data()) &&
sensor_status_map_.count(sensor_name.data()))) {
return false;
return SensorReadStatus::ERROR;
}
const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
@@ -1261,7 +1275,7 @@ bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *t
if (sensor_status.override_status.emul_temp != nullptr) {
*temp = sensor_status.override_status.emul_temp->temp;
(*sensor_log_map)[sensor_name.data()] = *temp;
return true;
return SensorReadStatus::OKAY;
}
}
@@ -1276,7 +1290,7 @@ bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *t
*temp = sensor_status.thermal_cached.temp;
(*sensor_log_map)[sensor_name.data()] = *temp;
ATRACE_INT((sensor_name.data() + std::string("-cached")).c_str(), static_cast<int>(*temp));
return true;
return SensorReadStatus::OKAY;
}
// Reading thermal sensor according to it's composition
@@ -1284,7 +1298,7 @@ bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *t
if (!thermal_sensors_.readThermalFile(sensor_name.data(), &file_reading) ||
file_reading.empty()) {
LOG(ERROR) << "failed to read sensor: " << sensor_name << " zone: " << sensor_info.zone_name;
return false;
return SensorReadStatus::ERROR;
}
*temp = std::stof(::android::base::Trim(file_reading));
} else {
@@ -1299,21 +1313,26 @@ bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *t
force_no_cache, sensor_log_map)) {
LOG(ERROR) << "Failed to read " << sensor_name.data() << "'s linked sensor "
<< sensor_info.virtual_sensor_info->linked_sensors[i];
return false;
return SensorReadStatus::ERROR;
}
if (std::isnan(sensor_readings[i])) {
LOG(INFO) << sensor_name << " data is under collecting";
return true;
return SensorReadStatus::UNDER_COLLECTING;
}
}
if ((sensor_info.virtual_sensor_info->formula == FormulaOption::USE_ML_MODEL) ||
(sensor_info.virtual_sensor_info->formula == FormulaOption::USE_LINEAR_MODEL)) {
if (sensor_info.virtual_sensor_info->formula == FormulaOption::PREVIOUSLY_PREDICTED) {
const auto ret = thermal_predictions_helper_.readSensor(sensor_name, temp);
if (ret != SensorReadStatus::OKAY) {
return ret;
}
} else if ((sensor_info.virtual_sensor_info->formula == FormulaOption::USE_ML_MODEL) ||
(sensor_info.virtual_sensor_info->formula == FormulaOption::USE_LINEAR_MODEL)) {
std::vector<float> vt_estimator_out;
if (!runVirtualTempEstimator(sensor_name, sensor_log_map, force_no_cache,
&vt_estimator_out)) {
LOG(ERROR) << "Failed running VirtualEstimator for " << sensor_name;
return false;
return SensorReadStatus::ERROR;
}
*temp = vt_estimator_out[0];
} else {
@@ -1325,11 +1344,11 @@ bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *t
force_no_cache, sensor_log_map)) {
LOG(ERROR) << "Failed to read " << sensor_name.data() << "'s coefficient "
<< sensor_info.virtual_sensor_info->coefficients[i];
return false;
return SensorReadStatus::ERROR;
}
if (std::isnan(coefficient)) {
LOG(INFO) << sensor_name << " data is under collecting";
return true;
return SensorReadStatus::UNDER_COLLECTING;
}
switch (sensor_info.virtual_sensor_info->formula) {
case FormulaOption::COUNT_THRESHOLD:
@@ -1354,7 +1373,7 @@ bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *t
break;
default:
LOG(ERROR) << "Unknown formula type for sensor " << sensor_name.data();
return false;
return SensorReadStatus::ERROR;
}
}
*temp = (temp_val + sensor_info.virtual_sensor_info->offset);
@@ -1377,7 +1396,7 @@ bool ThermalHelperImpl::readThermalSensor(std::string_view sensor_name, float *t
}
auto real_temp = (*temp) * sensor_info.multiplier;
thermal_stats_helper_.updateSensorTempStatsByThreshold(sensor_name, real_temp);
return true;
return SensorReadStatus::OKAY;
}
// This is called in the different thread context and will update sensor_status
@@ -1493,12 +1512,19 @@ std::chrono::milliseconds ThermalHelperImpl::thermalWatcherCallbackFunc(
}
std::pair<ThrottlingSeverity, ThrottlingSeverity> throttling_status;
if (!readTemperature(name_status_pair.first, &temp, force_no_cache)) {
const auto ret = readTemperature(name_status_pair.first, &temp, force_no_cache);
if (ret == SensorReadStatus::ERROR) {
LOG(ERROR) << __func__
<< ": error reading temperature for sensor: " << name_status_pair.first;
continue;
}
if (ret == SensorReadStatus::UNDER_COLLECTING) {
LOG(INFO) << __func__
<< ": data under collecting for sensor: " << name_status_pair.first;
continue;
}
{
std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
if (sensor_status.pending_notification) {

View File

@@ -23,6 +23,7 @@
#include "utils/powerhal_helper.h"
#include "utils/thermal_files.h"
#include "utils/thermal_info.h"
#include "utils/thermal_predictions_helper.h"
#include "utils/thermal_stats_helper.h"
#include "utils/thermal_throttling.h"
#include "utils/thermal_watcher.h"
@@ -81,8 +82,8 @@ class ThermalHelper {
const bool max_throttling) = 0;
virtual bool emulClear(std::string_view target_sensor) = 0;
virtual bool isInitializedOk() const = 0;
virtual bool readTemperature(std::string_view sensor_name, Temperature *out,
const bool force_sysfs = false) = 0;
virtual SensorReadStatus readTemperature(std::string_view sensor_name, Temperature *out,
const bool force_sysfs = false) = 0;
virtual bool readTemperatureThreshold(std::string_view sensor_name,
TemperatureThreshold *out) const = 0;
virtual bool readCoolingDevice(std::string_view cooling_device, CoolingDevice *out) const = 0;
@@ -130,8 +131,8 @@ class ThermalHelperImpl : public ThermalHelper {
bool isInitializedOk() const override { return is_initialized_; }
// Read the temperature of a single sensor.
bool readTemperature(std::string_view sensor_name, Temperature *out,
const bool force_sysfs = false) override;
SensorReadStatus readTemperature(std::string_view sensor_name, Temperature *out,
const bool force_sysfs = false) override;
bool readTemperatureThreshold(std::string_view sensor_name,
TemperatureThreshold *out) const override;
@@ -203,8 +204,9 @@ class ThermalHelperImpl : public ThermalHelper {
bool readDataByType(std::string_view sensor_data, float *reading_value,
const SensorFusionType type, const bool force_no_cache,
std::map<std::string, float> *sensor_log_map);
bool readThermalSensor(std::string_view sensor_name, float *temp, const bool force_sysfs,
std::map<std::string, float> *sensor_log_map);
SensorReadStatus readThermalSensor(std::string_view sensor_name, float *temp,
const bool force_sysfs,
std::map<std::string, float> *sensor_log_map);
bool runVirtualTempEstimator(std::string_view sensor_name,
std::map<std::string, float> *sensor_log_map,
const bool force_no_cache, std::vector<float> *outputs);
@@ -231,6 +233,7 @@ class ThermalHelperImpl : public ThermalHelper {
supported_powerhint_map_;
PowerHalService power_hal_service_;
ThermalStatsHelper thermal_stats_helper_;
ThermalPredictionsHelper thermal_predictions_helper_;
mutable std::shared_mutex sensor_status_map_mutex_;
std::unordered_map<std::string, SensorStatus> sensor_status_map_;
};

View File

@@ -348,8 +348,11 @@ bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sens
formula = FormulaOption::USE_ML_MODEL;
} else if (sensor["Formula"].asString().compare("USE_LINEAR_MODEL") == 0) {
formula = FormulaOption::USE_LINEAR_MODEL;
} else if (sensor["Formula"].asString().compare("PREVIOUSLY_PREDICTED") == 0) {
formula = FormulaOption::PREVIOUSLY_PREDICTED;
} else {
LOG(ERROR) << "Sensor[" << name << "]'s Formula is invalid";
LOG(ERROR) << "Sensor[" << name << "]'s Formula: " << sensor["Formula"].asString()
<< " is invalid";
return false;
}
@@ -389,12 +392,14 @@ bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sens
coefficients.emplace_back(values[j].asString());
LOG(INFO) << "Sensor[" << name << "]'s coefficient[" << j << "]: " << coefficients[j];
}
} else if ((formula != FormulaOption::USE_ML_MODEL)) {
} else if ((formula != FormulaOption::USE_ML_MODEL) &&
(formula != FormulaOption::PREVIOUSLY_PREDICTED)) {
LOG(ERROR) << "Sensor[" << name << "] has no Coefficient setting";
return false;
}
if ((linked_sensors.size() != coefficients.size()) &&
(formula != FormulaOption::USE_ML_MODEL) && (formula != FormulaOption::USE_LINEAR_MODEL)) {
(formula != FormulaOption::USE_ML_MODEL) && (formula != FormulaOption::USE_LINEAR_MODEL) &&
(formula != FormulaOption::PREVIOUSLY_PREDICTED)) {
LOG(ERROR) << "Sensor[" << name << "] has invalid Coefficient size";
return false;
}
@@ -594,47 +599,88 @@ bool ParseVirtualSensorInfo(const std::string_view name, const Json::Value &sens
bool ParsePredictorInfo(const std::string_view name, const Json::Value &sensor,
std::unique_ptr<PredictorInfo> *predictor_info) {
Json::Value predictor = sensor["PredictorInfo"];
if (predictor.empty()) {
return true;
}
LOG(INFO) << "Start to parse Sensor[" << name << "]'s PredictorInfo";
if (predictor["Sensor"].empty()) {
LOG(ERROR) << "Failed to parse Sensor [" << name << "]'s PredictorInfo";
return false;
}
std::string predict_sensor;
bool support_pid_compensation = false;
std::vector<float> prediction_weights;
ThrottlingArray k_p_compensate;
predict_sensor = predictor["Sensor"].asString();
LOG(INFO) << "Sensor [" << name << "]'s predictor name is " << predict_sensor;
// parse pid compensation configuration
if ((!predictor["PredictionWeight"].empty()) && (!predictor["KPCompensate"].empty())) {
support_pid_compensation = true;
if (!predictor["PredictionWeight"].size()) {
LOG(ERROR) << "Failed to parse PredictionWeight";
bool supports_predictions = false;
int prediction_sample_interval = 0;
int num_prediction_samples = 0;
int prediction_duration = 0;
bool set_predictor_info = false;
if (!predictor.empty()) {
set_predictor_info = true;
LOG(INFO) << "Start to parse Sensor[" << name << "]'s PredictorInfo";
if (predictor["Sensor"].empty()) {
LOG(ERROR) << "Failed to parse Sensor [" << name << "]'s PredictorInfo";
return false;
}
prediction_weights.reserve(predictor["PredictionWeight"].size());
for (Json::Value::ArrayIndex i = 0; i < predictor["PredictionWeight"].size(); ++i) {
float weight = predictor["PredictionWeight"][i].asFloat();
if (std::isnan(weight)) {
LOG(ERROR) << "Unexpected NAN prediction weight for sensor [" << name << "]";
predict_sensor = predictor["Sensor"].asString();
LOG(INFO) << "Sensor [" << name << "]'s predictor name is " << predict_sensor;
// parse pid compensation configuration
if ((!predictor["PredictionWeight"].empty()) && (!predictor["KPCompensate"].empty())) {
support_pid_compensation = true;
if (!predictor["PredictionWeight"].size()) {
LOG(ERROR) << "Failed to parse PredictionWeight";
return false;
}
prediction_weights.reserve(predictor["PredictionWeight"].size());
for (Json::Value::ArrayIndex i = 0; i < predictor["PredictionWeight"].size(); ++i) {
float weight = predictor["PredictionWeight"][i].asFloat();
if (std::isnan(weight)) {
LOG(ERROR) << "Unexpected NAN prediction weight for sensor [" << name << "]";
}
prediction_weights.emplace_back(weight);
LOG(INFO) << "Sensor[" << name << "]'s prediction weights [" << i
<< "]: " << weight;
}
if (!getFloatFromJsonValues(predictor["KPCompensate"], &k_p_compensate, false, false)) {
LOG(ERROR) << "Failed to parse KPCompensate";
return false;
}
prediction_weights.emplace_back(weight);
LOG(INFO) << "Sensor[" << name << "]'s prediction weights [" << i << "]: " << weight;
}
if (!getFloatFromJsonValues(predictor["KPCompensate"], &k_p_compensate, false, false)) {
LOG(ERROR) << "Failed to parse KPCompensate";
return false;
}
}
LOG(INFO) << "Successfully created PredictorInfo for Sensor[" << name << "]";
predictor_info->reset(new PredictorInfo{predict_sensor, support_pid_compensation,
prediction_weights, k_p_compensate});
if (sensor["SupportPrediction"].asBool()) {
set_predictor_info = true;
supports_predictions = true;
LOG(INFO) << "Sensor[" << name << "] supports predictions.";
if (sensor["SampleDuration"].empty()) {
LOG(ERROR) << "SampleDuration is empty for predictor sensor: " << name;
return false;
}
if (sensor["OutputLabelCount"].empty()) {
LOG(ERROR) << "OutputLabelCount is empty for predictor sensor: " << name;
return false;
}
prediction_sample_interval = sensor["SampleDuration"].asInt();
num_prediction_samples = sensor["OutputLabelCount"].asInt();
}
if (sensor["Formula"].asString().compare("PREVIOUSLY_PREDICTED") == 0) {
set_predictor_info = true;
if (sensor["PredictionDuration"].empty()) {
LOG(ERROR) << "Sensor[" << name
<< "] is a PREVIOUSLY_PREDICTED sensor and has no PredictionDuration";
return false;
}
prediction_duration = sensor["PredictionDuration"].asInt();
}
if (set_predictor_info) {
LOG(INFO) << "Successfully created PredictorInfo for Sensor[" << name << "]";
predictor_info->reset(new PredictorInfo{predict_sensor, support_pid_compensation,
prediction_weights, k_p_compensate,
supports_predictions, prediction_sample_interval,
num_prediction_samples, prediction_duration});
}
return true;
}
@@ -1477,8 +1523,8 @@ bool ParseSensorInfo(const Json::Value &config,
.hot_hysteresis = hot_hysteresis,
.cold_hysteresis = cold_hysteresis,
.temp_path = temp_path,
.zone_name = zone_name,
.severity_reference = severity_reference,
.zone_name = zone_name,
.vr_threshold = vr_threshold,
.multiplier = multiplier,
.polling_delay = polling_delay,

View File

@@ -46,7 +46,8 @@ enum class FormulaOption : uint32_t {
MAXIMUM,
MINIMUM,
USE_ML_MODEL,
USE_LINEAR_MODEL
USE_LINEAR_MODEL,
PREVIOUSLY_PREDICTED
};
template <typename T>
@@ -120,6 +121,12 @@ enum class SensorFusionType : uint32_t {
CDEV,
};
enum class SensorReadStatus : uint32_t {
OKAY = 0,
UNDER_COLLECTING,
ERROR,
};
std::ostream &operator<<(std::ostream &os, const SensorFusionType &sensor_fusion_type);
struct VirtualSensorInfo {
@@ -141,6 +148,11 @@ struct PredictorInfo {
bool support_pid_compensation;
std::vector<float> prediction_weights;
ThrottlingArray k_p_compensate;
bool supports_predictions; // Does this sensor support predictions
int prediction_sample_interval; // Interval between each predicted sample
int num_prediction_samples; // How many samples are predicted for each iteration
int prediction_duration; // Prediction duration for a PREDICTED sensor
};
struct VirtualPowerRailInfo {
@@ -205,8 +217,8 @@ struct SensorInfo {
ThrottlingArray hot_hysteresis;
ThrottlingArray cold_hysteresis;
std::string temp_path;
std::string zone_name;
std::string severity_reference;
std::string zone_name;
float vr_threshold;
float multiplier;
std::chrono::milliseconds polling_delay;

View File

@@ -0,0 +1,205 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "thermal_predictions_helper.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <algorithm>
#include <numeric>
#include <string_view>
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
namespace implementation {
bool ThermalPredictionsHelper::registerPredictorSensor(std::string_view sensor_name,
int sample_duration, int num_out_samples) {
if (sample_duration <= 0 || num_out_samples <= 0) {
LOG(ERROR) << "Invalid sample_duration: " << sample_duration
<< " or num_out_samples: " << num_out_samples << " for sensor: " << sensor_name;
return false;
}
if (predictor_sensors_.count(sensor_name.data())) {
LOG(ERROR) << "sensor_name " << sensor_name << " is already registered as predictor";
return false;
}
predictor_sensors_[sensor_name.data()] = PredictorSensorInfo(
{std::string(sensor_name), sample_duration, num_out_samples,
std::vector<PredictionSample>(num_out_samples, PredictionSample(num_out_samples)), 0});
return true;
}
bool ThermalPredictionsHelper::registerPredictedSensor(std::string_view sensor_name,
std::string_view linked_sensor,
int duration) {
if (duration < 0) {
LOG(ERROR) << "Invalid duration: " << duration << " for sensor: " << sensor_name;
return false;
}
if (predicted_sensors_.count(sensor_name.data())) {
LOG(ERROR) << "sensor_name " << sensor_name << " is already registered as predicted sensor";
return false;
}
if (predictor_sensors_.count(linked_sensor.data()) == 0) {
LOG(ERROR) << "linked_sensor_name " << linked_sensor << " is not registered as predictor";
return false;
}
PredictorSensorInfo &predictor_sensor_info = predictor_sensors_[linked_sensor.data()];
const int max_prediction_duration =
(predictor_sensor_info.num_out_samples - 1) * predictor_sensor_info.sample_duration;
if (duration > max_prediction_duration) {
LOG(ERROR) << "Predicted sensor " << sensor_name
<< " duration is greater than max prediction duration of predictor "
<< linked_sensor << " which is " << max_prediction_duration;
return false;
}
// round up to nearest lower index
const int prediction_index = duration / predictor_sensor_info.sample_duration;
if (duration % predictor_sensor_info.sample_duration != 0) {
LOG(INFO) << "Predicted sensor " << sensor_name << " duration " << duration
<< " is not a multiple of " << linked_sensor << " sample duration "
<< predictor_sensor_info.sample_duration << " and hence updated to "
<< prediction_index * predictor_sensor_info.sample_duration;
}
predicted_sensors_[sensor_name.data()] = PredictedSensorInfo(
{std::string(sensor_name), std::string(linked_sensor), duration, prediction_index});
return true;
}
bool ThermalPredictionsHelper::updateSensor(std::string_view sensor_name,
std::vector<float> &values) {
std::unique_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
const auto sensor_itr = predictor_sensors_.find(sensor_name.data());
if (sensor_itr == predictor_sensors_.end()) {
LOG(ERROR) << "sensor_name " << sensor_name << " is not registered as predictor";
return false;
}
PredictorSensorInfo &predictor_sensor_info = predictor_sensors_[sensor_name.data()];
if (values.size() != static_cast<size_t>(predictor_sensor_info.num_out_samples)) {
LOG(ERROR) << "Invalid number of values: " << values.size()
<< " for sensor: " << sensor_name
<< ", expected: " << predictor_sensor_info.num_out_samples;
return false;
}
predictor_sensor_info.samples[predictor_sensor_info.cur_index].timestamp = boot_clock::now();
predictor_sensor_info.samples[predictor_sensor_info.cur_index].values = values;
predictor_sensor_info.cur_index++;
predictor_sensor_info.cur_index %= predictor_sensor_info.num_out_samples;
return true;
}
SensorReadStatus ThermalPredictionsHelper::readSensor(std::string_view sensor_name, float *temp) {
std::shared_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
const auto sensor_itr = predicted_sensors_.find(sensor_name.data());
if (sensor_itr == predicted_sensors_.end()) {
LOG(ERROR) << "sensor_name " << sensor_name << " is not registered as predicted sensor";
return SensorReadStatus::ERROR;
}
PredictedSensorInfo &predicted_sensor_info = predicted_sensors_[sensor_name.data()];
const int prediction_index = predicted_sensor_info.prediction_index;
const auto linked_sensor_itr = predictor_sensors_.find(predicted_sensor_info.linked_sensor);
if (linked_sensor_itr == predictor_sensors_.end()) {
LOG(ERROR) << "linked_sensor_name " << predicted_sensor_info.linked_sensor
<< " is not registered as predictor for sensor" << sensor_name;
return SensorReadStatus::ERROR;
}
PredictorSensorInfo predictor_sensor_info = linked_sensor_itr->second;
boot_clock::time_point now = boot_clock::now();
const auto min_time_elapsed_ms = predicted_sensor_info.duration - kToleranceIntervalMs;
const auto max_time_elapsed_ms = predicted_sensor_info.duration + kToleranceIntervalMs;
int loop_count = 0;
do {
int index = predictor_sensor_info.cur_index - loop_count - 1;
if (index < 0) {
index += predictor_sensor_info.num_out_samples;
}
const auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
now - predictor_sensor_info.samples[index].timestamp);
if (time_elapsed.count() <= max_time_elapsed_ms &&
time_elapsed.count() >= min_time_elapsed_ms) {
*temp = predictor_sensor_info.samples[index].values[prediction_index];
return SensorReadStatus::OKAY;
}
loop_count++;
} while (loop_count < predictor_sensor_info.num_out_samples);
LOG(INFO) << "sensor_name: " << sensor_name << " no valid prediction samples found";
return SensorReadStatus::UNDER_COLLECTING;
}
bool ThermalPredictionsHelper::initializePredictionSensors(
const std::unordered_map<std::string, SensorInfo> &sensor_info_map) {
std::unique_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
for (auto it = sensor_info_map.begin(); it != sensor_info_map.end(); ++it) {
const std::string_view sensor_name = it->first;
const SensorInfo &sensor_info = it->second;
if (!sensor_info.predictor_info || !sensor_info.virtual_sensor_info ||
(!sensor_info.predictor_info->supports_predictions)) {
continue;
}
if (!registerPredictorSensor(sensor_name,
sensor_info.predictor_info->prediction_sample_interval,
sensor_info.predictor_info->num_prediction_samples)) {
LOG(ERROR) << "Failed to register predictor sensor: " << sensor_name;
return false;
}
}
for (auto it = sensor_info_map.begin(); it != sensor_info_map.end(); ++it) {
const std::string_view sensor_name = it->first;
const SensorInfo &sensor_info = it->second;
if (!sensor_info.predictor_info || !sensor_info.virtual_sensor_info ||
(sensor_info.virtual_sensor_info->formula != FormulaOption::PREVIOUSLY_PREDICTED)) {
continue;
}
if (sensor_info.virtual_sensor_info->linked_sensors.size() != 1) {
LOG(ERROR) << "Invalid number of linked sensors: "
<< sensor_info.virtual_sensor_info->linked_sensors.size()
<< " for sensor: " << sensor_name;
return false;
}
if (!registerPredictedSensor(sensor_name,
sensor_info.virtual_sensor_info->linked_sensors[0],
sensor_info.predictor_info->prediction_duration)) {
LOG(ERROR) << "Failed to register predicted sensor: " << sensor_name;
return false;
}
}
return true;
}
} // namespace implementation
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,81 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/android/hardware/thermal/Temperature.h>
#include <android-base/chrono_utils.h>
#include <chrono>
#include <shared_mutex>
#include <string_view>
#include <unordered_map>
#include <vector>
#include "thermal_info.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
namespace implementation {
using ::android::base::boot_clock;
constexpr int kToleranceIntervalMs = 1000;
struct PredictionSample {
PredictionSample(int num_out_samples) {
timestamp = boot_clock::time_point::min();
values = std::vector<float>(num_out_samples, NAN);
}
boot_clock::time_point timestamp;
std::vector<float> values;
};
struct PredictorSensorInfo {
std::string sensor_name;
int sample_duration;
int num_out_samples;
std::vector<PredictionSample> samples;
int cur_index;
};
struct PredictedSensorInfo {
std::string sensor_name;
std::string linked_sensor;
int duration;
int prediction_index;
};
class ThermalPredictionsHelper {
public:
ThermalPredictionsHelper() = default;
~ThermalPredictionsHelper() = default;
// Disallow copy and assign
ThermalPredictionsHelper(const ThermalPredictionsHelper &) = delete;
void operator=(const ThermalPredictionsHelper &) = delete;
bool initializePredictionSensors(
const std::unordered_map<std::string, SensorInfo> &sensor_info_map);
bool updateSensor(std::string_view sensor_name, std::vector<float> &values);
SensorReadStatus readSensor(std::string_view sensor_name, float *temp);
private:
std::unordered_map<std::string, PredictorSensorInfo> predictor_sensors_;
std::unordered_map<std::string, PredictedSensorInfo> predicted_sensors_;
mutable std::shared_mutex sensor_predictions_mutex_;
bool registerPredictedSensor(std::string_view sensor_name, std::string_view linked_sensor,
int duration);
bool registerPredictorSensor(std::string_view sensor_name, int sample_duration,
int num_out_samples);
};
} // namespace implementation
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -181,14 +181,33 @@ float ThermalThrottling::updatePowerBudget(
float p = 0, d = 0;
float power_budget = std::numeric_limits<float>::max();
bool target_changed = false;
bool is_fully_throttle = true;
bool is_fully_release = true;
float budget_transient = 0.0;
auto &throttling_status = thermal_throttling_status_map_.at(temp.name);
const auto &profile = throttling_status.profile;
std::string sensor_name = temp.name;
if (curr_severity == ThrottlingSeverity::NONE) {
return power_budget;
}
// Go through the binded cdev, check current throttle status
for (const auto &binded_cdev_info_pair :
((sensor_info.throttling_info->profile_map.empty() ||
!sensor_info.throttling_info->profile_map.contains(profile))
? sensor_info.throttling_info->binded_cdev_info_map
: sensor_info.throttling_info->profile_map.at(profile))) {
if (throttling_status.pid_cdev_request_map.at(binded_cdev_info_pair.first) >
binded_cdev_info_pair.second.limit_info[static_cast<size_t>(curr_severity)]) {
is_fully_release = false;
}
if (throttling_status.pid_cdev_request_map.at(binded_cdev_info_pair.first) <
binded_cdev_info_pair.second.cdev_ceiling[static_cast<size_t>(curr_severity)]) {
is_fully_throttle = false;
}
}
const auto target_state = getTargetStateOfPID(sensor_info, curr_severity);
if (throttling_status.prev_target != static_cast<size_t>(ThrottlingSeverity::NONE) &&
target_state != throttling_status.prev_target &&
@@ -206,9 +225,11 @@ float ThermalThrottling::updatePowerBudget(
return sensor_info.throttling_info->min_alloc_power[target_state];
}
// Calculate P budget
p = err * (err < 0 ? sensor_info.throttling_info->k_po[target_state]
: sensor_info.throttling_info->k_pu[target_state]);
// Calculate I budget
if (std::isnan(throttling_status.i_budget)) {
if (std::isnan(sensor_info.throttling_info->i_default_pct)) {
throttling_status.i_budget = sensor_info.throttling_info->i_default;
@@ -227,15 +248,16 @@ float ThermalThrottling::updatePowerBudget(
}
if (err < sensor_info.throttling_info->i_cutoff[target_state]) {
if (!(throttling_status.prev_power_budget <=
sensor_info.throttling_info->min_alloc_power[target_state] &&
err < 0) &&
!(throttling_status.prev_power_budget >=
sensor_info.throttling_info->max_alloc_power[target_state] &&
err > 0)) {
throttling_status.i_budget +=
err * (err < 0 ? sensor_info.throttling_info->k_io[target_state]
: sensor_info.throttling_info->k_iu[target_state]);
if (err < 0 &&
throttling_status.prev_power_budget >
sensor_info.throttling_info->min_alloc_power[target_state] &&
!is_fully_throttle) {
throttling_status.i_budget += err * sensor_info.throttling_info->k_io[target_state];
} else if (err > 0 &&
throttling_status.prev_power_budget <
sensor_info.throttling_info->max_alloc_power[target_state] &&
!is_fully_release) {
throttling_status.i_budget += err * sensor_info.throttling_info->k_iu[target_state];
}
}
@@ -244,6 +266,7 @@ float ThermalThrottling::updatePowerBudget(
(throttling_status.i_budget > 0 ? 1 : -1);
}
// Calculate D budget
if (!std::isnan(throttling_status.prev_err) &&
time_elapsed_ms != std::chrono::milliseconds::zero()) {
d = sensor_info.throttling_info->k_d[target_state] * (err - throttling_status.prev_err) /
@@ -382,7 +405,7 @@ bool ThermalThrottling::allocatePowerToCdev(
}
}
// Compute total cdev weight
// Go through binded cdev, compute total cdev weight
for (const auto &binded_cdev_info_pair :
(sensor_info.throttling_info->profile_map.count(profile)
? sensor_info.throttling_info->profile_map.at(profile)