Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 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 "AidlPowerHalWrapperTest" |
| 19 | |
Xiang Wang | 0aba49e | 2022-04-06 16:13:59 +0000 | [diff] [blame] | 20 | #include <android-base/stringprintf.h> |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 21 | #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 | |
| 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 | |
| 42 | namespace android::Hwc2::impl { |
| 43 | |
| 44 | class AidlPowerHalWrapperTest : public testing::Test { |
| 45 | public: |
| 46 | void SetUp() override; |
| 47 | |
| 48 | protected: |
| 49 | std::unique_ptr<AidlPowerHalWrapper> mWrapper = nullptr; |
| 50 | sp<NiceMock<MockIPower>> mMockHal = nullptr; |
| 51 | sp<NiceMock<MockIPowerHintSession>> mMockSession = nullptr; |
| 52 | void verifyAndClearExpectations(); |
Matt Buckley | 44e612e | 2022-08-30 22:02:37 +0000 | [diff] [blame] | 53 | void sendActualWorkDurationGroup(std::vector<WorkDuration> durations); |
| 54 | static constexpr std::chrono::duration kStaleTimeout = 100ms; |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 55 | }; |
| 56 | |
| 57 | void AidlPowerHalWrapperTest::SetUp() { |
Ady Abraham | d11bade | 2022-08-01 16:18:03 -0700 | [diff] [blame] | 58 | mMockHal = sp<NiceMock<MockIPower>>::make(); |
| 59 | mMockSession = sp<NiceMock<MockIPowerHintSession>>::make(); |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 60 | ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)).WillByDefault(Return(Status::ok())); |
| 61 | mWrapper = std::make_unique<AidlPowerHalWrapper>(mMockHal); |
| 62 | } |
| 63 | |
| 64 | void AidlPowerHalWrapperTest::verifyAndClearExpectations() { |
| 65 | Mock::VerifyAndClearExpectations(mMockHal.get()); |
| 66 | Mock::VerifyAndClearExpectations(mMockSession.get()); |
| 67 | } |
| 68 | |
Matt Buckley | 44e612e | 2022-08-30 22:02:37 +0000 | [diff] [blame] | 69 | void AidlPowerHalWrapperTest::sendActualWorkDurationGroup(std::vector<WorkDuration> durations) { |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 70 | for (size_t i = 0; i < durations.size(); i++) { |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 71 | auto duration = durations[i]; |
Matt Buckley | 2fa8501 | 2022-08-30 22:38:45 +0000 | [diff] [blame^] | 72 | mWrapper->sendActualWorkDuration(Duration::fromNs(duration.durationNanos), |
| 73 | TimePoint::fromNs(duration.timeStampNanos)); |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 74 | } |
| 75 | } |
Matt Buckley | 50c4406 | 2022-01-17 20:48:10 +0000 | [diff] [blame] | 76 | |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 77 | WorkDuration toWorkDuration(std::chrono::nanoseconds durationNanos, int64_t timeStampNanos) { |
| 78 | WorkDuration duration; |
| 79 | duration.durationNanos = durationNanos.count(); |
| 80 | duration.timeStampNanos = timeStampNanos; |
| 81 | return duration; |
| 82 | } |
| 83 | |
Matt Buckley | 50c4406 | 2022-01-17 20:48:10 +0000 | [diff] [blame] | 84 | WorkDuration toWorkDuration(std::pair<std::chrono::nanoseconds, nsecs_t> timePair) { |
| 85 | return toWorkDuration(timePair.first, timePair.second); |
| 86 | } |
| 87 | |
Xiang Wang | 0aba49e | 2022-04-06 16:13:59 +0000 | [diff] [blame] | 88 | std::string printWorkDurations(const ::std::vector<WorkDuration>& durations) { |
| 89 | std::ostringstream os; |
| 90 | for (auto duration : durations) { |
| 91 | os << duration.toString(); |
| 92 | os << "\n"; |
| 93 | } |
| 94 | return os.str(); |
| 95 | } |
| 96 | |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 97 | namespace { |
| 98 | TEST_F(AidlPowerHalWrapperTest, supportsPowerHintSession) { |
| 99 | ASSERT_TRUE(mWrapper->supportsPowerHintSession()); |
| 100 | Mock::VerifyAndClearExpectations(mMockHal.get()); |
| 101 | ON_CALL(*mMockHal.get(), getHintSessionPreferredRate(_)) |
| 102 | .WillByDefault(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE))); |
| 103 | auto newWrapper = AidlPowerHalWrapper(mMockHal); |
| 104 | EXPECT_FALSE(newWrapper.supportsPowerHintSession()); |
| 105 | } |
| 106 | |
| 107 | TEST_F(AidlPowerHalWrapperTest, startPowerHintSession) { |
| 108 | ASSERT_TRUE(mWrapper->supportsPowerHintSession()); |
| 109 | std::vector<int32_t> threadIds = {1, 2}; |
| 110 | mWrapper->setPowerHintSessionThreadIds(threadIds); |
| 111 | EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) |
| 112 | .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); |
| 113 | EXPECT_TRUE(mWrapper->startPowerHintSession()); |
| 114 | EXPECT_FALSE(mWrapper->startPowerHintSession()); |
| 115 | } |
| 116 | |
Matt Buckley | 50c4406 | 2022-01-17 20:48:10 +0000 | [diff] [blame] | 117 | TEST_F(AidlPowerHalWrapperTest, restartNewPowerHintSessionWithNewThreadIds) { |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 118 | ASSERT_TRUE(mWrapper->supportsPowerHintSession()); |
| 119 | |
| 120 | std::vector<int32_t> threadIds = {1, 2}; |
| 121 | EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) |
| 122 | .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); |
| 123 | mWrapper->setPowerHintSessionThreadIds(threadIds); |
| 124 | EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds); |
| 125 | ASSERT_TRUE(mWrapper->startPowerHintSession()); |
| 126 | verifyAndClearExpectations(); |
| 127 | |
| 128 | threadIds = {2, 3}; |
| 129 | EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) |
| 130 | .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); |
| 131 | EXPECT_CALL(*mMockSession.get(), close()).Times(1); |
| 132 | mWrapper->setPowerHintSessionThreadIds(threadIds); |
| 133 | EXPECT_EQ(mWrapper->getPowerHintSessionThreadIds(), threadIds); |
| 134 | verifyAndClearExpectations(); |
| 135 | |
| 136 | EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)).Times(0); |
| 137 | EXPECT_CALL(*mMockSession.get(), close()).Times(0); |
| 138 | mWrapper->setPowerHintSessionThreadIds(threadIds); |
| 139 | verifyAndClearExpectations(); |
| 140 | } |
| 141 | |
| 142 | TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration) { |
| 143 | ASSERT_TRUE(mWrapper->supportsPowerHintSession()); |
| 144 | |
| 145 | std::vector<int32_t> threadIds = {1, 2}; |
| 146 | mWrapper->setPowerHintSessionThreadIds(threadIds); |
| 147 | EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) |
| 148 | .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); |
| 149 | ASSERT_TRUE(mWrapper->startPowerHintSession()); |
| 150 | verifyAndClearExpectations(); |
| 151 | |
| 152 | std::chrono::nanoseconds base = 100ms; |
| 153 | // test cases with target work duration and whether it should update hint against baseline 100ms |
Matt Buckley | 50c4406 | 2022-01-17 20:48:10 +0000 | [diff] [blame] | 154 | const std::vector<std::pair<std::chrono::nanoseconds, bool>> testCases = |
| 155 | {{0ms, true}, {-1ms, true}, {200ms, true}, {2ms, true}, {100ms, false}, {109ms, true}}; |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 156 | |
| 157 | for (const auto& test : testCases) { |
| 158 | // reset to 100ms baseline |
Matt Buckley | 2fa8501 | 2022-08-30 22:38:45 +0000 | [diff] [blame^] | 159 | mWrapper->setTargetWorkDuration(1ns); |
| 160 | mWrapper->setTargetWorkDuration(base); |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 161 | |
Matt Buckley | 2fa8501 | 2022-08-30 22:38:45 +0000 | [diff] [blame^] | 162 | std::chrono::nanoseconds target = test.first; |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 163 | EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(target.count())) |
| 164 | .Times(test.second ? 1 : 0); |
Matt Buckley | 2fa8501 | 2022-08-30 22:38:45 +0000 | [diff] [blame^] | 165 | mWrapper->setTargetWorkDuration(target); |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 166 | verifyAndClearExpectations(); |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | TEST_F(AidlPowerHalWrapperTest, setTargetWorkDuration_shouldReconnectOnError) { |
| 171 | ASSERT_TRUE(mWrapper->supportsPowerHintSession()); |
| 172 | |
| 173 | std::vector<int32_t> threadIds = {1, 2}; |
| 174 | mWrapper->setPowerHintSessionThreadIds(threadIds); |
| 175 | EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) |
| 176 | .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); |
| 177 | ASSERT_TRUE(mWrapper->startPowerHintSession()); |
| 178 | verifyAndClearExpectations(); |
| 179 | |
| 180 | EXPECT_CALL(*mMockSession.get(), updateTargetWorkDuration(1)) |
| 181 | .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE))); |
Matt Buckley | 2fa8501 | 2022-08-30 22:38:45 +0000 | [diff] [blame^] | 182 | mWrapper->setTargetWorkDuration(1ns); |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 183 | EXPECT_TRUE(mWrapper->shouldReconnectHAL()); |
| 184 | } |
| 185 | |
| 186 | TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration) { |
| 187 | ASSERT_TRUE(mWrapper->supportsPowerHintSession()); |
| 188 | |
| 189 | std::vector<int32_t> threadIds = {1, 2}; |
| 190 | mWrapper->setPowerHintSessionThreadIds(threadIds); |
| 191 | EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) |
| 192 | .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); |
| 193 | ASSERT_TRUE(mWrapper->startPowerHintSession()); |
| 194 | verifyAndClearExpectations(); |
| 195 | |
| 196 | auto base = toWorkDuration(100ms, 0); |
| 197 | // test cases with actual work durations and whether it should update hint against baseline |
| 198 | // 100ms |
| 199 | const std::vector<std::pair<std::vector<std::pair<std::chrono::nanoseconds, nsecs_t>>, bool>> |
| 200 | testCases = {{{{-1ms, 100}}, false}, |
Matt Buckley | 44e612e | 2022-08-30 22:02:37 +0000 | [diff] [blame] | 201 | {{{50ms, 100}}, true}, |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 202 | {{{100ms, 100}, {200ms, 200}}, true}, |
| 203 | {{{100ms, 500}, {100ms, 600}, {3ms, 600}}, true}}; |
| 204 | |
| 205 | for (const auto& test : testCases) { |
| 206 | // reset actual duration |
Matt Buckley | 44e612e | 2022-08-30 22:02:37 +0000 | [diff] [blame] | 207 | sendActualWorkDurationGroup({base}); |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 208 | |
| 209 | auto raw = test.first; |
| 210 | std::vector<WorkDuration> durations(raw.size()); |
| 211 | std::transform(raw.begin(), raw.end(), durations.begin(), |
Matt Buckley | 50c4406 | 2022-01-17 20:48:10 +0000 | [diff] [blame] | 212 | [](auto d) { return toWorkDuration(d); }); |
Matt Buckley | 44e612e | 2022-08-30 22:02:37 +0000 | [diff] [blame] | 213 | for (auto& duration : durations) { |
| 214 | EXPECT_CALL(*mMockSession.get(), |
| 215 | reportActualWorkDuration(std::vector<WorkDuration>{duration})) |
| 216 | .Times(test.second ? 1 : 0); |
| 217 | } |
| 218 | sendActualWorkDurationGroup(durations); |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 219 | verifyAndClearExpectations(); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | TEST_F(AidlPowerHalWrapperTest, sendActualWorkDuration_shouldReconnectOnError) { |
| 224 | ASSERT_TRUE(mWrapper->supportsPowerHintSession()); |
| 225 | |
| 226 | std::vector<int32_t> threadIds = {1, 2}; |
| 227 | mWrapper->setPowerHintSessionThreadIds(threadIds); |
| 228 | EXPECT_CALL(*mMockHal.get(), createHintSession(_, _, threadIds, _, _)) |
| 229 | .WillOnce(DoAll(SetArgPointee<4>(mMockSession), Return(Status::ok()))); |
| 230 | ASSERT_TRUE(mWrapper->startPowerHintSession()); |
| 231 | verifyAndClearExpectations(); |
| 232 | WorkDuration duration; |
| 233 | duration.durationNanos = 1; |
| 234 | EXPECT_CALL(*mMockSession.get(), reportActualWorkDuration(_)) |
| 235 | .WillOnce(Return(Status::fromExceptionCode(Status::Exception::EX_ILLEGAL_STATE))); |
Matt Buckley | 44e612e | 2022-08-30 22:02:37 +0000 | [diff] [blame] | 236 | sendActualWorkDurationGroup({duration}); |
Xiang Wang | e12b4fa | 2022-03-25 23:48:40 +0000 | [diff] [blame] | 237 | EXPECT_TRUE(mWrapper->shouldReconnectHAL()); |
| 238 | } |
| 239 | |
| 240 | } // namespace |
| 241 | } // namespace android::Hwc2::impl |