Add FMQ support in PowerAdvisor
Bug: 284324521
Flag: android.os.adpf_use_fmq_channel_fixed
Test: atest PowerAdvisorTest
Change-Id: Iec3d861d1a7603cbe6b924453344725431573ed7
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 96d5ca6..6c1a813 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -46,10 +46,21 @@
namespace impl {
using aidl::android::hardware::power::Boost;
+using aidl::android::hardware::power::ChannelConfig;
using aidl::android::hardware::power::Mode;
using aidl::android::hardware::power::SessionHint;
using aidl::android::hardware::power::SessionTag;
using aidl::android::hardware::power::WorkDuration;
+using aidl::android::hardware::power::WorkDurationFixedV1;
+
+using aidl::android::hardware::common::fmq::MQDescriptor;
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::power::ChannelMessage;
+using android::hardware::EventFlag;
+
+using ChannelMessageContents = ChannelMessage::ChannelMessageContents;
+using MsgQueue = android::AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>;
+using FlagQueue = android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
PowerAdvisor::~PowerAdvisor() = default;
@@ -140,15 +151,7 @@
if (!mBootFinished.load()) {
return;
}
- if (usePowerHintSession()) {
- std::lock_guard lock(mHintSessionMutex);
- if (ensurePowerHintSessionRunning()) {
- auto ret = mHintSession->sendHint(SessionHint::CPU_LOAD_UP);
- if (!ret.isOk()) {
- mHintSession = nullptr;
- }
- }
- }
+ sendHintSessionHint(SessionHint::CPU_LOAD_UP);
}
void PowerAdvisor::notifyDisplayUpdateImminentAndCpuReset() {
@@ -160,15 +163,7 @@
if (mSendUpdateImminent.exchange(false)) {
ALOGV("AIDL notifyDisplayUpdateImminentAndCpuReset");
- if (usePowerHintSession()) {
- std::lock_guard lock(mHintSessionMutex);
- if (ensurePowerHintSessionRunning()) {
- auto ret = mHintSession->sendHint(SessionHint::CPU_LOAD_RESET);
- if (!ret.isOk()) {
- mHintSession = nullptr;
- }
- }
- }
+ sendHintSessionHint(SessionHint::CPU_LOAD_RESET);
if (!mHasDisplayUpdateImminent) {
ALOGV("Skipped sending DISPLAY_UPDATE_IMMINENT because HAL doesn't support it");
@@ -210,6 +205,30 @@
FlagManager::getInstance().adpf_use_fmq_channel();
}
+void PowerAdvisor::sendHintSessionHint(SessionHint hint) {
+ if (!mBootFinished || !usePowerHintSession()) {
+ ALOGV("Power hint session is not enabled, skip sending session hint");
+ return;
+ }
+ ATRACE_CALL();
+ if (sTraceHintSessionData) ATRACE_INT("Session hint", static_cast<int>(hint));
+ {
+ std::scoped_lock lock(mHintSessionMutex);
+ if (!ensurePowerHintSessionRunning()) {
+ ALOGV("Hint session not running and could not be started, skip sending session hint");
+ return;
+ }
+ ALOGV("Sending session hint: %d", static_cast<int>(hint));
+ if (!writeHintSessionMessage<ChannelMessageContents::Tag::hint>(&hint, 1)) {
+ auto ret = mHintSession->sendHint(hint);
+ if (!ret.isOk()) {
+ ALOGW("Failed to send session hint with error: %s", ret.errorMessage());
+ mHintSession = nullptr;
+ }
+ }
+ }
+}
+
bool PowerAdvisor::ensurePowerHintSessionRunning() {
if (mHintSession == nullptr && !mHintSessionThreadIds.empty() && usePowerHintSession()) {
if (shouldCreateSessionWithConfig()) {
@@ -221,6 +240,9 @@
&mSessionConfig);
if (ret.isOk()) {
mHintSession = ret.value();
+ if (FlagManager::getInstance().adpf_use_fmq_channel_fixed()) {
+ setUpFmq();
+ }
}
// If it fails the first time we try, or ever returns unsupported, assume unsupported
else if (mFirstConfigSupportCheck || ret.isUnsupported()) {
@@ -241,9 +263,36 @@
return mHintSession != nullptr;
}
+void PowerAdvisor::setUpFmq() {
+ auto&& channelRet = getPowerHal().getSessionChannel(getpid(), static_cast<int32_t>(getuid()));
+ if (!channelRet.isOk()) {
+ ALOGE("Failed to get session channel with error: %s", channelRet.errorMessage());
+ return;
+ }
+ auto& channelConfig = channelRet.value();
+ mMsgQueue = std::make_unique<MsgQueue>(std::move(channelConfig.channelDescriptor), true);
+ LOG_ALWAYS_FATAL_IF(!mMsgQueue->isValid(), "Failed to set up hint session msg queue");
+ LOG_ALWAYS_FATAL_IF(channelConfig.writeFlagBitmask <= 0,
+ "Invalid flag bit masks found in channel config: writeBitMask(%d)",
+ channelConfig.writeFlagBitmask);
+ mFmqWriteMask = static_cast<uint32_t>(channelConfig.writeFlagBitmask);
+ if (!channelConfig.eventFlagDescriptor.has_value()) {
+ // For FMQ v1 in Android 15 we will force using shared event flag since the default
+ // no-op FMQ impl in Power HAL v5 will always return a valid channel config with
+ // non-zero masks but no shared flag.
+ mMsgQueue = nullptr;
+ ALOGE("No event flag descriptor found in channel config");
+ return;
+ }
+ mFlagQueue = std::make_unique<FlagQueue>(std::move(*channelConfig.eventFlagDescriptor), true);
+ LOG_ALWAYS_FATAL_IF(!mFlagQueue->isValid(), "Failed to set up hint session flag queue");
+ auto status = EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(), &mEventFlag);
+ LOG_ALWAYS_FATAL_IF(status != OK, "Failed to set up hint session event flag");
+}
+
void PowerAdvisor::updateTargetWorkDuration(Duration targetDuration) {
if (!mBootFinished || !usePowerHintSession()) {
- ALOGV("Power hint session target duration cannot be set, skipping");
+ ALOGV("Power hint session is not enabled, skipping target update");
return;
}
ATRACE_CALL();
@@ -251,10 +300,15 @@
mTargetDuration = targetDuration;
if (sTraceHintSessionData) ATRACE_INT64("Time target", targetDuration.ns());
if (targetDuration == mLastTargetDurationSent) return;
- std::lock_guard lock(mHintSessionMutex);
- if (ensurePowerHintSessionRunning()) {
- ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns());
- mLastTargetDurationSent = targetDuration;
+ std::scoped_lock lock(mHintSessionMutex);
+ if (!ensurePowerHintSessionRunning()) {
+ ALOGV("Hint session not running and could not be started, skip updating target");
+ return;
+ }
+ ALOGV("Sending target time: %" PRId64 "ns", targetDuration.ns());
+ mLastTargetDurationSent = targetDuration;
+ auto target = targetDuration.ns();
+ if (!writeHintSessionMessage<ChannelMessageContents::Tag::targetDuration>(&target, 1)) {
auto ret = mHintSession->updateTargetWorkDuration(targetDuration.ns());
if (!ret.isOk()) {
ALOGW("Failed to set power hint target work duration with error: %s",
@@ -302,23 +356,73 @@
}
{
- std::lock_guard lock(mHintSessionMutex);
+ std::scoped_lock lock(mHintSessionMutex);
if (!ensurePowerHintSessionRunning()) {
- ALOGV("Hint session not running and could not be started, skipping");
+ ALOGV("Hint session not running and could not be started, skip reporting durations");
return;
}
mHintSessionQueue.push_back(*actualDuration);
-
- auto ret = mHintSession->reportActualWorkDuration(mHintSessionQueue);
- if (!ret.isOk()) {
- ALOGW("Failed to report actual work durations with error: %s", ret.errorMessage());
- mHintSession = nullptr;
- return;
+ if (!writeHintSessionMessage<
+ ChannelMessageContents::Tag::workDuration>(mHintSessionQueue.data(),
+ mHintSessionQueue.size())) {
+ auto ret = mHintSession->reportActualWorkDuration(mHintSessionQueue);
+ if (!ret.isOk()) {
+ ALOGW("Failed to report actual work durations with error: %s", ret.errorMessage());
+ mHintSession = nullptr;
+ return;
+ }
}
}
mHintSessionQueue.clear();
}
+template <ChannelMessage::ChannelMessageContents::Tag T, class In>
+bool PowerAdvisor::writeHintSessionMessage(In* contents, size_t count) {
+ if (!mMsgQueue) {
+ ALOGV("Skip using FMQ with message tag %hhd as it's not supported", T);
+ return false;
+ }
+ auto availableSize = mMsgQueue->availableToWrite();
+ if (availableSize < count) {
+ ALOGW("Skip using FMQ with message tag %hhd as there isn't enough space", T);
+ return false;
+ }
+ MsgQueue::MemTransaction tx;
+ if (!mMsgQueue->beginWrite(count, &tx)) {
+ ALOGW("Failed to begin writing message with tag %hhd", T);
+ return false;
+ }
+ for (size_t i = 0; i < count; ++i) {
+ if constexpr (T == ChannelMessageContents::Tag::workDuration) {
+ const WorkDuration& duration = contents[i];
+ new (tx.getSlot(i)) ChannelMessage{
+ .sessionID = static_cast<int32_t>(mSessionConfig.id),
+ .timeStampNanos =
+ (i == count - 1) ? ::android::uptimeNanos() : duration.timeStampNanos,
+ .data = ChannelMessageContents::make<ChannelMessageContents::Tag::workDuration,
+ WorkDurationFixedV1>({
+ .durationNanos = duration.durationNanos,
+ .workPeriodStartTimestampNanos = duration.workPeriodStartTimestampNanos,
+ .cpuDurationNanos = duration.cpuDurationNanos,
+ .gpuDurationNanos = duration.gpuDurationNanos,
+ }),
+ };
+ } else {
+ new (tx.getSlot(i)) ChannelMessage{
+ .sessionID = static_cast<int32_t>(mSessionConfig.id),
+ .timeStampNanos = ::android::uptimeNanos(),
+ .data = ChannelMessageContents::make<T, In>(std::move(contents[i])),
+ };
+ }
+ }
+ if (!mMsgQueue->commitWrite(count)) {
+ ALOGW("Failed to send message with tag %hhd, fall back to binder call", T);
+ return false;
+ }
+ mEventFlag->wake(mFmqWriteMask);
+ return true;
+}
+
void PowerAdvisor::enablePowerHintSession(bool enabled) {
mHintSessionEnabled = enabled;
}
@@ -334,12 +438,14 @@
}
LOG_ALWAYS_FATAL_IF(mHintSessionThreadIds.empty(),
"No thread IDs provided to power hint session!");
- std::lock_guard lock(mHintSessionMutex);
- if (mHintSession != nullptr) {
- ALOGE("Cannot start power hint session: already running");
- return false;
+ {
+ std::scoped_lock lock(mHintSessionMutex);
+ if (mHintSession != nullptr) {
+ ALOGE("Cannot start power hint session: already running");
+ return false;
+ }
+ return ensurePowerHintSessionRunning();
}
- return ensurePowerHintSessionRunning();
}
bool PowerAdvisor::supportsGpuReporting() {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 161ca63..bc4a41b 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -29,6 +29,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#include <aidl/android/hardware/power/IPower.h>
+#include <fmq/AidlMessageQueue.h>
#include <powermanager/PowerHalController.h>
#pragma clang diagnostic pop
@@ -237,6 +238,7 @@
bool shouldCreateSessionWithConfig() REQUIRES(mHintSessionMutex);
bool ensurePowerHintSessionRunning() REQUIRES(mHintSessionMutex);
+ void setUpFmq() REQUIRES(mHintSessionMutex);
std::unordered_map<DisplayId, DisplayTimingData> mDisplayTimingData;
// Current frame's delay
Duration mFrameDelayDuration{0ns};
@@ -272,6 +274,15 @@
bool mHasDisplayUpdateImminent = true;
// Queue of actual durations saved to report
std::vector<aidl::android::hardware::power::WorkDuration> mHintSessionQueue;
+ std::unique_ptr<::android::AidlMessageQueue<
+ aidl::android::hardware::power::ChannelMessage,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>
+ mMsgQueue GUARDED_BY(mHintSessionMutex);
+ std::unique_ptr<::android::AidlMessageQueue<
+ int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>>
+ mFlagQueue GUARDED_BY(mHintSessionMutex);
+ android::hardware::EventFlag* mEventFlag;
+ uint32_t mFmqWriteMask;
// The latest values we have received for target and actual
Duration mTargetDuration = kDefaultTargetDuration;
// The list of thread ids, stored so we can restart the session from this class if needed
@@ -306,6 +317,12 @@
// How long we expect hwc to run after the present call until it waits for the fence
static constexpr const Duration kFenceWaitStartDelayValidated{150us};
static constexpr const Duration kFenceWaitStartDelaySkippedValidate{250us};
+
+ void sendHintSessionHint(aidl::android::hardware::power::SessionHint hint);
+
+ template <aidl::android::hardware::power::ChannelMessage::ChannelMessageContents::Tag T,
+ class In>
+ bool writeHintSessionMessage(In* elements, size_t count) REQUIRES(mHintSessionMutex);
};
} // namespace impl
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index f074b7d..45b3290 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -249,5 +249,6 @@
/// Trunk stable readonly flags from outside SurfaceFlinger ///
FLAG_MANAGER_READ_ONLY_FLAG_IMPORTED(idle_screen_refresh_rate_timeout, "",
com::android::server::display::feature::flags)
+FLAG_MANAGER_READ_ONLY_FLAG_IMPORTED(adpf_use_fmq_channel_fixed, "", android::os)
} // namespace android
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index 0acf754..592e774 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -51,6 +51,7 @@
bool refresh_rate_overlay_on_external_display() const;
bool adpf_gpu_sf() const;
bool adpf_use_fmq_channel() const;
+ bool adpf_use_fmq_channel_fixed() const;
/// Trunk stable readonly flags ///
bool connected_display() const;
diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
index 86ad86e..e74f643 100644
--- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
@@ -45,6 +45,7 @@
class PowerAdvisorTest : public testing::Test {
public:
void SetUp() override;
+ void SetUpFmq(bool usesSharedEventFlag, bool isQueueFull);
void startPowerHintSession(bool returnValidSession = true);
void fakeBasicFrameTiming(TimePoint startTime, Duration vsyncPeriod);
void setExpectedTiming(Duration totalFrameTargetDuration, TimePoint expectedPresentTime);
@@ -64,16 +65,26 @@
Duration postCompDuration = 0ms;
bool frame1RequiresRenderEngine;
bool frame2RequiresRenderEngine;
+ bool usesFmq = false;
+ bool usesSharedFmqFlag = true;
+ bool fmqFull = false;
};
- WorkDuration testGpuScenario(GpuTestConfig& config);
+ void testGpuScenario(GpuTestConfig& config, WorkDuration& ret);
protected:
TestableSurfaceFlinger mFlinger;
std::unique_ptr<PowerAdvisor> mPowerAdvisor;
MockPowerHalController* mMockPowerHalController;
std::shared_ptr<MockPowerHintSessionWrapper> mMockPowerHintSession;
+ std::shared_ptr<AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>> mBackendFmq;
+ std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> mBackendFlagQueue;
+ android::hardware::EventFlag* mEventFlag;
+ uint32_t mWriteFlagBitmask = 2;
+ uint32_t mReadFlagBitmask = 1;
+ int64_t mSessionId = 123;
SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel, true);
+ SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, false);
};
bool PowerAdvisorTest::sessionExists() {
@@ -95,12 +106,44 @@
ByMove(HalResult<int64_t>::fromStatus(ndk::ScopedAStatus::ok(), 16000))));
}
+void PowerAdvisorTest::SetUpFmq(bool usesSharedEventFlag, bool isQueueFull) {
+ mBackendFmq = std::make_shared<
+ AidlMessageQueue<ChannelMessage, SynchronizedReadWrite>>(2, !usesSharedEventFlag);
+ ChannelConfig config;
+ config.channelDescriptor = mBackendFmq->dupeDesc();
+ if (usesSharedEventFlag) {
+ mBackendFlagQueue =
+ std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(1, true);
+ config.eventFlagDescriptor = mBackendFlagQueue->dupeDesc();
+ ASSERT_EQ(android::hardware::EventFlag::createEventFlag(mBackendFlagQueue
+ ->getEventFlagWord(),
+ &mEventFlag),
+ android::NO_ERROR);
+ } else {
+ ASSERT_EQ(android::hardware::EventFlag::createEventFlag(mBackendFmq->getEventFlagWord(),
+ &mEventFlag),
+ android::NO_ERROR);
+ }
+ config.writeFlagBitmask = static_cast<int32_t>(mWriteFlagBitmask);
+ config.readFlagBitmask = static_cast<int32_t>(mReadFlagBitmask);
+ ON_CALL(*mMockPowerHalController, getSessionChannel)
+ .WillByDefault(Return(
+ ByMove(HalResult<ChannelConfig>::fromStatus(Status::ok(), std::move(config)))));
+ startPowerHintSession();
+ if (isQueueFull) {
+ std::vector<ChannelMessage> msgs;
+ msgs.resize(2);
+ mBackendFmq->writeBlocking(msgs.data(), 2, mReadFlagBitmask, mWriteFlagBitmask,
+ std::chrono::nanoseconds(1ms).count(), mEventFlag);
+ }
+}
+
void PowerAdvisorTest::startPowerHintSession(bool returnValidSession) {
mMockPowerHintSession = std::make_shared<NiceMock<MockPowerHintSessionWrapper>>();
if (returnValidSession) {
ON_CALL(*mMockPowerHalController, createHintSessionWithConfig)
.WillByDefault(DoAll(SetArgPointee<5>(aidl::android::hardware::power::SessionConfig{
- .id = 12}),
+ .id = mSessionId}),
Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
fromStatus(binder::Status::ok(),
mMockPowerHintSession))));
@@ -137,11 +180,17 @@
mPowerAdvisor->mDelayReportActualMutexAcquisitonPromise.set_value(true);
}
-WorkDuration PowerAdvisorTest::testGpuScenario(GpuTestConfig& config) {
+void PowerAdvisorTest::testGpuScenario(GpuTestConfig& config, WorkDuration& ret) {
SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_gpu_sf,
config.adpfGpuFlagOn);
+ SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, config.usesFmq);
mPowerAdvisor->onBootFinished();
- startPowerHintSession();
+ bool expectsFmqSuccess = config.usesSharedFmqFlag && !config.fmqFull;
+ if (config.usesFmq) {
+ SetUpFmq(config.usesSharedFmqFlag, config.fmqFull);
+ } else {
+ startPowerHintSession();
+ }
std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
GpuVirtualDisplayId(1)};
@@ -150,8 +199,41 @@
// 60hz
TimePoint startTime = TimePoint::now();
+ int64_t target;
+ SessionHint hint;
+ if (!config.usesFmq || !expectsFmqSuccess) {
+ EXPECT_CALL(*mMockPowerHintSession, updateTargetWorkDuration(_))
+ .Times(1)
+ .WillOnce(DoAll(testing::SaveArg<0>(&target),
+ testing::Return(testing::ByMove(HalResult<void>::ok()))));
+ EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
+ .Times(1)
+ .WillOnce(DoAll(testing::SaveArg<0>(&hint),
+ testing::Return(testing::ByMove(HalResult<void>::ok()))));
+ }
// advisor only starts on frame 2 so do an initial frame
fakeBasicFrameTiming(startTime, config.vsyncPeriod);
+ // send a load hint
+ mPowerAdvisor->notifyCpuLoadUp();
+ if (config.usesFmq && expectsFmqSuccess) {
+ std::vector<ChannelMessage> msgs;
+ ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
+ msgs.resize(2);
+ ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 2, mReadFlagBitmask, mWriteFlagBitmask,
+ std::chrono::nanoseconds(1ms).count(), mEventFlag));
+ ASSERT_EQ(msgs[0].sessionID, mSessionId);
+ ASSERT_GE(msgs[0].timeStampNanos, startTime.ns());
+ ASSERT_EQ(msgs[0].data.getTag(),
+ ChannelMessage::ChannelMessageContents::Tag::targetDuration);
+ target = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::targetDuration>();
+ ASSERT_EQ(msgs[1].sessionID, mSessionId);
+ ASSERT_GE(msgs[1].timeStampNanos, startTime.ns());
+ ASSERT_EQ(msgs[1].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::hint);
+ hint = msgs[1].data.get<ChannelMessage::ChannelMessageContents::Tag::hint>();
+ }
+ ASSERT_EQ(target, config.vsyncPeriod.ns());
+ ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
+
setExpectedTiming(config.vsyncPeriod, startTime + config.vsyncPeriod);
// report GPU
@@ -171,6 +253,10 @@
std::this_thread::sleep_for(config.vsyncPeriod);
startTime = TimePoint::now();
fakeBasicFrameTiming(startTime, config.vsyncPeriod);
+ if (config.usesFmq && expectsFmqSuccess) {
+ // same target update will not trigger FMQ write
+ ASSERT_EQ(mBackendFmq->availableToRead(), 0uL);
+ }
setExpectedTiming(config.vsyncPeriod, startTime + config.vsyncPeriod);
// report GPU
@@ -192,14 +278,31 @@
mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime, startTime);
mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime, startTime);
- std::vector<aidl::android::hardware::power::WorkDuration> durationReq;
- EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration(_))
- .Times(1)
- .WillOnce(DoAll(testing::SaveArg<0>(&durationReq),
- testing::Return(testing::ByMove(HalResult<void>::ok()))));
- mPowerAdvisor->reportActualWorkDuration();
- EXPECT_EQ(durationReq.size(), 1u);
- return durationReq[0];
+ if (config.usesFmq && expectsFmqSuccess) {
+ mPowerAdvisor->reportActualWorkDuration();
+ ASSERT_EQ(mBackendFmq->availableToRead(), 1uL);
+ std::vector<ChannelMessage> msgs;
+ msgs.resize(1);
+ ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
+ std::chrono::nanoseconds(1ms).count(), mEventFlag));
+ ASSERT_EQ(msgs[0].sessionID, mSessionId);
+ ASSERT_GE(msgs[0].timeStampNanos, startTime.ns());
+ ASSERT_EQ(msgs[0].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::workDuration);
+ auto actual = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::workDuration>();
+ ret.workPeriodStartTimestampNanos = actual.workPeriodStartTimestampNanos;
+ ret.cpuDurationNanos = actual.cpuDurationNanos;
+ ret.gpuDurationNanos = actual.gpuDurationNanos;
+ ret.durationNanos = actual.durationNanos;
+ } else {
+ std::vector<aidl::android::hardware::power::WorkDuration> durationReq;
+ EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration(_))
+ .Times(1)
+ .WillOnce(DoAll(testing::SaveArg<0>(&durationReq),
+ testing::Return(testing::ByMove(HalResult<void>::ok()))));
+ mPowerAdvisor->reportActualWorkDuration();
+ ASSERT_EQ(durationReq.size(), 1u);
+ ret = std::move(durationReq[0]);
+ }
}
Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
@@ -375,13 +478,6 @@
mPowerAdvisor->reportActualWorkDuration();
}
-TEST_F(PowerAdvisorTest, hintSessionOnlyCreatedOnce) {
- EXPECT_CALL(*mMockPowerHalController, createHintSessionWithConfig(_, _, _, _, _, _)).Times(1);
- mPowerAdvisor->onBootFinished();
- startPowerHintSession();
- mPowerAdvisor->startPowerHintSession({1, 2, 3});
-}
-
TEST_F(PowerAdvisorTest, hintSessionTestNotifyReportRace) {
// notifyDisplayUpdateImminentAndCpuReset or notifyCpuLoadUp gets called in background
// reportActual gets called during callback and sees true session, passes ensure
@@ -464,15 +560,21 @@
}
TEST_F(PowerAdvisorTest, legacyHintSessionCreationStillWorks) {
- SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel, false);
mPowerAdvisor->onBootFinished();
mMockPowerHintSession = std::make_shared<NiceMock<MockPowerHintSessionWrapper>>();
+ EXPECT_CALL(*mMockPowerHalController, createHintSessionWithConfig)
+ .Times(1)
+ .WillOnce(Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
+ fromStatus(ndk::ScopedAStatus::fromExceptionCode(
+ EX_UNSUPPORTED_OPERATION),
+ nullptr)));
+
EXPECT_CALL(*mMockPowerHalController, createHintSession)
.Times(1)
.WillOnce(Return(HalResult<std::shared_ptr<PowerHintSessionWrapper>>::
fromStatus(binder::Status::ok(), mMockPowerHintSession)));
mPowerAdvisor->enablePowerHintSession(true);
- mPowerAdvisor->startPowerHintSession({1, 2, 3});
+ ASSERT_TRUE(mPowerAdvisor->startPowerHintSession({1, 2, 3}));
}
TEST_F(PowerAdvisorTest, setGpuFenceTime_cpuThenGpuFrames) {
@@ -487,7 +589,8 @@
.frame1RequiresRenderEngine = false,
.frame2RequiresRenderEngine = true,
};
- WorkDuration res = testGpuScenario(config);
+ WorkDuration res;
+ testGpuScenario(config, res);
EXPECT_EQ(res.gpuDurationNanos, 0L);
EXPECT_EQ(res.cpuDurationNanos, 0L);
EXPECT_GE(res.durationNanos, toNanos(30ms + getErrorMargin()));
@@ -505,7 +608,8 @@
.frame1RequiresRenderEngine = false,
.frame2RequiresRenderEngine = true,
};
- WorkDuration res = testGpuScenario(config);
+ WorkDuration res;
+ testGpuScenario(config, res);
EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
EXPECT_EQ(res.durationNanos, toNanos(30ms + getErrorMargin()));
@@ -523,7 +627,8 @@
.frame1RequiresRenderEngine = true,
.frame2RequiresRenderEngine = false,
};
- WorkDuration res = testGpuScenario(config);
+ WorkDuration res;
+ testGpuScenario(config, res);
EXPECT_EQ(res.gpuDurationNanos, 0L);
EXPECT_EQ(res.cpuDurationNanos, 0L);
EXPECT_EQ(res.durationNanos, toNanos(10ms + getErrorMargin()));
@@ -540,7 +645,8 @@
.frame1RequiresRenderEngine = true,
.frame2RequiresRenderEngine = false,
};
- WorkDuration res = testGpuScenario(config);
+ WorkDuration res;
+ testGpuScenario(config, res);
EXPECT_EQ(res.gpuDurationNanos, 0L);
EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
EXPECT_EQ(res.durationNanos, toNanos(10ms + getErrorMargin()));
@@ -559,7 +665,8 @@
.frame1RequiresRenderEngine = true,
.frame2RequiresRenderEngine = true,
};
- WorkDuration res = testGpuScenario(config);
+ WorkDuration res;
+ testGpuScenario(config, res);
EXPECT_EQ(res.gpuDurationNanos, 0L);
EXPECT_EQ(res.cpuDurationNanos, 0L);
EXPECT_GE(res.durationNanos, toNanos(50ms + getErrorMargin()));
@@ -577,7 +684,8 @@
.frame1RequiresRenderEngine = true,
.frame2RequiresRenderEngine = true,
};
- WorkDuration res = testGpuScenario(config);
+ WorkDuration res;
+ testGpuScenario(config, res);
EXPECT_EQ(res.gpuDurationNanos, toNanos(50ms));
EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
EXPECT_EQ(res.durationNanos, toNanos(50ms + getErrorMargin()));
@@ -594,7 +702,8 @@
.frame1RequiresRenderEngine = true,
.frame2RequiresRenderEngine = true,
};
- WorkDuration res = testGpuScenario(config);
+ WorkDuration res;
+ testGpuScenario(config, res);
EXPECT_EQ(res.gpuDurationNanos, 0L);
EXPECT_EQ(res.cpuDurationNanos, 0L);
EXPECT_GE(res.durationNanos, toNanos(30ms + getErrorMargin()));
@@ -612,11 +721,122 @@
.frame1RequiresRenderEngine = true,
.frame2RequiresRenderEngine = true,
};
- WorkDuration res = testGpuScenario(config);
+ WorkDuration res;
+ testGpuScenario(config, res);
EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
}
+TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = true,
+ .frame1GpuFenceDuration = 30ms,
+ .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
+ .vsyncPeriod = 10ms,
+ .presentDuration = 22ms,
+ .postCompDuration = 88ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = true,
+ .usesFmq = true,
+ .usesSharedFmqFlag = true,
+ };
+ WorkDuration res;
+ testGpuScenario(config, res);
+ EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
+ EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
+ EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration_noSharedFlag) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = true,
+ .frame1GpuFenceDuration = 30ms,
+ .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
+ .vsyncPeriod = 10ms,
+ .presentDuration = 22ms,
+ .postCompDuration = 88ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = true,
+ .usesFmq = true,
+ .usesSharedFmqFlag = false,
+ };
+ WorkDuration res;
+ testGpuScenario(config, res);
+ EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
+ EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
+ EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, fmq_sendTargetAndActualDuration_queueFull) {
+ GpuTestConfig config{.adpfGpuFlagOn = true,
+ .frame1GpuFenceDuration = 30ms,
+ .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
+ .vsyncPeriod = 10ms,
+ .presentDuration = 22ms,
+ .postCompDuration = 88ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = true,
+ .usesFmq = true,
+ .usesSharedFmqFlag = true,
+ .fmqFull = true};
+ WorkDuration res;
+ testGpuScenario(config, res);
+ EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
+ EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
+ EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, fmq_sendHint) {
+ SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
+ mPowerAdvisor->onBootFinished();
+ SetUpFmq(true, false);
+ auto startTime = uptimeNanos();
+ mPowerAdvisor->notifyCpuLoadUp();
+ std::vector<ChannelMessage> msgs;
+ ASSERT_EQ(mBackendFmq->availableToRead(), 1uL);
+ msgs.resize(1);
+ ASSERT_TRUE(mBackendFmq->readBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
+ std::chrono::nanoseconds(1ms).count(), mEventFlag));
+ ASSERT_EQ(msgs[0].sessionID, mSessionId);
+ ASSERT_GE(msgs[0].timeStampNanos, startTime);
+ ASSERT_EQ(msgs[0].data.getTag(), ChannelMessage::ChannelMessageContents::Tag::hint);
+ auto hint = msgs[0].data.get<ChannelMessage::ChannelMessageContents::Tag::hint>();
+ ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
+}
+
+TEST_F(PowerAdvisorTest, fmq_sendHint_noSharedFlag) {
+ SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
+ mPowerAdvisor->onBootFinished();
+ SetUpFmq(false, false);
+ SessionHint hint;
+ EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
+ .Times(1)
+ .WillOnce(DoAll(testing::SaveArg<0>(&hint),
+ testing::Return(testing::ByMove(HalResult<void>::ok()))));
+ mPowerAdvisor->notifyCpuLoadUp();
+ ASSERT_EQ(mBackendFmq->availableToRead(), 0uL);
+ ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
+}
+
+TEST_F(PowerAdvisorTest, fmq_sendHint_queueFull) {
+ SET_FLAG_FOR_TEST(android::os::adpf_use_fmq_channel_fixed, true);
+ mPowerAdvisor->onBootFinished();
+ SetUpFmq(true, true);
+ ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
+ SessionHint hint;
+ EXPECT_CALL(*mMockPowerHintSession, sendHint(_))
+ .Times(1)
+ .WillOnce(DoAll(testing::SaveArg<0>(&hint),
+ testing::Return(testing::ByMove(HalResult<void>::ok()))));
+ std::vector<ChannelMessage> msgs;
+ msgs.resize(1);
+ mBackendFmq->writeBlocking(msgs.data(), 1, mReadFlagBitmask, mWriteFlagBitmask,
+ std::chrono::nanoseconds(1ms).count(), mEventFlag);
+ mPowerAdvisor->notifyCpuLoadUp();
+ ASSERT_EQ(mBackendFmq->availableToRead(), 2uL);
+ ASSERT_EQ(hint, SessionHint::CPU_LOAD_UP);
+}
+
} // namespace
} // namespace android::Hwc2::impl