Loading core/java/android/os/flags.aconfig +0 −8 Original line number Diff line number Diff line Loading @@ -65,14 +65,6 @@ flag { bug: "315894228" } flag { name: "adpf_use_load_hints" namespace: "game" description: "Guards use of the ADPF public load hints behind a readonly flag" is_fixed_read_only: true bug: "367803904" } flag { name: "allow_consentless_bugreport_delegated_consent" namespace: "crumpet" Loading native/android/libandroid.map.txt +0 −4 Original line number Diff line number Diff line Loading @@ -361,8 +361,6 @@ LIBANDROID { APerformanceHint_setThreads; # introduced=UpsideDownCake APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream APerformanceHint_notifyWorkloadIncrease; # introduced=36 APerformanceHint_notifyWorkloadReset; # introduced=36 AWorkDuration_create; # introduced=VanillaIceCream AWorkDuration_release; # introduced=VanillaIceCream AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream Loading @@ -381,8 +379,6 @@ LIBANDROID_PLATFORM { APerformanceHint_getThreadIds; APerformanceHint_createSessionInternal; APerformanceHint_setUseFMQForTesting; APerformanceHint_getRateLimiterPropertiesForTesting; APerformanceHint_setUseNewLoadHintBehaviorForTesting; extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; Loading native/android/performance_hint.cpp +37 −162 Original line number Diff line number Diff line Loading @@ -33,14 +33,12 @@ #include <android/performance_hint.h> #include <android/trace.h> #include <android_os.h> #include <cutils/trace.h> #include <fmq/AidlMessageQueue.h> #include <inttypes.h> #include <performance_hint_private.h> #include <utils/SystemClock.h> #include <chrono> #include <format> #include <future> #include <set> #include <utility> Loading @@ -65,22 +63,6 @@ struct APerformanceHintSession; constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count(); struct AWorkDuration : public hal::WorkDuration {}; // A pair of values that determine the behavior of the // load hint rate limiter, to only allow "X hints every Y seconds" constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count(); constexpr double kMaxLoadHintsPerInterval = 20; constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval; bool kForceNewHintBehavior = false; template <class T> constexpr int32_t enum_size() { return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1; } bool useNewLoadHintBehavior() { return android::os::adpf_use_load_hints() || kForceNewHintBehavior; } // Shared lock for the whole PerformanceHintManager and sessions static std::mutex sHintMutex = std::mutex{}; class FMQWrapper { Loading @@ -94,8 +76,7 @@ public: hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex); bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config, int64_t targetDurationNanos) REQUIRES(sHintMutex); bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint, int64_t now) REQUIRES(sHintMutex); bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex); bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled) REQUIRES(sHintMutex); void setToken(ndk::SpAIBinder& token); Loading @@ -105,11 +86,10 @@ public: private: template <HalChannelMessageContents::Tag T, bool urgent = false, class C = HalChannelMessageContents::_at<T>> bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1, int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex); template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1) REQUIRES(sHintMutex); template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex); bool isActiveLocked() REQUIRES(sHintMutex); bool updatePersistentTransaction() REQUIRES(sHintMutex); Loading Loading @@ -140,7 +120,6 @@ public: hal::SessionTag tag = hal::SessionTag::APP); int64_t getPreferredRateNanos() const; FMQWrapper& getFMQWrapper(); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); private: // Necessary to create an empty binder object Loading @@ -159,8 +138,6 @@ private: ndk::SpAIBinder mToken; const int64_t mPreferredRateNanos; FMQWrapper mFMQWrapper; double mHintBudget = kMaxLoadHintsPerInterval; int64_t mLastBudgetReplenish = 0; }; struct APerformanceHintSession { Loading @@ -174,9 +151,7 @@ public: int updateTargetWorkDuration(int64_t targetDurationNanos); int reportActualWorkDuration(int64_t actualDurationNanos); int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName); int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName); int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName); int sendHint(SessionHint hint); int setThreads(const int32_t* threadIds, size_t size); int getThreadIds(int32_t* const threadIds, size_t* size); int setPreferPowerEfficiency(bool enabled); Loading @@ -198,8 +173,6 @@ private: // Last target hit timestamp int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex); // Last hint reported from sendHint indexed by hint value // This is only used by the old rate limiter impl and is replaced // with the new rate limiter under a flag std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex); // Cached samples std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex); Loading Loading @@ -282,21 +255,6 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa return new APerformanceHintManager(manager, preferredRateNanos); } bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { mHintBudget = std::max(kMaxLoadHintsPerInterval, mHintBudget + static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate); mLastBudgetReplenish = now; // If this youngest timestamp isn't older than the timeout time, we can't send if (hints.size() > mHintBudget) { return false; } mHintBudget -= hints.size(); return true; } APerformanceHintSession* APerformanceHintManager::createSession( const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos, hal::SessionTag tag) { Loading Loading @@ -334,7 +292,9 @@ FMQWrapper& APerformanceHintManager::getFMQWrapper() { // ===================================== APerformanceHintSession implementation constexpr int kNumEnums = enum_size<hal::SessionHint>(); constexpr int kNumEnums = ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin(); APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager, std::shared_ptr<IHintSession> session, int64_t preferredRateNanos, Loading Loading @@ -401,83 +361,31 @@ int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNano return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration)); } int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char*) { int APerformanceHintSession::sendHint(SessionHint hint) { std::scoped_lock lock(sHintMutex); if (hints.empty()) { return EINVAL; } for (auto&& hint : hints) { if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) { if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) { ALOGE("%s: invalid session hint %d", __FUNCTION__, hint); return EINVAL; } } int64_t now = uptimeNanos(); if (useNewLoadHintBehavior()) { if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) { return EBUSY; } } // keep old rate limiter behavior for legacy flag else { for (auto&& hint : hints) { if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) { return EBUSY; } } // Limit sendHint to a pre-detemined rate for safety if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) { return 0; } if (!getFMQ().sendHints(mSessionConfig, hints, now)) { for (auto&& hint : hints) { ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint)); if (!getFMQ().sendHint(mSessionConfig, hint)) { ndk::ScopedAStatus ret = mHintSession->sendHint(hint); if (!ret.isOk()) { ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage()); return EPIPE; } } } if (!useNewLoadHintBehavior()) { for (auto&& hint : hints) { mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now; } } if (ATrace_isEnabled()) { ATRACE_INSTANT("Sending load hint"); } mLastHintSentTimestamp[hint] = now; return 0; } int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) { std::vector<hal::SessionHint> hints(2); hints.clear(); if (cpu) { hints.push_back(hal::SessionHint::CPU_LOAD_UP); } if (gpu) { hints.push_back(hal::SessionHint::GPU_LOAD_UP); } int64_t now = ::android::uptimeNanos(); return sendHints(hints, now, debugName); } int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) { std::vector<hal::SessionHint> hints(2); hints.clear(); if (cpu) { hints.push_back(hal::SessionHint::CPU_LOAD_RESET); } if (gpu) { hints.push_back(hal::SessionHint::GPU_LOAD_RESET); } int64_t now = ::android::uptimeNanos(); return sendHints(hints, now, debugName); } int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) { if (size == 0) { ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__); Loading Loading @@ -657,25 +565,24 @@ void FMQWrapper::stopChannel(IHintManager* manager) { } template <HalChannelMessageContents::Tag T, class C> void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) { for (size_t i = 0; i < count; ++i) { new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{ void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) { new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{ .sessionID = static_cast<int32_t>(config.id), .timeStampNanos = now, .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))), .timeStampNanos = ::android::uptimeNanos(), .data = HalChannelMessageContents::make<T, C>(std::move(*message)), }; } } template <> void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages, hal::SessionConfig& config, size_t count, int64_t now) { size_t count) { for (size_t i = 0; i < count; ++i) { hal::WorkDuration& message = messages[i]; new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{ .sessionID = static_cast<int32_t>(config.id), .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos, .timeStampNanos = (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos, .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration, hal::WorkDurationFixedV1>({ .durationNanos = message.cpuDurationNanos, Loading @@ -688,8 +595,7 @@ void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkD } template <HalChannelMessageContents::Tag T, bool urgent, class C> bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count, int64_t now) { bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) { if (!isActiveLocked() || !config.has_value() || mCorrupted) { return false; } Loading @@ -703,7 +609,7 @@ bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* mess return false; } } writeBuffer<T, C>(message, *config, count, now); writeBuffer<T, C>(message, *config, count); mQueue->commitWrite(count); mEventFlag->wake(mWriteMask); // Re-create the persistent transaction after writing Loading Loading @@ -735,9 +641,10 @@ bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& con return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos); } bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hints, int64_t now) { return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now); bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) { return sendMessages<HalChannelMessageContents::hint>(config, reinterpret_cast<hal::SessionHint*>( &hint)); } bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode, Loading Loading @@ -851,9 +758,7 @@ void APerformanceHint_closeSession(APerformanceHintSession* session) { int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) { VALIDATE_PTR(session) std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)}; int64_t now = ::android::uptimeNanos(); return session->sendHints(hints, now, "HWUI hint"); return session->sendHint(hint); } int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds, Loading Loading @@ -886,26 +791,6 @@ int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session, return session->reportActualWorkDuration(workDurationPtr); } int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu, const char* debugName) { VALIDATE_PTR(session) VALIDATE_PTR(debugName) if (!useNewLoadHintBehavior()) { return ENOTSUP; } return session->notifyWorkloadIncrease(cpu, gpu, debugName); } int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu, const char* debugName) { VALIDATE_PTR(session) VALIDATE_PTR(debugName) if (!useNewLoadHintBehavior()) { return ENOTSUP; } return session->notifyWorkloadReset(cpu, gpu, debugName); } AWorkDuration* AWorkDuration_create() { return new AWorkDuration(); } Loading Loading @@ -953,13 +838,3 @@ void APerformanceHint_setIHintManagerForTesting(void* iManager) { void APerformanceHint_setUseFMQForTesting(bool enabled) { gForceFMQEnabled = enabled; } void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval, int64_t* loadHintInterval) { *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval; *loadHintInterval = kLoadHintInterval; } void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) { kForceNewHintBehavior = newBehavior; } native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +7 −22 Original line number Diff line number Diff line Loading @@ -90,10 +90,7 @@ class PerformanceHintTest : public Test { public: void SetUp() override { mMockIHintManager = ndk::SharedRefBase::make<NiceMock<MockIHintManager>>(); APerformanceHint_getRateLimiterPropertiesForTesting(&mMaxLoadHintsPerInterval, &mLoadHintInterval); APerformanceHint_setIHintManagerForTesting(&mMockIHintManager); APerformanceHint_setUseNewLoadHintBehaviorForTesting(true); } void TearDown() override { Loading Loading @@ -179,9 +176,6 @@ public: int kMockQueueSize = 20; bool mUsingFMQ = false; int32_t mMaxLoadHintsPerInterval; int64_t mLoadHintInterval; template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> void expectToReadFromFmq(C expected) { hal::ChannelMessage readData; Loading Loading @@ -224,6 +218,7 @@ TEST_F(PerformanceHintTest, TestSession) { EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(Exactly(1)); result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos); EXPECT_EQ(0, result); result = APerformanceHint_updateTargetWorkDuration(session, -1L); EXPECT_EQ(EINVAL, result); result = APerformanceHint_reportActualWorkDuration(session, -1L); Loading @@ -233,28 +228,18 @@ TEST_F(PerformanceHintTest, TestSession) { EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_UP))).Times(Exactly(1)); result = APerformanceHint_notifyWorkloadIncrease(session, true, false, "Test hint"); usleep(110000); // Sleep for longer than the update timeout. EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_RESET))).Times(Exactly(1)); EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::GPU_LOAD_RESET))).Times(Exactly(1)); result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint"); // Expect to get rate limited if we try to send faster than the limiter allows EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(0)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); result = APerformanceHint_sendHint(session, static_cast<SessionHint>(-1)); EXPECT_EQ(EINVAL, result); Mock::VerifyAndClearExpectations(mMockSession.get()); for (int i = 0; i < mMaxLoadHintsPerInterval; ++i) { APerformanceHint_sendHint(session, hintId); } // Expect to get rate limited if we try to send faster than the limiter allows EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0)); result = APerformanceHint_notifyWorkloadIncrease(session, true, true, "Test hint"); EXPECT_EQ(result, EBUSY); EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0)); result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint"); EXPECT_CALL(*mMockSession, close()).Times(Exactly(1)); APerformanceHint_closeSession(session); } Loading Loading
core/java/android/os/flags.aconfig +0 −8 Original line number Diff line number Diff line Loading @@ -65,14 +65,6 @@ flag { bug: "315894228" } flag { name: "adpf_use_load_hints" namespace: "game" description: "Guards use of the ADPF public load hints behind a readonly flag" is_fixed_read_only: true bug: "367803904" } flag { name: "allow_consentless_bugreport_delegated_consent" namespace: "crumpet" Loading
native/android/libandroid.map.txt +0 −4 Original line number Diff line number Diff line Loading @@ -361,8 +361,6 @@ LIBANDROID { APerformanceHint_setThreads; # introduced=UpsideDownCake APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream APerformanceHint_notifyWorkloadIncrease; # introduced=36 APerformanceHint_notifyWorkloadReset; # introduced=36 AWorkDuration_create; # introduced=VanillaIceCream AWorkDuration_release; # introduced=VanillaIceCream AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream Loading @@ -381,8 +379,6 @@ LIBANDROID_PLATFORM { APerformanceHint_getThreadIds; APerformanceHint_createSessionInternal; APerformanceHint_setUseFMQForTesting; APerformanceHint_getRateLimiterPropertiesForTesting; APerformanceHint_setUseNewLoadHintBehaviorForTesting; extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; Loading
native/android/performance_hint.cpp +37 −162 Original line number Diff line number Diff line Loading @@ -33,14 +33,12 @@ #include <android/performance_hint.h> #include <android/trace.h> #include <android_os.h> #include <cutils/trace.h> #include <fmq/AidlMessageQueue.h> #include <inttypes.h> #include <performance_hint_private.h> #include <utils/SystemClock.h> #include <chrono> #include <format> #include <future> #include <set> #include <utility> Loading @@ -65,22 +63,6 @@ struct APerformanceHintSession; constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count(); struct AWorkDuration : public hal::WorkDuration {}; // A pair of values that determine the behavior of the // load hint rate limiter, to only allow "X hints every Y seconds" constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count(); constexpr double kMaxLoadHintsPerInterval = 20; constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval; bool kForceNewHintBehavior = false; template <class T> constexpr int32_t enum_size() { return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1; } bool useNewLoadHintBehavior() { return android::os::adpf_use_load_hints() || kForceNewHintBehavior; } // Shared lock for the whole PerformanceHintManager and sessions static std::mutex sHintMutex = std::mutex{}; class FMQWrapper { Loading @@ -94,8 +76,7 @@ public: hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex); bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config, int64_t targetDurationNanos) REQUIRES(sHintMutex); bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint, int64_t now) REQUIRES(sHintMutex); bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex); bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled) REQUIRES(sHintMutex); void setToken(ndk::SpAIBinder& token); Loading @@ -105,11 +86,10 @@ public: private: template <HalChannelMessageContents::Tag T, bool urgent = false, class C = HalChannelMessageContents::_at<T>> bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1, int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex); template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1) REQUIRES(sHintMutex); template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex); bool isActiveLocked() REQUIRES(sHintMutex); bool updatePersistentTransaction() REQUIRES(sHintMutex); Loading Loading @@ -140,7 +120,6 @@ public: hal::SessionTag tag = hal::SessionTag::APP); int64_t getPreferredRateNanos() const; FMQWrapper& getFMQWrapper(); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); private: // Necessary to create an empty binder object Loading @@ -159,8 +138,6 @@ private: ndk::SpAIBinder mToken; const int64_t mPreferredRateNanos; FMQWrapper mFMQWrapper; double mHintBudget = kMaxLoadHintsPerInterval; int64_t mLastBudgetReplenish = 0; }; struct APerformanceHintSession { Loading @@ -174,9 +151,7 @@ public: int updateTargetWorkDuration(int64_t targetDurationNanos); int reportActualWorkDuration(int64_t actualDurationNanos); int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName); int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName); int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName); int sendHint(SessionHint hint); int setThreads(const int32_t* threadIds, size_t size); int getThreadIds(int32_t* const threadIds, size_t* size); int setPreferPowerEfficiency(bool enabled); Loading @@ -198,8 +173,6 @@ private: // Last target hit timestamp int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex); // Last hint reported from sendHint indexed by hint value // This is only used by the old rate limiter impl and is replaced // with the new rate limiter under a flag std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex); // Cached samples std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex); Loading Loading @@ -282,21 +255,6 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa return new APerformanceHintManager(manager, preferredRateNanos); } bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { mHintBudget = std::max(kMaxLoadHintsPerInterval, mHintBudget + static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate); mLastBudgetReplenish = now; // If this youngest timestamp isn't older than the timeout time, we can't send if (hints.size() > mHintBudget) { return false; } mHintBudget -= hints.size(); return true; } APerformanceHintSession* APerformanceHintManager::createSession( const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos, hal::SessionTag tag) { Loading Loading @@ -334,7 +292,9 @@ FMQWrapper& APerformanceHintManager::getFMQWrapper() { // ===================================== APerformanceHintSession implementation constexpr int kNumEnums = enum_size<hal::SessionHint>(); constexpr int kNumEnums = ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin(); APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager, std::shared_ptr<IHintSession> session, int64_t preferredRateNanos, Loading Loading @@ -401,83 +361,31 @@ int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNano return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration)); } int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char*) { int APerformanceHintSession::sendHint(SessionHint hint) { std::scoped_lock lock(sHintMutex); if (hints.empty()) { return EINVAL; } for (auto&& hint : hints) { if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) { if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) { ALOGE("%s: invalid session hint %d", __FUNCTION__, hint); return EINVAL; } } int64_t now = uptimeNanos(); if (useNewLoadHintBehavior()) { if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) { return EBUSY; } } // keep old rate limiter behavior for legacy flag else { for (auto&& hint : hints) { if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) { return EBUSY; } } // Limit sendHint to a pre-detemined rate for safety if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) { return 0; } if (!getFMQ().sendHints(mSessionConfig, hints, now)) { for (auto&& hint : hints) { ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint)); if (!getFMQ().sendHint(mSessionConfig, hint)) { ndk::ScopedAStatus ret = mHintSession->sendHint(hint); if (!ret.isOk()) { ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage()); return EPIPE; } } } if (!useNewLoadHintBehavior()) { for (auto&& hint : hints) { mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now; } } if (ATrace_isEnabled()) { ATRACE_INSTANT("Sending load hint"); } mLastHintSentTimestamp[hint] = now; return 0; } int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) { std::vector<hal::SessionHint> hints(2); hints.clear(); if (cpu) { hints.push_back(hal::SessionHint::CPU_LOAD_UP); } if (gpu) { hints.push_back(hal::SessionHint::GPU_LOAD_UP); } int64_t now = ::android::uptimeNanos(); return sendHints(hints, now, debugName); } int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) { std::vector<hal::SessionHint> hints(2); hints.clear(); if (cpu) { hints.push_back(hal::SessionHint::CPU_LOAD_RESET); } if (gpu) { hints.push_back(hal::SessionHint::GPU_LOAD_RESET); } int64_t now = ::android::uptimeNanos(); return sendHints(hints, now, debugName); } int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) { if (size == 0) { ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__); Loading Loading @@ -657,25 +565,24 @@ void FMQWrapper::stopChannel(IHintManager* manager) { } template <HalChannelMessageContents::Tag T, class C> void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) { for (size_t i = 0; i < count; ++i) { new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{ void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) { new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{ .sessionID = static_cast<int32_t>(config.id), .timeStampNanos = now, .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))), .timeStampNanos = ::android::uptimeNanos(), .data = HalChannelMessageContents::make<T, C>(std::move(*message)), }; } } template <> void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages, hal::SessionConfig& config, size_t count, int64_t now) { size_t count) { for (size_t i = 0; i < count; ++i) { hal::WorkDuration& message = messages[i]; new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{ .sessionID = static_cast<int32_t>(config.id), .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos, .timeStampNanos = (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos, .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration, hal::WorkDurationFixedV1>({ .durationNanos = message.cpuDurationNanos, Loading @@ -688,8 +595,7 @@ void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkD } template <HalChannelMessageContents::Tag T, bool urgent, class C> bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count, int64_t now) { bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) { if (!isActiveLocked() || !config.has_value() || mCorrupted) { return false; } Loading @@ -703,7 +609,7 @@ bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* mess return false; } } writeBuffer<T, C>(message, *config, count, now); writeBuffer<T, C>(message, *config, count); mQueue->commitWrite(count); mEventFlag->wake(mWriteMask); // Re-create the persistent transaction after writing Loading Loading @@ -735,9 +641,10 @@ bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& con return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos); } bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hints, int64_t now) { return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now); bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) { return sendMessages<HalChannelMessageContents::hint>(config, reinterpret_cast<hal::SessionHint*>( &hint)); } bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode, Loading Loading @@ -851,9 +758,7 @@ void APerformanceHint_closeSession(APerformanceHintSession* session) { int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) { VALIDATE_PTR(session) std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)}; int64_t now = ::android::uptimeNanos(); return session->sendHints(hints, now, "HWUI hint"); return session->sendHint(hint); } int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds, Loading Loading @@ -886,26 +791,6 @@ int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session, return session->reportActualWorkDuration(workDurationPtr); } int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu, const char* debugName) { VALIDATE_PTR(session) VALIDATE_PTR(debugName) if (!useNewLoadHintBehavior()) { return ENOTSUP; } return session->notifyWorkloadIncrease(cpu, gpu, debugName); } int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu, const char* debugName) { VALIDATE_PTR(session) VALIDATE_PTR(debugName) if (!useNewLoadHintBehavior()) { return ENOTSUP; } return session->notifyWorkloadReset(cpu, gpu, debugName); } AWorkDuration* AWorkDuration_create() { return new AWorkDuration(); } Loading Loading @@ -953,13 +838,3 @@ void APerformanceHint_setIHintManagerForTesting(void* iManager) { void APerformanceHint_setUseFMQForTesting(bool enabled) { gForceFMQEnabled = enabled; } void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval, int64_t* loadHintInterval) { *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval; *loadHintInterval = kLoadHintInterval; } void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) { kForceNewHintBehavior = newBehavior; }
native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +7 −22 Original line number Diff line number Diff line Loading @@ -90,10 +90,7 @@ class PerformanceHintTest : public Test { public: void SetUp() override { mMockIHintManager = ndk::SharedRefBase::make<NiceMock<MockIHintManager>>(); APerformanceHint_getRateLimiterPropertiesForTesting(&mMaxLoadHintsPerInterval, &mLoadHintInterval); APerformanceHint_setIHintManagerForTesting(&mMockIHintManager); APerformanceHint_setUseNewLoadHintBehaviorForTesting(true); } void TearDown() override { Loading Loading @@ -179,9 +176,6 @@ public: int kMockQueueSize = 20; bool mUsingFMQ = false; int32_t mMaxLoadHintsPerInterval; int64_t mLoadHintInterval; template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> void expectToReadFromFmq(C expected) { hal::ChannelMessage readData; Loading Loading @@ -224,6 +218,7 @@ TEST_F(PerformanceHintTest, TestSession) { EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(Exactly(1)); result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos); EXPECT_EQ(0, result); result = APerformanceHint_updateTargetWorkDuration(session, -1L); EXPECT_EQ(EINVAL, result); result = APerformanceHint_reportActualWorkDuration(session, -1L); Loading @@ -233,28 +228,18 @@ TEST_F(PerformanceHintTest, TestSession) { EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_UP))).Times(Exactly(1)); result = APerformanceHint_notifyWorkloadIncrease(session, true, false, "Test hint"); usleep(110000); // Sleep for longer than the update timeout. EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_RESET))).Times(Exactly(1)); EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::GPU_LOAD_RESET))).Times(Exactly(1)); result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint"); // Expect to get rate limited if we try to send faster than the limiter allows EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(0)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); result = APerformanceHint_sendHint(session, static_cast<SessionHint>(-1)); EXPECT_EQ(EINVAL, result); Mock::VerifyAndClearExpectations(mMockSession.get()); for (int i = 0; i < mMaxLoadHintsPerInterval; ++i) { APerformanceHint_sendHint(session, hintId); } // Expect to get rate limited if we try to send faster than the limiter allows EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0)); result = APerformanceHint_notifyWorkloadIncrease(session, true, true, "Test hint"); EXPECT_EQ(result, EBUSY); EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0)); result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint"); EXPECT_CALL(*mMockSession, close()).Times(Exactly(1)); APerformanceHint_closeSession(session); } Loading