Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 691c31df authored by Matt Buckley's avatar Matt Buckley Committed by Automerger Merge Worker
Browse files

Add additional tests for PowerAdvisor am: 57274054 am: e3f13500

parents 8b294d52 e3f13500
Loading
Loading
Loading
Loading
+17 −20
Original line number Diff line number Diff line
@@ -839,10 +839,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;
    }

@@ -850,57 +847,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
+7 −0
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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",
+203 −0
Original line number Diff line number Diff line
/*
 * 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
+26 −0
Original line number Diff line number Diff line
/*
 * 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
Loading