1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "thermal_predictions_helper.h"
18
19 #include <android-base/logging.h>
20 #include <android/binder_manager.h>
21
22 #include <algorithm>
23 #include <numeric>
24 #include <string_view>
25
26 namespace aidl {
27 namespace android {
28 namespace hardware {
29 namespace thermal {
30 namespace implementation {
31
registerPredictorSensor(std::string_view sensor_name,int sample_duration,int num_out_samples)32 bool ThermalPredictionsHelper::registerPredictorSensor(std::string_view sensor_name,
33 int sample_duration, int num_out_samples) {
34 if (sample_duration <= 0 || num_out_samples <= 0) {
35 LOG(ERROR) << "Invalid sample_duration: " << sample_duration
36 << " or num_out_samples: " << num_out_samples << " for sensor: " << sensor_name;
37 return false;
38 }
39
40 if (predictor_sensors_.count(sensor_name.data())) {
41 LOG(ERROR) << "sensor_name " << sensor_name << " is already registered as predictor";
42 return false;
43 }
44
45 predictor_sensors_[sensor_name.data()] = PredictorSensorInfo(
46 {std::string(sensor_name), sample_duration, num_out_samples,
47 std::vector<PredictionSample>(num_out_samples, PredictionSample(num_out_samples)), 0});
48 return true;
49 }
50
registerPredictedSensor(std::string_view sensor_name,std::string_view linked_sensor,int duration)51 bool ThermalPredictionsHelper::registerPredictedSensor(std::string_view sensor_name,
52 std::string_view linked_sensor,
53 int duration) {
54 if (duration < 0) {
55 LOG(ERROR) << "Invalid duration: " << duration << " for sensor: " << sensor_name;
56 return false;
57 }
58
59 if (predicted_sensors_.count(sensor_name.data())) {
60 LOG(ERROR) << "sensor_name " << sensor_name << " is already registered as predicted sensor";
61 return false;
62 }
63
64 if (predictor_sensors_.count(linked_sensor.data()) == 0) {
65 LOG(ERROR) << "linked_sensor_name " << linked_sensor << " is not registered as predictor";
66 return false;
67 }
68
69 PredictorSensorInfo &predictor_sensor_info = predictor_sensors_[linked_sensor.data()];
70 const int max_prediction_duration =
71 (predictor_sensor_info.num_out_samples - 1) * predictor_sensor_info.sample_duration;
72
73 if (duration > max_prediction_duration) {
74 LOG(ERROR) << "Predicted sensor " << sensor_name
75 << " duration is greater than max prediction duration of predictor "
76 << linked_sensor << " which is " << max_prediction_duration;
77 return false;
78 }
79
80 // round up to nearest lower index
81 const int prediction_index = duration / predictor_sensor_info.sample_duration;
82 if (duration % predictor_sensor_info.sample_duration != 0) {
83 LOG(INFO) << "Predicted sensor " << sensor_name << " duration " << duration
84 << " is not a multiple of " << linked_sensor << " sample duration "
85 << predictor_sensor_info.sample_duration << " and hence updated to "
86 << prediction_index * predictor_sensor_info.sample_duration;
87 }
88
89 predicted_sensors_[sensor_name.data()] = PredictedSensorInfo(
90 {std::string(sensor_name), std::string(linked_sensor), duration, prediction_index});
91 return true;
92 }
93
updateSensor(std::string_view sensor_name,std::vector<float> & values)94 bool ThermalPredictionsHelper::updateSensor(std::string_view sensor_name,
95 std::vector<float> &values) {
96 std::unique_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
97 const auto sensor_itr = predictor_sensors_.find(sensor_name.data());
98 if (sensor_itr == predictor_sensors_.end()) {
99 LOG(ERROR) << "sensor_name " << sensor_name << " is not registered as predictor";
100 return false;
101 }
102
103 PredictorSensorInfo &predictor_sensor_info = predictor_sensors_[sensor_name.data()];
104 if (values.size() != static_cast<size_t>(predictor_sensor_info.num_out_samples)) {
105 LOG(ERROR) << "Invalid number of values: " << values.size()
106 << " for sensor: " << sensor_name
107 << ", expected: " << predictor_sensor_info.num_out_samples;
108 return false;
109 }
110
111 predictor_sensor_info.samples[predictor_sensor_info.cur_index].timestamp = boot_clock::now();
112 predictor_sensor_info.samples[predictor_sensor_info.cur_index].values = values;
113 predictor_sensor_info.cur_index++;
114 predictor_sensor_info.cur_index %= predictor_sensor_info.num_out_samples;
115
116 return true;
117 }
118
readSensor(std::string_view sensor_name,float * temp)119 SensorReadStatus ThermalPredictionsHelper::readSensor(std::string_view sensor_name, float *temp) {
120 std::shared_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
121 const auto sensor_itr = predicted_sensors_.find(sensor_name.data());
122 if (sensor_itr == predicted_sensors_.end()) {
123 LOG(ERROR) << "sensor_name " << sensor_name << " is not registered as predicted sensor";
124 return SensorReadStatus::ERROR;
125 }
126
127 PredictedSensorInfo &predicted_sensor_info = predicted_sensors_[sensor_name.data()];
128 const int prediction_index = predicted_sensor_info.prediction_index;
129
130 const auto linked_sensor_itr = predictor_sensors_.find(predicted_sensor_info.linked_sensor);
131 if (linked_sensor_itr == predictor_sensors_.end()) {
132 LOG(ERROR) << "linked_sensor_name " << predicted_sensor_info.linked_sensor
133 << " is not registered as predictor for sensor" << sensor_name;
134 return SensorReadStatus::ERROR;
135 }
136
137 PredictorSensorInfo predictor_sensor_info = linked_sensor_itr->second;
138 boot_clock::time_point now = boot_clock::now();
139 const auto min_time_elapsed_ms = predicted_sensor_info.duration - kToleranceIntervalMs;
140 const auto max_time_elapsed_ms = predicted_sensor_info.duration + kToleranceIntervalMs;
141 int loop_count = 0;
142 do {
143 int index = predictor_sensor_info.cur_index - loop_count - 1;
144 if (index < 0) {
145 index += predictor_sensor_info.num_out_samples;
146 }
147
148 const auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
149 now - predictor_sensor_info.samples[index].timestamp);
150 if (time_elapsed.count() <= max_time_elapsed_ms &&
151 time_elapsed.count() >= min_time_elapsed_ms) {
152 *temp = predictor_sensor_info.samples[index].values[prediction_index];
153 return SensorReadStatus::OKAY;
154 }
155
156 loop_count++;
157 } while (loop_count < predictor_sensor_info.num_out_samples);
158
159 LOG(INFO) << "sensor_name: " << sensor_name << " no valid prediction samples found";
160 return SensorReadStatus::UNDER_COLLECTING;
161 }
162
initializePredictionSensors(const std::unordered_map<std::string,SensorInfo> & sensor_info_map)163 bool ThermalPredictionsHelper::initializePredictionSensors(
164 const std::unordered_map<std::string, SensorInfo> &sensor_info_map) {
165 std::unique_lock<std::shared_mutex> _lock(sensor_predictions_mutex_);
166
167 for (auto it = sensor_info_map.begin(); it != sensor_info_map.end(); ++it) {
168 const std::string_view sensor_name = it->first;
169 const SensorInfo &sensor_info = it->second;
170
171 if (!sensor_info.predictor_info || !sensor_info.virtual_sensor_info ||
172 (!sensor_info.predictor_info->supports_predictions)) {
173 continue;
174 }
175
176 if (!registerPredictorSensor(sensor_name,
177 sensor_info.predictor_info->prediction_sample_interval,
178 sensor_info.predictor_info->num_prediction_samples)) {
179 LOG(ERROR) << "Failed to register predictor sensor: " << sensor_name;
180 return false;
181 }
182 }
183
184 for (auto it = sensor_info_map.begin(); it != sensor_info_map.end(); ++it) {
185 const std::string_view sensor_name = it->first;
186 const SensorInfo &sensor_info = it->second;
187
188 if (!sensor_info.predictor_info || !sensor_info.virtual_sensor_info ||
189 (sensor_info.virtual_sensor_info->formula != FormulaOption::PREVIOUSLY_PREDICTED)) {
190 continue;
191 }
192
193 if (sensor_info.virtual_sensor_info->linked_sensors.size() != 1) {
194 LOG(ERROR) << "Invalid number of linked sensors: "
195 << sensor_info.virtual_sensor_info->linked_sensors.size()
196 << " for sensor: " << sensor_name;
197 return false;
198 }
199
200 if (!registerPredictedSensor(sensor_name,
201 sensor_info.virtual_sensor_info->linked_sensors[0],
202 sensor_info.predictor_info->prediction_duration)) {
203 LOG(ERROR) << "Failed to register predicted sensor: " << sensor_name;
204 return false;
205 }
206 }
207
208 return true;
209 }
210
211 } // namespace implementation
212 } // namespace thermal
213 } // namespace hardware
214 } // namespace android
215 } // namespace aidl
216