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