diff options
author | Matt Buckley <mattbuckley@google.com> | 2022-08-12 21:54:23 +0000 |
---|---|---|
committer | Matt Buckley <mattbuckley@google.com> | 2022-08-19 21:13:40 +0000 |
commit | 5727405482a5f4b2177f08d5c7d2c76b1632a232 (patch) | |
tree | 5a9767500600054a276d68defa21ce83cf36b14a | |
parent | 0d4ac562fbf70ea385de91a3e56bd4183f00052e (diff) | |
download | native-5727405482a5f4b2177f08d5c7d2c76b1632a232.tar.gz |
Add additional tests for PowerAdvisor
Adds additional tests for PowerAdvisor functionality regarding
timing and multidisplay
Bug: b/241465879
Test: atest
libsurfaceflinger_unittest:libsurfaceflinger_unittest.PowerAdvisorTest
Change-Id: I833e91efb5608d5972220c679a061c9bb51372fa
6 files changed, 306 insertions, 20 deletions
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp index 4018c6b1af..a0350b717a 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp @@ -838,10 +838,7 @@ const bool AidlPowerHalWrapper::sTraceHintSessionData = base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false); PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { - static std::unique_ptr<HalWrapper> sHalWrapper = nullptr; - static bool sHasHal = true; - - if (!sHasHal) { + if (!mHasHal) { return nullptr; } @@ -849,57 +846,57 @@ PowerAdvisor::HalWrapper* PowerAdvisor::getPowerHal() { std::vector<int32_t> oldPowerHintSessionThreadIds; std::optional<int64_t> oldTargetWorkDuration; - if (sHalWrapper != nullptr) { - oldPowerHintSessionThreadIds = sHalWrapper->getPowerHintSessionThreadIds(); - oldTargetWorkDuration = sHalWrapper->getTargetWorkDuration(); + if (mHalWrapper != nullptr) { + oldPowerHintSessionThreadIds = mHalWrapper->getPowerHintSessionThreadIds(); + oldTargetWorkDuration = mHalWrapper->getTargetWorkDuration(); } // If we used to have a HAL, but it stopped responding, attempt to reconnect if (mReconnectPowerHal) { - sHalWrapper = nullptr; + mHalWrapper = nullptr; mReconnectPowerHal = false; } - if (sHalWrapper != nullptr) { - auto wrapper = sHalWrapper.get(); + if (mHalWrapper != nullptr) { + auto wrapper = mHalWrapper.get(); // If the wrapper is fine, return it, but if it indicates a reconnect, remake it if (!wrapper->shouldReconnectHAL()) { return wrapper; } ALOGD("Reconnecting Power HAL"); - sHalWrapper = nullptr; + mHalWrapper = nullptr; } // At this point, we know for sure there is no running session mPowerHintSessionRunning = false; // First attempt to connect to the AIDL Power HAL - sHalWrapper = AidlPowerHalWrapper::connect(); + mHalWrapper = AidlPowerHalWrapper::connect(); // If that didn't succeed, attempt to connect to the HIDL Power HAL - if (sHalWrapper == nullptr) { - sHalWrapper = HidlPowerHalWrapper::connect(); + if (mHalWrapper == nullptr) { + mHalWrapper = HidlPowerHalWrapper::connect(); } else { ALOGD("Successfully connecting AIDL Power HAL"); // If AIDL, pass on any existing hint session values - sHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds); + mHalWrapper->setPowerHintSessionThreadIds(oldPowerHintSessionThreadIds); // Only set duration and start if duration is defined if (oldTargetWorkDuration.has_value()) { - sHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration); + mHalWrapper->setTargetWorkDuration(*oldTargetWorkDuration); // Only start if possible to run and both threadids and duration are defined if (usePowerHintSession() && !oldPowerHintSessionThreadIds.empty()) { - mPowerHintSessionRunning = sHalWrapper->startPowerHintSession(); + mPowerHintSessionRunning = mHalWrapper->startPowerHintSession(); } } } // If we make it to this point and still don't have a HAL, it's unlikely we // will, so stop trying - if (sHalWrapper == nullptr) { - sHasHal = false; + if (mHalWrapper == nullptr) { + mHasHal = false; } - return sHalWrapper.get(); + return mHalWrapper.get(); } } // namespace impl diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h index 71a1f8c03b..6e25f787d7 100644 --- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h +++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h @@ -154,6 +154,13 @@ public: void setTotalFrameTargetWorkDuration(nsecs_t targetDuration) override; private: + friend class PowerAdvisorTest; + + // Tracks if powerhal exists + bool mHasHal = true; + // Holds the hal wrapper for getPowerHal + std::unique_ptr<HalWrapper> mHalWrapper GUARDED_BY(mPowerHalMutex) = nullptr; + HalWrapper* getPowerHal() REQUIRES(mPowerHalMutex); bool mReconnectPowerHal GUARDED_BY(mPowerHalMutex) = false; std::mutex mPowerHalMutex; diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 7823363e1e..004f31c562 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -24,6 +24,7 @@ package { filegroup { name: "libsurfaceflinger_mock_sources", srcs: [ + "mock/DisplayHardware/MockAidlPowerHalWrapper.cpp", "mock/DisplayHardware/MockComposer.cpp", "mock/DisplayHardware/MockHWC2.cpp", "mock/DisplayHardware/MockIPower.cpp", @@ -95,6 +96,7 @@ cc_test { "LayerTest.cpp", "LayerTestUtils.cpp", "MessageQueueTest.cpp", + "PowerAdvisorTest.cpp", "SurfaceFlinger_CreateDisplayTest.cpp", "SurfaceFlinger_DestroyDisplayTest.cpp", "SurfaceFlinger_DisplayModeSwitching.cpp", diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp new file mode 100644 index 0000000000..8711a42b2b --- /dev/null +++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp @@ -0,0 +1,203 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "PowerAdvisorTest" + +#include <DisplayHardware/PowerAdvisor.h> +#include <compositionengine/Display.h> +#include <ftl/fake_guard.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <ui/DisplayId.h> +#include <chrono> +#include "TestableSurfaceFlinger.h" +#include "mock/DisplayHardware/MockAidlPowerHalWrapper.h" + +using namespace android; +using namespace android::Hwc2::mock; +using namespace android::hardware::power; +using namespace std::chrono_literals; +using namespace testing; + +namespace android::Hwc2::impl { + +class PowerAdvisorTest : public testing::Test { +public: + void SetUp() override; + void startPowerHintSession(); + void fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod); + void setExpectedTiming(nsecs_t startTime, nsecs_t vsyncPeriod); + nsecs_t getFenceWaitDelayDuration(bool skipValidate); + +protected: + TestableSurfaceFlinger mFlinger; + std::unique_ptr<PowerAdvisor> mPowerAdvisor; + NiceMock<MockAidlPowerHalWrapper>* mMockAidlWrapper; + nsecs_t kErrorMargin = std::chrono::nanoseconds(1ms).count(); +}; + +void PowerAdvisorTest::SetUp() FTL_FAKE_GUARD(mPowerAdvisor->mPowerHalMutex) { + std::unique_ptr<MockAidlPowerHalWrapper> mockAidlWrapper = + std::make_unique<NiceMock<MockAidlPowerHalWrapper>>(); + mPowerAdvisor = std::make_unique<PowerAdvisor>(*mFlinger.flinger()); + ON_CALL(*mockAidlWrapper.get(), supportsPowerHintSession()).WillByDefault(Return(true)); + ON_CALL(*mockAidlWrapper.get(), startPowerHintSession()).WillByDefault(Return(true)); + mPowerAdvisor->mHalWrapper = std::move(mockAidlWrapper); + mMockAidlWrapper = + reinterpret_cast<NiceMock<MockAidlPowerHalWrapper>*>(mPowerAdvisor->mHalWrapper.get()); +} + +void PowerAdvisorTest::startPowerHintSession() { + const std::vector<int32_t> threadIds = {1, 2, 3}; + mPowerAdvisor->enablePowerHint(true); + mPowerAdvisor->startPowerHintSession(threadIds); +} + +void PowerAdvisorTest::setExpectedTiming(nsecs_t totalFrameTarget, nsecs_t expectedPresentTime) { + mPowerAdvisor->setTotalFrameTargetWorkDuration(totalFrameTarget); + mPowerAdvisor->setExpectedPresentTime(expectedPresentTime); +} + +void PowerAdvisorTest::fakeBasicFrameTiming(nsecs_t startTime, nsecs_t vsyncPeriod) { + mPowerAdvisor->setCommitStart(startTime); + mPowerAdvisor->setFrameDelay(0); + mPowerAdvisor->setTargetWorkDuration(vsyncPeriod); +} + +nsecs_t PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) { + return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate + : PowerAdvisor::kFenceWaitStartDelayValidated) + .count(); +} + +namespace { + +TEST_F(PowerAdvisorTest, hintSessionUseHwcDisplay) { + mPowerAdvisor->onBootFinished(); + startPowerHintSession(); + + std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)}; + + // 60hz + const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60; + const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count(); + const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count(); + + nsecs_t startTime = 100; + + // advisor only starts on frame 2 so do an initial no-op frame + fakeBasicFrameTiming(startTime, vsyncPeriod); + setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); + mPowerAdvisor->setDisplays(displayIds); + mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); + mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration); + + // increment the frame + startTime += vsyncPeriod; + + const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration; + EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); + + fakeBasicFrameTiming(startTime, vsyncPeriod); + setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); + mPowerAdvisor->setDisplays(displayIds); + mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000); + mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000); + mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); + mPowerAdvisor->sendActualWorkDuration(); +} + +TEST_F(PowerAdvisorTest, hintSessionSubtractsHwcFenceTime) { + mPowerAdvisor->onBootFinished(); + startPowerHintSession(); + + std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u)}; + + // 60hz + const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60; + const nsecs_t presentDuration = std::chrono::nanoseconds(5ms).count(); + const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count(); + const nsecs_t hwcBlockedDuration = std::chrono::nanoseconds(500us).count(); + + nsecs_t startTime = 100; + + // advisor only starts on frame 2 so do an initial no-op frame + fakeBasicFrameTiming(startTime, vsyncPeriod); + setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); + mPowerAdvisor->setDisplays(displayIds); + mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); + mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration); + + // increment the frame + startTime += vsyncPeriod; + + const nsecs_t expectedDuration = kErrorMargin + presentDuration + + getFenceWaitDelayDuration(false) - hwcBlockedDuration + postCompDuration; + EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); + + fakeBasicFrameTiming(startTime, vsyncPeriod); + setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); + mPowerAdvisor->setDisplays(displayIds); + mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000); + mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 3000000); + // now report the fence as having fired during the display HWC time + mPowerAdvisor->setSfPresentTiming(startTime + 2000000 + hwcBlockedDuration, + startTime + presentDuration); + mPowerAdvisor->sendActualWorkDuration(); +} + +TEST_F(PowerAdvisorTest, hintSessionUsingSecondaryVirtualDisplays) { + mPowerAdvisor->onBootFinished(); + startPowerHintSession(); + + std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0), + GpuVirtualDisplayId(1)}; + + // 60hz + const nsecs_t vsyncPeriod = std::chrono::nanoseconds(1s).count() / 60; + // make present duration much later than the hwc display by itself will account for + const nsecs_t presentDuration = std::chrono::nanoseconds(10ms).count(); + const nsecs_t postCompDuration = std::chrono::nanoseconds(1ms).count(); + + nsecs_t startTime = 100; + + // advisor only starts on frame 2 so do an initial no-op frame + fakeBasicFrameTiming(startTime, vsyncPeriod); + setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); + mPowerAdvisor->setDisplays(displayIds); + mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); + mPowerAdvisor->setCompositeEnd(startTime + presentDuration + postCompDuration); + + // increment the frame + startTime += vsyncPeriod; + + const nsecs_t expectedDuration = kErrorMargin + presentDuration + postCompDuration; + EXPECT_CALL(*mMockAidlWrapper, sendActualWorkDuration(Eq(expectedDuration), _)).Times(1); + + fakeBasicFrameTiming(startTime, vsyncPeriod); + setExpectedTiming(vsyncPeriod, startTime + vsyncPeriod); + mPowerAdvisor->setDisplays(displayIds); + + // don't report timing for the gpu displays since they don't use hwc + mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime + 1000000, startTime + 1500000); + mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime + 2000000, startTime + 2500000); + mPowerAdvisor->setSfPresentTiming(startTime, startTime + presentDuration); + mPowerAdvisor->sendActualWorkDuration(); +} + +} // namespace +} // namespace android::Hwc2::impl diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp new file mode 100644 index 0000000000..5049b1d367 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "MockAidlPowerHalWrapper.h" +#include "MockIPower.h" + +namespace android::Hwc2::mock { + +MockAidlPowerHalWrapper::MockAidlPowerHalWrapper() + : AidlPowerHalWrapper(sp<testing::NiceMock<MockIPower>>::make()){}; +MockAidlPowerHalWrapper::~MockAidlPowerHalWrapper() = default; + +} // namespace android::Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h new file mode 100644 index 0000000000..657ced3d08 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockAidlPowerHalWrapper.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <gmock/gmock.h> + +#include "DisplayHardware/PowerAdvisor.h" + +namespace android { +namespace hardware { +namespace power { +class IPower; +} +} // namespace hardware +} // namespace android + +namespace android::Hwc2::mock { + +class MockAidlPowerHalWrapper : public Hwc2::impl::AidlPowerHalWrapper { +public: + MockAidlPowerHalWrapper(); + ~MockAidlPowerHalWrapper() override; + MOCK_METHOD(bool, setExpensiveRendering, (bool enabled), (override)); + MOCK_METHOD(bool, notifyDisplayUpdateImminent, (), (override)); + MOCK_METHOD(bool, supportsPowerHintSession, (), (override)); + MOCK_METHOD(bool, isPowerHintSessionRunning, (), (override)); + MOCK_METHOD(void, restartPowerHintSession, (), (override)); + MOCK_METHOD(void, setPowerHintSessionThreadIds, (const std::vector<int32_t>& threadIds), + (override)); + MOCK_METHOD(bool, startPowerHintSession, (), (override)); + MOCK_METHOD(void, setTargetWorkDuration, (nsecs_t targetDuration), (override)); + MOCK_METHOD(void, sendActualWorkDuration, (nsecs_t actualDuration, nsecs_t timestamp), + (override)); + MOCK_METHOD(bool, shouldReconnectHAL, (), (override)); +}; + +} // namespace android::Hwc2::mock
\ No newline at end of file |