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 #include <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <android-base/properties.h>
20 #include <android-base/stringprintf.h>
21 #include <gtest/gtest.h>
22
23 #include <algorithm>
24 #include <thread>
25
26 #include "perfmgr/AdpfConfig.h"
27 #include "perfmgr/FileNode.h"
28 #include "perfmgr/HintManager.h"
29 #include "perfmgr/PropertyNode.h"
30
31 namespace android {
32 namespace perfmgr {
33
34 using std::literals::chrono_literals::operator""ms;
35
36 constexpr auto kSLEEP_TOLERANCE_MS = 50ms;
37
38 constexpr char kJSON_RAW[] = R"(
39 {
40 "Nodes": [
41 {
42 "Name": "CPUCluster0MinFreq",
43 "Path": "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq",
44 "Values": [
45 "1512000",
46 "1134000",
47 "384000"
48 ],
49 "DefaultIndex": 2,
50 "ResetOnInit": true
51 },
52 {
53 "Name": "CPUCluster1MinFreq",
54 "Path": "/sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq",
55 "Values": [
56 "1512000",
57 "1134000",
58 "384000"
59 ],
60 "HoldFd": true
61 },
62 {
63 "Name": "ModeProperty",
64 "Path": "vendor.pwhal.mode",
65 "Values": [
66 "HIGH",
67 "LOW",
68 "NONE"
69 ],
70 "Type": "Property"
71 },
72 {
73 "Name": "TestEnableProperty",
74 "Path": "vendor.pwhal.enable.test",
75 "Values": [
76 "0",
77 "1"
78 ],
79 "Type": "Property",
80 "ResetOnInit": true
81 }
82 ],
83 "Actions": [
84 {
85 "PowerHint": "INTERACTION",
86 "Node": "CPUCluster1MinFreq",
87 "Value": "1134000",
88 "Duration": 800
89 },
90 {
91 "PowerHint": "INTERACTION",
92 "Node": "ModeProperty",
93 "Value": "LOW",
94 "Duration": 800
95 },
96 {
97 "PowerHint": "LAUNCH",
98 "Node": "CPUCluster0MinFreq",
99 "Value": "1134000",
100 "EnableProperty": "vendor.pwhal.enable.no_exist",
101 "Duration": 500
102 },
103 {
104 "PowerHint": "LAUNCH",
105 "Node": "ModeProperty",
106 "Value": "HIGH",
107 "Duration": 500
108 },
109 {
110 "PowerHint": "LAUNCH",
111 "Node": "CPUCluster1MinFreq",
112 "Value": "1512000",
113 "EnableProperty": "vendor.pwhal.enable.test",
114 "Duration": 2000
115 },
116 {
117 "PowerHint": "DISABLE_LAUNCH_ACT2",
118 "Node": "TestEnableProperty",
119 "Value": "0",
120 "Duration": 0
121 },
122 {
123 "PowerHint": "MASK_LAUNCH_MODE",
124 "Type": "MaskHint",
125 "Value": "LAUNCH"
126 },
127 {
128 "PowerHint": "MASK_LAUNCH_INTERACTION_MODE",
129 "Type": "MaskHint",
130 "Value": "LAUNCH"
131 },
132 {
133 "PowerHint": "MASK_LAUNCH_INTERACTION_MODE",
134 "Type": "MaskHint",
135 "Value": "INTERACTION"
136 },
137 {
138 "PowerHint": "END_LAUNCH_MODE",
139 "Type": "EndHint",
140 "Value": "LAUNCH"
141 },
142 {
143 "PowerHint": "DO_LAUNCH_MODE",
144 "Type": "DoHint",
145 "Value": "LAUNCH"
146 }
147 ],
148 "AdpfConfig": [
149 {
150 "Name": "REFRESH_120FPS",
151 "PID_On": true,
152 "PID_Po": 5.0,
153 "PID_Pu": 3.0,
154 "PID_I": 0.001,
155 "PID_I_Init": 200,
156 "PID_I_High": 512,
157 "PID_I_Low": -120,
158 "PID_Do": 500.0,
159 "PID_Du": 0.0,
160 "SamplingWindow_P": 1,
161 "SamplingWindow_I": 0,
162 "SamplingWindow_D": 1,
163 "UclampMin_On": true,
164 "UclampMin_Init": 100,
165 "UclampMin_High": 384,
166 "UclampMin_Low": 0,
167 "ReportingRateLimitNs": 166666660,
168 "EarlyBoost_On": false,
169 "EarlyBoost_TimeFactor": 0.8,
170 "TargetTimeFactor": 1.0,
171 "StaleTimeFactor": 10.0
172 },
173 {
174 "Name": "REFRESH_60FPS",
175 "PID_On": false,
176 "PID_Po": 0,
177 "PID_Pu": 0,
178 "PID_I": 0,
179 "PID_I_Init": 0,
180 "PID_I_High": 0,
181 "PID_I_Low": 0,
182 "PID_Do": 0,
183 "PID_Du": 0,
184 "SamplingWindow_P": 0,
185 "SamplingWindow_I": 0,
186 "SamplingWindow_D": 0,
187 "UclampMin_On": true,
188 "UclampMin_Init": 200,
189 "UclampMin_High": 157,
190 "UclampMin_Low": 157,
191 "ReportingRateLimitNs": 83333330,
192 "EarlyBoost_On": true,
193 "EarlyBoost_TimeFactor": 1.2,
194 "TargetTimeFactor": 1.4,
195 "StaleTimeFactor": 5.0
196 }
197 ]
198 }
199 )";
200
201 class HintManagerTest : public ::testing::Test, public HintManager {
202 protected:
HintManagerTest()203 HintManagerTest()
204 : HintManager(nullptr, std::unordered_map<std::string, Hint>{},
205 std::vector<std::shared_ptr<AdpfConfig>>()) {
206 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
207 prop_ = "vendor.pwhal.mode";
208 }
209
SetUp()210 virtual void SetUp() {
211 // Set up 3 dummy nodes
212 std::unique_ptr<TemporaryFile> tf = std::make_unique<TemporaryFile>();
213 nodes_.emplace_back(new FileNode(
214 "n0", tf->path, {{"n0_value0"}, {"n0_value1"}, {"n0_value2"}}, 2,
215 false, false));
216 files_.emplace_back(std::move(tf));
217 tf = std::make_unique<TemporaryFile>();
218 nodes_.emplace_back(new FileNode(
219 "n1", tf->path, {{"n1_value0"}, {"n1_value1"}, {"n1_value2"}}, 2,
220 true, true));
221 files_.emplace_back(std::move(tf));
222 nodes_.emplace_back(new PropertyNode(
223 "n2", prop_, {{"n2_value0"}, {"n2_value1"}, {"n2_value2"}}, 2,
224 true));
225 nm_ = new NodeLooperThread(std::move(nodes_));
226 // Set up dummy actions
227 // "INTERACTION"
228 // Node0, value1, 800ms
229 // Node1, value1, forever
230 // Node2, value1, 800ms
231 // "LAUNCH"
232 // Node0, value0, forever
233 // Node1, value0, 400ms
234 // Node2, value0, 400ms
235 actions_["INTERACTION"].node_actions =
236 std::vector<NodeAction>{{0, 1, 800ms}, {1, 1, 0ms}, {2, 1, 800ms}};
237 actions_["LAUNCH"].node_actions =
238 std::vector<NodeAction>{{0, 0, 0ms}, {1, 0, 400ms}, {2, 0, 400ms}};
239
240 // Prepare dummy files to replace the nodes' path in example json_doc
241 files_.emplace_back(std::make_unique<TemporaryFile>());
242 files_.emplace_back(std::make_unique<TemporaryFile>());
243 // replace file path
244 json_doc_ = kJSON_RAW;
245 std::string from =
246 "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq";
247 size_t start_pos = json_doc_.find(from);
248 json_doc_.replace(start_pos, from.length(), files_[0 + 2]->path);
249 from = "/sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq";
250 start_pos = json_doc_.find(from);
251 json_doc_.replace(start_pos, from.length(), files_[1 + 2]->path);
252 EXPECT_TRUE(android::base::SetProperty(prop_, ""))
253 << "failed to clear property";
254 }
255
TearDown()256 virtual void TearDown() {
257 actions_.clear();
258 nodes_.clear();
259 files_.clear();
260 nm_ = nullptr;
261 }
262 sp<NodeLooperThread> nm_;
263 std::unordered_map<std::string, Hint> actions_;
264 std::vector<std::unique_ptr<Node>> nodes_;
265 std::vector<std::unique_ptr<TemporaryFile>> files_;
266 std::string json_doc_;
267 std::string prop_;
268 };
269
_VerifyPropertyValue(const std::string & path,const std::string & value)270 static inline void _VerifyPropertyValue(const std::string& path,
271 const std::string& value) {
272 std::string s = android::base::GetProperty(path, "");
273 EXPECT_EQ(value, s);
274 }
275
_VerifyPathValue(const std::string & path,const std::string & value)276 static inline void _VerifyPathValue(const std::string& path,
277 const std::string& value) {
278 std::string s;
279 EXPECT_TRUE(android::base::ReadFileToString(path, &s)) << strerror(errno);
280 EXPECT_EQ(value, s);
281 }
282
_VerifyStats(const HintStats & stats,uint32_t count,uint64_t duration_min,uint64_t duration_max)283 static inline void _VerifyStats(const HintStats &stats, uint32_t count, uint64_t duration_min,
284 uint64_t duration_max) {
285 EXPECT_EQ(stats.count, count);
286 EXPECT_GE(stats.duration_ms, duration_min);
287 EXPECT_LT(stats.duration_ms, duration_max);
288 }
289
290 // Test GetHints
TEST_F(HintManagerTest,GetHintsTest)291 TEST_F(HintManagerTest, GetHintsTest) {
292 HintManager hm(nm_, actions_, std::vector<std::shared_ptr<AdpfConfig>>());
293 EXPECT_TRUE(hm.Start());
294 std::vector<std::string> hints = hm.GetHints();
295 EXPECT_TRUE(hm.IsRunning());
296 EXPECT_EQ(2u, hints.size());
297 EXPECT_NE(std::find(hints.begin(), hints.end(), "INTERACTION"), hints.end());
298 EXPECT_NE(std::find(hints.begin(), hints.end(), "LAUNCH"), hints.end());
299 }
300
301 // Test GetHintStats
TEST_F(HintManagerTest,GetHintStatsTest)302 TEST_F(HintManagerTest, GetHintStatsTest) {
303 auto hm = std::make_unique<HintManager>(nm_, actions_,
304 std::vector<std::shared_ptr<AdpfConfig>>());
305 EXPECT_TRUE(InitHintStatus(hm));
306 EXPECT_TRUE(hm->Start());
307 HintStats launch_stats(hm->GetHintStats("LAUNCH"));
308 EXPECT_EQ(0, launch_stats.count);
309 EXPECT_EQ(0, launch_stats.duration_ms);
310 HintStats interaction_stats(hm->GetHintStats("INTERACTION"));
311 EXPECT_EQ(0, interaction_stats.count);
312 EXPECT_EQ(0, interaction_stats.duration_ms);
313 }
314
315 // Test initialization of default values
TEST_F(HintManagerTest,HintInitDefaultTest)316 TEST_F(HintManagerTest, HintInitDefaultTest) {
317 HintManager hm(nm_, actions_, std::vector<std::shared_ptr<AdpfConfig>>());
318 EXPECT_TRUE(hm.Start());
319 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
320 EXPECT_TRUE(hm.IsRunning());
321 _VerifyPathValue(files_[0]->path, "");
322 _VerifyPathValue(files_[1]->path, "n1_value2");
323 _VerifyPropertyValue(prop_, "n2_value2");
324 }
325
326 // Test IsHintSupported
TEST_F(HintManagerTest,HintSupportedTest)327 TEST_F(HintManagerTest, HintSupportedTest) {
328 HintManager hm(nm_, actions_, std::vector<std::shared_ptr<AdpfConfig>>());
329 EXPECT_TRUE(hm.IsHintSupported("INTERACTION"));
330 EXPECT_TRUE(hm.IsHintSupported("LAUNCH"));
331 EXPECT_FALSE(hm.IsHintSupported("NO_SUCH_HINT"));
332 }
333
334 // Test hint/cancel/expire with dummy actions
TEST_F(HintManagerTest,HintTest)335 TEST_F(HintManagerTest, HintTest) {
336 auto hm = std::make_unique<HintManager>(nm_, actions_,
337 std::vector<std::shared_ptr<AdpfConfig>>());
338 EXPECT_TRUE(InitHintStatus(hm));
339 EXPECT_TRUE(hm->Start());
340 EXPECT_TRUE(hm->IsRunning());
341 EXPECT_TRUE(hm->DoHint("INTERACTION"));
342 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
343 _VerifyPathValue(files_[0]->path, "n0_value1");
344 _VerifyPathValue(files_[1]->path, "n1_value1");
345 _VerifyPropertyValue(prop_, "n2_value1");
346 // this won't change the expire time of INTERACTION hint
347 EXPECT_TRUE(hm->DoHint("INTERACTION", 200ms));
348 // now place new hint
349 EXPECT_TRUE(hm->DoHint("LAUNCH"));
350 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
351 _VerifyPathValue(files_[0]->path, "n0_value0");
352 _VerifyPathValue(files_[1]->path, "n1_value0");
353 _VerifyPropertyValue(prop_, "n2_value0");
354 EXPECT_TRUE(hm->DoHint("LAUNCH", 500ms));
355 // "LAUNCH" node1 not expired
356 std::this_thread::sleep_for(400ms);
357 _VerifyPathValue(files_[0]->path, "n0_value0");
358 _VerifyPathValue(files_[1]->path, "n1_value0");
359 _VerifyPropertyValue(prop_, "n2_value0");
360 // "LAUNCH" node1 expired
361 std::this_thread::sleep_for(100ms + kSLEEP_TOLERANCE_MS);
362 _VerifyPathValue(files_[0]->path, "n0_value0");
363 _VerifyPathValue(files_[1]->path, "n1_value1");
364 _VerifyPropertyValue(prop_, "n2_value1");
365 EXPECT_TRUE(hm->EndHint("LAUNCH"));
366 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
367 // "LAUNCH" canceled
368 _VerifyPathValue(files_[0]->path, "n0_value1");
369 _VerifyPathValue(files_[1]->path, "n1_value1");
370 _VerifyPropertyValue(prop_, "n2_value1");
371 std::this_thread::sleep_for(200ms);
372 // "INTERACTION" node0 expired
373 _VerifyPathValue(files_[0]->path, "n0_value2");
374 _VerifyPathValue(files_[1]->path, "n1_value1");
375 _VerifyPropertyValue(prop_, "n2_value2");
376 EXPECT_TRUE(hm->EndHint("INTERACTION"));
377 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
378 // "INTERACTION" canceled
379 _VerifyPathValue(files_[0]->path, "n0_value2");
380 _VerifyPathValue(files_[1]->path, "n1_value2");
381 _VerifyPropertyValue(prop_, "n2_value2");
382 }
383
384 // Test collecting stats with simple actions
TEST_F(HintManagerTest,HintStatsTest)385 TEST_F(HintManagerTest, HintStatsTest) {
386 auto hm = std::make_unique<HintManager>(nm_, actions_,
387 std::vector<std::shared_ptr<AdpfConfig>>());
388 EXPECT_TRUE(InitHintStatus(hm));
389 EXPECT_TRUE(hm->Start());
390 EXPECT_TRUE(hm->IsRunning());
391 EXPECT_TRUE(hm->DoHint("INTERACTION"));
392 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
393 _VerifyPathValue(files_[0]->path, "n0_value1");
394 _VerifyPathValue(files_[1]->path, "n1_value1");
395 _VerifyPropertyValue(prop_, "n2_value1");
396 // now place "LAUNCH" hint with timeout of 500ms
397 EXPECT_TRUE(hm->DoHint("LAUNCH", 500ms));
398 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
399 _VerifyPathValue(files_[0]->path, "n0_value0");
400 _VerifyPathValue(files_[1]->path, "n1_value0");
401 _VerifyPropertyValue(prop_, "n2_value0");
402 // "LAUNCH" expired
403 std::this_thread::sleep_for(500ms + kSLEEP_TOLERANCE_MS);
404 _VerifyPathValue(files_[0]->path, "n0_value1");
405 _VerifyPathValue(files_[1]->path, "n1_value1");
406 _VerifyPropertyValue(prop_, "n2_value1");
407 HintStats launch_stats(hm->GetHintStats("LAUNCH"));
408 // Since duration is recorded at the next DoHint,
409 // duration should be 0.
410 _VerifyStats(launch_stats, 1, 0, 100);
411 std::this_thread::sleep_for(100ms + kSLEEP_TOLERANCE_MS);
412 EXPECT_TRUE(hm->EndHint("INTERACTION"));
413 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
414 // "INTERACTION" canceled
415 _VerifyPathValue(files_[0]->path, "n0_value2");
416 _VerifyPathValue(files_[1]->path, "n1_value2");
417 _VerifyPropertyValue(prop_, "n2_value2");
418 HintStats interaction_stats(hm->GetHintStats("INTERACTION"));
419 _VerifyStats(interaction_stats, 1, 800, 900);
420 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
421 // Second LAUNCH hint sent to get the first duration recorded.
422 EXPECT_TRUE(hm->DoHint("LAUNCH"));
423 launch_stats = hm->GetHintStats("LAUNCH");
424 _VerifyStats(launch_stats, 2, 500, 600);
425 }
426
427 // Test parsing nodes
TEST_F(HintManagerTest,ParseNodesTest)428 TEST_F(HintManagerTest, ParseNodesTest) {
429 std::vector<std::unique_ptr<Node>> nodes =
430 HintManager::ParseNodes(json_doc_);
431 EXPECT_EQ(4u, nodes.size());
432 EXPECT_EQ("CPUCluster0MinFreq", nodes[0]->GetName());
433 EXPECT_EQ("CPUCluster1MinFreq", nodes[1]->GetName());
434 EXPECT_EQ(files_[0 + 2]->path, nodes[0]->GetPath());
435 EXPECT_EQ(files_[1 + 2]->path, nodes[1]->GetPath());
436 EXPECT_EQ("1512000", nodes[0]->GetValues()[0]);
437 EXPECT_EQ("1134000", nodes[0]->GetValues()[1]);
438 EXPECT_EQ("384000", nodes[0]->GetValues()[2]);
439 EXPECT_EQ("1512000", nodes[1]->GetValues()[0]);
440 EXPECT_EQ("1134000", nodes[1]->GetValues()[1]);
441 EXPECT_EQ("384000", nodes[1]->GetValues()[2]);
442 EXPECT_EQ(2u, nodes[0]->GetDefaultIndex());
443 EXPECT_EQ(2u, nodes[1]->GetDefaultIndex());
444 EXPECT_TRUE(nodes[0]->GetResetOnInit());
445 EXPECT_FALSE(nodes[1]->GetResetOnInit());
446 // no dynamic_cast intentionally in Android
447 EXPECT_FALSE(reinterpret_cast<FileNode*>(nodes[0].get())->GetHoldFd());
448 EXPECT_TRUE(reinterpret_cast<FileNode*>(nodes[1].get())->GetHoldFd());
449 EXPECT_EQ("ModeProperty", nodes[2]->GetName());
450 EXPECT_EQ(prop_, nodes[2]->GetPath());
451 EXPECT_EQ("HIGH", nodes[2]->GetValues()[0]);
452 EXPECT_EQ("LOW", nodes[2]->GetValues()[1]);
453 EXPECT_EQ("NONE", nodes[2]->GetValues()[2]);
454 EXPECT_EQ(2u, nodes[2]->GetDefaultIndex());
455 EXPECT_FALSE(nodes[2]->GetResetOnInit());
456 }
457
458 // Test parsing nodes with duplicate name
TEST_F(HintManagerTest,ParseNodesDuplicateNameTest)459 TEST_F(HintManagerTest, ParseNodesDuplicateNameTest) {
460 std::string from = "CPUCluster0MinFreq";
461 size_t start_pos = json_doc_.find(from);
462 json_doc_.replace(start_pos, from.length(), "CPUCluster1MinFreq");
463 std::vector<std::unique_ptr<Node>> nodes =
464 HintManager::ParseNodes(json_doc_);
465 EXPECT_EQ(0u, nodes.size());
466 }
467
TEST_F(HintManagerTest,ParsePropertyNodesDuplicatNameTest)468 TEST_F(HintManagerTest, ParsePropertyNodesDuplicatNameTest) {
469 std::string from = "ModeProperty";
470 size_t start_pos = json_doc_.find(from);
471 json_doc_.replace(start_pos, from.length(), "CPUCluster1MinFreq");
472 std::vector<std::unique_ptr<Node>> nodes =
473 HintManager::ParseNodes(json_doc_);
474 EXPECT_EQ(0u, nodes.size());
475 }
476
477 // Test parsing nodes with duplicate path
TEST_F(HintManagerTest,ParseNodesDuplicatePathTest)478 TEST_F(HintManagerTest, ParseNodesDuplicatePathTest) {
479 std::string from = files_[0 + 2]->path;
480 size_t start_pos = json_doc_.find(from);
481 json_doc_.replace(start_pos, from.length(), files_[1 + 2]->path);
482 std::vector<std::unique_ptr<Node>> nodes =
483 HintManager::ParseNodes(json_doc_);
484 EXPECT_EQ(0u, nodes.size());
485 }
486
487 // Test parsing file node with duplicate value
TEST_F(HintManagerTest,ParseFileNodesDuplicateValueTest)488 TEST_F(HintManagerTest, ParseFileNodesDuplicateValueTest) {
489 std::string from = "1512000";
490 size_t start_pos = json_doc_.find(from);
491 json_doc_.replace(start_pos, from.length(), "1134000");
492 std::vector<std::unique_ptr<Node>> nodes =
493 HintManager::ParseNodes(json_doc_);
494 EXPECT_EQ(0u, nodes.size());
495 }
496
497 // Test parsing property node with duplicate value
TEST_F(HintManagerTest,ParsePropertyNodesDuplicateValueTest)498 TEST_F(HintManagerTest, ParsePropertyNodesDuplicateValueTest) {
499 std::string from = "HIGH";
500 size_t start_pos = json_doc_.find(from);
501 json_doc_.replace(start_pos, from.length(), "LOW");
502 std::vector<std::unique_ptr<Node>> nodes =
503 HintManager::ParseNodes(json_doc_);
504 EXPECT_EQ(0u, nodes.size());
505 }
506
507 // Test parsing file node with empty value
TEST_F(HintManagerTest,ParseFileNodesEmptyValueTest)508 TEST_F(HintManagerTest, ParseFileNodesEmptyValueTest) {
509 std::string from = "384000";
510 size_t start_pos = json_doc_.find(from);
511 json_doc_.replace(start_pos, from.length(), "");
512 std::vector<std::unique_ptr<Node>> nodes =
513 HintManager::ParseNodes(json_doc_);
514 EXPECT_EQ(0u, nodes.size());
515 }
516
517 // Test parsing property node with empty value
TEST_F(HintManagerTest,ParsePropertyNodesEmptyValueTest)518 TEST_F(HintManagerTest, ParsePropertyNodesEmptyValueTest) {
519 std::string from = "LOW";
520 size_t start_pos = json_doc_.find(from);
521 json_doc_.replace(start_pos, from.length(), "");
522 std::vector<std::unique_ptr<Node>> nodes =
523 HintManager::ParseNodes(json_doc_);
524 EXPECT_EQ(4u, nodes.size());
525 EXPECT_EQ("CPUCluster0MinFreq", nodes[0]->GetName());
526 EXPECT_EQ("CPUCluster1MinFreq", nodes[1]->GetName());
527 EXPECT_EQ(files_[0 + 2]->path, nodes[0]->GetPath());
528 EXPECT_EQ(files_[1 + 2]->path, nodes[1]->GetPath());
529 EXPECT_EQ("1512000", nodes[0]->GetValues()[0]);
530 EXPECT_EQ("1134000", nodes[0]->GetValues()[1]);
531 EXPECT_EQ("384000", nodes[0]->GetValues()[2]);
532 EXPECT_EQ("1512000", nodes[1]->GetValues()[0]);
533 EXPECT_EQ("1134000", nodes[1]->GetValues()[1]);
534 EXPECT_EQ("384000", nodes[1]->GetValues()[2]);
535 EXPECT_EQ(2u, nodes[0]->GetDefaultIndex());
536 EXPECT_EQ(2u, nodes[1]->GetDefaultIndex());
537 EXPECT_TRUE(nodes[0]->GetResetOnInit());
538 EXPECT_FALSE(nodes[1]->GetResetOnInit());
539 // no dynamic_cast intentionally in Android
540 EXPECT_FALSE(reinterpret_cast<FileNode*>(nodes[0].get())->GetHoldFd());
541 EXPECT_TRUE(reinterpret_cast<FileNode*>(nodes[1].get())->GetHoldFd());
542 EXPECT_EQ("ModeProperty", nodes[2]->GetName());
543 EXPECT_EQ(prop_, nodes[2]->GetPath());
544 EXPECT_EQ("HIGH", nodes[2]->GetValues()[0]);
545 EXPECT_EQ("", nodes[2]->GetValues()[1]);
546 EXPECT_EQ("NONE", nodes[2]->GetValues()[2]);
547 EXPECT_EQ(2u, nodes[2]->GetDefaultIndex());
548 EXPECT_FALSE(nodes[2]->GetResetOnInit());
549 }
550
551 // Test parsing invalid json for nodes
TEST_F(HintManagerTest,ParseBadFileNodesTest)552 TEST_F(HintManagerTest, ParseBadFileNodesTest) {
553 std::vector<std::unique_ptr<Node>> nodes =
554 HintManager::ParseNodes("invalid json");
555 EXPECT_EQ(0u, nodes.size());
556 nodes = HintManager::ParseNodes(
557 "{\"devices\":{\"15\":[\"armeabi-v7a\"],\"16\":[\"armeabi-v7a\"],"
558 "\"26\":[\"armeabi-v7a\",\"arm64-v8a\",\"x86\",\"x86_64\"]}}");
559 EXPECT_EQ(0u, nodes.size());
560 }
561
562 // Test parsing actions
TEST_F(HintManagerTest,ParseActionsTest)563 TEST_F(HintManagerTest, ParseActionsTest) {
564 std::vector<std::unique_ptr<Node>> nodes =
565 HintManager::ParseNodes(json_doc_);
566 std::unordered_map<std::string, Hint> actions = HintManager::ParseActions(json_doc_, nodes);
567 EXPECT_EQ(7u, actions.size());
568
569 EXPECT_EQ(2u, actions["INTERACTION"].node_actions.size());
570 EXPECT_EQ(1u, actions["INTERACTION"].node_actions[0].node_index);
571 EXPECT_EQ(1u, actions["INTERACTION"].node_actions[0].value_index);
572 EXPECT_EQ(std::chrono::milliseconds(800).count(),
573 actions["INTERACTION"].node_actions[0].timeout_ms.count());
574
575 EXPECT_EQ(2u, actions["INTERACTION"].node_actions[1].node_index);
576 EXPECT_EQ(1u, actions["INTERACTION"].node_actions[1].value_index);
577 EXPECT_EQ(std::chrono::milliseconds(800).count(),
578 actions["INTERACTION"].node_actions[1].timeout_ms.count());
579
580 EXPECT_EQ(3u, actions["LAUNCH"].node_actions.size());
581
582 EXPECT_EQ(0u, actions["LAUNCH"].node_actions[0].node_index);
583 EXPECT_EQ(1u, actions["LAUNCH"].node_actions[0].value_index);
584 EXPECT_EQ(std::chrono::milliseconds(500).count(),
585 actions["LAUNCH"].node_actions[0].timeout_ms.count());
586
587 EXPECT_EQ(2u, actions["LAUNCH"].node_actions[1].node_index);
588 EXPECT_EQ(0u, actions["LAUNCH"].node_actions[1].value_index);
589 EXPECT_EQ(std::chrono::milliseconds(500).count(),
590 actions["LAUNCH"].node_actions[1].timeout_ms.count());
591
592 EXPECT_EQ(1u, actions["LAUNCH"].node_actions[2].node_index);
593 EXPECT_EQ(0u, actions["LAUNCH"].node_actions[2].value_index);
594 EXPECT_EQ(std::chrono::milliseconds(2000).count(),
595 actions["LAUNCH"].node_actions[2].timeout_ms.count());
596 EXPECT_EQ("vendor.pwhal.enable.test", actions["LAUNCH"].node_actions[2].enable_property);
597
598 EXPECT_EQ(1u, actions["MASK_LAUNCH_MODE"].hint_actions.size());
599 EXPECT_EQ(HintActionType::MaskHint, actions["MASK_LAUNCH_MODE"].hint_actions[0].type);
600 EXPECT_EQ("LAUNCH", actions["MASK_LAUNCH_MODE"].hint_actions[0].value);
601
602 EXPECT_EQ(2u, actions["MASK_LAUNCH_INTERACTION_MODE"].hint_actions.size());
603 EXPECT_EQ(HintActionType::MaskHint,
604 actions["MASK_LAUNCH_INTERACTION_MODE"].hint_actions[0].type);
605 EXPECT_EQ("LAUNCH", actions["MASK_LAUNCH_INTERACTION_MODE"].hint_actions[0].value);
606 EXPECT_EQ(HintActionType::MaskHint,
607 actions["MASK_LAUNCH_INTERACTION_MODE"].hint_actions[1].type);
608 EXPECT_EQ("INTERACTION", actions["MASK_LAUNCH_INTERACTION_MODE"].hint_actions[1].value);
609
610 EXPECT_EQ(1u, actions["DO_LAUNCH_MODE"].hint_actions.size());
611 EXPECT_EQ(HintActionType::DoHint, actions["DO_LAUNCH_MODE"].hint_actions[0].type);
612 EXPECT_EQ("LAUNCH", actions["DO_LAUNCH_MODE"].hint_actions[0].value);
613
614 EXPECT_EQ(1u, actions["END_LAUNCH_MODE"].hint_actions.size());
615 EXPECT_EQ(HintActionType::EndHint, actions["END_LAUNCH_MODE"].hint_actions[0].type);
616 EXPECT_EQ("LAUNCH", actions["END_LAUNCH_MODE"].hint_actions[0].value);
617 }
618
619 // Test parsing actions with duplicate File node
TEST_F(HintManagerTest,ParseActionDuplicateFileNodeTest)620 TEST_F(HintManagerTest, ParseActionDuplicateFileNodeTest) {
621 std::string from = R"("Node": "CPUCluster0MinFreq")";
622 size_t start_pos = json_doc_.find(from);
623 json_doc_.replace(start_pos, from.length(), R"("Node": "CPUCluster1MinFreq")");
624 std::vector<std::unique_ptr<Node>> nodes =
625 HintManager::ParseNodes(json_doc_);
626 EXPECT_EQ(4u, nodes.size());
627 auto actions = HintManager::ParseActions(json_doc_, nodes);
628 EXPECT_EQ(0u, actions.size());
629 }
630
631 // Test parsing actions with duplicate Property node
TEST_F(HintManagerTest,ParseActionDuplicatePropertyNodeTest)632 TEST_F(HintManagerTest, ParseActionDuplicatePropertyNodeTest) {
633 std::string from = R"("Node": "CPUCluster0MinFreq")";
634 size_t start_pos = json_doc_.find(from);
635 json_doc_.replace(start_pos, from.length(), R"("Node": "ModeProperty")");
636 auto nodes = HintManager::ParseNodes(json_doc_);
637 EXPECT_EQ(4u, nodes.size());
638 auto actions = HintManager::ParseActions(json_doc_, nodes);
639 EXPECT_EQ(0u, actions.size());
640 }
641
642 // Test parsing invalid json for actions
TEST_F(HintManagerTest,ParseBadActionsTest)643 TEST_F(HintManagerTest, ParseBadActionsTest) {
644 std::vector<std::unique_ptr<Node>> nodes =
645 HintManager::ParseNodes(json_doc_);
646 auto actions = HintManager::ParseActions("invalid json", nodes);
647 EXPECT_EQ(0u, actions.size());
648 actions = HintManager::ParseActions(
649 "{\"devices\":{\"15\":[\"armeabi-v7a\"],\"16\":[\"armeabi-v7a\"],"
650 "\"26\":[\"armeabi-v7a\",\"arm64-v8a\",\"x86\",\"x86_64\"]}}",
651 nodes);
652 EXPECT_EQ(0u, actions.size());
653 }
654
655 // Test hint/cancel/expire with json config
TEST_F(HintManagerTest,GetFromJSONTest)656 TEST_F(HintManagerTest, GetFromJSONTest) {
657 TemporaryFile json_file;
658 ASSERT_TRUE(android::base::WriteStringToFile(json_doc_, json_file.path))
659 << strerror(errno);
660 std::unique_ptr<HintManager> hm =
661 HintManager::GetFromJSON(json_file.path, false);
662 EXPECT_NE(nullptr, hm.get());
663 EXPECT_FALSE(hm->IsRunning());
664 EXPECT_TRUE(hm->Start());
665 EXPECT_TRUE(hm->IsRunning());
666 hm = HintManager::GetFromJSON(json_file.path);
667 EXPECT_NE(nullptr, hm.get());
668 EXPECT_TRUE(hm->IsRunning());
669 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
670 EXPECT_TRUE(hm->IsRunning());
671 // Initial default value on Node0
672 _VerifyPathValue(files_[0 + 2]->path, "384000");
673 _VerifyPathValue(files_[1 + 2]->path, "");
674 _VerifyPropertyValue(prop_, "");
675 // Do INTERACTION
676 EXPECT_TRUE(hm->DoHint("INTERACTION"));
677 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
678 _VerifyPathValue(files_[0 + 2]->path, "384000");
679 _VerifyPathValue(files_[1 + 2]->path, "1134000");
680 _VerifyPropertyValue(prop_, "LOW");
681 // Do LAUNCH
682 _VerifyPropertyValue("vendor.pwhal.enable.test", "1");
683 EXPECT_TRUE(hm->DoHint("LAUNCH"));
684 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
685 _VerifyPathValue(files_[0 + 2]->path, "1134000");
686 _VerifyPathValue(files_[1 + 2]->path, "1512000");
687 _VerifyPropertyValue(prop_, "HIGH");
688 std::this_thread::sleep_for(500ms);
689 // "LAUNCH" node0 expired
690 _VerifyPathValue(files_[0 + 2]->path, "384000");
691 _VerifyPathValue(files_[1 + 2]->path, "1512000");
692 _VerifyPropertyValue(prop_, "LOW");
693 EXPECT_TRUE(hm->EndHint("LAUNCH"));
694 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
695 // "LAUNCH" canceled
696 _VerifyPathValue(files_[0 + 2]->path, "384000");
697 _VerifyPathValue(files_[1 + 2]->path, "1134000");
698 _VerifyPropertyValue(prop_, "LOW");
699 std::this_thread::sleep_for(300ms);
700 // "INTERACTION" node1 expired
701 _VerifyPathValue(files_[0 + 2]->path, "384000");
702 _VerifyPathValue(files_[1 + 2]->path, "384000");
703 _VerifyPropertyValue(prop_, "NONE");
704
705 // Disable action[2] of LAUNCH
706 EXPECT_TRUE(hm->EndHint("LAUNCH"));
707 _VerifyPropertyValue("vendor.pwhal.enable.test", "1");
708 EXPECT_TRUE(hm->DoHint("DISABLE_LAUNCH_ACT2"));
709 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
710 _VerifyPropertyValue("vendor.pwhal.enable.test", "0");
711 EXPECT_TRUE(hm->DoHint("LAUNCH"));
712 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
713 _VerifyPathValue(files_[0 + 2]->path, "1134000");
714 // action[2] have no effect.
715 _VerifyPathValue(files_[1 + 2]->path, "384000");
716 _VerifyPropertyValue(prop_, "HIGH");
717 EXPECT_TRUE(hm->EndHint("LAUNCH"));
718 EXPECT_TRUE(hm->EndHint("DISABLE_LAUNCH_ACT2"));
719
720 // Mask LAUNCH and do LAUNCH
721 EXPECT_TRUE(hm->DoHint("MASK_LAUNCH_MODE"));
722 EXPECT_FALSE(hm->DoHint("LAUNCH")); // should fail
723 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
724 _VerifyPathValue(files_[0 + 2]->path, "384000");
725 _VerifyPathValue(files_[1 + 2]->path, "384000");
726 _VerifyPropertyValue(prop_, "NONE");
727
728 // UnMask LAUNCH and do LAUNCH
729 EXPECT_TRUE(hm->EndHint("MASK_LAUNCH_MODE"));
730 EXPECT_TRUE(hm->DoHint("LAUNCH"));
731 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
732 _VerifyPathValue(files_[0 + 2]->path, "1134000");
733 _VerifyPathValue(files_[1 + 2]->path, "1512000");
734 _VerifyPropertyValue(prop_, "HIGH");
735 // END_LAUNCH_MODE should deactivate LAUNCH
736 EXPECT_TRUE(hm->DoHint("END_LAUNCH_MODE"));
737 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
738 _VerifyPathValue(files_[0 + 2]->path, "384000");
739 _VerifyPathValue(files_[1 + 2]->path, "384000");
740 _VerifyPropertyValue(prop_, "NONE");
741 EXPECT_TRUE(hm->EndHint("END_LAUNCH_MODE"));
742
743 // DO_LAUNCH_MODE should activate LAUNCH
744 EXPECT_TRUE(hm->DoHint("DO_LAUNCH_MODE"));
745 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
746 _VerifyPathValue(files_[0 + 2]->path, "1134000");
747 _VerifyPathValue(files_[1 + 2]->path, "1512000");
748 _VerifyPropertyValue(prop_, "HIGH");
749
750 // Mask LAUNCH
751 EXPECT_TRUE(hm->DoHint("MASK_LAUNCH_MODE"));
752 EXPECT_FALSE(hm->IsHintEnabled("LAUNCH"));
753 // Mask LAUNCH and INTERACTION
754 EXPECT_TRUE(hm->DoHint("MASK_LAUNCH_INTERACTION_MODE"));
755 EXPECT_FALSE(hm->IsHintEnabled("LAUNCH"));
756 EXPECT_FALSE(hm->IsHintEnabled("INTERACTION"));
757 // End Mask LAUNCH and INTERACTION
758 EXPECT_TRUE(hm->EndHint("MASK_LAUNCH_INTERACTION_MODE"));
759 EXPECT_FALSE(hm->IsHintEnabled("LAUNCH"));
760 EXPECT_TRUE(hm->IsHintEnabled("INTERACTION"));
761 // End Mask LAUNCH
762 EXPECT_TRUE(hm->EndHint("MASK_LAUNCH_MODE"));
763 EXPECT_TRUE(hm->IsHintEnabled("LAUNCH"));
764 }
765
766 // Test parsing AdpfConfig
TEST_F(HintManagerTest,ParseAdpfConfigsTest)767 TEST_F(HintManagerTest, ParseAdpfConfigsTest) {
768 std::vector<std::shared_ptr<AdpfConfig>> adpfs = HintManager::ParseAdpfConfigs(json_doc_);
769 EXPECT_EQ(2u, adpfs.size());
770 EXPECT_EQ("REFRESH_120FPS", adpfs[0]->mName);
771 EXPECT_EQ("REFRESH_60FPS", adpfs[1]->mName);
772 EXPECT_TRUE(adpfs[0]->mPidOn);
773 EXPECT_FALSE(adpfs[1]->mPidOn);
774 EXPECT_EQ(5.0, adpfs[0]->mPidPo);
775 EXPECT_EQ(0.0, adpfs[1]->mPidPo);
776 EXPECT_EQ(3.0, adpfs[0]->mPidPu);
777 EXPECT_EQ(0.0, adpfs[1]->mPidPu);
778 EXPECT_EQ(0.001, adpfs[0]->mPidI);
779 EXPECT_EQ(0.0, adpfs[1]->mPidI);
780 EXPECT_EQ(200LL, adpfs[0]->mPidIInit);
781 EXPECT_EQ(0LL, adpfs[1]->mPidIInit);
782 EXPECT_EQ(512LL, adpfs[0]->mPidIHigh);
783 EXPECT_EQ(0LL, adpfs[1]->mPidIHigh);
784 EXPECT_EQ(-120LL, adpfs[0]->mPidILow);
785 EXPECT_EQ(0LL, adpfs[1]->mPidILow);
786 EXPECT_EQ(500.0, adpfs[0]->mPidDo);
787 EXPECT_EQ(0.0, adpfs[1]->mPidDo);
788 EXPECT_EQ(500.0, adpfs[0]->mPidDo);
789 EXPECT_EQ(0.0, adpfs[1]->mPidDo);
790 EXPECT_EQ(1LLU, adpfs[0]->mSamplingWindowP);
791 EXPECT_EQ(0LLU, adpfs[1]->mSamplingWindowP);
792 EXPECT_EQ(0LLU, adpfs[0]->mSamplingWindowI);
793 EXPECT_EQ(0LLU, adpfs[1]->mSamplingWindowI);
794 EXPECT_EQ(1LLU, adpfs[0]->mSamplingWindowD);
795 EXPECT_EQ(0LLU, adpfs[1]->mSamplingWindowD);
796 EXPECT_TRUE(adpfs[0]->mUclampMinOn);
797 EXPECT_TRUE(adpfs[1]->mUclampMinOn);
798 EXPECT_EQ(100U, adpfs[0]->mUclampMinInit);
799 EXPECT_EQ(200U, adpfs[1]->mUclampMinInit);
800 EXPECT_EQ(384U, adpfs[0]->mUclampMinHigh);
801 EXPECT_EQ(157U, adpfs[1]->mUclampMinHigh);
802 EXPECT_EQ(0U, adpfs[0]->mUclampMinLow);
803 EXPECT_EQ(157U, adpfs[1]->mUclampMinLow);
804 EXPECT_EQ(166666660LL, adpfs[0]->mReportingRateLimitNs);
805 EXPECT_EQ(83333330LL, adpfs[1]->mReportingRateLimitNs);
806 EXPECT_EQ(false, adpfs[0]->mEarlyBoostOn);
807 EXPECT_EQ(true, adpfs[1]->mEarlyBoostOn);
808 EXPECT_EQ(0.8, adpfs[0]->mEarlyBoostTimeFactor);
809 EXPECT_EQ(1.2, adpfs[1]->mEarlyBoostTimeFactor);
810 EXPECT_EQ(1.0, adpfs[0]->mTargetTimeFactor);
811 EXPECT_EQ(1.4, adpfs[1]->mTargetTimeFactor);
812 EXPECT_EQ(10.0, adpfs[0]->mStaleTimeFactor);
813 EXPECT_EQ(5.0, adpfs[1]->mStaleTimeFactor);
814 }
815
816 // Test parsing adpf configs with duplicate name
TEST_F(HintManagerTest,ParseAdpfConfigsDuplicateNameTest)817 TEST_F(HintManagerTest, ParseAdpfConfigsDuplicateNameTest) {
818 std::string from = "REFRESH_120FPS";
819 size_t start_pos = json_doc_.find(from);
820 json_doc_.replace(start_pos, from.length(), "REFRESH_60FPS");
821 std::vector<std::shared_ptr<AdpfConfig>> adpfs = HintManager::ParseAdpfConfigs(json_doc_);
822 EXPECT_EQ(0u, adpfs.size());
823 }
824
825 // Test parsing adpf configs without PID_Po
TEST_F(HintManagerTest,ParseAdpfConfigsWithoutPIDPoTest)826 TEST_F(HintManagerTest, ParseAdpfConfigsWithoutPIDPoTest) {
827 std::string from = "\"PID_Po\": 0,";
828 size_t start_pos = json_doc_.find(from);
829 json_doc_.replace(start_pos, from.length(), "");
830 std::vector<std::shared_ptr<AdpfConfig>> adpfs = HintManager::ParseAdpfConfigs(json_doc_);
831 EXPECT_EQ(0u, adpfs.size());
832 }
833
834 // Test hint/cancel/expire with json config
TEST_F(HintManagerTest,GetFromJSONAdpfConfigTest)835 TEST_F(HintManagerTest, GetFromJSONAdpfConfigTest) {
836 TemporaryFile json_file;
837 ASSERT_TRUE(android::base::WriteStringToFile(json_doc_, json_file.path)) << strerror(errno);
838 std::unique_ptr<HintManager> hm = HintManager::GetFromJSON(json_file.path, false);
839 EXPECT_NE(nullptr, hm.get());
840 EXPECT_TRUE(hm->Start());
841 EXPECT_TRUE(hm->IsRunning());
842
843 // Get default Adpf Profile
844 EXPECT_EQ("REFRESH_120FPS", hm->GetAdpfProfile()->mName);
845
846 // Set specific Adpf Profile
847 EXPECT_FALSE(hm->SetAdpfProfile("NoSuchProfile"));
848 EXPECT_TRUE(hm->SetAdpfProfile("REFRESH_60FPS"));
849 EXPECT_EQ("REFRESH_60FPS", hm->GetAdpfProfile()->mName);
850 EXPECT_TRUE(hm->SetAdpfProfile("REFRESH_120FPS"));
851 EXPECT_EQ("REFRESH_120FPS", hm->GetAdpfProfile()->mName);
852 }
853
854 } // namespace perfmgr
855 } // namespace android
856