1 /*
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 "PowerAdvisorTest"
19
20 #include <DisplayHardware/PowerAdvisor.h>
21 #include <android_os.h>
22 #include <binder/Status.h>
23 #include <com_android_graphics_surfaceflinger_flags.h>
24 #include <common/FlagManager.h>
25 #include <common/test/FlagUtils.h>
26 #include <gmock/gmock.h>
27 #include <gtest/gtest.h>
28 #include <powermanager/PowerHalWrapper.h>
29 #include <ui/DisplayId.h>
30 #include <chrono>
31 #include <future>
32 #include "TestableSurfaceFlinger.h"
33 #include "mock/DisplayHardware/MockPowerHalController.h"
34 #include "mock/DisplayHardware/MockPowerHintSessionWrapper.h"
35
36 using namespace android;
37 using namespace android::Hwc2::mock;
38 using namespace android::hardware::power;
39 using namespace std::chrono_literals;
40 using namespace testing;
41 using namespace android::power;
42
43 namespace android::Hwc2::impl {
44
45 class PowerAdvisorTest : public testing::Test {
46 public:
47 void SetUp() override;
48 void SetUpFmq(bool usesSharedEventFlag, bool isQueueFull);
49 void startPowerHintSession(bool returnValidSession = true);
50 void fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod);
51 void setExpectedTiming(Duration totalFrameTargetDuration, TimePoint expectedPresentTime);
52 Duration getFenceWaitDelayDuration(bool skipValidate);
53 Duration getErrorMargin();
54 void setTimingTestingMode(bool testinMode);
55 void allowReportActualToAcquireMutex();
56 bool sessionExists();
57 int64_t toNanos(Duration d);
58
59 struct GpuTestConfig {
60 bool adpfGpuFlagOn;
61 Duration frame1GpuFenceDuration;
62 Duration frame2GpuFenceDuration;
63 Duration vsyncPeriod;
64 Duration presentDuration = 0ms;
65 Duration postCompDuration = 0ms;
66 bool frame1RequiresRenderEngine;
67 bool frame2RequiresRenderEngine;
68 bool usesFmq = false;
69 bool usesSharedFmqFlag = true;
70 bool fmqFull = false;
71 };
72
73 void testGpuScenario(GpuTestConfig& config, WorkDuration& ret);
74
75 protected:
76 TestableSurfaceFlinger mFlinger;
77 std::unique_ptr<PowerAdvisor> mPowerAdvisor;
78 MockPowerHalController* mMockPowerHalController;
79 std::shared_ptr<MockPowerHintSessionWrapper> mMockPowerHintSession;
80 std::shared_ptr<AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>> mBackendFmq;
81 std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> mBackendFlagQueue;
82 android::hardware::EventFlag* mEventFlag;
83 uint32_t mWriteFlagBitmask = 2;
84 uint32_t mReadFlagBitmask = 1;
85 int64_t mSessionId = 123;
86 SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel, true);
87 SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, false);
88 };
89
sessionExists()90 bool PowerAdvisorTest::sessionExists() {
91 std::scoped_lock lock(mPowerAdvisor->mHintSessionMutex);
92 return mPowerAdvisor->mHintSession != nullptr;
93 }
94
toNanos(Duration d)95 int64_t PowerAdvisorTest::toNanos(Duration d) {
96 return std::chrono::nanoseconds(d).count();
97 }
98
SetUp()99 void PowerAdvisorTest::SetUp() {
100 mPowerAdvisor = std::make_unique<impl::PowerAdvisor>(*mFlinger.flinger());
101 mPowerAdvisor->mPowerHal = std::make_unique<NiceMock<MockPowerHalController>>();
102 mMockPowerHalController =
103 reinterpret_cast<MockPowerHalController*>(mPowerAdvisor->mPowerHal.get());
104 ON_CALL(*mMockPowerHalController, getHintSessionPreferredRate)
105 .WillByDefault(Return(
106 ByMove(HalResult<int64_t>::fromStatus(ndk::ScopedAStatus::ok(), 16000))));
107 }
108
SetUpFmq(bool usesSharedEventFlag,bool isQueueFull)109 void PowerAdvisorTest::SetUpFmq(bool usesSharedEventFlag, bool isQueueFull) {
110 mBackendFmq = std::make_shared<
111 AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>>(2, !usesSharedEventFlag);
112 ChannelConfig config;
113 config.channelDescriptor = mBackendFmq->dupeDesc();
114 if (usesSharedEventFlag) {
115 mBackendFlagQueue =
116 std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(1, true);
117 config.eventFlagDescriptor = mBackendFlagQueue->dupeDesc();
118 ASSERT_EQ(android::hardware::EventFlag::createEventFlag(mBackendFlagQueue
119 ->getEventFlagWord(),
120 &mEventFlag),
121 android::NO_ERROR);
122 } else {
123 ASSERT_EQ(android::hardware::EventFlag::createEventFlag(mBackendFmq->getEventFlagWord(),
124 &mEventFlag),
125 android::NO_ERROR);
126 }
127 config.writeFlagBitmask = static_cast<int32_t>(mWriteFlagBitmask);
128 config.readFlagBitmask = static_cast<int32_t>(mReadFlagBitmask);
129 ON_CALL(*mMockPowerHalController, getSessionChannel)
130 .WillByDefault(Return(
131 ByMove(HalResult<ChannelConfig>::fromStatus(Status::ok(), std::move(config)))));
132 startPowerHintSession();
133 if (isQueueFull) {
134 std::vector<ChannelMessage> msgs;
135 msgs.resize(2);
136 mBackendFmq->writeBlocking(msgs.data(), 2, mReadFlagBitmask, mWriteFlagBitmask,
137 std::chrono::nanoseconds(1ms).count(), mEventFlag);
138 }
139 }
140
startPowerHintSession(bool returnValidSession)141 void PowerAdvisorTest::startPowerHintSession(bool returnValidSession) {
142 mMockPowerHintSession = std::make_shared<NiceMock<MockPowerHintSessionWrapper>>();
143 if (returnValidSession) {
144 ON_CALL(*mMockPowerHalController, createHintSessionWithConfig)
145 .WillByDefault(DoAll(SetArgPointee<5>(aidl::android::hardware::power::SessionConfig{
146 .id = mSessionId}),
147 Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
148 fromStatus(binder::Status::ok(),
149 mMockPowerHintSession))));
150 } else {
151 ON_CALL(*mMockPowerHalController, createHintSessionWithConfig).WillByDefault([] {
152 return HalResult<
153 std::shared_ptr<PowerHintSessionWrapper>>::fromStatus(ndk::ScopedAStatus::ok(),
154 nullptr);
155 });
156 }
157 mPowerAdvisor->enablePowerHintSession(true);
158 mPowerAdvisor->startPowerHintSession({1, 2, 3});
159 ON_CALL(*mMockPowerHintSession, updateTargetWorkDuration)
160 .WillByDefault(Return(testing::ByMove(HalResult<void>::ok())));
161 }
162
setExpectedTiming(Duration totalFrameTargetDuration,TimePoint expectedPresentTime)163 void PowerAdvisorTest::setExpectedTiming(Duration totalFrameTargetDuration,
164 TimePoint expectedPresentTime) {
165 mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTargetDuration);
166 mPowerAdvisor->setExpectedPresentTime(expectedPresentTime);
167 }
168
fakeBasicFrameTiming(TimePoint startTime,Duration vsyncPeriod)169 void PowerAdvisorTest::fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod) {
170 mPowerAdvisor->setCommitStart(startTime);
171 mPowerAdvisor->setFrameDelay(0ns);
172 mPowerAdvisor->updateTargetWorkDuration(vsyncPeriod);
173 }
174
setTimingTestingMode(bool testingMode)175 void PowerAdvisorTest::setTimingTestingMode(bool testingMode) {
176 mPowerAdvisor->mTimingTestingMode = testingMode;
177 }
178
allowReportActualToAcquireMutex()179 void PowerAdvisorTest::allowReportActualToAcquireMutex() {
180 mPowerAdvisor->mDelayReportActualMutexAcquisitonPromise.set_value(true);
181 }
182
testGpuScenario(GpuTestConfig & config,WorkDuration & ret)183 void PowerAdvisorTest::testGpuScenario(GpuTestConfig& config, WorkDuration& ret) {
184 SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_gpu_sf,
185 config.adpfGpuFlagOn);
186 SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, config.usesFmq);
187 mPowerAdvisor->onBootFinished();
188 bool expectsFmqSuccess = config.usesSharedFmqFlag && !config.fmqFull;
189 if (config.usesFmq) {
190 SetUpFmq(config.usesSharedFmqFlag, config.fmqFull);
191 } else {
192 startPowerHintSession();
193 }
194
195 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
196 GpuVirtualDisplayId(1)};
197 mPowerAdvisor->setDisplays(displayIds);
198 auto display1 = displayIds[0];
199 // 60hz
200
201 TimePoint startTime = TimePoint::now();
202 int64_t target;
203 SessionHint hint;
204 if (!config.usesFmq || !expectsFmqSuccess) {
205 EXPECT_CALL(*mMockPowerHintSession, updateTargetWorkDuration(_))
206 .Times(1)
207 .WillOnce(DoAll(testing::SaveArg<0>(&target),
208 testing::Return(testing::ByMove(HalResult<void>::ok()))));
209 EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
210 .Times(1)
211 .WillOnce(DoAll(testing::SaveArg<0>(&hint),
212 testing::Return(testing::ByMove(HalResult<void>::ok()))));
213 }
214 // advisor only starts on frame 2 so do an initial frame
215 fakeBasicFrameTiming(startTime, config.vsyncPeriod);
216 // send a load hint
217 mPowerAdvisor->notifyCpuLoadUp();
218 if (config.usesFmq && expectsFmqSuccess) {
219 std::vector<ChannelMessage> msgs;
220 ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
221 msgs.resize(2);
222 ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 2, mReadFlagBitmask, mWriteFlagBitmask,
223 std::chrono::nanoseconds(1ms).count(), mEventFlag));
224 ASSERT_EQ(msgs[0].sessionID, mSessionId);
225 ASSERT_GE(msgs[0].timeStampNanos, startTime.ns());
226 ASSERT_EQ(msgs[0].data.getTag(),
227 ChannelMessage::ChannelMessageContents::Tag::targetDuration);
228 target = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::targetDuration>();
229 ASSERT_EQ(msgs[1].sessionID, mSessionId);
230 ASSERT_GE(msgs[1].timeStampNanos, startTime.ns());
231 ASSERT_EQ(msgs[1].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::hint);
232 hint = msgs[1].data.get<ChannelMessage::ChannelMessageContents::Tag::hint>();
233 }
234 ASSERT_EQ(target, config.vsyncPeriod.ns());
235 ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
236
237 setExpectedTiming(config.vsyncPeriod, startTime + config.vsyncPeriod);
238
239 // report GPU
240 mPowerAdvisor->setRequiresRenderEngine(display1, config.frame1RequiresRenderEngine);
241 if (config.adpfGpuFlagOn) {
242 mPowerAdvisor->setGpuStartTime(display1, startTime);
243 }
244 if (config.frame1GpuFenceDuration.count() == Fence::SIGNAL_TIME_PENDING) {
245 mPowerAdvisor->setGpuFenceTime(display1,
246 std::make_unique<FenceTime>(Fence::SIGNAL_TIME_PENDING));
247 } else {
248 TimePoint end = startTime + config.frame1GpuFenceDuration;
249 mPowerAdvisor->setGpuFenceTime(display1, std::make_unique<FenceTime>(end.ns()));
250 }
251
252 // increment the frame
253 std::this_thread::sleep_for(config.vsyncPeriod);
254 startTime = TimePoint::now();
255 fakeBasicFrameTiming(startTime, config.vsyncPeriod);
256 if (config.usesFmq && expectsFmqSuccess) {
257 // same target update will not trigger FMQ write
258 ASSERT_EQ(mBackendFmq->availableToRead(), 0uL);
259 }
260 setExpectedTiming(config.vsyncPeriod, startTime + config.vsyncPeriod);
261
262 // report GPU
263 mPowerAdvisor->setRequiresRenderEngine(display1, config.frame2RequiresRenderEngine);
264 if (config.adpfGpuFlagOn) {
265 mPowerAdvisor->setGpuStartTime(display1, startTime);
266 }
267 if (config.frame2GpuFenceDuration.count() == Fence::SIGNAL_TIME_PENDING) {
268 mPowerAdvisor->setGpuFenceTime(display1,
269 std::make_unique<FenceTime>(Fence::SIGNAL_TIME_PENDING));
270 } else {
271 TimePoint end = startTime + config.frame2GpuFenceDuration;
272 mPowerAdvisor->setGpuFenceTime(display1, std::make_unique<FenceTime>(end.ns()));
273 }
274 mPowerAdvisor->setSfPresentTiming(startTime, startTime + config.presentDuration);
275 mPowerAdvisor->setCompositeEnd(startTime + config.presentDuration + config.postCompDuration);
276
277 // don't report timing for the HWC
278 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime, startTime);
279 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime, startTime);
280
281 if (config.usesFmq && expectsFmqSuccess) {
282 mPowerAdvisor->reportActualWorkDuration();
283 ASSERT_EQ(mBackendFmq->availableToRead(), 1uL);
284 std::vector<ChannelMessage> msgs;
285 msgs.resize(1);
286 ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
287 std::chrono::nanoseconds(1ms).count(), mEventFlag));
288 ASSERT_EQ(msgs[0].sessionID, mSessionId);
289 ASSERT_GE(msgs[0].timeStampNanos, startTime.ns());
290 ASSERT_EQ(msgs[0].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::workDuration);
291 auto actual = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::workDuration>();
292 ret.workPeriodStartTimestampNanos = actual.workPeriodStartTimestampNanos;
293 ret.cpuDurationNanos = actual.cpuDurationNanos;
294 ret.gpuDurationNanos = actual.gpuDurationNanos;
295 ret.durationNanos = actual.durationNanos;
296 } else {
297 std::vector<aidl::android::hardware::power::WorkDuration> durationReq;
298 EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration(_))
299 .Times(1)
300 .WillOnce(DoAll(testing::SaveArg<0>(&durationReq),
301 testing::Return(testing::ByMove(HalResult<void>::ok()))));
302 mPowerAdvisor->reportActualWorkDuration();
303 ASSERT_EQ(durationReq.size(), 1u);
304 ret = std::move(durationReq[0]);
305 }
306 }
307
getFenceWaitDelayDuration(bool skipValidate)308 Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
309 return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate
310 : PowerAdvisor::kFenceWaitStartDelayValidated);
311 }
312
getErrorMargin()313 Duration PowerAdvisorTest::getErrorMargin() {
314 return mPowerAdvisor->sTargetSafetyMargin;
315 }
316
317 namespace {
318
TEST_F(PowerAdvisorTest,hintSessionUseHwcDisplay)319 TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) {
320 mPowerAdvisor->onBootFinished();
321 startPowerHintSession();
322
323 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
324
325 // 60hz
326 const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
327 const Duration presentDuration = 5ms;
328 const Duration postCompDuration = 1ms;
329
330 TimePoint startTime{100ns};
331
332 // advisor only starts on frame 2 so do an initial no-op frame
333 fakeBasicFrameTiming(startTime, vsyncPeriod);
334 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
335 mPowerAdvisor->setDisplays(displayIds);
336 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
337 mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
338
339 // increment the frame
340 startTime += vsyncPeriod;
341
342 const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration;
343 EXPECT_CALL(*mMockPowerHintSession,
344 reportActualWorkDuration(ElementsAre(
345 Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
346 .Times(1)
347 .WillOnce(Return(testing::ByMove(HalResult<void>::ok())));
348 fakeBasicFrameTiming(startTime, vsyncPeriod);
349 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
350 mPowerAdvisor->setDisplays(displayIds);
351 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
352 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
353 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
354 mPowerAdvisor->reportActualWorkDuration();
355 }
356
TEST_F(PowerAdvisorTest,hintSessionSubtractsHwcFenceTime)357 TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) {
358 mPowerAdvisor->onBootFinished();
359 startPowerHintSession();
360
361 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
362
363 // 60hz
364 const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
365 const Duration presentDuration = 5ms;
366 const Duration postCompDuration = 1ms;
367 const Duration hwcBlockedDuration = 500us;
368
369 TimePoint startTime{100ns};
370
371 // advisor only starts on frame 2 so do an initial no-op frame
372 fakeBasicFrameTiming(startTime, vsyncPeriod);
373 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
374 mPowerAdvisor->setDisplays(displayIds);
375 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
376 mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
377
378 // increment the frame
379 startTime += vsyncPeriod;
380
381 const Duration expectedDuration = getErrorMargin() + presentDuration +
382 getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration;
383 EXPECT_CALL(*mMockPowerHintSession,
384 reportActualWorkDuration(ElementsAre(
385 Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
386 .Times(1)
387 .WillOnce(Return(testing::ByMove(HalResult<void>::ok())));
388
389 fakeBasicFrameTiming(startTime, vsyncPeriod);
390 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
391 mPowerAdvisor->setDisplays(displayIds);
392 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
393 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 3ms);
394 // now report the fence as having fired during the display HWC time
395 mPowerAdvisor->setSfPresentTiming(startTime + 2ms + hwcBlockedDuration,
396 startTime + presentDuration);
397 mPowerAdvisor->reportActualWorkDuration();
398 }
399
TEST_F(PowerAdvisorTest,hintSessionUsingSecondaryVirtualDisplays)400 TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) {
401 mPowerAdvisor->onBootFinished();
402 startPowerHintSession();
403
404 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
405 GpuVirtualDisplayId(1)};
406
407 // 60hz
408 const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
409 // make present duration much later than the hwc display by itself will account for
410 const Duration presentDuration{10ms};
411 const Duration postCompDuration{1ms};
412
413 TimePoint startTime{100ns};
414
415 // advisor only starts on frame 2 so do an initial no-op frame
416 fakeBasicFrameTiming(startTime, vsyncPeriod);
417 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
418 mPowerAdvisor->setDisplays(displayIds);
419 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
420 mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
421
422 // increment the frame
423 startTime += vsyncPeriod;
424
425 const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration;
426 EXPECT_CALL(*mMockPowerHintSession,
427 reportActualWorkDuration(ElementsAre(
428 Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
429 .Times(1)
430 .WillOnce(Return(testing::ByMove(HalResult<void>::ok())));
431
432 fakeBasicFrameTiming(startTime, vsyncPeriod);
433 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
434 mPowerAdvisor->setDisplays(displayIds);
435
436 // don't report timing for the gpu displays since they don't use hwc
437 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
438 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
439 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
440 mPowerAdvisor->reportActualWorkDuration();
441 }
442
TEST_F(PowerAdvisorTest,hintSessionValidWhenNullFromPowerHAL)443 TEST_F(PowerAdvisorTest, hintSessionValidWhenNullFromPowerHAL) {
444 mPowerAdvisor->onBootFinished();
445
446 startPowerHintSession(false);
447
448 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
449
450 // 60hz
451 const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
452 const Duration presentDuration = 5ms;
453 const Duration postCompDuration = 1ms;
454
455 TimePoint startTime{100ns};
456
457 // advisor only starts on frame 2 so do an initial no-op frame
458 fakeBasicFrameTiming(startTime, vsyncPeriod);
459 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
460 mPowerAdvisor->setDisplays(displayIds);
461 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
462 mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
463
464 // increment the frame
465 startTime += vsyncPeriod;
466
467 const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration;
468 EXPECT_CALL(*mMockPowerHintSession,
469 reportActualWorkDuration(ElementsAre(
470 Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
471 .Times(0);
472 fakeBasicFrameTiming(startTime, vsyncPeriod);
473 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
474 mPowerAdvisor->setDisplays(displayIds);
475 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
476 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
477 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
478 mPowerAdvisor->reportActualWorkDuration();
479 }
480
TEST_F(PowerAdvisorTest,hintSessionTestNotifyReportRace)481 TEST_F(PowerAdvisorTest, hintSessionTestNotifyReportRace) {
482 // notifyDisplayUpdateImminentAndCpuReset or notifyCpuLoadUp gets called in background
483 // reportActual gets called during callback and sees true session, passes ensure
484 // first notify finishes, setting value to true. Another async method gets called, acquires the
485 // lock between reportactual finishing ensure and acquiring the lock itself, and sets session to
486 // nullptr. reportActual acquires the lock, and the session is now null, so it does nullptr
487 // deref
488
489 mPowerAdvisor->onBootFinished();
490 startPowerHintSession();
491
492 // --- fake a bunch of timing data
493 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
494 // 60hz
495 const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
496 const Duration presentDuration = 5ms;
497 const Duration postCompDuration = 1ms;
498 TimePoint startTime{100ns};
499 // advisor only starts on frame 2 so do an initial no-op frame
500 fakeBasicFrameTiming(startTime, vsyncPeriod);
501 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
502 mPowerAdvisor->setDisplays(displayIds);
503 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
504 mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
505 // increment the frame
506 startTime += vsyncPeriod;
507 fakeBasicFrameTiming(startTime, vsyncPeriod);
508 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
509 mPowerAdvisor->setDisplays(displayIds);
510 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
511 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
512 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
513 // --- Done faking timing data
514
515 setTimingTestingMode(true);
516 std::promise<bool> letSendHintFinish;
517
518 ON_CALL(*mMockPowerHintSession, sendHint).WillByDefault([&letSendHintFinish] {
519 letSendHintFinish.get_future().wait();
520 return HalResult<void>::fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127));
521 });
522
523 ON_CALL(*mMockPowerHintSession, reportActualWorkDuration).WillByDefault([] {
524 return HalResult<void>::fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127));
525 });
526
527 ON_CALL(*mMockPowerHalController, createHintSessionWithConfig).WillByDefault([] {
528 return HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
529 fromStatus(ndk::ScopedAStatus::fromExceptionCode(-127), nullptr);
530 });
531
532 // First background call, to notice the session is down
533 auto firstHint = std::async(std::launch::async, [this] {
534 mPowerAdvisor->notifyCpuLoadUp();
535 return true;
536 });
537 std::this_thread::sleep_for(10ms);
538
539 // Call reportActual while callback is resolving to try and sneak past ensure
540 auto reportActual =
541 std::async(std::launch::async, [this] { mPowerAdvisor->reportActualWorkDuration(); });
542
543 std::this_thread::sleep_for(10ms);
544 // Let the first call finish
545 letSendHintFinish.set_value(true);
546 letSendHintFinish = std::promise<bool>{};
547 firstHint.wait();
548
549 // Do the second notify call, to ensure the session is nullptr
550 auto secondHint = std::async(std::launch::async, [this] {
551 mPowerAdvisor->notifyCpuLoadUp();
552 return true;
553 });
554 letSendHintFinish.set_value(true);
555 secondHint.wait();
556 // Let report finish, potentially dereferencing
557 allowReportActualToAcquireMutex();
558 reportActual.wait();
559 EXPECT_EQ(sessionExists(), false);
560 }
561
TEST_F(PowerAdvisorTest,legacyHintSessionCreationStillWorks)562 TEST_F(PowerAdvisorTest, legacyHintSessionCreationStillWorks) {
563 mPowerAdvisor->onBootFinished();
564 mMockPowerHintSession = std::make_shared<NiceMock<MockPowerHintSessionWrapper>>();
565 EXPECT_CALL(*mMockPowerHalController, createHintSessionWithConfig)
566 .Times(1)
567 .WillOnce(Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
568 fromStatus(ndk::ScopedAStatus::fromExceptionCode(
569 EX_UNSUPPORTED_OPERATION),
570 nullptr)));
571
572 EXPECT_CALL(*mMockPowerHalController, createHintSession)
573 .Times(1)
574 .WillOnce(Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
575 fromStatus(binder::Status::ok(), mMockPowerHintSession)));
576 mPowerAdvisor->enablePowerHintSession(true);
577 ASSERT_TRUE(mPowerAdvisor->startPowerHintSession({1, 2, 3}));
578 }
579
TEST_F(PowerAdvisorTest,setGpuFenceTime_cpuThenGpuFrames)580 TEST_F(PowerAdvisorTest, setGpuFenceTime_cpuThenGpuFrames) {
581 GpuTestConfig config{
582 .adpfGpuFlagOn = false,
583 // faked buffer fence time for testing
584 .frame1GpuFenceDuration = 41ms,
585 .frame2GpuFenceDuration = 31ms,
586 .vsyncPeriod = 10ms,
587 .presentDuration = 2ms,
588 .postCompDuration = 8ms,
589 .frame1RequiresRenderEngine = false,
590 .frame2RequiresRenderEngine = true,
591 };
592 WorkDuration res;
593 testGpuScenario(config, res);
594 EXPECT_EQ(res.gpuDurationNanos, 0L);
595 EXPECT_EQ(res.cpuDurationNanos, 0L);
596 EXPECT_GE(res.durationNanos, toNanos(30ms + getErrorMargin()));
597 EXPECT_LE(res.durationNanos, toNanos(31ms + getErrorMargin()));
598 }
599
TEST_F(PowerAdvisorTest,setGpuFenceTime_cpuThenGpuFrames_flagOn)600 TEST_F(PowerAdvisorTest, setGpuFenceTime_cpuThenGpuFrames_flagOn) {
601 GpuTestConfig config{
602 .adpfGpuFlagOn = true,
603 .frame1GpuFenceDuration = 40ms,
604 .frame2GpuFenceDuration = 30ms,
605 .vsyncPeriod = 10ms,
606 .presentDuration = 2ms,
607 .postCompDuration = 8ms,
608 .frame1RequiresRenderEngine = false,
609 .frame2RequiresRenderEngine = true,
610 };
611 WorkDuration res;
612 testGpuScenario(config, res);
613 EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
614 EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
615 EXPECT_EQ(res.durationNanos, toNanos(30ms + getErrorMargin()));
616 }
617
TEST_F(PowerAdvisorTest,setGpuFenceTime_gpuThenCpuFrames)618 TEST_F(PowerAdvisorTest, setGpuFenceTime_gpuThenCpuFrames) {
619 GpuTestConfig config{
620 .adpfGpuFlagOn = false,
621 // faked fence time for testing
622 .frame1GpuFenceDuration = 41ms,
623 .frame2GpuFenceDuration = 31ms,
624 .vsyncPeriod = 10ms,
625 .presentDuration = 2ms,
626 .postCompDuration = 8ms,
627 .frame1RequiresRenderEngine = true,
628 .frame2RequiresRenderEngine = false,
629 };
630 WorkDuration res;
631 testGpuScenario(config, res);
632 EXPECT_EQ(res.gpuDurationNanos, 0L);
633 EXPECT_EQ(res.cpuDurationNanos, 0L);
634 EXPECT_EQ(res.durationNanos, toNanos(10ms + getErrorMargin()));
635 }
636
TEST_F(PowerAdvisorTest,setGpuFenceTime_gpuThenCpuFrames_flagOn)637 TEST_F(PowerAdvisorTest, setGpuFenceTime_gpuThenCpuFrames_flagOn) {
638 GpuTestConfig config{
639 .adpfGpuFlagOn = true,
640 .frame1GpuFenceDuration = 40ms,
641 .frame2GpuFenceDuration = 30ms,
642 .vsyncPeriod = 10ms,
643 .presentDuration = 2ms,
644 .postCompDuration = 8ms,
645 .frame1RequiresRenderEngine = true,
646 .frame2RequiresRenderEngine = false,
647 };
648 WorkDuration res;
649 testGpuScenario(config, res);
650 EXPECT_EQ(res.gpuDurationNanos, 0L);
651 EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
652 EXPECT_EQ(res.durationNanos, toNanos(10ms + getErrorMargin()));
653 }
654
TEST_F(PowerAdvisorTest,setGpuFenceTime_twoSignaledGpuFrames)655 TEST_F(PowerAdvisorTest, setGpuFenceTime_twoSignaledGpuFrames) {
656 GpuTestConfig config{
657 .adpfGpuFlagOn = false,
658 // added a margin as a workaround since we set GPU start time at the time of fence set
659 // call
660 .frame1GpuFenceDuration = 31ms,
661 .frame2GpuFenceDuration = 51ms,
662 .vsyncPeriod = 10ms,
663 .presentDuration = 2ms,
664 .postCompDuration = 8ms,
665 .frame1RequiresRenderEngine = true,
666 .frame2RequiresRenderEngine = true,
667 };
668 WorkDuration res;
669 testGpuScenario(config, res);
670 EXPECT_EQ(res.gpuDurationNanos, 0L);
671 EXPECT_EQ(res.cpuDurationNanos, 0L);
672 EXPECT_GE(res.durationNanos, toNanos(50ms + getErrorMargin()));
673 EXPECT_LE(res.durationNanos, toNanos(51ms + getErrorMargin()));
674 }
675
TEST_F(PowerAdvisorTest,setGpuFenceTime_twoSignaledGpuFenceFrames_flagOn)676 TEST_F(PowerAdvisorTest, setGpuFenceTime_twoSignaledGpuFenceFrames_flagOn) {
677 GpuTestConfig config{
678 .adpfGpuFlagOn = true,
679 .frame1GpuFenceDuration = 30ms,
680 .frame2GpuFenceDuration = 50ms,
681 .vsyncPeriod = 10ms,
682 .presentDuration = 2ms,
683 .postCompDuration = 8ms,
684 .frame1RequiresRenderEngine = true,
685 .frame2RequiresRenderEngine = true,
686 };
687 WorkDuration res;
688 testGpuScenario(config, res);
689 EXPECT_EQ(res.gpuDurationNanos, toNanos(50ms));
690 EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
691 EXPECT_EQ(res.durationNanos, toNanos(50ms + getErrorMargin()));
692 }
693
TEST_F(PowerAdvisorTest,setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame)694 TEST_F(PowerAdvisorTest, setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame) {
695 GpuTestConfig config{
696 .adpfGpuFlagOn = false,
697 .frame1GpuFenceDuration = 31ms,
698 .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
699 .vsyncPeriod = 10ms,
700 .presentDuration = 2ms,
701 .postCompDuration = 8ms,
702 .frame1RequiresRenderEngine = true,
703 .frame2RequiresRenderEngine = true,
704 };
705 WorkDuration res;
706 testGpuScenario(config, res);
707 EXPECT_EQ(res.gpuDurationNanos, 0L);
708 EXPECT_EQ(res.cpuDurationNanos, 0L);
709 EXPECT_GE(res.durationNanos, toNanos(30ms + getErrorMargin()));
710 EXPECT_LE(res.durationNanos, toNanos(31ms + getErrorMargin()));
711 }
712
TEST_F(PowerAdvisorTest,setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame_flagOn)713 TEST_F(PowerAdvisorTest, setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame_flagOn) {
714 GpuTestConfig config{
715 .adpfGpuFlagOn = true,
716 .frame1GpuFenceDuration = 30ms,
717 .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
718 .vsyncPeriod = 10ms,
719 .presentDuration = 22ms,
720 .postCompDuration = 88ms,
721 .frame1RequiresRenderEngine = true,
722 .frame2RequiresRenderEngine = true,
723 };
724 WorkDuration res;
725 testGpuScenario(config, res);
726 EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
727 EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
728 EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
729 }
730
TEST_F(PowerAdvisorTest,fmq_sendTargetAndActualDuration)731 TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration) {
732 GpuTestConfig config{
733 .adpfGpuFlagOn = true,
734 .frame1GpuFenceDuration = 30ms,
735 .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
736 .vsyncPeriod = 10ms,
737 .presentDuration = 22ms,
738 .postCompDuration = 88ms,
739 .frame1RequiresRenderEngine = true,
740 .frame2RequiresRenderEngine = true,
741 .usesFmq = true,
742 .usesSharedFmqFlag = true,
743 };
744 WorkDuration res;
745 testGpuScenario(config, res);
746 EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
747 EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
748 EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
749 }
750
TEST_F(PowerAdvisorTest,fmq_sendTargetAndActualDuration_noSharedFlag)751 TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration_noSharedFlag) {
752 GpuTestConfig config{
753 .adpfGpuFlagOn = true,
754 .frame1GpuFenceDuration = 30ms,
755 .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
756 .vsyncPeriod = 10ms,
757 .presentDuration = 22ms,
758 .postCompDuration = 88ms,
759 .frame1RequiresRenderEngine = true,
760 .frame2RequiresRenderEngine = true,
761 .usesFmq = true,
762 .usesSharedFmqFlag = false,
763 };
764 WorkDuration res;
765 testGpuScenario(config, res);
766 EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
767 EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
768 EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
769 }
770
TEST_F(PowerAdvisorTest,fmq_sendTargetAndActualDuration_queueFull)771 TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration_queueFull) {
772 GpuTestConfig config{.adpfGpuFlagOn = true,
773 .frame1GpuFenceDuration = 30ms,
774 .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
775 .vsyncPeriod = 10ms,
776 .presentDuration = 22ms,
777 .postCompDuration = 88ms,
778 .frame1RequiresRenderEngine = true,
779 .frame2RequiresRenderEngine = true,
780 .usesFmq = true,
781 .usesSharedFmqFlag = true,
782 .fmqFull = true};
783 WorkDuration res;
784 testGpuScenario(config, res);
785 EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
786 EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
787 EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
788 }
789
TEST_F(PowerAdvisorTest,fmq_sendHint)790 TEST_F(PowerAdvisorTest, fmq_sendHint) {
791 SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
792 mPowerAdvisor->onBootFinished();
793 SetUpFmq(true, false);
794 auto startTime = uptimeNanos();
795 mPowerAdvisor->notifyCpuLoadUp();
796 std::vector<ChannelMessage> msgs;
797 ASSERT_EQ(mBackendFmq->availableToRead(), 1uL);
798 msgs.resize(1);
799 ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
800 std::chrono::nanoseconds(1ms).count(), mEventFlag));
801 ASSERT_EQ(msgs[0].sessionID, mSessionId);
802 ASSERT_GE(msgs[0].timeStampNanos, startTime);
803 ASSERT_EQ(msgs[0].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::hint);
804 auto hint = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::hint>();
805 ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
806 }
807
TEST_F(PowerAdvisorTest,fmq_sendHint_noSharedFlag)808 TEST_F(PowerAdvisorTest, fmq_sendHint_noSharedFlag) {
809 SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
810 mPowerAdvisor->onBootFinished();
811 SetUpFmq(false, false);
812 SessionHint hint;
813 EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
814 .Times(1)
815 .WillOnce(DoAll(testing::SaveArg<0>(&hint),
816 testing::Return(testing::ByMove(HalResult<void>::ok()))));
817 mPowerAdvisor->notifyCpuLoadUp();
818 ASSERT_EQ(mBackendFmq->availableToRead(), 0uL);
819 ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
820 }
821
TEST_F(PowerAdvisorTest,fmq_sendHint_queueFull)822 TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) {
823 SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
824 mPowerAdvisor->onBootFinished();
825 SetUpFmq(true, true);
826 ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
827 SessionHint hint;
828 EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
829 .Times(1)
830 .WillOnce(DoAll(testing::SaveArg<0>(&hint),
831 testing::Return(testing::ByMove(HalResult<void>::ok()))));
832 std::vector<ChannelMessage> msgs;
833 msgs.resize(1);
834 mBackendFmq->writeBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
835 std::chrono::nanoseconds(1ms).count(), mEventFlag);
836 mPowerAdvisor->notifyCpuLoadUp();
837 ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
838 ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
839 }
840
841 } // namespace
842 } // namespace android::Hwc2::impl
843