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/FileNode.h"
27 #include "perfmgr/HintManager.h"
28 #include "perfmgr/PropertyNode.h"
29
30 namespace android {
31 namespace perfmgr {
32
33 using namespace std::chrono_literals;
34
35 constexpr auto kSLEEP_TOLERANCE_MS = 50ms;
36
37 // JSON_CONFIG
38 // {
39 // "Nodes": [
40 // {
41 // "Name": "CPUCluster0MinFreq",
42 // "Path": "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq",
43 // "Values": [
44 // "1512000",
45 // "1134000",
46 // "384000"
47 // ],
48 // "DefaultIndex": 2,
49 // "ResetOnInit": true
50 // },
51 // {
52 // "Name": "CPUCluster1MinFreq",
53 // "Path": "/sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq",
54 // "Values": [
55 // "1512000",
56 // "1134000",
57 // "384000"
58 // ],
59 // "HoldFd": true
60 // },
61 // {
62 // "Name": "ModeProperty",
63 // "Path": "vendor.pwhal.mode",
64 // "Values": [
65 // "HIGH",
66 // "LOW",
67 // "NONE"
68 // ],
69 // "Type": "Property"
70 // }
71 // ],
72 // "Actions": [
73 // {
74 // "PowerHint": "INTERACTION",
75 // "Node": "CPUCluster1MinFreq",
76 // "Value": "1134000",
77 // "Duration": 800
78 // },
79 // {
80 // "PowerHint": "INTERACTION",
81 // "Node": "ModeProperty",
82 // "Value": "LOW",
83 // "Duration": 800
84 // },
85 // {
86 // "PowerHint": "LAUNCH",
87 // "Node": "CPUCluster0MinFreq",
88 // "Value": "1134000",
89 // "Duration": 500
90 // },
91 // {
92 // "PowerHint": "LAUNCH",
93 // "Node": "ModeProperty",
94 // "Value": "HIGH",
95 // "Duration": 500
96 // },
97 // {
98 // "PowerHint": "LAUNCH",
99 // "Node": "CPUCluster1MinFreq",
100 // "Value": "1512000",
101 // "Duration": 2000
102 // }
103 // ]
104 // }
105 constexpr char kJSON_RAW[] =
106 "{\"Nodes\":[{\"Name\":\"CPUCluster0MinFreq\",\"Path\":\"/sys/devices/"
107 "system/cpu/cpu0/cpufreq/"
108 "scaling_min_freq\",\"Values\":[\"1512000\",\"1134000\",\"384000\"],"
109 "\"DefaultIndex\":2,\"ResetOnInit\":true},{\"Name\":\"CPUCluster1MinFreq\","
110 "\"Path\":\"/sys/devices/system/cpu/cpu4/cpufreq/"
111 "scaling_min_freq\",\"Values\":[\"1512000\",\"1134000\",\"384000\"],"
112 "\"HoldFd\":true},{\"Name\":\"ModeProperty\",\"Path\":\"vendor.pwhal."
113 "mode\",\"Values\":[\"HIGH\",\"LOW\",\"NONE\"],\"Type\":\"Property\"}],"
114 "\"Actions\":[{\"PowerHint\":\"INTERACTION\",\"Node\":"
115 "\"CPUCluster1MinFreq\",\"Value\":\"1134000\",\"Duration\":800},{"
116 "\"PowerHint\":\"INTERACTION\",\"Node\":\"ModeProperty\",\"Value\":\"LOW\","
117 "\"Duration\":800},{\"PowerHint\":\"LAUNCH\",\"Node\":"
118 "\"CPUCluster0MinFreq\",\"Value\":\"1134000\",\"Duration\":500},{"
119 "\"PowerHint\":\"LAUNCH\",\"Node\":\"ModeProperty\",\"Value\":\"HIGH\","
120 "\"Duration\":500},{\"PowerHint\":\"LAUNCH\",\"Node\":"
121 "\"CPUCluster1MinFreq\",\"Value\":\"1512000\",\"Duration\":2000}]}";
122
123 class HintManagerTest : public ::testing::Test, public HintManager {
124 protected:
HintManagerTest()125 HintManagerTest()
126 : HintManager(nullptr,
127 std::map<std::string, std::vector<NodeAction>>{}) {
128 android::base::SetMinimumLogSeverity(android::base::VERBOSE);
129 prop_ = "vendor.pwhal.mode";
130 }
131
SetUp()132 virtual void SetUp() {
133 // Set up 3 dummy nodes
134 std::unique_ptr<TemporaryFile> tf = std::make_unique<TemporaryFile>();
135 nodes_.emplace_back(new FileNode(
136 "n0", tf->path, {{"n0_value0"}, {"n0_value1"}, {"n0_value2"}}, 2,
137 false));
138 files_.emplace_back(std::move(tf));
139 tf = std::make_unique<TemporaryFile>();
140 nodes_.emplace_back(new FileNode(
141 "n1", tf->path, {{"n1_value0"}, {"n1_value1"}, {"n1_value2"}}, 2,
142 true));
143 files_.emplace_back(std::move(tf));
144 nodes_.emplace_back(new PropertyNode(
145 "n2", prop_, {{"n2_value0"}, {"n2_value1"}, {"n2_value2"}}, 2,
146 true));
147 nm_ = new NodeLooperThread(std::move(nodes_));
148 // Set up dummy actions
149 // "INTERACTION"
150 // Node0, value1, 800ms
151 // Node1, value1, forever
152 // Node2, value1, 800ms
153 // "LAUNCH"
154 // Node0, value0, forever
155 // Node1, value0, 400ms
156 // Node2, value0, 400ms
157 actions_ = std::map<std::string, std::vector<NodeAction>>{
158 {"INTERACTION", {{0, 1, 800ms}, {1, 1, 0ms}, {2, 1, 800ms}}},
159 {"LAUNCH", {{0, 0, 0ms}, {1, 0, 400ms}, {2, 0, 400ms}}}};
160
161 // Prepare dummy files to replace the nodes' path in example json_doc
162 files_.emplace_back(std::make_unique<TemporaryFile>());
163 files_.emplace_back(std::make_unique<TemporaryFile>());
164 // replace file path
165 json_doc_ = kJSON_RAW;
166 std::string from =
167 "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq";
168 size_t start_pos = json_doc_.find(from);
169 json_doc_.replace(start_pos, from.length(), files_[0 + 2]->path);
170 from = "/sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq";
171 start_pos = json_doc_.find(from);
172 json_doc_.replace(start_pos, from.length(), files_[1 + 2]->path);
173 EXPECT_TRUE(android::base::SetProperty(prop_, ""))
174 << "failed to clear property";
175 }
176
TearDown()177 virtual void TearDown() {
178 actions_.clear();
179 nodes_.clear();
180 files_.clear();
181 nm_ = nullptr;
182 }
183 sp<NodeLooperThread> nm_;
184 std::map<std::string, std::vector<NodeAction>> actions_;
185 std::vector<std::unique_ptr<Node>> nodes_;
186 std::vector<std::unique_ptr<TemporaryFile>> files_;
187 std::string json_doc_;
188 std::string prop_;
189 };
190
_VerifyPropertyValue(const std::string & path,const std::string & value)191 static inline void _VerifyPropertyValue(const std::string& path,
192 const std::string& value) {
193 std::string s = android::base::GetProperty(path, "");
194 EXPECT_EQ(value, s);
195 }
196
_VerifyPathValue(const std::string & path,const std::string & value)197 static inline void _VerifyPathValue(const std::string& path,
198 const std::string& value) {
199 std::string s;
200 EXPECT_TRUE(android::base::ReadFileToString(path, &s)) << strerror(errno);
201 EXPECT_EQ(value, s);
202 }
203
204 // Test GetHints
TEST_F(HintManagerTest,GetHintsTest)205 TEST_F(HintManagerTest, GetHintsTest) {
206 HintManager hm(nm_, actions_);
207 EXPECT_TRUE(hm.Start());
208 std::vector<std::string> hints = hm.GetHints();
209 EXPECT_TRUE(hm.IsRunning());
210 EXPECT_EQ(2u, hints.size());
211 EXPECT_NE(std::find(hints.begin(), hints.end(), "INTERACTION"), hints.end());
212 EXPECT_NE(std::find(hints.begin(), hints.end(), "LAUNCH"), hints.end());
213 }
214
215 // Test initialization of default values
TEST_F(HintManagerTest,HintInitDefaultTest)216 TEST_F(HintManagerTest, HintInitDefaultTest) {
217 HintManager hm(nm_, actions_);
218 EXPECT_TRUE(hm.Start());
219 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
220 EXPECT_TRUE(hm.IsRunning());
221 _VerifyPathValue(files_[0]->path, "");
222 _VerifyPathValue(files_[1]->path, "n1_value2");
223 _VerifyPropertyValue(prop_, "n2_value2");
224 }
225
226 // Test IsHintSupported
TEST_F(HintManagerTest,HintSupportedTest)227 TEST_F(HintManagerTest, HintSupportedTest) {
228 HintManager hm(nm_, actions_);
229 EXPECT_TRUE(hm.IsHintSupported("INTERACTION"));
230 EXPECT_TRUE(hm.IsHintSupported("LAUNCH"));
231 EXPECT_FALSE(hm.IsHintSupported("NO_SUCH_HINT"));
232 }
233
234 // Test DumpToFd
TEST_F(HintManagerTest,DumpToFdTest)235 TEST_F(HintManagerTest, DumpToFdTest) {
236 HintManager hm(nm_, actions_);
237 TemporaryFile dumptf;
238 hm.DumpToFd(dumptf.fd);
239 fsync(dumptf.fd);
240 std::ostringstream dump_buf;
241 dump_buf << "========== Begin perfmgr nodes ==========\nNode Name\tNode "
242 "Path\tCurrent Index\tCurrent Value\nn0\t"
243 << files_[0]->path << "\t2\t\nn1\t" << files_[1]->path
244 << "\t2\t\nn2\tvendor.pwhal.mode\t2\t\n========== End perfmgr "
245 "nodes ==========\n";
246 _VerifyPathValue(dumptf.path, dump_buf.str());
247 TemporaryFile dumptf_started;
248 EXPECT_TRUE(hm.Start());
249 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
250 EXPECT_TRUE(hm.IsRunning());
251 hm.DumpToFd(dumptf_started.fd);
252 fsync(dumptf_started.fd);
253 dump_buf.str("");
254 dump_buf.clear();
255 dump_buf << "========== Begin perfmgr nodes ==========\nNode Name\tNode "
256 "Path\tCurrent Index\tCurrent Value\nn0\t"
257 << files_[0]->path << "\t2\t\nn1\t" << files_[1]->path
258 << "\t2\tn1_value2\nn2\tvendor.pwhal.mode\t2\tn2_value2\n========="
259 "= End perfmgr nodes ==========\n";
260 _VerifyPathValue(dumptf_started.path, dump_buf.str());
261 }
262
263 // Test hint/cancel/expire with dummy actions
TEST_F(HintManagerTest,HintTest)264 TEST_F(HintManagerTest, HintTest) {
265 HintManager hm(nm_, actions_);
266 EXPECT_TRUE(hm.Start());
267 EXPECT_TRUE(hm.IsRunning());
268 EXPECT_TRUE(hm.DoHint("INTERACTION"));
269 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
270 _VerifyPathValue(files_[0]->path, "n0_value1");
271 _VerifyPathValue(files_[1]->path, "n1_value1");
272 _VerifyPropertyValue(prop_, "n2_value1");
273 // this won't change the expire time of INTERACTION hint
274 EXPECT_TRUE(hm.DoHint("INTERACTION", 200ms));
275 // now place new hint
276 EXPECT_TRUE(hm.DoHint("LAUNCH"));
277 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
278 _VerifyPathValue(files_[0]->path, "n0_value0");
279 _VerifyPathValue(files_[1]->path, "n1_value0");
280 _VerifyPropertyValue(prop_, "n2_value0");
281 EXPECT_TRUE(hm.DoHint("LAUNCH", 500ms));
282 // "LAUNCH" node1 not expired
283 std::this_thread::sleep_for(400ms);
284 _VerifyPathValue(files_[0]->path, "n0_value0");
285 _VerifyPathValue(files_[1]->path, "n1_value0");
286 _VerifyPropertyValue(prop_, "n2_value0");
287 // "LAUNCH" node1 expired
288 std::this_thread::sleep_for(100ms + kSLEEP_TOLERANCE_MS);
289 _VerifyPathValue(files_[0]->path, "n0_value0");
290 _VerifyPathValue(files_[1]->path, "n1_value1");
291 _VerifyPropertyValue(prop_, "n2_value1");
292 EXPECT_TRUE(hm.EndHint("LAUNCH"));
293 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
294 // "LAUNCH" canceled
295 _VerifyPathValue(files_[0]->path, "n0_value1");
296 _VerifyPathValue(files_[1]->path, "n1_value1");
297 _VerifyPropertyValue(prop_, "n2_value1");
298 std::this_thread::sleep_for(200ms);
299 // "INTERACTION" node0 expired
300 _VerifyPathValue(files_[0]->path, "n0_value2");
301 _VerifyPathValue(files_[1]->path, "n1_value1");
302 _VerifyPropertyValue(prop_, "n2_value2");
303 EXPECT_TRUE(hm.EndHint("INTERACTION"));
304 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
305 // "INTERACTION" canceled
306 _VerifyPathValue(files_[0]->path, "n0_value2");
307 _VerifyPathValue(files_[1]->path, "n1_value2");
308 _VerifyPropertyValue(prop_, "n2_value2");
309 }
310
311 // Test parsing nodes
TEST_F(HintManagerTest,ParseNodesTest)312 TEST_F(HintManagerTest, ParseNodesTest) {
313 std::vector<std::unique_ptr<Node>> nodes =
314 HintManager::ParseNodes(json_doc_);
315 EXPECT_EQ(3u, nodes.size());
316 EXPECT_EQ("CPUCluster0MinFreq", nodes[0]->GetName());
317 EXPECT_EQ("CPUCluster1MinFreq", nodes[1]->GetName());
318 EXPECT_EQ(files_[0 + 2]->path, nodes[0]->GetPath());
319 EXPECT_EQ(files_[1 + 2]->path, nodes[1]->GetPath());
320 EXPECT_EQ("1512000", nodes[0]->GetValues()[0]);
321 EXPECT_EQ("1134000", nodes[0]->GetValues()[1]);
322 EXPECT_EQ("384000", nodes[0]->GetValues()[2]);
323 EXPECT_EQ("1512000", nodes[1]->GetValues()[0]);
324 EXPECT_EQ("1134000", nodes[1]->GetValues()[1]);
325 EXPECT_EQ("384000", nodes[1]->GetValues()[2]);
326 EXPECT_EQ(2u, nodes[0]->GetDefaultIndex());
327 EXPECT_EQ(2u, nodes[1]->GetDefaultIndex());
328 EXPECT_TRUE(nodes[0]->GetResetOnInit());
329 EXPECT_FALSE(nodes[1]->GetResetOnInit());
330 // no dynamic_cast intentionally in Android
331 EXPECT_FALSE(reinterpret_cast<FileNode*>(nodes[0].get())->GetHoldFd());
332 EXPECT_TRUE(reinterpret_cast<FileNode*>(nodes[1].get())->GetHoldFd());
333 EXPECT_EQ("ModeProperty", nodes[2]->GetName());
334 EXPECT_EQ(prop_, nodes[2]->GetPath());
335 EXPECT_EQ("HIGH", nodes[2]->GetValues()[0]);
336 EXPECT_EQ("LOW", nodes[2]->GetValues()[1]);
337 EXPECT_EQ("NONE", nodes[2]->GetValues()[2]);
338 EXPECT_EQ(2u, nodes[2]->GetDefaultIndex());
339 EXPECT_FALSE(nodes[2]->GetResetOnInit());
340 }
341
342 // Test parsing nodes with duplicate name
TEST_F(HintManagerTest,ParseNodesDuplicateNameTest)343 TEST_F(HintManagerTest, ParseNodesDuplicateNameTest) {
344 std::string from = "CPUCluster0MinFreq";
345 size_t start_pos = json_doc_.find(from);
346 json_doc_.replace(start_pos, from.length(), "CPUCluster1MinFreq");
347 std::vector<std::unique_ptr<Node>> nodes =
348 HintManager::ParseNodes(json_doc_);
349 EXPECT_EQ(0u, nodes.size());
350 }
351
TEST_F(HintManagerTest,ParsePropertyNodesDuplicatNameTest)352 TEST_F(HintManagerTest, ParsePropertyNodesDuplicatNameTest) {
353 std::string from = "ModeProperty";
354 size_t start_pos = json_doc_.find(from);
355 json_doc_.replace(start_pos, from.length(), "CPUCluster1MinFreq");
356 std::vector<std::unique_ptr<Node>> nodes =
357 HintManager::ParseNodes(json_doc_);
358 EXPECT_EQ(0u, nodes.size());
359 }
360
361 // Test parsing nodes with duplicate path
TEST_F(HintManagerTest,ParseNodesDuplicatePathTest)362 TEST_F(HintManagerTest, ParseNodesDuplicatePathTest) {
363 std::string from = files_[0 + 2]->path;
364 size_t start_pos = json_doc_.find(from);
365 json_doc_.replace(start_pos, from.length(), files_[1 + 2]->path);
366 std::vector<std::unique_ptr<Node>> nodes =
367 HintManager::ParseNodes(json_doc_);
368 EXPECT_EQ(0u, nodes.size());
369 }
370
371 // Test parsing file node with duplicate value
TEST_F(HintManagerTest,ParseFileNodesDuplicateValueTest)372 TEST_F(HintManagerTest, ParseFileNodesDuplicateValueTest) {
373 std::string from = "1512000";
374 size_t start_pos = json_doc_.find(from);
375 json_doc_.replace(start_pos, from.length(), "1134000");
376 std::vector<std::unique_ptr<Node>> nodes =
377 HintManager::ParseNodes(json_doc_);
378 EXPECT_EQ(0u, nodes.size());
379 }
380
381 // Test parsing property node with duplicate value
TEST_F(HintManagerTest,ParsePropertyNodesDuplicateValueTest)382 TEST_F(HintManagerTest, ParsePropertyNodesDuplicateValueTest) {
383 std::string from = "HIGH";
384 size_t start_pos = json_doc_.find(from);
385 json_doc_.replace(start_pos, from.length(), "LOW");
386 std::vector<std::unique_ptr<Node>> nodes =
387 HintManager::ParseNodes(json_doc_);
388 EXPECT_EQ(0u, nodes.size());
389 }
390
391 // Test parsing file node with empty value
TEST_F(HintManagerTest,ParseFileNodesEmptyValueTest)392 TEST_F(HintManagerTest, ParseFileNodesEmptyValueTest) {
393 std::string from = "384000";
394 size_t start_pos = json_doc_.find(from);
395 json_doc_.replace(start_pos, from.length(), "");
396 std::vector<std::unique_ptr<Node>> nodes =
397 HintManager::ParseNodes(json_doc_);
398 EXPECT_EQ(0u, nodes.size());
399 }
400
401 // Test parsing property node with empty value
TEST_F(HintManagerTest,ParsePropertyNodesEmptyValueTest)402 TEST_F(HintManagerTest, ParsePropertyNodesEmptyValueTest) {
403 std::string from = "LOW";
404 size_t start_pos = json_doc_.find(from);
405 json_doc_.replace(start_pos, from.length(), "");
406 std::vector<std::unique_ptr<Node>> nodes =
407 HintManager::ParseNodes(json_doc_);
408 EXPECT_EQ(3u, nodes.size());
409 EXPECT_EQ("CPUCluster0MinFreq", nodes[0]->GetName());
410 EXPECT_EQ("CPUCluster1MinFreq", nodes[1]->GetName());
411 EXPECT_EQ(files_[0 + 2]->path, nodes[0]->GetPath());
412 EXPECT_EQ(files_[1 + 2]->path, nodes[1]->GetPath());
413 EXPECT_EQ("1512000", nodes[0]->GetValues()[0]);
414 EXPECT_EQ("1134000", nodes[0]->GetValues()[1]);
415 EXPECT_EQ("384000", nodes[0]->GetValues()[2]);
416 EXPECT_EQ("1512000", nodes[1]->GetValues()[0]);
417 EXPECT_EQ("1134000", nodes[1]->GetValues()[1]);
418 EXPECT_EQ("384000", nodes[1]->GetValues()[2]);
419 EXPECT_EQ(2u, nodes[0]->GetDefaultIndex());
420 EXPECT_EQ(2u, nodes[1]->GetDefaultIndex());
421 EXPECT_TRUE(nodes[0]->GetResetOnInit());
422 EXPECT_FALSE(nodes[1]->GetResetOnInit());
423 // no dynamic_cast intentionally in Android
424 EXPECT_FALSE(reinterpret_cast<FileNode*>(nodes[0].get())->GetHoldFd());
425 EXPECT_TRUE(reinterpret_cast<FileNode*>(nodes[1].get())->GetHoldFd());
426 EXPECT_EQ("ModeProperty", nodes[2]->GetName());
427 EXPECT_EQ(prop_, nodes[2]->GetPath());
428 EXPECT_EQ("HIGH", nodes[2]->GetValues()[0]);
429 EXPECT_EQ("", nodes[2]->GetValues()[1]);
430 EXPECT_EQ("NONE", nodes[2]->GetValues()[2]);
431 EXPECT_EQ(2u, nodes[2]->GetDefaultIndex());
432 EXPECT_FALSE(nodes[2]->GetResetOnInit());
433 }
434
435 // Test parsing invalid json for nodes
TEST_F(HintManagerTest,ParseBadFileNodesTest)436 TEST_F(HintManagerTest, ParseBadFileNodesTest) {
437 std::vector<std::unique_ptr<Node>> nodes =
438 HintManager::ParseNodes("invalid json");
439 EXPECT_EQ(0u, nodes.size());
440 nodes = HintManager::ParseNodes(
441 "{\"devices\":{\"15\":[\"armeabi-v7a\"],\"16\":[\"armeabi-v7a\"],"
442 "\"26\":[\"armeabi-v7a\",\"arm64-v8a\",\"x86\",\"x86_64\"]}}");
443 EXPECT_EQ(0u, nodes.size());
444 }
445
446 // Test parsing actions
TEST_F(HintManagerTest,ParseActionsTest)447 TEST_F(HintManagerTest, ParseActionsTest) {
448 std::vector<std::unique_ptr<Node>> nodes =
449 HintManager::ParseNodes(json_doc_);
450 std::map<std::string, std::vector<NodeAction>> actions =
451 HintManager::ParseActions(json_doc_, nodes);
452 EXPECT_EQ(2u, actions.size());
453
454 EXPECT_EQ(2u, actions["INTERACTION"].size());
455 EXPECT_EQ(1u, actions["INTERACTION"][0].node_index);
456 EXPECT_EQ(1u, actions["INTERACTION"][0].value_index);
457 EXPECT_EQ(std::chrono::milliseconds(800).count(),
458 actions["INTERACTION"][0].timeout_ms.count());
459
460 EXPECT_EQ(2u, actions["INTERACTION"][1].node_index);
461 EXPECT_EQ(1u, actions["INTERACTION"][1].value_index);
462 EXPECT_EQ(std::chrono::milliseconds(800).count(),
463 actions["INTERACTION"][1].timeout_ms.count());
464
465 EXPECT_EQ(3u, actions["LAUNCH"].size());
466
467 EXPECT_EQ(0u, actions["LAUNCH"][0].node_index);
468 EXPECT_EQ(1u, actions["LAUNCH"][0].value_index);
469 EXPECT_EQ(std::chrono::milliseconds(500).count(),
470 actions["LAUNCH"][0].timeout_ms.count());
471
472 EXPECT_EQ(2u, actions["LAUNCH"][1].node_index);
473 EXPECT_EQ(0u, actions["LAUNCH"][1].value_index);
474 EXPECT_EQ(std::chrono::milliseconds(500).count(),
475 actions["LAUNCH"][1].timeout_ms.count());
476
477 EXPECT_EQ(1u, actions["LAUNCH"][2].node_index);
478 EXPECT_EQ(0u, actions["LAUNCH"][2].value_index);
479 EXPECT_EQ(std::chrono::milliseconds(2000).count(),
480 actions["LAUNCH"][2].timeout_ms.count());
481 }
482
483 // Test parsing actions with duplicate File node
TEST_F(HintManagerTest,ParseActionDuplicateFileNodeTest)484 TEST_F(HintManagerTest, ParseActionDuplicateFileNodeTest) {
485 std::string from = "\"Node\":\"CPUCluster0MinFreq\"";
486 size_t start_pos = json_doc_.find(from);
487 json_doc_.replace(start_pos, from.length(),
488 "\"Node\":\"CPUCluster1MinFreq\"");
489 std::vector<std::unique_ptr<Node>> nodes =
490 HintManager::ParseNodes(json_doc_);
491 EXPECT_EQ(3u, nodes.size());
492 std::map<std::string, std::vector<NodeAction>> actions =
493 HintManager::ParseActions(json_doc_, nodes);
494 EXPECT_EQ(0u, actions.size());
495 }
496
497 // Test parsing actions with duplicate Property node
TEST_F(HintManagerTest,ParseActionDuplicatePropertyNodeTest)498 TEST_F(HintManagerTest, ParseActionDuplicatePropertyNodeTest) {
499 std::string from = "\"Node\":\"CPUCluster0MinFreq\"";
500 size_t start_pos = json_doc_.find(from);
501 json_doc_.replace(start_pos, from.length(), "\"Node\":\"ModeProperty\"");
502 std::vector<std::unique_ptr<Node>> nodes =
503 HintManager::ParseNodes(json_doc_);
504 EXPECT_EQ(3u, nodes.size());
505 std::map<std::string, std::vector<NodeAction>> actions =
506 HintManager::ParseActions(json_doc_, nodes);
507 EXPECT_EQ(0u, actions.size());
508 }
509
510 // Test parsing invalid json for actions
TEST_F(HintManagerTest,ParseBadActionsTest)511 TEST_F(HintManagerTest, ParseBadActionsTest) {
512 std::vector<std::unique_ptr<Node>> nodes =
513 HintManager::ParseNodes(json_doc_);
514 std::map<std::string, std::vector<NodeAction>> actions =
515 HintManager::ParseActions("invalid json", nodes);
516 EXPECT_EQ(0u, actions.size());
517 actions = HintManager::ParseActions(
518 "{\"devices\":{\"15\":[\"armeabi-v7a\"],\"16\":[\"armeabi-v7a\"],"
519 "\"26\":[\"armeabi-v7a\",\"arm64-v8a\",\"x86\",\"x86_64\"]}}",
520 nodes);
521 EXPECT_EQ(0u, actions.size());
522 }
523
524 // Test hint/cancel/expire with json config
TEST_F(HintManagerTest,GetFromJSONTest)525 TEST_F(HintManagerTest, GetFromJSONTest) {
526 TemporaryFile json_file;
527 ASSERT_TRUE(android::base::WriteStringToFile(json_doc_, json_file.path))
528 << strerror(errno);
529 std::unique_ptr<HintManager> hm =
530 HintManager::GetFromJSON(json_file.path, false);
531 EXPECT_NE(nullptr, hm.get());
532 EXPECT_FALSE(hm->IsRunning());
533 EXPECT_TRUE(hm->Start());
534 EXPECT_TRUE(hm->IsRunning());
535 hm = HintManager::GetFromJSON(json_file.path);
536 EXPECT_NE(nullptr, hm.get());
537 EXPECT_TRUE(hm->IsRunning());
538 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
539 EXPECT_TRUE(hm->IsRunning());
540 // Initial default value on Node0
541 _VerifyPathValue(files_[0 + 2]->path, "384000");
542 _VerifyPathValue(files_[1 + 2]->path, "");
543 _VerifyPropertyValue(prop_, "");
544 // Do INTERACTION
545 EXPECT_TRUE(hm->DoHint("INTERACTION"));
546 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
547 _VerifyPathValue(files_[0 + 2]->path, "384000");
548 _VerifyPathValue(files_[1 + 2]->path, "1134000");
549 _VerifyPropertyValue(prop_, "LOW");
550 // Do LAUNCH
551 EXPECT_TRUE(hm->DoHint("LAUNCH"));
552 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
553 _VerifyPathValue(files_[0 + 2]->path, "1134000");
554 _VerifyPathValue(files_[1 + 2]->path, "1512000");
555 _VerifyPropertyValue(prop_, "HIGH");
556 std::this_thread::sleep_for(500ms);
557 // "LAUNCH" node0 expired
558 _VerifyPathValue(files_[0 + 2]->path, "384000");
559 _VerifyPathValue(files_[1 + 2]->path, "1512000");
560 _VerifyPropertyValue(prop_, "LOW");
561 EXPECT_TRUE(hm->EndHint("LAUNCH"));
562 std::this_thread::sleep_for(kSLEEP_TOLERANCE_MS);
563 // "LAUNCH" canceled
564 _VerifyPathValue(files_[0 + 2]->path, "384000");
565 _VerifyPathValue(files_[1 + 2]->path, "1134000");
566 _VerifyPropertyValue(prop_, "LOW");
567 std::this_thread::sleep_for(300ms);
568 // "INTERACTION" node1 expired
569 _VerifyPathValue(files_[0 + 2]->path, "384000");
570 _VerifyPathValue(files_[1 + 2]->path, "384000");
571 _VerifyPropertyValue(prop_, "NONE");
572 }
573
574 } // namespace perfmgr
575 } // namespace android
576