1 /*
2 * Copyright (C) 2017 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 specic language governing permissions and
14 * limitations under the License.
15 */
16
17 #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
18 #define LOG_TAG "libperfmgr"
19
20 #include "perfmgr/HintManager.h"
21
22 #include <android-base/file.h>
23 #include <android-base/logging.h>
24 #include <android-base/properties.h>
25 #include <android-base/stringprintf.h>
26 #include <inttypes.h>
27 #include <json/reader.h>
28 #include <json/value.h>
29 #include <utils/Trace.h>
30
31 #include <algorithm>
32 #include <set>
33
34 #include "perfmgr/FileNode.h"
35 #include "perfmgr/PropertyNode.h"
36
37 namespace android {
38 namespace perfmgr {
39
40 namespace {
41 constexpr std::chrono::milliseconds kMilliSecondZero = std::chrono::milliseconds(0);
42 constexpr std::chrono::steady_clock::time_point kTimePointMax =
43 std::chrono::steady_clock::time_point::max();
44 } // namespace
45
46 constexpr char kPowerHalTruncateProp[] = "vendor.powerhal.truncate";
47 constexpr std::string_view kConfigDebugPathProperty("vendor.powerhal.config.debug");
48 constexpr std::string_view kConfigProperty("vendor.powerhal.config");
49 constexpr std::string_view kConfigDefaultFileName("powerhint.json");
50
ValidateHint(const std::string & hint_type) const51 bool HintManager::ValidateHint(const std::string& hint_type) const {
52 if (nm_.get() == nullptr) {
53 LOG(ERROR) << "NodeLooperThread not present";
54 return false;
55 }
56 return IsHintSupported(hint_type);
57 }
58
IsHintSupported(const std::string & hint_type) const59 bool HintManager::IsHintSupported(const std::string& hint_type) const {
60 if (actions_.find(hint_type) == actions_.end()) {
61 LOG(INFO) << "Hint type not present in actions: " << hint_type;
62 return false;
63 }
64 return true;
65 }
66
IsHintEnabled(const std::string & hint_type) const67 bool HintManager::IsHintEnabled(const std::string &hint_type) const {
68 std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
69 return actions_.at(hint_type).mask_requesters.empty();
70 }
71
InitHintStatus(const std::unique_ptr<HintManager> & hm)72 bool HintManager::InitHintStatus(const std::unique_ptr<HintManager> &hm) {
73 if (hm.get() == nullptr) {
74 return false;
75 }
76 for (auto &a : hm->actions_) {
77 // timeout_ms equaling kMilliSecondZero means forever until cancelling.
78 // As a result, if there's one NodeAction has timeout_ms of 0, we will store
79 // 0 instead of max. Also node actions could be empty, set to 0 in that case.
80 std::chrono::milliseconds timeout = kMilliSecondZero;
81 if (a.second.node_actions.size()) {
82 auto [min, max] =
83 std::minmax_element(a.second.node_actions.begin(), a.second.node_actions.end(),
84 [](const auto act1, const auto act2) {
85 return act1.timeout_ms < act2.timeout_ms;
86 });
87 timeout = min->timeout_ms == kMilliSecondZero ? kMilliSecondZero : max->timeout_ms;
88 }
89 a.second.status.reset(new HintStatus(timeout));
90 }
91 return true;
92 }
93
DoHintStatus(const std::string & hint_type,std::chrono::milliseconds timeout_ms)94 void HintManager::DoHintStatus(const std::string &hint_type, std::chrono::milliseconds timeout_ms) {
95 std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
96 actions_.at(hint_type).status->stats.count.fetch_add(1);
97 auto now = std::chrono::steady_clock::now();
98 ATRACE_INT(hint_type.c_str(), (timeout_ms == kMilliSecondZero) ? std::numeric_limits<int>::max()
99 : timeout_ms.count());
100 if (now > actions_.at(hint_type).status->end_time) {
101 actions_.at(hint_type).status->stats.duration_ms.fetch_add(
102 std::chrono::duration_cast<std::chrono::milliseconds>(
103 actions_.at(hint_type).status->end_time -
104 actions_.at(hint_type).status->start_time)
105 .count());
106 actions_.at(hint_type).status->start_time = now;
107 }
108 actions_.at(hint_type).status->end_time =
109 (timeout_ms == kMilliSecondZero) ? kTimePointMax : now + timeout_ms;
110 }
111
EndHintStatus(const std::string & hint_type)112 void HintManager::EndHintStatus(const std::string &hint_type) {
113 std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
114 // Update HintStats if the hint ends earlier than expected end_time
115 auto now = std::chrono::steady_clock::now();
116 ATRACE_INT(hint_type.c_str(), 0);
117 if (now < actions_.at(hint_type).status->end_time) {
118 actions_.at(hint_type).status->stats.duration_ms.fetch_add(
119 std::chrono::duration_cast<std::chrono::milliseconds>(
120 now - actions_.at(hint_type).status->start_time)
121 .count());
122 actions_.at(hint_type).status->end_time = now;
123 }
124 }
125
DoHintAction(const std::string & hint_type)126 void HintManager::DoHintAction(const std::string &hint_type) {
127 for (auto &action : actions_.at(hint_type).hint_actions) {
128 if (!action.enable_property.empty() &&
129 !android::base::GetBoolProperty(action.enable_property, true)) {
130 // Disabled action based on its control property
131 continue;
132 }
133 switch (action.type) {
134 case HintActionType::DoHint:
135 DoHint(action.value);
136 break;
137 case HintActionType::EndHint:
138 EndHint(action.value);
139 break;
140 case HintActionType::MaskHint:
141 if (actions_.find(action.value) == actions_.end()) {
142 LOG(ERROR) << "Failed to find " << action.value << " action";
143 } else {
144 std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
145 actions_.at(action.value).mask_requesters.insert(hint_type);
146 }
147 break;
148 default:
149 // should not reach here
150 LOG(ERROR) << "Invalid "
151 << static_cast<std::underlying_type<HintActionType>::type>(action.type)
152 << " type";
153 }
154 }
155 }
156
EndHintAction(const std::string & hint_type)157 void HintManager::EndHintAction(const std::string &hint_type) {
158 for (auto &action : actions_.at(hint_type).hint_actions) {
159 if (action.type == HintActionType::MaskHint &&
160 actions_.find(action.value) != actions_.end()) {
161 std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
162 actions_.at(action.value).mask_requesters.erase(hint_type);
163 }
164 }
165 }
166
DoHint(const std::string & hint_type)167 bool HintManager::DoHint(const std::string& hint_type) {
168 LOG(VERBOSE) << "Do Powerhint: " << hint_type;
169 if (!ValidateHint(hint_type) || !IsHintEnabled(hint_type) ||
170 !nm_->Request(actions_.at(hint_type).node_actions, hint_type)) {
171 return false;
172 }
173 DoHintStatus(hint_type, actions_.at(hint_type).status->max_timeout);
174 DoHintAction(hint_type);
175 return true;
176 }
177
DoHint(const std::string & hint_type,std::chrono::milliseconds timeout_ms_override)178 bool HintManager::DoHint(const std::string& hint_type,
179 std::chrono::milliseconds timeout_ms_override) {
180 LOG(VERBOSE) << "Do Powerhint: " << hint_type << " for "
181 << timeout_ms_override.count() << "ms";
182 if (!ValidateHint(hint_type) || !IsHintEnabled(hint_type)) {
183 return false;
184 }
185 std::vector<NodeAction> actions_override = actions_.at(hint_type).node_actions;
186 for (auto& action : actions_override) {
187 action.timeout_ms = timeout_ms_override;
188 }
189 if (!nm_->Request(actions_override, hint_type)) {
190 return false;
191 }
192 DoHintStatus(hint_type, timeout_ms_override);
193 DoHintAction(hint_type);
194 return true;
195 }
196
EndHint(const std::string & hint_type)197 bool HintManager::EndHint(const std::string& hint_type) {
198 LOG(VERBOSE) << "End Powerhint: " << hint_type;
199 if (!ValidateHint(hint_type) || !nm_->Cancel(actions_.at(hint_type).node_actions, hint_type)) {
200 return false;
201 }
202 EndHintStatus(hint_type);
203 EndHintAction(hint_type);
204 return true;
205 }
206
IsRunning() const207 bool HintManager::IsRunning() const {
208 return (nm_.get() == nullptr) ? false : nm_->isRunning();
209 }
210
GetHints() const211 std::vector<std::string> HintManager::GetHints() const {
212 std::vector<std::string> hints;
213 for (auto const& action : actions_) {
214 hints.push_back(action.first);
215 }
216 return hints;
217 }
218
GetHintStats(const std::string & hint_type) const219 HintStats HintManager::GetHintStats(const std::string &hint_type) const {
220 HintStats hint_stats;
221 if (ValidateHint(hint_type)) {
222 std::lock_guard<std::mutex> lock(actions_.at(hint_type).hint_lock);
223 hint_stats.count =
224 actions_.at(hint_type).status->stats.count.load(std::memory_order_relaxed);
225 hint_stats.duration_ms =
226 actions_.at(hint_type).status->stats.duration_ms.load(std::memory_order_relaxed);
227 }
228 return hint_stats;
229 }
230
DumpToFd(int fd)231 void HintManager::DumpToFd(int fd) {
232 std::string header("========== Begin perfmgr nodes ==========\n");
233 if (!android::base::WriteStringToFd(header, fd)) {
234 LOG(ERROR) << "Failed to dump fd: " << fd;
235 }
236 nm_->DumpToFd(fd);
237 std::string footer("========== End perfmgr nodes ==========\n");
238 if (!android::base::WriteStringToFd(footer, fd)) {
239 LOG(ERROR) << "Failed to dump fd: " << fd;
240 }
241 header = "========== Begin perfmgr stats ==========\n"
242 "Hint Name\t"
243 "Counts\t"
244 "Duration\n";
245 if (!android::base::WriteStringToFd(header, fd)) {
246 LOG(ERROR) << "Failed to dump fd: " << fd;
247 }
248 std::string hint_stats_string;
249 std::vector<std::string> keys(GetHints());
250 std::sort(keys.begin(), keys.end());
251 for (const auto &ordered_key : keys) {
252 HintStats hint_stats(GetHintStats(ordered_key));
253 hint_stats_string +=
254 android::base::StringPrintf("%s\t%" PRIu32 "\t%" PRIu64 "\n", ordered_key.c_str(),
255 hint_stats.count, hint_stats.duration_ms);
256 }
257 if (!android::base::WriteStringToFd(hint_stats_string, fd)) {
258 LOG(ERROR) << "Failed to dump fd: " << fd;
259 }
260 footer = "========== End perfmgr stats ==========\n";
261 if (!android::base::WriteStringToFd(footer, fd)) {
262 LOG(ERROR) << "Failed to dump fd: " << fd;
263 }
264
265 // Dump current ADPF profile
266 if (GetAdpfProfile()) {
267 header = "========== Begin current adpf profile ==========\n";
268 if (!android::base::WriteStringToFd(header, fd)) {
269 LOG(ERROR) << "Failed to dump fd: " << fd;
270 }
271 GetAdpfProfile()->dumpToFd(fd);
272 footer = "========== End current adpf profile ==========\n";
273 if (!android::base::WriteStringToFd(footer, fd)) {
274 LOG(ERROR) << "Failed to dump fd: " << fd;
275 }
276 }
277 fsync(fd);
278 }
279
Start()280 bool HintManager::Start() {
281 return nm_->Start();
282 }
283
284 std::shared_ptr<HintManager> HintManager::mInstance = nullptr;
285
Reload(bool start)286 std::shared_ptr<HintManager> HintManager::Reload(bool start) {
287 std::string config_path = "/vendor/etc/";
288 if (android::base::GetBoolProperty(kConfigDebugPathProperty.data(), false)) {
289 config_path = "/data/vendor/etc/";
290 LOG(WARNING) << "Pixel Power HAL AIDL Service is using debug config from: " << config_path;
291 }
292 config_path.append(
293 android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()));
294
295 LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is starting with config: "
296 << config_path;
297 // Reload and start the HintManager
298 mInstance = HintManager::GetFromJSON(config_path, start);
299 if (!mInstance) {
300 LOG(FATAL) << "Invalid config: " << config_path;
301 }
302 return mInstance;
303 }
304
GetInstance()305 std::shared_ptr<HintManager> HintManager::GetInstance() {
306 if (!mInstance) {
307 mInstance = HintManager::Reload(false);
308 }
309 return mInstance;
310 }
311
GetFromJSON(const std::string & config_path,bool start)312 std::unique_ptr<HintManager> HintManager::GetFromJSON(
313 const std::string& config_path, bool start) {
314 std::string json_doc;
315
316 if (!android::base::ReadFileToString(config_path, &json_doc)) {
317 LOG(ERROR) << "Failed to read JSON config from " << config_path;
318 return nullptr;
319 }
320
321 std::vector<std::unique_ptr<Node>> nodes = ParseNodes(json_doc);
322 if (nodes.empty()) {
323 LOG(ERROR) << "Failed to parse Nodes section from " << config_path;
324 return nullptr;
325 }
326 std::vector<std::shared_ptr<AdpfConfig>> adpfs = HintManager::ParseAdpfConfigs(json_doc);
327 if (adpfs.empty()) {
328 LOG(INFO) << "No AdpfConfig section in the " << config_path;
329 }
330
331 std::unordered_map<std::string, Hint> actions = HintManager::ParseActions(json_doc, nodes);
332
333 if (actions.empty()) {
334 LOG(ERROR) << "Failed to parse Actions section from " << config_path;
335 return nullptr;
336 }
337
338 sp<NodeLooperThread> nm = new NodeLooperThread(std::move(nodes));
339 std::unique_ptr<HintManager> hm = std::make_unique<HintManager>(std::move(nm), actions, adpfs);
340
341 if (!HintManager::InitHintStatus(hm)) {
342 LOG(ERROR) << "Failed to initialize hint status";
343 return nullptr;
344 }
345
346 LOG(INFO) << "Initialized HintManager from JSON config: " << config_path;
347
348 if (start) {
349 hm->Start();
350 }
351 return hm;
352 }
353
ParseNodes(const std::string & json_doc)354 std::vector<std::unique_ptr<Node>> HintManager::ParseNodes(
355 const std::string& json_doc) {
356 // function starts
357 std::vector<std::unique_ptr<Node>> nodes_parsed;
358 std::set<std::string> nodes_name_parsed;
359 std::set<std::string> nodes_path_parsed;
360 Json::Value root;
361 Json::CharReaderBuilder builder;
362 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
363 std::string errorMessage;
364
365 if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
366 LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
367 return nodes_parsed;
368 }
369
370 Json::Value nodes = root["Nodes"];
371 for (Json::Value::ArrayIndex i = 0; i < nodes.size(); ++i) {
372 std::string name = nodes[i]["Name"].asString();
373 LOG(VERBOSE) << "Node[" << i << "]'s Name: " << name;
374 if (name.empty()) {
375 LOG(ERROR) << "Failed to read "
376 << "Node[" << i << "]'s Name";
377 nodes_parsed.clear();
378 return nodes_parsed;
379 }
380
381 auto result = nodes_name_parsed.insert(name);
382 if (!result.second) {
383 LOG(ERROR) << "Duplicate Node[" << i << "]'s Name";
384 nodes_parsed.clear();
385 return nodes_parsed;
386 }
387
388 std::string path = nodes[i]["Path"].asString();
389 LOG(VERBOSE) << "Node[" << i << "]'s Path: " << path;
390 if (path.empty()) {
391 LOG(ERROR) << "Failed to read "
392 << "Node[" << i << "]'s Path";
393 nodes_parsed.clear();
394 return nodes_parsed;
395 }
396
397 result = nodes_path_parsed.insert(path);
398 if (!result.second) {
399 LOG(ERROR) << "Duplicate Node[" << i << "]'s Path";
400 nodes_parsed.clear();
401 return nodes_parsed;
402 }
403
404 bool is_file = true;
405 std::string node_type = nodes[i]["Type"].asString();
406 LOG(VERBOSE) << "Node[" << i << "]'s Type: " << node_type;
407 if (node_type.empty()) {
408 LOG(VERBOSE) << "Failed to read "
409 << "Node[" << i << "]'s Type, set to 'File' as default";
410 } else if (node_type == "File") {
411 is_file = true;
412 } else if (node_type == "Property") {
413 is_file = false;
414 } else {
415 LOG(ERROR) << "Invalid Node[" << i
416 << "]'s Type: only File and Property supported.";
417 nodes_parsed.clear();
418 return nodes_parsed;
419 }
420
421 std::vector<RequestGroup> values_parsed;
422 std::set<std::string> values_set_parsed;
423 Json::Value values = nodes[i]["Values"];
424 for (Json::Value::ArrayIndex j = 0; j < values.size(); ++j) {
425 std::string value = values[j].asString();
426 LOG(VERBOSE) << "Node[" << i << "]'s Value[" << j << "]: " << value;
427 auto result = values_set_parsed.insert(value);
428 if (!result.second) {
429 LOG(ERROR) << "Duplicate value parsed in Node[" << i
430 << "]'s Value[" << j << "]";
431 nodes_parsed.clear();
432 return nodes_parsed;
433 }
434 if (is_file && value.empty()) {
435 LOG(ERROR) << "Failed to read Node[" << i << "]'s Value[" << j
436 << "]";
437 nodes_parsed.clear();
438 return nodes_parsed;
439 }
440 values_parsed.emplace_back(value);
441 }
442 if (values_parsed.size() < 1) {
443 LOG(ERROR) << "Failed to read Node[" << i << "]'s Values";
444 nodes_parsed.clear();
445 return nodes_parsed;
446 }
447
448 Json::UInt64 default_index = values_parsed.size() - 1;
449 if (nodes[i]["DefaultIndex"].empty() ||
450 !nodes[i]["DefaultIndex"].isUInt64()) {
451 LOG(INFO) << "Failed to read Node[" << i
452 << "]'s DefaultIndex, set to last index: "
453 << default_index;
454 } else {
455 default_index = nodes[i]["DefaultIndex"].asUInt64();
456 }
457 if (default_index > values_parsed.size() - 1) {
458 default_index = values_parsed.size() - 1;
459 LOG(ERROR) << "Node[" << i
460 << "]'s DefaultIndex out of bound, max value index: "
461 << default_index;
462 nodes_parsed.clear();
463 return nodes_parsed;
464 }
465 LOG(VERBOSE) << "Node[" << i << "]'s DefaultIndex: " << default_index;
466
467 bool reset = false;
468 if (nodes[i]["ResetOnInit"].empty() ||
469 !nodes[i]["ResetOnInit"].isBool()) {
470 LOG(INFO) << "Failed to read Node[" << i
471 << "]'s ResetOnInit, set to 'false'";
472 } else {
473 reset = nodes[i]["ResetOnInit"].asBool();
474 }
475 LOG(VERBOSE) << "Node[" << i << "]'s ResetOnInit: " << std::boolalpha
476 << reset << std::noboolalpha;
477
478 if (is_file) {
479 bool truncate = android::base::GetBoolProperty(kPowerHalTruncateProp, true);
480 if (nodes[i]["Truncate"].empty() || !nodes[i]["Truncate"].isBool()) {
481 LOG(INFO) << "Failed to read Node[" << i << "]'s Truncate, set to 'true'";
482 } else {
483 truncate = nodes[i]["Truncate"].asBool();
484 }
485 LOG(VERBOSE) << "Node[" << i << "]'s Truncate: " << std::boolalpha << truncate
486 << std::noboolalpha;
487
488 bool hold_fd = false;
489 if (nodes[i]["HoldFd"].empty() || !nodes[i]["HoldFd"].isBool()) {
490 LOG(INFO) << "Failed to read Node[" << i
491 << "]'s HoldFd, set to 'false'";
492 } else {
493 hold_fd = nodes[i]["HoldFd"].asBool();
494 }
495 LOG(VERBOSE) << "Node[" << i << "]'s HoldFd: " << std::boolalpha
496 << hold_fd << std::noboolalpha;
497
498 bool write_only = false;
499 if (nodes[i]["WriteOnly"].empty() || !nodes[i]["WriteOnly"].isBool()) {
500 LOG(INFO) << "Failed to read Node[" << i
501 << "]'s WriteOnly, set to 'false'";
502 } else {
503 write_only = nodes[i]["WriteOnly"].asBool();
504 }
505 LOG(VERBOSE) << "Node[" << i << "]'s WriteOnly: " << std::boolalpha
506 << write_only << std::noboolalpha;
507
508 nodes_parsed.emplace_back(std::make_unique<FileNode>(
509 name, path, values_parsed, static_cast<std::size_t>(default_index), reset,
510 truncate, hold_fd, write_only));
511 } else {
512 nodes_parsed.emplace_back(std::make_unique<PropertyNode>(
513 name, path, values_parsed,
514 static_cast<std::size_t>(default_index), reset));
515 }
516 }
517 LOG(INFO) << nodes_parsed.size() << " Nodes parsed successfully";
518 return nodes_parsed;
519 }
520
ParseActions(const std::string & json_doc,const std::vector<std::unique_ptr<Node>> & nodes)521 std::unordered_map<std::string, Hint> HintManager::ParseActions(
522 const std::string &json_doc, const std::vector<std::unique_ptr<Node>> &nodes) {
523 // function starts
524 std::unordered_map<std::string, Hint> actions_parsed;
525 Json::Value root;
526 Json::CharReaderBuilder builder;
527 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
528 std::string errorMessage;
529
530 if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
531 LOG(ERROR) << "Failed to parse JSON config";
532 return actions_parsed;
533 }
534
535 Json::Value actions = root["Actions"];
536 std::size_t total_parsed = 0;
537
538 std::map<std::string, std::size_t> nodes_index;
539 for (std::size_t i = 0; i < nodes.size(); ++i) {
540 nodes_index[nodes[i]->GetName()] = i;
541 }
542
543 for (Json::Value::ArrayIndex i = 0; i < actions.size(); ++i) {
544 const std::string& hint_type = actions[i]["PowerHint"].asString();
545 LOG(VERBOSE) << "Action[" << i << "]'s PowerHint: " << hint_type;
546 if (hint_type.empty()) {
547 LOG(ERROR) << "Failed to read "
548 << "Action[" << i << "]'s PowerHint";
549 actions_parsed.clear();
550 return actions_parsed;
551 }
552
553 HintActionType action_type = HintActionType::Node;
554 std::string type_string = actions[i]["Type"].asString();
555 std::string enable_property = actions[i]["EnableProperty"].asString();
556 LOG(VERBOSE) << "Action[" << i << "]'s Type: " << type_string;
557 if (type_string.empty()) {
558 LOG(VERBOSE) << "Failed to read "
559 << "Action[" << i << "]'s Type, set to 'Node' as default";
560 } else if (type_string == "DoHint") {
561 action_type = HintActionType::DoHint;
562 } else if (type_string == "EndHint") {
563 action_type = HintActionType::EndHint;
564 } else if (type_string == "MaskHint") {
565 action_type = HintActionType::MaskHint;
566 } else {
567 LOG(ERROR) << "Invalid Action[" << i << "]'s Type: " << type_string;
568 actions_parsed.clear();
569 return actions_parsed;
570 }
571 if (action_type == HintActionType::Node) {
572 std::string node_name = actions[i]["Node"].asString();
573 LOG(VERBOSE) << "Action[" << i << "]'s Node: " << node_name;
574 std::size_t node_index;
575
576 if (nodes_index.find(node_name) == nodes_index.end()) {
577 LOG(ERROR) << "Failed to find "
578 << "Action[" << i << "]'s Node from Nodes section: [" << node_name
579 << "]";
580 actions_parsed.clear();
581 return actions_parsed;
582 }
583 node_index = nodes_index[node_name];
584
585 std::string value_name = actions[i]["Value"].asString();
586 LOG(VERBOSE) << "Action[" << i << "]'s Value: " << value_name;
587 std::size_t value_index = 0;
588
589 if (!nodes[node_index]->GetValueIndex(value_name, &value_index)) {
590 LOG(ERROR) << "Failed to read Action[" << i << "]'s Value";
591 LOG(ERROR) << "Action[" << i << "]'s Value " << value_name
592 << " is not defined in Node[" << node_name << "]";
593 actions_parsed.clear();
594 return actions_parsed;
595 }
596 LOG(VERBOSE) << "Action[" << i << "]'s ValueIndex: " << value_index;
597
598 Json::UInt64 duration = 0;
599 if (actions[i]["Duration"].empty() || !actions[i]["Duration"].isUInt64()) {
600 LOG(ERROR) << "Failed to read Action[" << i << "]'s Duration";
601 actions_parsed.clear();
602 return actions_parsed;
603 } else {
604 duration = actions[i]["Duration"].asUInt64();
605 }
606 LOG(VERBOSE) << "Action[" << i << "]'s Duration: " << duration;
607
608 for (const auto &action : actions_parsed[hint_type].node_actions) {
609 if (action.node_index == node_index) {
610 LOG(ERROR)
611 << "Action[" << i
612 << "]'s NodeIndex is duplicated with another Action";
613 actions_parsed.clear();
614 return actions_parsed;
615 }
616 }
617 actions_parsed[hint_type].node_actions.emplace_back(
618 node_index, value_index, std::chrono::milliseconds(duration), enable_property);
619
620 } else {
621 const std::string &hint_value = actions[i]["Value"].asString();
622 LOG(VERBOSE) << "Action[" << i << "]'s Value: " << hint_value;
623 if (hint_value.empty()) {
624 LOG(ERROR) << "Failed to read "
625 << "Action[" << i << "]'s Value";
626 actions_parsed.clear();
627 return actions_parsed;
628 }
629 actions_parsed[hint_type].hint_actions.emplace_back(action_type, hint_value,
630 enable_property);
631 }
632
633 ++total_parsed;
634 }
635
636 LOG(INFO) << total_parsed << " actions parsed successfully";
637
638 for (const auto& action : actions_parsed) {
639 LOG(INFO) << "PowerHint " << action.first << " has " << action.second.node_actions.size()
640 << " node actions"
641 << ", and " << action.second.hint_actions.size() << " hint actions parsed";
642 }
643
644 return actions_parsed;
645 }
646
ParseAdpfConfigs(const std::string & json_doc)647 std::vector<std::shared_ptr<AdpfConfig>> HintManager::ParseAdpfConfigs(
648 const std::string &json_doc) {
649 // function starts
650 bool pidOn;
651 double pidPOver;
652 double pidPUnder;
653 double pidI;
654 double pidDOver;
655 double pidDUnder;
656 int64_t pidIInit;
657 int64_t pidIHighLimit;
658 int64_t pidILowLimit;
659 bool adpfUclamp;
660 uint32_t uclampMinInit;
661 uint32_t uclampMinHighLimit;
662 uint32_t uclampMinLowLimit;
663 uint64_t samplingWindowP;
664 uint64_t samplingWindowI;
665 uint64_t samplingWindowD;
666 double staleTimeFactor;
667 uint64_t reportingRate;
668 bool earlyBoostOn;
669 double earlyBoostTimeFactor;
670 double targetTimeFactor;
671 std::vector<std::shared_ptr<AdpfConfig>> adpfs_parsed;
672 std::set<std::string> name_parsed;
673 Json::Value root;
674 Json::CharReaderBuilder builder;
675 std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
676 std::string errorMessage;
677 if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
678 LOG(ERROR) << "Failed to parse JSON config: " << errorMessage;
679 return adpfs_parsed;
680 }
681 Json::Value adpfs = root["AdpfConfig"];
682 for (Json::Value::ArrayIndex i = 0; i < adpfs.size(); ++i) {
683 std::string name = adpfs[i]["Name"].asString();
684 LOG(VERBOSE) << "AdpfConfig[" << i << "]'s Name: " << name;
685 if (name.empty()) {
686 LOG(ERROR) << "Failed to read "
687 << "AdpfConfig[" << i << "]'s Name";
688 adpfs_parsed.clear();
689 return adpfs_parsed;
690 }
691 auto result = name_parsed.insert(name);
692 if (!result.second) {
693 LOG(ERROR) << "Duplicate AdpfConfig[" << i << "]'s Name";
694 adpfs_parsed.clear();
695 return adpfs_parsed;
696 }
697
698 if (adpfs[i]["PID_On"].empty() || !adpfs[i]["PID_On"].isBool()) {
699 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_On]'s Values";
700 adpfs_parsed.clear();
701 return adpfs_parsed;
702 }
703 pidOn = adpfs[i]["PID_On"].asBool();
704
705 if (adpfs[i]["PID_Po"].empty() || !adpfs[i]["PID_Po"].isDouble()) {
706 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_Po]'s Values";
707 adpfs_parsed.clear();
708 return adpfs_parsed;
709 }
710 pidPOver = adpfs[i]["PID_Po"].asDouble();
711
712 if (adpfs[i]["PID_Pu"].empty() || !adpfs[i]["PID_Pu"].isDouble()) {
713 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_Pu]'s Values";
714 adpfs_parsed.clear();
715 return adpfs_parsed;
716 }
717 pidPUnder = adpfs[i]["PID_Pu"].asDouble();
718
719 if (adpfs[i]["PID_I"].empty() || !adpfs[i]["PID_I"].isDouble()) {
720 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_I]'s Values";
721 adpfs_parsed.clear();
722 return adpfs_parsed;
723 }
724 pidI = adpfs[i]["PID_I"].asDouble();
725
726 if (adpfs[i]["PID_I_Init"].empty() || !adpfs[i]["PID_I_Init"].isInt64()) {
727 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_I_Init]'s Values";
728 adpfs_parsed.clear();
729 return adpfs_parsed;
730 }
731 pidIInit = adpfs[i]["PID_I_Init"].asInt64();
732
733 if (adpfs[i]["PID_I_High"].empty() || !adpfs[i]["PID_I_High"].isInt64()) {
734 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_I_High]'s Values";
735 adpfs_parsed.clear();
736 return adpfs_parsed;
737 }
738 pidIHighLimit = adpfs[i]["PID_I_High"].asInt64();
739
740 if (adpfs[i]["PID_I_Low"].empty() || !adpfs[i]["PID_I_Low"].isInt64()) {
741 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_I_Low]'s Values";
742 adpfs_parsed.clear();
743 return adpfs_parsed;
744 }
745 pidILowLimit = adpfs[i]["PID_I_Low"].asInt64();
746
747 if (adpfs[i]["PID_Do"].empty() || !adpfs[i]["PID_Do"].isDouble()) {
748 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_Do]'s Values";
749 adpfs_parsed.clear();
750 return adpfs_parsed;
751 }
752 pidDOver = adpfs[i]["PID_Do"].asDouble();
753
754 if (adpfs[i]["PID_Du"].empty() || !adpfs[i]["PID_Du"].isDouble()) {
755 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][PID_Du]'s Values";
756 adpfs_parsed.clear();
757 return adpfs_parsed;
758 }
759 pidDUnder = adpfs[i]["PID_Du"].asDouble();
760
761 if (adpfs[i]["UclampMin_On"].empty() || !adpfs[i]["UclampMin_On"].isBool()) {
762 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][UclampMin_On]'s Values";
763 adpfs_parsed.clear();
764 return adpfs_parsed;
765 }
766 adpfUclamp = adpfs[i]["UclampMin_On"].asBool();
767
768 if (adpfs[i]["UclampMin_Init"].empty() || !adpfs[i]["UclampMin_Init"].isInt()) {
769 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][UclampMin_Init]'s Values";
770 adpfs_parsed.clear();
771 return adpfs_parsed;
772 }
773 uclampMinInit = adpfs[i]["UclampMin_Init"].asInt();
774
775 if (adpfs[i]["UclampMin_High"].empty() || !adpfs[i]["UclampMin_High"].isUInt()) {
776 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][UclampMin_High]'s Values";
777 adpfs_parsed.clear();
778 return adpfs_parsed;
779 }
780 uclampMinHighLimit = adpfs[i]["UclampMin_High"].asUInt();
781
782 if (adpfs[i]["UclampMin_Low"].empty() || !adpfs[i]["UclampMin_Low"].isUInt()) {
783 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][UclampMin_Low]'s Values";
784 adpfs_parsed.clear();
785 return adpfs_parsed;
786 }
787 uclampMinLowLimit = adpfs[i]["UclampMin_Low"].asUInt();
788
789 if (adpfs[i]["SamplingWindow_P"].empty() || !adpfs[i]["SamplingWindow_P"].isUInt64()) {
790 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][SamplingWindow_P]'s Values";
791 adpfs_parsed.clear();
792 return adpfs_parsed;
793 }
794 samplingWindowP = adpfs[i]["SamplingWindow_P"].asUInt64();
795
796 if (adpfs[i]["SamplingWindow_I"].empty() || !adpfs[i]["SamplingWindow_I"].isUInt64()) {
797 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][SamplingWindow_I]'s Values";
798 adpfs_parsed.clear();
799 return adpfs_parsed;
800 }
801 samplingWindowI = adpfs[i]["SamplingWindow_I"].asUInt64();
802
803 if (adpfs[i]["SamplingWindow_D"].empty() || !adpfs[i]["SamplingWindow_D"].isUInt64()) {
804 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][SamplingWindow_D]'s Values";
805 adpfs_parsed.clear();
806 return adpfs_parsed;
807 }
808 samplingWindowD = adpfs[i]["SamplingWindow_D"].asUInt64();
809
810 if (adpfs[i]["StaleTimeFactor"].empty() || !adpfs[i]["StaleTimeFactor"].isUInt64()) {
811 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][StaleTimeFactor]'s Values";
812 adpfs_parsed.clear();
813 return adpfs_parsed;
814 }
815 staleTimeFactor = adpfs[i]["StaleTimeFactor"].asDouble();
816
817 if (adpfs[i]["ReportingRateLimitNs"].empty() ||
818 !adpfs[i]["ReportingRateLimitNs"].isInt64()) {
819 LOG(ERROR) << "Failed to read AdpfConfig[" << name
820 << "][ReportingRateLimitNs]'s Values";
821 adpfs_parsed.clear();
822 return adpfs_parsed;
823 }
824 reportingRate = adpfs[i]["ReportingRateLimitNs"].asInt64();
825
826 if (adpfs[i]["EarlyBoost_On"].empty() || !adpfs[i]["EarlyBoost_On"].isBool()) {
827 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][EarlyBoost_On]'s Values";
828 adpfs_parsed.clear();
829 return adpfs_parsed;
830 }
831 earlyBoostOn = adpfs[i]["EarlyBoost_On"].asBool();
832
833 if (adpfs[i]["EarlyBoost_TimeFactor"].empty() ||
834 !adpfs[i]["EarlyBoost_TimeFactor"].isDouble()) {
835 LOG(ERROR) << "Failed to read AdpfConfig[" << name
836 << "][EarlyBoost_TimeFactor]'s Values";
837 adpfs_parsed.clear();
838 return adpfs_parsed;
839 }
840 earlyBoostTimeFactor = adpfs[i]["EarlyBoost_TimeFactor"].asDouble();
841
842 if (adpfs[i]["TargetTimeFactor"].empty() || !adpfs[i]["TargetTimeFactor"].isDouble()) {
843 LOG(ERROR) << "Failed to read AdpfConfig[" << name << "][TargetTimeFactor]'s Values";
844 adpfs_parsed.clear();
845 return adpfs_parsed;
846 }
847 targetTimeFactor = adpfs[i]["TargetTimeFactor"].asDouble();
848
849 adpfs_parsed.emplace_back(std::make_shared<AdpfConfig>(
850 name, pidOn, pidPOver, pidPUnder, pidI, pidIInit, pidIHighLimit, pidILowLimit,
851 pidDOver, pidDUnder, adpfUclamp, uclampMinInit, uclampMinHighLimit,
852 uclampMinLowLimit, samplingWindowP, samplingWindowI, samplingWindowD, reportingRate,
853 earlyBoostOn, earlyBoostTimeFactor, targetTimeFactor, staleTimeFactor));
854 }
855 LOG(INFO) << adpfs_parsed.size() << " AdpfConfigs parsed successfully";
856 return adpfs_parsed;
857 }
858
GetAdpfProfile() const859 std::shared_ptr<AdpfConfig> HintManager::GetAdpfProfile() const {
860 if (adpfs_.empty())
861 return nullptr;
862 return adpfs_[adpf_index_];
863 }
864
SetAdpfProfile(const std::string & profile_name)865 bool HintManager::SetAdpfProfile(const std::string &profile_name) {
866 for (std::size_t i = 0; i < adpfs_.size(); ++i) {
867 if (adpfs_[i]->mName == profile_name) {
868 adpf_index_ = i;
869 return true;
870 }
871 }
872 return false;
873 }
874
875 } // namespace perfmgr
876 } // namespace android
877