blob: 9ab35d741a52c9adf6d1ea7e4009e3c7e418a426 [file] [log] [blame]
Xiang Wange12b4fa2022-03-25 23:48:40 +00001/*
2 * Copyright 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#undef LOG_TAG
18#define LOG_TAG "AidlPowerHalWrapperTest"
19
Xiang Wang0aba49e2022-04-06 16:13:59 +000020#include <android-base/stringprintf.h>
Xiang Wange12b4fa2022-03-25 23:48:40 +000021#include <android/hardware/power/IPower.h>
22#include <android/hardware/power/IPowerHintSession.h>
23#include <gmock/gmock.h>
24#include <gtest/gtest.h>
25#include <algorithm>
26#include <chrono>
27#include <memory>
28#include "DisplayHardware/PowerAdvisor.h"
29#include "android/hardware/power/WorkDuration.h"
30#include "binder/Status.h"
31#include "log/log_main.h"
32#include "mock/DisplayHardware/MockIPower.h"
33#include "mock/DisplayHardware/MockIPowerHintSession.h"
34#include "utils/Timers.h"
35
36using namespace android;
37using namespace android::Hwc2::mock;
38using namespace android::hardware::power;
39using namespace std::chrono_literals;
40using namespace testing;
41
42namespace android::Hwc2::impl {
43
44class AidlPowerHalWrapperTest : public testing::Test {
45public:
46 void SetUp() override;
47
48protected:
49 std::unique_ptr<AidlPowerHalWrapper> mWrapper = nullptr;
50 sp<NiceMock<MockIPower>> mMockHal = nullptr;
51 sp<NiceMock<MockIPowerHintSession>> mMockSession = nullptr;
52 void verifyAndClearExpectations();
53 void sendActualWorkDurationGroup(std::vector<WorkDuration> durations,
54 std::chrono::nanoseconds sleepBeforeLastSend);
55};
56
57void AidlPowerHalWrapperTest::SetUp() {
58 mMockHal = new NiceMock<MockIPower>();
59 mMockSession = new NiceMock<MockIPowerHintSession>();
60 ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok()));
61 mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal);
62}
63
64void AidlPowerHalWrapperTest::verifyAndClearExpectations() {
65 Mock::VerifyAndClearExpectations(mMockHal.get());
66 Mock::VerifyAndClearExpectations(mMockSession.get());
67}
68
69void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(
70 std::vector<WorkDuration> durations, std::chrono::nanoseconds sleepBeforeLastSend) {
71 for (size_t i = 0; i < durations.size(); i++) {
72 if (i == durations.size() - 1) {
73 std::this_thread::sleep_for(sleepBeforeLastSend);
74 }
75 auto duration = durations[i];
76 mWrapper->sendActualWorkDuration(duration.durationNanos, duration.timeStampNanos);
77 }
78}
79WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) {
80 WorkDuration duration;
81 duration.durationNanos = durationNanos.count();
82 duration.timeStampNanos = timeStampNanos;
83 return duration;
84}
85
Xiang Wang0aba49e2022-04-06 16:13:59 +000086std::string printWorkDurations(const ::std::vector<WorkDuration>& durations) {
87 std::ostringstream os;
88 for (auto duration : durations) {
89 os << duration.toString();
90 os << "\n";
91 }
92 return os.str();
93}
94
Xiang Wange12b4fa2022-03-25 23:48:40 +000095namespace {
96TEST_F(AidlPowerHalWrapperTest, supportsPowerHintSession) {
97 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
98 Mock::VerifyAndClearExpectations(mMockHal.get());
99 ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_))
100 .WillByDefault(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
101 auto newWrapper = AidlPowerHalWrapper(mMockHal);
102 EXPECT_FALSE(newWrapper.supportsPowerHintSession());
103}
104
105TEST_F(AidlPowerHalWrapperTest, startPowerHintSession) {
106 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
107 std::vector<int32_t> threadIds = {1, 2};
108 mWrapper->setPowerHintSessionThreadIds(threadIds);
109 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
110 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
111 EXPECT_TRUE(mWrapper->startPowerHintSession());
112 EXPECT_FALSE(mWrapper->startPowerHintSession());
113}
114
115TEST_F(AidlPowerHalWrapperTest, restartNewPoserHintSessionWithNewThreadIds) {
116 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
117
118 std::vector<int32_t> threadIds = {1, 2};
119 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
120 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
121 mWrapper->setPowerHintSessionThreadIds(threadIds);
122 EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds);
123 ASSERT_TRUE(mWrapper->startPowerHintSession());
124 verifyAndClearExpectations();
125
126 threadIds = {2, 3};
127 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
128 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
129 EXPECT_CALL(*mMockSession.get(), close()).Times(1);
130 mWrapper->setPowerHintSessionThreadIds(threadIds);
131 EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds);
132 verifyAndClearExpectations();
133
134 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)).Times(0);
135 EXPECT_CALL(*mMockSession.get(), close()).Times(0);
136 mWrapper->setPowerHintSessionThreadIds(threadIds);
137 verifyAndClearExpectations();
138}
139
140TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration) {
141 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
142
143 std::vector<int32_t> threadIds = {1, 2};
144 mWrapper->setPowerHintSessionThreadIds(threadIds);
145 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
146 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
147 ASSERT_TRUE(mWrapper->startPowerHintSession());
148 verifyAndClearExpectations();
149
150 std::chrono::nanoseconds base = 100ms;
151 // test cases with target work duration and whether it should update hint against baseline 100ms
152 const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases = {{0ms, false},
153 {-1ms, false},
154 {200ms, true},
155 {2ms, true},
Xiang Wang0aba49e2022-04-06 16:13:59 +0000156 {91ms, false},
157 {109ms, false}};
Xiang Wange12b4fa2022-03-25 23:48:40 +0000158
159 for (const auto& test : testCases) {
160 // reset to 100ms baseline
161 mWrapper->setTargetWorkDuration(1);
162 mWrapper->setTargetWorkDuration(base.count());
163
164 auto target = test.first;
165 EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(target.count()))
166 .Times(test.second ? 1 : 0);
167 mWrapper->setTargetWorkDuration(target.count());
168 verifyAndClearExpectations();
169 }
170}
171
172TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration_shouldReconnectOnError) {
173 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
174
175 std::vector<int32_t> threadIds = {1, 2};
176 mWrapper->setPowerHintSessionThreadIds(threadIds);
177 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
178 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
179 ASSERT_TRUE(mWrapper->startPowerHintSession());
180 verifyAndClearExpectations();
181
182 EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1))
183 .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
184 mWrapper->setTargetWorkDuration(1);
185 EXPECT_TRUE(mWrapper->shouldReconnectHAL());
186}
187
188TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration) {
189 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
190
191 std::vector<int32_t> threadIds = {1, 2};
192 mWrapper->setPowerHintSessionThreadIds(threadIds);
193 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
194 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
195 ASSERT_TRUE(mWrapper->startPowerHintSession());
196 verifyAndClearExpectations();
197
198 auto base = toWorkDuration(100ms, 0);
199 // test cases with actual work durations and whether it should update hint against baseline
200 // 100ms
201 const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
202 testCases = {{{{-1ms, 100}}, false},
203 {{{91ms, 100}}, false},
204 {{{109ms, 100}}, false},
205 {{{100ms, 100}, {200ms, 200}}, true},
206 {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}};
207
208 for (const auto& test : testCases) {
209 // reset actual duration
210 sendActualWorkDurationGroup({base}, 80ms);
211
212 auto raw = test.first;
213 std::vector<WorkDuration> durations(raw.size());
214 std::transform(raw.begin(), raw.end(), durations.begin(),
215 [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
216 return toWorkDuration(d.first, d.second);
217 });
218 EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
219 .Times(test.second ? 1 : 0);
220 sendActualWorkDurationGroup(durations, 0ms);
221 verifyAndClearExpectations();
222 }
223}
224
Xiang Wang0aba49e2022-04-06 16:13:59 +0000225TEST_F(AidlPowerHalWrapperTest, sendAdjustedActualWorkDuration) {
226 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
227
228 std::vector<int32_t> threadIds = {1, 2};
229 mWrapper->setPowerHintSessionThreadIds(threadIds);
230 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
231 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
232 ASSERT_TRUE(mWrapper->startPowerHintSession());
233 verifyAndClearExpectations();
234
235 std::chrono::nanoseconds lastTarget = 100ms;
236 EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(lastTarget.count())).Times(1);
237 mWrapper->setTargetWorkDuration(lastTarget.count());
238 std::chrono::nanoseconds newTarget = 105ms;
239 mWrapper->setTargetWorkDuration(newTarget.count());
240 EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(newTarget.count())).Times(0);
241 std::chrono::nanoseconds actual = 21ms;
242 // 100 / 105 * 21ms = 20ms
243 std::chrono::nanoseconds expectedActualSent = 20ms;
244 std::vector<WorkDuration> expectedDurations = {toWorkDuration(expectedActualSent, 1)};
245
246 EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
247 .WillOnce(DoAll(
248 [expectedDurations](const ::std::vector<WorkDuration>& durationsSent) {
249 EXPECT_EQ(expectedDurations, durationsSent)
250 << base::StringPrintf("actual sent: %s vs expected: %s",
251 printWorkDurations(durationsSent).c_str(),
252 printWorkDurations(expectedDurations)
253 .c_str());
254 },
255 Return(Status::ok())));
256 mWrapper->sendActualWorkDuration(actual.count(), 1);
257}
258
Xiang Wange12b4fa2022-03-25 23:48:40 +0000259TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_exceedsStaleTime) {
260 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
261
262 std::vector<int32_t> threadIds = {1, 2};
263 mWrapper->setPowerHintSessionThreadIds(threadIds);
264 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
265 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
266 ASSERT_TRUE(mWrapper->startPowerHintSession());
267 verifyAndClearExpectations();
268
269 auto base = toWorkDuration(100ms, 0);
270 // test cases with actual work durations and whether it should update hint against baseline
271 // 100ms
272 const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>>
273 testCases = {{{{91ms, 100}}, true}, {{{109ms, 100}}, true}};
274
275 for (const auto& test : testCases) {
276 // reset actual duration
277 sendActualWorkDurationGroup({base}, 80ms);
278
279 auto raw = test.first;
280 std::vector<WorkDuration> durations(raw.size());
281 std::transform(raw.begin(), raw.end(), durations.begin(),
282 [](std::pair<std::chrono::nanoseconds, nsecs_t> d) {
283 return toWorkDuration(d.first, d.second);
284 });
285 EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(durations))
286 .Times(test.second ? 1 : 0);
287 sendActualWorkDurationGroup(durations, 80ms);
288 verifyAndClearExpectations();
289 }
290}
291
292TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_shouldReconnectOnError) {
293 ASSERT_TRUE(mWrapper->supportsPowerHintSession());
294
295 std::vector<int32_t> threadIds = {1, 2};
296 mWrapper->setPowerHintSessionThreadIds(threadIds);
297 EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _))
298 .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok())));
299 ASSERT_TRUE(mWrapper->startPowerHintSession());
300 verifyAndClearExpectations();
301 WorkDuration duration;
302 duration.durationNanos = 1;
303 EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_))
304 .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE)));
305 sendActualWorkDurationGroup({duration}, 0ms);
306 EXPECT_TRUE(mWrapper->shouldReconnectHAL());
307}
308
309} // namespace
310} // namespace android::Hwc2::impl