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 <compositionengine/Display.h>
22 #include <ftl/fake_guard.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <ui/DisplayId.h>
26 #include <chrono>
27 #include "TestableSurfaceFlinger.h"
28 #include "mock/DisplayHardware/MockIPowerHintSession.h"
29 #include "mock/DisplayHardware/MockPowerHalController.h"
30
31 using namespace android;
32 using namespace android::Hwc2::mock;
33 using namespace android::hardware::power;
34 using namespace std::chrono_literals;
35 using namespace testing;
36 using namespace android::power;
37
38 namespace android::Hwc2::impl {
39
40 class PowerAdvisorTest : public testing::Test {
41 public:
42 void SetUp() override;
43 void startPowerHintSession();
44 void fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod);
45 void setExpectedTiming(Duration totalFrameTargetDuration, TimePoint expectedPresentTime);
46 Duration getFenceWaitDelayDuration(bool skipValidate);
47 Duration getErrorMargin();
48
49 protected:
50 TestableSurfaceFlinger mFlinger;
51 std::unique_ptr<PowerAdvisor> mPowerAdvisor;
52 MockPowerHalController* mMockPowerHalController;
53 sp<MockIPowerHintSession> mMockPowerHintSession;
54 };
55
SetUp()56 void PowerAdvisorTest::SetUp() {
57 mPowerAdvisor = std::make_unique<impl::PowerAdvisor>(*mFlinger.flinger());
58 mPowerAdvisor->mPowerHal = std::make_unique<NiceMock<MockPowerHalController>>();
59 mMockPowerHalController =
60 reinterpret_cast<MockPowerHalController*>(mPowerAdvisor->mPowerHal.get());
61 ON_CALL(*mMockPowerHalController, getHintSessionPreferredRate)
62 .WillByDefault(Return(HalResult<int64_t>::fromStatus(binder::Status::ok(), 16000)));
63 }
64
startPowerHintSession()65 void PowerAdvisorTest::startPowerHintSession() {
66 const std::vector<int32_t> threadIds = {1, 2, 3};
67 mMockPowerHintSession = android::sp<NiceMock<MockIPowerHintSession>>::make();
68 ON_CALL(*mMockPowerHalController, createHintSession)
69 .WillByDefault(
70 Return(HalResult<sp<IPowerHintSession>>::fromStatus(binder::Status::ok(),
71 mMockPowerHintSession)));
72 mPowerAdvisor->enablePowerHintSession(true);
73 mPowerAdvisor->startPowerHintSession(threadIds);
74 }
75
setExpectedTiming(Duration totalFrameTargetDuration,TimePoint expectedPresentTime)76 void PowerAdvisorTest::setExpectedTiming(Duration totalFrameTargetDuration,
77 TimePoint expectedPresentTime) {
78 mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTargetDuration);
79 mPowerAdvisor->setExpectedPresentTime(expectedPresentTime);
80 }
81
fakeBasicFrameTiming(TimePoint startTime,Duration vsyncPeriod)82 void PowerAdvisorTest::fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod) {
83 mPowerAdvisor->setCommitStart(startTime);
84 mPowerAdvisor->setFrameDelay(0ns);
85 mPowerAdvisor->updateTargetWorkDuration(vsyncPeriod);
86 }
87
getFenceWaitDelayDuration(bool skipValidate)88 Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
89 return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate
90 : PowerAdvisor::kFenceWaitStartDelayValidated);
91 }
92
getErrorMargin()93 Duration PowerAdvisorTest::getErrorMargin() {
94 return mPowerAdvisor->sTargetSafetyMargin;
95 }
96
97 namespace {
98
TEST_F(PowerAdvisorTest,hintSessionUseHwcDisplay)99 TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) {
100 mPowerAdvisor->onBootFinished();
101 startPowerHintSession();
102
103 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
104
105 // 60hz
106 const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
107 const Duration presentDuration = 5ms;
108 const Duration postCompDuration = 1ms;
109
110 TimePoint startTime{100ns};
111
112 // advisor only starts on frame 2 so do an initial no-op frame
113 fakeBasicFrameTiming(startTime, vsyncPeriod);
114 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
115 mPowerAdvisor->setDisplays(displayIds);
116 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
117 mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
118
119 // increment the frame
120 startTime += vsyncPeriod;
121
122 const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration;
123 EXPECT_CALL(*mMockPowerHintSession,
124 reportActualWorkDuration(ElementsAre(
125 Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
126 .Times(1);
127
128 fakeBasicFrameTiming(startTime, vsyncPeriod);
129 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
130 mPowerAdvisor->setDisplays(displayIds);
131 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
132 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
133 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
134 mPowerAdvisor->reportActualWorkDuration();
135 }
136
TEST_F(PowerAdvisorTest,hintSessionSubtractsHwcFenceTime)137 TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) {
138 mPowerAdvisor->onBootFinished();
139 startPowerHintSession();
140
141 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)};
142
143 // 60hz
144 const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
145 const Duration presentDuration = 5ms;
146 const Duration postCompDuration = 1ms;
147 const Duration hwcBlockedDuration = 500us;
148
149 TimePoint startTime{100ns};
150
151 // advisor only starts on frame 2 so do an initial no-op frame
152 fakeBasicFrameTiming(startTime, vsyncPeriod);
153 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
154 mPowerAdvisor->setDisplays(displayIds);
155 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
156 mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
157
158 // increment the frame
159 startTime += vsyncPeriod;
160
161 const Duration expectedDuration = getErrorMargin() + presentDuration +
162 getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration;
163 EXPECT_CALL(*mMockPowerHintSession,
164 reportActualWorkDuration(ElementsAre(
165 Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
166 .Times(1);
167
168 fakeBasicFrameTiming(startTime, vsyncPeriod);
169 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
170 mPowerAdvisor->setDisplays(displayIds);
171 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
172 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 3ms);
173 // now report the fence as having fired during the display HWC time
174 mPowerAdvisor->setSfPresentTiming(startTime + 2ms + hwcBlockedDuration,
175 startTime + presentDuration);
176 mPowerAdvisor->reportActualWorkDuration();
177 }
178
TEST_F(PowerAdvisorTest,hintSessionUsingSecondaryVirtualDisplays)179 TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) {
180 mPowerAdvisor->onBootFinished();
181 startPowerHintSession();
182
183 std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
184 GpuVirtualDisplayId(1)};
185
186 // 60hz
187 const Duration vsyncPeriod{std::chrono::nanoseconds(1s) / 60};
188 // make present duration much later than the hwc display by itself will account for
189 const Duration presentDuration{10ms};
190 const Duration postCompDuration{1ms};
191
192 TimePoint startTime{100ns};
193
194 // advisor only starts on frame 2 so do an initial no-op frame
195 fakeBasicFrameTiming(startTime, vsyncPeriod);
196 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
197 mPowerAdvisor->setDisplays(displayIds);
198 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
199 mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration);
200
201 // increment the frame
202 startTime += vsyncPeriod;
203
204 const Duration expectedDuration = getErrorMargin() + presentDuration + postCompDuration;
205 EXPECT_CALL(*mMockPowerHintSession,
206 reportActualWorkDuration(ElementsAre(
207 Field(&WorkDuration::durationNanos, Eq(expectedDuration.ns())))))
208 .Times(1);
209
210 fakeBasicFrameTiming(startTime, vsyncPeriod);
211 setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod);
212 mPowerAdvisor->setDisplays(displayIds);
213
214 // don't report timing for the gpu displays since they don't use hwc
215 mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1ms, startTime + 1500us);
216 mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2ms, startTime + 2500us);
217 mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration);
218 mPowerAdvisor->reportActualWorkDuration();
219 }
220
221 } // namespace
222 } // namespace android::Hwc2::impl
223