You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
510 lines
25 KiB
510 lines
25 KiB
1 year ago
|
/*
|
||
|
* 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_stats_helper.h"
|
||
|
|
||
|
#include <android-base/logging.h>
|
||
|
#include <android/binder_manager.h>
|
||
|
#include <hardware/google/pixel/pixelstats/pixelatoms.pb.h>
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <numeric>
|
||
|
#include <string_view>
|
||
|
|
||
|
namespace aidl {
|
||
|
namespace android {
|
||
|
namespace hardware {
|
||
|
namespace thermal {
|
||
|
namespace implementation {
|
||
|
|
||
|
constexpr std::string_view kCustomThresholdSetSuffix("-TH-");
|
||
|
constexpr std::string_view kCompressedThresholdSuffix("-CMBN-TH");
|
||
|
|
||
|
using aidl::android::frameworks::stats::VendorAtom;
|
||
|
namespace PixelAtoms = ::android::hardware::google::pixel::PixelAtoms;
|
||
|
|
||
|
namespace {
|
||
|
static std::shared_ptr<IStats> stats_client = nullptr;
|
||
|
std::shared_ptr<IStats> getStatsService() {
|
||
|
static std::once_flag statsServiceFlag;
|
||
|
std::call_once(statsServiceFlag, []() {
|
||
|
const std::string instance = std::string() + IStats::descriptor + "/default";
|
||
|
bool isStatsDeclared = AServiceManager_isDeclared(instance.c_str());
|
||
|
if (!isStatsDeclared) {
|
||
|
LOG(ERROR) << "Stats service is not registered.";
|
||
|
return;
|
||
|
}
|
||
|
stats_client = IStats::fromBinder(
|
||
|
ndk::SpAIBinder(AServiceManager_waitForService(instance.c_str())));
|
||
|
});
|
||
|
return stats_client;
|
||
|
}
|
||
|
|
||
|
bool isRecordByDefaultThreshold(const std::variant<bool, std::unordered_set<std::string>>
|
||
|
&record_by_default_threshold_all_or_name_set_,
|
||
|
std::string_view name) {
|
||
|
if (std::holds_alternative<bool>(record_by_default_threshold_all_or_name_set_)) {
|
||
|
return std::get<bool>(record_by_default_threshold_all_or_name_set_);
|
||
|
}
|
||
|
return std::get<std::unordered_set<std::string>>(record_by_default_threshold_all_or_name_set_)
|
||
|
.count(name.data());
|
||
|
}
|
||
|
|
||
|
template <typename T>
|
||
|
int calculateThresholdBucket(const std::vector<T> &thresholds, T value) {
|
||
|
if (thresholds.empty()) {
|
||
|
LOG(VERBOSE) << "No threshold present, so bucket is " << value << " as int.";
|
||
|
return static_cast<int>(value);
|
||
|
}
|
||
|
auto threshold_idx = std::upper_bound(thresholds.begin(), thresholds.end(), value);
|
||
|
int bucket = (threshold_idx - thresholds.begin());
|
||
|
LOG(VERBOSE) << "For value: " << value << " bucket is: " << bucket;
|
||
|
return bucket;
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
bool ThermalStatsHelper::initializeStats(
|
||
|
const Json::Value &config,
|
||
|
const std::unordered_map<std::string, SensorInfo> &sensor_info_map_,
|
||
|
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map_) {
|
||
|
StatsConfig stats_config;
|
||
|
if (!ParseStatsConfig(config, sensor_info_map_, cooling_device_info_map_, &stats_config)) {
|
||
|
LOG(ERROR) << "Failed to parse stats config";
|
||
|
return false;
|
||
|
}
|
||
|
bool is_initialized_ =
|
||
|
initializeSensorTempStats(stats_config.sensor_stats_info, sensor_info_map_) &&
|
||
|
initializeSensorCdevRequestStats(stats_config.cooling_device_request_info,
|
||
|
sensor_info_map_, cooling_device_info_map_);
|
||
|
if (is_initialized_) {
|
||
|
last_total_stats_report_time = boot_clock::now();
|
||
|
LOG(INFO) << "Thermal Stats Initialized Successfully";
|
||
|
}
|
||
|
return is_initialized_;
|
||
|
}
|
||
|
|
||
|
bool ThermalStatsHelper::initializeSensorCdevRequestStats(
|
||
|
const StatsInfo<int> &request_stats_info,
|
||
|
const std::unordered_map<std::string, SensorInfo> &sensor_info_map_,
|
||
|
const std::unordered_map<std::string, CdevInfo> &cooling_device_info_map_) {
|
||
|
std::unique_lock<std::shared_mutex> _lock(sensor_cdev_request_stats_map_mutex_);
|
||
|
for (const auto &[sensor, sensor_info] : sensor_info_map_) {
|
||
|
for (const auto &binded_cdev_info_pair :
|
||
|
sensor_info.throttling_info->binded_cdev_info_map) {
|
||
|
const auto &cdev = binded_cdev_info_pair.first;
|
||
|
const auto &max_state =
|
||
|
cooling_device_info_map_.at(binded_cdev_info_pair.first).max_state;
|
||
|
// Record by all state
|
||
|
if (isRecordByDefaultThreshold(
|
||
|
request_stats_info.record_by_default_threshold_all_or_name_set_, cdev)) {
|
||
|
// if the number of states is greater / equal(as state starts from 0) than
|
||
|
// residency_buckets in atom combine the initial states
|
||
|
if (max_state >= kMaxStatsResidencyCount) {
|
||
|
// buckets = [max_state -kMaxStatsResidencyCount + 1, ...max_state]
|
||
|
// idx = [1, .. max_state - (max_state - kMaxStatsResidencyCount + 1) + 1]
|
||
|
// idx = [1, .. kMaxStatsResidencyCount]
|
||
|
const auto starting_state = max_state - kMaxStatsResidencyCount + 1;
|
||
|
std::vector<int> thresholds(kMaxStatsResidencyCount);
|
||
|
std::iota(thresholds.begin(), thresholds.end(), starting_state);
|
||
|
const auto logging_name = cdev + kCompressedThresholdSuffix.data();
|
||
|
ThresholdList<int> threshold_list(logging_name, thresholds);
|
||
|
sensor_cdev_request_stats_map_[sensor][cdev]
|
||
|
.stats_by_custom_threshold.emplace_back(threshold_list);
|
||
|
} else {
|
||
|
// buckets = [0, 1, 2, 3, ...max_state]
|
||
|
const auto default_threshold_time_in_state_size = max_state + 1;
|
||
|
sensor_cdev_request_stats_map_[sensor][cdev].stats_by_default_threshold =
|
||
|
StatsRecord(default_threshold_time_in_state_size);
|
||
|
}
|
||
|
LOG(INFO) << "Sensor Cdev user vote stats on basis of all state initialized for ["
|
||
|
<< sensor << "-" << cdev << "]";
|
||
|
}
|
||
|
|
||
|
// Record by custom threshold
|
||
|
if (request_stats_info.record_by_threshold.count(cdev)) {
|
||
|
for (const auto &threshold_list : request_stats_info.record_by_threshold.at(cdev)) {
|
||
|
// check last threshold value(which is >= number of buckets as numbers in
|
||
|
// threshold are strictly increasing from 0) is less than max_state
|
||
|
if (threshold_list.thresholds.back() >= max_state) {
|
||
|
LOG(ERROR) << "For sensor " << sensor << " bindedCdev: " << cdev
|
||
|
<< "Invalid bindedCdev stats threshold: "
|
||
|
<< threshold_list.thresholds.back() << " >= " << max_state;
|
||
|
sensor_cdev_request_stats_map_.clear();
|
||
|
return false;
|
||
|
}
|
||
|
sensor_cdev_request_stats_map_[sensor][cdev]
|
||
|
.stats_by_custom_threshold.emplace_back(threshold_list);
|
||
|
LOG(INFO)
|
||
|
<< "Sensor Cdev user vote stats on basis of threshold initialized for ["
|
||
|
<< sensor << "-" << cdev << "]";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool ThermalStatsHelper::initializeSensorTempStats(
|
||
|
const StatsInfo<float> &sensor_stats_info,
|
||
|
const std::unordered_map<std::string, SensorInfo> &sensor_info_map_) {
|
||
|
std::unique_lock<std::shared_mutex> _lock(sensor_temp_stats_map_mutex_);
|
||
|
const int severity_time_in_state_size = kThrottlingSeverityCount;
|
||
|
for (const auto &[sensor, sensor_info] : sensor_info_map_) {
|
||
|
// Record by severity
|
||
|
if (sensor_info.is_watch &&
|
||
|
isRecordByDefaultThreshold(
|
||
|
sensor_stats_info.record_by_default_threshold_all_or_name_set_, sensor)) {
|
||
|
// number of buckets = number of severity
|
||
|
sensor_temp_stats_map_[sensor].stats_by_default_threshold =
|
||
|
StatsRecord(severity_time_in_state_size);
|
||
|
LOG(INFO) << "Sensor temp stats on basis of severity initialized for [" << sensor
|
||
|
<< "]";
|
||
|
}
|
||
|
|
||
|
// Record by custom threshold
|
||
|
if (sensor_stats_info.record_by_threshold.count(sensor)) {
|
||
|
for (const auto &threshold_list : sensor_stats_info.record_by_threshold.at(sensor)) {
|
||
|
sensor_temp_stats_map_[sensor].stats_by_custom_threshold.emplace_back(
|
||
|
threshold_list);
|
||
|
LOG(INFO) << "Sensor temp stats on basis of threshold initialized for [" << sensor
|
||
|
<< "]";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void ThermalStatsHelper::updateStatsRecord(StatsRecord *stats_record, int new_state) {
|
||
|
const auto now = boot_clock::now();
|
||
|
const auto cur_state_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||
|
now - stats_record->cur_state_start_time);
|
||
|
LOG(VERBOSE) << "Adding duration " << cur_state_duration.count()
|
||
|
<< " for cur_state: " << stats_record->cur_state << " with value: "
|
||
|
<< stats_record->time_in_state_ms[stats_record->cur_state].count();
|
||
|
// Update last record end time
|
||
|
stats_record->time_in_state_ms[stats_record->cur_state] += cur_state_duration;
|
||
|
stats_record->cur_state_start_time = now;
|
||
|
stats_record->cur_state = new_state;
|
||
|
}
|
||
|
|
||
|
void ThermalStatsHelper::updateSensorCdevRequestStats(std::string_view sensor,
|
||
|
std::string_view cdev, int new_value) {
|
||
|
std::unique_lock<std::shared_mutex> _lock(sensor_cdev_request_stats_map_mutex_);
|
||
|
if (!sensor_cdev_request_stats_map_.count(sensor.data()) ||
|
||
|
!sensor_cdev_request_stats_map_[sensor.data()].count(cdev.data())) {
|
||
|
return;
|
||
|
}
|
||
|
auto &request_stats = sensor_cdev_request_stats_map_[sensor.data()][cdev.data()];
|
||
|
for (auto &stats_by_threshold : request_stats.stats_by_custom_threshold) {
|
||
|
int value = calculateThresholdBucket(stats_by_threshold.thresholds, new_value);
|
||
|
if (value != stats_by_threshold.stats_record.cur_state) {
|
||
|
LOG(VERBOSE) << "Updating bindedCdev stats for sensor: " << sensor.data()
|
||
|
<< " , cooling_device: " << cdev.data() << " with new value: " << value;
|
||
|
updateStatsRecord(&stats_by_threshold.stats_record, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (request_stats.stats_by_default_threshold.has_value()) {
|
||
|
auto &stats_record = request_stats.stats_by_default_threshold.value();
|
||
|
if (new_value != stats_record.cur_state) {
|
||
|
LOG(VERBOSE) << "Updating bindedCdev stats for sensor: " << sensor.data()
|
||
|
<< " , cooling_device: " << cdev.data()
|
||
|
<< " with new value: " << new_value;
|
||
|
updateStatsRecord(&stats_record, new_value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ThermalStatsHelper::updateSensorTempStatsByThreshold(std::string_view sensor,
|
||
|
float temperature) {
|
||
|
std::unique_lock<std::shared_mutex> _lock(sensor_temp_stats_map_mutex_);
|
||
|
if (!sensor_temp_stats_map_.count(sensor.data())) {
|
||
|
return;
|
||
|
}
|
||
|
auto &sensor_temp_stats = sensor_temp_stats_map_[sensor.data()];
|
||
|
for (auto &stats_by_threshold : sensor_temp_stats.stats_by_custom_threshold) {
|
||
|
int value = calculateThresholdBucket(stats_by_threshold.thresholds, temperature);
|
||
|
if (value != stats_by_threshold.stats_record.cur_state) {
|
||
|
LOG(VERBOSE) << "Updating sensor stats for sensor: " << sensor.data()
|
||
|
<< " with value: " << value;
|
||
|
updateStatsRecord(&stats_by_threshold.stats_record, value);
|
||
|
}
|
||
|
}
|
||
|
if (temperature > sensor_temp_stats.max_temp) {
|
||
|
sensor_temp_stats.max_temp = temperature;
|
||
|
sensor_temp_stats.max_temp_timestamp = system_clock::now();
|
||
|
}
|
||
|
if (temperature < sensor_temp_stats.min_temp) {
|
||
|
sensor_temp_stats.min_temp = temperature;
|
||
|
sensor_temp_stats.min_temp_timestamp = system_clock::now();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ThermalStatsHelper::updateSensorTempStatsBySeverity(std::string_view sensor,
|
||
|
const ThrottlingSeverity &severity) {
|
||
|
std::unique_lock<std::shared_mutex> _lock(sensor_temp_stats_map_mutex_);
|
||
|
if (sensor_temp_stats_map_.count(sensor.data()) &&
|
||
|
sensor_temp_stats_map_[sensor.data()].stats_by_default_threshold.has_value()) {
|
||
|
auto &stats_record =
|
||
|
sensor_temp_stats_map_[sensor.data()].stats_by_default_threshold.value();
|
||
|
int value = static_cast<int>(severity);
|
||
|
if (value != stats_record.cur_state) {
|
||
|
LOG(VERBOSE) << "Updating sensor stats for sensor: " << sensor.data()
|
||
|
<< " with value: " << value;
|
||
|
updateStatsRecord(&stats_record, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ThermalStatsHelper::reportStats() {
|
||
|
const auto curTime = boot_clock::now();
|
||
|
const auto since_last_total_stats_update_ms =
|
||
|
std::chrono::duration_cast<std::chrono::milliseconds>(curTime -
|
||
|
last_total_stats_report_time);
|
||
|
LOG(VERBOSE) << "Duration from last total stats update is: "
|
||
|
<< since_last_total_stats_update_ms.count();
|
||
|
if (since_last_total_stats_update_ms < kUpdateIntervalMs) {
|
||
|
LOG(VERBOSE) << "Time elapsed since last update less than " << kUpdateIntervalMs.count();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
const std::shared_ptr<IStats> stats_client = getStatsService();
|
||
|
if (!stats_client) {
|
||
|
LOG(ERROR) << "Unable to get AIDL Stats service";
|
||
|
return -1;
|
||
|
}
|
||
|
int count_failed_reporting =
|
||
|
reportAllSensorTempStats(stats_client) + reportAllSensorCdevRequestStats(stats_client);
|
||
|
last_total_stats_report_time = curTime;
|
||
|
return count_failed_reporting;
|
||
|
}
|
||
|
|
||
|
int ThermalStatsHelper::reportAllSensorTempStats(const std::shared_ptr<IStats> &stats_client) {
|
||
|
int count_failed_reporting = 0;
|
||
|
std::unique_lock<std::shared_mutex> _lock(sensor_temp_stats_map_mutex_);
|
||
|
for (auto &[sensor, temp_stats] : sensor_temp_stats_map_) {
|
||
|
for (size_t threshold_set_idx = 0;
|
||
|
threshold_set_idx < temp_stats.stats_by_custom_threshold.size(); threshold_set_idx++) {
|
||
|
auto &stats_by_threshold = temp_stats.stats_by_custom_threshold[threshold_set_idx];
|
||
|
std::string sensor_name = stats_by_threshold.logging_name.value_or(
|
||
|
sensor + kCustomThresholdSetSuffix.data() + std::to_string(threshold_set_idx));
|
||
|
if (!reportSensorTempStats(stats_client, sensor_name, temp_stats,
|
||
|
&stats_by_threshold.stats_record)) {
|
||
|
count_failed_reporting++;
|
||
|
}
|
||
|
}
|
||
|
if (temp_stats.stats_by_default_threshold.has_value()) {
|
||
|
if (!reportSensorTempStats(stats_client, sensor, temp_stats,
|
||
|
&temp_stats.stats_by_default_threshold.value())) {
|
||
|
count_failed_reporting++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return count_failed_reporting;
|
||
|
}
|
||
|
|
||
|
bool ThermalStatsHelper::reportSensorTempStats(const std::shared_ptr<IStats> &stats_client,
|
||
|
std::string_view sensor,
|
||
|
const SensorTempStats &sensor_temp_stats,
|
||
|
StatsRecord *stats_record) {
|
||
|
LOG(VERBOSE) << "Reporting sensor stats for " << sensor;
|
||
|
// maintain a copy in case reporting fails
|
||
|
StatsRecord thermal_stats_before_reporting = *stats_record;
|
||
|
std::vector<VendorAtomValue> values(2);
|
||
|
values[0].set<VendorAtomValue::stringValue>(sensor);
|
||
|
std::vector<int64_t> time_in_state_ms = processStatsRecordForReporting(stats_record);
|
||
|
const auto since_last_update_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||
|
stats_record->cur_state_start_time - stats_record->last_stats_report_time);
|
||
|
values[1].set<VendorAtomValue::longValue>(since_last_update_ms.count());
|
||
|
VendorAtomValue tmp;
|
||
|
for (auto &time_in_state : time_in_state_ms) {
|
||
|
tmp.set<VendorAtomValue::longValue>(time_in_state);
|
||
|
values.push_back(tmp);
|
||
|
}
|
||
|
auto remaining_residency_buckets_count = kMaxStatsResidencyCount - time_in_state_ms.size();
|
||
|
if (remaining_residency_buckets_count > 0) {
|
||
|
tmp.set<VendorAtomValue::longValue>(0);
|
||
|
values.insert(values.end(), remaining_residency_buckets_count, tmp);
|
||
|
}
|
||
|
tmp.set<VendorAtomValue::floatValue>(sensor_temp_stats.max_temp);
|
||
|
values.push_back(tmp);
|
||
|
tmp.set<VendorAtomValue::longValue>(
|
||
|
system_clock::to_time_t(sensor_temp_stats.max_temp_timestamp));
|
||
|
values.push_back(tmp);
|
||
|
tmp.set<VendorAtomValue::floatValue>(sensor_temp_stats.min_temp);
|
||
|
values.push_back(tmp);
|
||
|
tmp.set<VendorAtomValue::longValue>(
|
||
|
system_clock::to_time_t(sensor_temp_stats.min_temp_timestamp));
|
||
|
values.push_back(tmp);
|
||
|
|
||
|
if (!reportAtom(stats_client, PixelAtoms::Atom::kVendorTempResidencyStats, std::move(values))) {
|
||
|
LOG(ERROR) << "Unable to report VendorTempResidencyStats to Stats service for "
|
||
|
"sensor: "
|
||
|
<< sensor;
|
||
|
*stats_record = restoreStatsRecordOnFailure(std::move(thermal_stats_before_reporting));
|
||
|
return false;
|
||
|
}
|
||
|
// Update last time of stats reporting
|
||
|
stats_record->last_stats_report_time = boot_clock::now();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int ThermalStatsHelper::reportAllSensorCdevRequestStats(
|
||
|
const std::shared_ptr<IStats> &stats_client) {
|
||
|
int count_failed_reporting = 0;
|
||
|
std::unique_lock<std::shared_mutex> _lock(sensor_cdev_request_stats_map_mutex_);
|
||
|
for (auto &[sensor, cdev_request_stats_map] : sensor_cdev_request_stats_map_) {
|
||
|
for (auto &[cdev, request_stats] : cdev_request_stats_map) {
|
||
|
for (size_t threshold_set_idx = 0;
|
||
|
threshold_set_idx < request_stats.stats_by_custom_threshold.size();
|
||
|
threshold_set_idx++) {
|
||
|
auto &stats_by_threshold =
|
||
|
request_stats.stats_by_custom_threshold[threshold_set_idx];
|
||
|
std::string cdev_name = stats_by_threshold.logging_name.value_or(
|
||
|
cdev + kCustomThresholdSetSuffix.data() +
|
||
|
std::to_string(threshold_set_idx));
|
||
|
if (!reportSensorCdevRequestStats(stats_client, sensor, cdev_name,
|
||
|
&stats_by_threshold.stats_record)) {
|
||
|
count_failed_reporting++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (request_stats.stats_by_default_threshold.has_value()) {
|
||
|
if (!reportSensorCdevRequestStats(
|
||
|
stats_client, sensor, cdev,
|
||
|
&request_stats.stats_by_default_threshold.value())) {
|
||
|
count_failed_reporting++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return count_failed_reporting;
|
||
|
}
|
||
|
|
||
|
bool ThermalStatsHelper::reportSensorCdevRequestStats(const std::shared_ptr<IStats> &stats_client,
|
||
|
std::string_view sensor,
|
||
|
std::string_view cdev,
|
||
|
StatsRecord *stats_record) {
|
||
|
LOG(VERBOSE) << "Reporting bindedCdev stats for sensor: " << sensor
|
||
|
<< " cooling_device: " << cdev;
|
||
|
// maintain a copy in case reporting fails
|
||
|
StatsRecord thermal_stats_before_reporting = *stats_record;
|
||
|
std::vector<VendorAtomValue> values(3);
|
||
|
values[0].set<VendorAtomValue::stringValue>(sensor);
|
||
|
values[1].set<VendorAtomValue::stringValue>(cdev);
|
||
|
std::vector<int64_t> time_in_state_ms = processStatsRecordForReporting(stats_record);
|
||
|
const auto since_last_update_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||
|
stats_record->cur_state_start_time - stats_record->last_stats_report_time);
|
||
|
values[2].set<VendorAtomValue::longValue>(since_last_update_ms.count());
|
||
|
VendorAtomValue tmp;
|
||
|
for (auto &time_in_state : time_in_state_ms) {
|
||
|
tmp.set<VendorAtomValue::longValue>(time_in_state);
|
||
|
values.push_back(tmp);
|
||
|
}
|
||
|
|
||
|
if (!reportAtom(stats_client, PixelAtoms::Atom::kVendorSensorCoolingDeviceStats,
|
||
|
std::move(values))) {
|
||
|
LOG(ERROR) << "Unable to report VendorSensorCoolingDeviceStats to Stats "
|
||
|
"service for sensor: "
|
||
|
<< sensor << " cooling_device: " << cdev;
|
||
|
*stats_record = restoreStatsRecordOnFailure(std::move(thermal_stats_before_reporting));
|
||
|
return false;
|
||
|
}
|
||
|
// Update last time of stats reporting
|
||
|
stats_record->last_stats_report_time = boot_clock::now();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
std::vector<int64_t> ThermalStatsHelper::processStatsRecordForReporting(StatsRecord *stats_record) {
|
||
|
// update the last unclosed entry and start new record with same state
|
||
|
updateStatsRecord(stats_record, stats_record->cur_state);
|
||
|
std::vector<std::chrono::milliseconds> &time_in_state_ms = stats_record->time_in_state_ms;
|
||
|
// convert std::chrono::milliseconds time_in_state to int64_t vector for reporting
|
||
|
std::vector<int64_t> stats_residency(time_in_state_ms.size());
|
||
|
std::transform(time_in_state_ms.begin(), time_in_state_ms.end(), stats_residency.begin(),
|
||
|
[](std::chrono::milliseconds time_ms) { return time_ms.count(); });
|
||
|
// clear previous stats
|
||
|
std::fill(time_in_state_ms.begin(), time_in_state_ms.end(), std::chrono::milliseconds::zero());
|
||
|
return stats_residency;
|
||
|
}
|
||
|
|
||
|
bool ThermalStatsHelper::reportAtom(const std::shared_ptr<IStats> &stats_client,
|
||
|
const int32_t &atom_id, std::vector<VendorAtomValue> &&values) {
|
||
|
LOG(VERBOSE) << "Reporting thermal stats for atom_id " << atom_id;
|
||
|
// Send vendor atom to IStats HAL
|
||
|
VendorAtom event = {.reverseDomainName = "", .atomId = atom_id, .values = std::move(values)};
|
||
|
const ndk::ScopedAStatus ret = stats_client->reportVendorAtom(event);
|
||
|
return ret.isOk();
|
||
|
}
|
||
|
|
||
|
StatsRecord ThermalStatsHelper::restoreStatsRecordOnFailure(
|
||
|
StatsRecord &&stats_record_before_failure) {
|
||
|
stats_record_before_failure.report_fail_count += 1;
|
||
|
// If consecutive count of failure is high, reset stat to avoid overflow
|
||
|
if (stats_record_before_failure.report_fail_count >= kMaxStatsReportingFailCount) {
|
||
|
return StatsRecord(stats_record_before_failure.time_in_state_ms.size(),
|
||
|
stats_record_before_failure.cur_state);
|
||
|
} else {
|
||
|
return stats_record_before_failure;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::unordered_map<std::string, SensorTempStats> ThermalStatsHelper::GetSensorTempStatsSnapshot() {
|
||
|
auto sensor_temp_stats_snapshot = sensor_temp_stats_map_;
|
||
|
for (auto &sensor_temp_stats_pair : sensor_temp_stats_snapshot) {
|
||
|
for (auto &temp_stats : sensor_temp_stats_pair.second.stats_by_custom_threshold) {
|
||
|
// update the last unclosed entry and start new record with same state
|
||
|
updateStatsRecord(&temp_stats.stats_record, temp_stats.stats_record.cur_state);
|
||
|
}
|
||
|
if (sensor_temp_stats_pair.second.stats_by_default_threshold.has_value()) {
|
||
|
auto &stats_by_default_threshold =
|
||
|
sensor_temp_stats_pair.second.stats_by_default_threshold.value();
|
||
|
// update the last unclosed entry and start new record with same state
|
||
|
updateStatsRecord(&stats_by_default_threshold, stats_by_default_threshold.cur_state);
|
||
|
}
|
||
|
}
|
||
|
return sensor_temp_stats_snapshot;
|
||
|
}
|
||
|
|
||
|
std::unordered_map<std::string, std::unordered_map<std::string, ThermalStats<int>>>
|
||
|
ThermalStatsHelper::GetSensorCoolingDeviceRequestStatsSnapshot() {
|
||
|
auto sensor_cdev_request_stats_snapshot = sensor_cdev_request_stats_map_;
|
||
|
for (auto &sensor_cdev_request_stats_pair : sensor_cdev_request_stats_snapshot) {
|
||
|
for (auto &cdev_request_stats_pair : sensor_cdev_request_stats_pair.second) {
|
||
|
for (auto &request_stats : cdev_request_stats_pair.second.stats_by_custom_threshold) {
|
||
|
// update the last unclosed entry and start new record with same state
|
||
|
updateStatsRecord(&request_stats.stats_record,
|
||
|
request_stats.stats_record.cur_state);
|
||
|
}
|
||
|
if (cdev_request_stats_pair.second.stats_by_default_threshold.has_value()) {
|
||
|
auto &stats_by_default_threshold =
|
||
|
cdev_request_stats_pair.second.stats_by_default_threshold.value();
|
||
|
// update the last unclosed entry and start new record with same state
|
||
|
updateStatsRecord(&stats_by_default_threshold,
|
||
|
stats_by_default_threshold.cur_state);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return sensor_cdev_request_stats_snapshot;
|
||
|
}
|
||
|
|
||
|
} // namespace implementation
|
||
|
} // namespace thermal
|
||
|
} // namespace hardware
|
||
|
} // namespace android
|
||
|
} // namespace aidl
|