Loading libs/hwui/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -717,6 +717,7 @@ cc_test { "tests/unit/EglManagerTests.cpp", "tests/unit/EglManagerTests.cpp", "tests/unit/FatVectorTests.cpp", "tests/unit/FatVectorTests.cpp", "tests/unit/GraphicsStatsServiceTests.cpp", "tests/unit/GraphicsStatsServiceTests.cpp", "tests/unit/HintSessionWrapperTests.cpp", "tests/unit/JankTrackerTests.cpp", "tests/unit/JankTrackerTests.cpp", "tests/unit/FrameMetricsReporterTests.cpp", "tests/unit/FrameMetricsReporterTests.cpp", "tests/unit/LayerUpdateQueueTests.cpp", "tests/unit/LayerUpdateQueueTests.cpp", Loading libs/hwui/renderthread/CanvasContext.cpp +7 −6 Original line number Original line Diff line number Diff line Loading @@ -123,7 +123,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos()) , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos()) , mContentDrawBounds(0, 0, 0, 0) , mContentDrawBounds(0, 0, 0, 0) , mRenderPipeline(std::move(renderPipeline)) , mRenderPipeline(std::move(renderPipeline)) , mHintSessionWrapper(uiThreadId, renderThreadId) { , mHintSessionWrapper(std::make_shared<HintSessionWrapper>(uiThreadId, renderThreadId)) { mRenderThread.cacheManager().registerCanvasContext(this); mRenderThread.cacheManager().registerCanvasContext(this); rootRenderNode->makeRoot(); rootRenderNode->makeRoot(); mRenderNodes.emplace_back(rootRenderNode); mRenderNodes.emplace_back(rootRenderNode); Loading Loading @@ -160,6 +160,7 @@ void CanvasContext::destroy() { destroyHardwareResources(); destroyHardwareResources(); mAnimationContext->destroy(); mAnimationContext->destroy(); mRenderThread.cacheManager().onContextStopped(this); mRenderThread.cacheManager().onContextStopped(this); mHintSessionWrapper->delayedDestroy(mRenderThread, 2_s, mHintSessionWrapper); } } static void setBufferCount(ANativeWindow* window) { static void setBufferCount(ANativeWindow* window) { Loading Loading @@ -739,7 +740,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline); int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline); int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); mHintSessionWrapper.updateTargetWorkDuration(frameDeadline - intendedVsync); mHintSessionWrapper->updateTargetWorkDuration(frameDeadline - intendedVsync); if (didDraw) { if (didDraw) { int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); Loading @@ -747,7 +748,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { int64_t actualDuration = frameDuration - int64_t actualDuration = frameDuration - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - dequeueBufferDuration - idleDuration; dequeueBufferDuration - idleDuration; mHintSessionWrapper.reportActualWorkDuration(actualDuration); mHintSessionWrapper->reportActualWorkDuration(actualDuration); } } mLastDequeueBufferDuration = dequeueBufferDuration; mLastDequeueBufferDuration = dequeueBufferDuration; Loading Loading @@ -1081,11 +1082,11 @@ void CanvasContext::prepareSurfaceControlForWebview() { } } void CanvasContext::sendLoadResetHint() { void CanvasContext::sendLoadResetHint() { mHintSessionWrapper.sendLoadResetHint(); mHintSessionWrapper->sendLoadResetHint(); } } void CanvasContext::sendLoadIncreaseHint() { void CanvasContext::sendLoadIncreaseHint() { mHintSessionWrapper.sendLoadIncreaseHint(); mHintSessionWrapper->sendLoadIncreaseHint(); } } void CanvasContext::setSyncDelayDuration(nsecs_t duration) { void CanvasContext::setSyncDelayDuration(nsecs_t duration) { Loading @@ -1093,7 +1094,7 @@ void CanvasContext::setSyncDelayDuration(nsecs_t duration) { } } void CanvasContext::startHintSession() { void CanvasContext::startHintSession() { mHintSessionWrapper.init(); mHintSessionWrapper->init(); } } bool CanvasContext::shouldDither() { bool CanvasContext::shouldDither() { Loading libs/hwui/renderthread/CanvasContext.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -359,7 +359,7 @@ private: std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback; std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback; std::function<void()> mPrepareSurfaceControlForWebviewCallback; std::function<void()> mPrepareSurfaceControlForWebviewCallback; HintSessionWrapper mHintSessionWrapper; std::shared_ptr<HintSessionWrapper> mHintSessionWrapper; nsecs_t mLastDequeueBufferDuration = 0; nsecs_t mLastDequeueBufferDuration = 0; nsecs_t mSyncDelayDuration = 0; nsecs_t mSyncDelayDuration = 0; nsecs_t mIdleDuration = 0; nsecs_t mIdleDuration = 0; Loading libs/hwui/renderthread/HintSessionWrapper.cpp +56 −65 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <vector> #include <vector> #include "../Properties.h" #include "../Properties.h" #include "RenderThread.h" #include "thread/CommonPool.h" #include "thread/CommonPool.h" using namespace std::chrono_literals; using namespace std::chrono_literals; Loading @@ -32,76 +33,42 @@ namespace android { namespace uirenderer { namespace uirenderer { namespace renderthread { namespace renderthread { namespace { #define BIND_APH_METHOD(name) \ name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \ LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name) typedef APerformanceHintManager* (*APH_getManager)(); void HintSessionWrapper::HintSessionBinding::init() { typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*, if (mInitialized) return; size_t, int64_t); typedef void (*APH_closeSession)(APerformanceHintSession* session); typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t); typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t); typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t); bool gAPerformanceHintBindingInitialized = false; APH_getManager gAPH_getManagerFn = nullptr; APH_createSession gAPH_createSessionFn = nullptr; APH_closeSession gAPH_closeSessionFn = nullptr; APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr; APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr; APH_sendHint gAPH_sendHintFn = nullptr; void ensureAPerformanceHintBindingInitialized() { if (gAPerformanceHintBindingInitialized) return; void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE); void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE); LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!"); LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!"); gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager"); BIND_APH_METHOD(getManager); LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr, BIND_APH_METHOD(createSession); "Failed to find required symbol APerformanceHint_getManager!"); BIND_APH_METHOD(closeSession); BIND_APH_METHOD(updateTargetWorkDuration); gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession"); BIND_APH_METHOD(reportActualWorkDuration); LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr, BIND_APH_METHOD(sendHint); "Failed to find required symbol APerformanceHint_createSession!"); gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession"); LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr, "Failed to find required symbol APerformanceHint_closeSession!"); gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym( handle_, "APerformanceHint_updateTargetWorkDuration"); LOG_ALWAYS_FATAL_IF( gAPH_updateTargetWorkDurationFn == nullptr, "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!"); gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym( mInitialized = true; handle_, "APerformanceHint_reportActualWorkDuration"); LOG_ALWAYS_FATAL_IF( gAPH_reportActualWorkDurationFn == nullptr, "Failed to find required symbol APerformanceHint_reportActualWorkDuration!"); gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint"); LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr, "Failed to find required symbol APerformanceHint_sendHint!"); gAPerformanceHintBindingInitialized = true; } } } // namespace HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId) HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId) : mUiThreadId(uiThreadId), mRenderThreadId(renderThreadId) {} : mUiThreadId(uiThreadId) , mRenderThreadId(renderThreadId) , mBinding(std::make_shared<HintSessionBinding>()) {} HintSessionWrapper::~HintSessionWrapper() { HintSessionWrapper::~HintSessionWrapper() { destroy(); destroy(); } } void HintSessionWrapper::destroy() { void HintSessionWrapper::destroy() { if (mHintSessionFuture.valid()) { if (mHintSessionFuture.has_value()) { mHintSession = mHintSessionFuture.get(); mHintSession = mHintSessionFuture->get(); mHintSessionFuture = std::nullopt; } } if (mHintSession) { if (mHintSession) { gAPH_closeSessionFn(mHintSession); mBinding->closeSession(mHintSession); mSessionValid = true; mSessionValid = true; mHintSession = nullptr; mHintSession = nullptr; } } Loading @@ -109,12 +76,12 @@ void HintSessionWrapper::destroy() { bool HintSessionWrapper::init() { bool HintSessionWrapper::init() { if (mHintSession != nullptr) return true; if (mHintSession != nullptr) return true; // If we're waiting for the session // If we're waiting for the session if (mHintSessionFuture.valid()) { if (mHintSessionFuture.has_value()) { // If the session is here // If the session is here if (mHintSessionFuture.wait_for(0s) == std::future_status::ready) { if (mHintSessionFuture->wait_for(0s) == std::future_status::ready) { mHintSession = mHintSessionFuture.get(); mHintSession = mHintSessionFuture->get(); mHintSessionFuture = std::nullopt; if (mHintSession != nullptr) { if (mHintSession != nullptr) { mSessionValid = true; mSessionValid = true; return true; return true; Loading @@ -133,9 +100,9 @@ bool HintSessionWrapper::init() { // Assume that if we return before the end, it broke // Assume that if we return before the end, it broke mSessionValid = false; mSessionValid = false; ensureAPerformanceHintBindingInitialized(); mBinding->init(); APerformanceHintManager* manager = gAPH_getManagerFn(); APerformanceHintManager* manager = mBinding->getManager(); if (!manager) return false; if (!manager) return false; std::vector<pid_t> tids = CommonPool::getThreadIds(); std::vector<pid_t> tids = CommonPool::getThreadIds(); Loading @@ -145,8 +112,9 @@ bool HintSessionWrapper::init() { // Use a placeholder target value to initialize, // Use a placeholder target value to initialize, // this will always be replaced elsewhere before it gets used // this will always be replaced elsewhere before it gets used int64_t defaultTargetDurationNanos = 16666667; int64_t defaultTargetDurationNanos = 16666667; mHintSessionFuture = CommonPool::async([=, tids = std::move(tids)] { mHintSessionFuture = CommonPool::async([=, this, tids = std::move(tids)] { return gAPH_createSessionFn(manager, tids.data(), tids.size(), defaultTargetDurationNanos); return mBinding->createSession(manager, tids.data(), tids.size(), defaultTargetDurationNanos); }); }); return false; return false; } } Loading @@ -158,7 +126,7 @@ void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) targetWorkDurationNanos > kSanityCheckLowerBound && targetWorkDurationNanos > kSanityCheckLowerBound && targetWorkDurationNanos < kSanityCheckUpperBound) { targetWorkDurationNanos < kSanityCheckUpperBound) { mLastTargetWorkDuration = targetWorkDurationNanos; mLastTargetWorkDuration = targetWorkDurationNanos; gAPH_updateTargetWorkDurationFn(mHintSession, targetWorkDurationNanos); mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos); } } mLastFrameNotification = systemTime(); mLastFrameNotification = systemTime(); } } Loading @@ -168,8 +136,9 @@ void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) { mResetsSinceLastReport = 0; mResetsSinceLastReport = 0; if (actualDurationNanos > kSanityCheckLowerBound && if (actualDurationNanos > kSanityCheckLowerBound && actualDurationNanos < kSanityCheckUpperBound) { actualDurationNanos < kSanityCheckUpperBound) { gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos); mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos); } } mLastFrameNotification = systemTime(); } } void HintSessionWrapper::sendLoadResetHint() { void HintSessionWrapper::sendLoadResetHint() { Loading @@ -179,14 +148,36 @@ void HintSessionWrapper::sendLoadResetHint() { if (now - mLastFrameNotification > kResetHintTimeout && if (now - mLastFrameNotification > kResetHintTimeout && mResetsSinceLastReport <= kMaxResetsSinceLastReport) { mResetsSinceLastReport <= kMaxResetsSinceLastReport) { ++mResetsSinceLastReport; ++mResetsSinceLastReport; gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_RESET)); mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET)); } } mLastFrameNotification = now; mLastFrameNotification = now; } } void HintSessionWrapper::sendLoadIncreaseHint() { void HintSessionWrapper::sendLoadIncreaseHint() { if (!init()) return; if (!init()) return; gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_UP)); mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP)); mLastFrameNotification = systemTime(); } bool HintSessionWrapper::alive() { return mHintSession != nullptr; } nsecs_t HintSessionWrapper::getLastUpdate() { return mLastFrameNotification; } // Requires passing in its shared_ptr since it shouldn't own a shared_ptr to itself void HintSessionWrapper::delayedDestroy(RenderThread& rt, nsecs_t delay, std::shared_ptr<HintSessionWrapper> wrapperPtr) { nsecs_t lastUpdate = wrapperPtr->getLastUpdate(); rt.queue().postDelayed(delay, [lastUpdate = lastUpdate, wrapper = wrapperPtr]() mutable { if (wrapper->getLastUpdate() == lastUpdate) { wrapper->destroy(); } // Ensure the shared_ptr is killed at the end of the method wrapper = nullptr; }); } } } /* namespace renderthread */ } /* namespace renderthread */ Loading libs/hwui/renderthread/HintSessionWrapper.h +33 −1 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <android/performance_hint.h> #include <android/performance_hint.h> #include <future> #include <future> #include <optional> #include "utils/TimeUtils.h" #include "utils/TimeUtils.h" Loading @@ -27,8 +28,12 @@ namespace uirenderer { namespace renderthread { namespace renderthread { class RenderThread; class HintSessionWrapper { class HintSessionWrapper { public: public: friend class HintSessionWrapperTests; HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId); HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId); ~HintSessionWrapper(); ~HintSessionWrapper(); Loading @@ -38,10 +43,15 @@ public: void sendLoadIncreaseHint(); void sendLoadIncreaseHint(); bool init(); bool init(); void destroy(); void destroy(); bool alive(); nsecs_t getLastUpdate(); void delayedDestroy(renderthread::RenderThread& rt, nsecs_t delay, std::shared_ptr<HintSessionWrapper> wrapperPtr); private: private: APerformanceHintSession* mHintSession = nullptr; APerformanceHintSession* mHintSession = nullptr; std::future<APerformanceHintSession*> mHintSessionFuture; // This needs to work concurrently for testing std::optional<std::shared_future<APerformanceHintSession*>> mHintSessionFuture; int mResetsSinceLastReport = 0; int mResetsSinceLastReport = 0; nsecs_t mLastFrameNotification = 0; nsecs_t mLastFrameNotification = 0; Loading @@ -55,6 +65,28 @@ private: static constexpr nsecs_t kResetHintTimeout = 100_ms; static constexpr nsecs_t kResetHintTimeout = 100_ms; static constexpr int64_t kSanityCheckLowerBound = 100_us; static constexpr int64_t kSanityCheckLowerBound = 100_us; static constexpr int64_t kSanityCheckUpperBound = 10_s; static constexpr int64_t kSanityCheckUpperBound = 10_s; // Allows easier stub when testing class HintSessionBinding { public: virtual ~HintSessionBinding() = default; virtual void init(); APerformanceHintManager* (*getManager)(); APerformanceHintSession* (*createSession)(APerformanceHintManager* manager, const int32_t* tids, size_t tidCount, int64_t defaultTarget) = nullptr; void (*closeSession)(APerformanceHintSession* session) = nullptr; void (*updateTargetWorkDuration)(APerformanceHintSession* session, int64_t targetDuration) = nullptr; void (*reportActualWorkDuration)(APerformanceHintSession* session, int64_t actualDuration) = nullptr; void (*sendHint)(APerformanceHintSession* session, int32_t hintId) = nullptr; private: bool mInitialized = false; }; std::shared_ptr<HintSessionBinding> mBinding; }; }; } /* namespace renderthread */ } /* namespace renderthread */ Loading Loading
libs/hwui/Android.bp +1 −0 Original line number Original line Diff line number Diff line Loading @@ -717,6 +717,7 @@ cc_test { "tests/unit/EglManagerTests.cpp", "tests/unit/EglManagerTests.cpp", "tests/unit/FatVectorTests.cpp", "tests/unit/FatVectorTests.cpp", "tests/unit/GraphicsStatsServiceTests.cpp", "tests/unit/GraphicsStatsServiceTests.cpp", "tests/unit/HintSessionWrapperTests.cpp", "tests/unit/JankTrackerTests.cpp", "tests/unit/JankTrackerTests.cpp", "tests/unit/FrameMetricsReporterTests.cpp", "tests/unit/FrameMetricsReporterTests.cpp", "tests/unit/LayerUpdateQueueTests.cpp", "tests/unit/LayerUpdateQueueTests.cpp", Loading
libs/hwui/renderthread/CanvasContext.cpp +7 −6 Original line number Original line Diff line number Diff line Loading @@ -123,7 +123,7 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos()) , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos()) , mContentDrawBounds(0, 0, 0, 0) , mContentDrawBounds(0, 0, 0, 0) , mRenderPipeline(std::move(renderPipeline)) , mRenderPipeline(std::move(renderPipeline)) , mHintSessionWrapper(uiThreadId, renderThreadId) { , mHintSessionWrapper(std::make_shared<HintSessionWrapper>(uiThreadId, renderThreadId)) { mRenderThread.cacheManager().registerCanvasContext(this); mRenderThread.cacheManager().registerCanvasContext(this); rootRenderNode->makeRoot(); rootRenderNode->makeRoot(); mRenderNodes.emplace_back(rootRenderNode); mRenderNodes.emplace_back(rootRenderNode); Loading Loading @@ -160,6 +160,7 @@ void CanvasContext::destroy() { destroyHardwareResources(); destroyHardwareResources(); mAnimationContext->destroy(); mAnimationContext->destroy(); mRenderThread.cacheManager().onContextStopped(this); mRenderThread.cacheManager().onContextStopped(this); mHintSessionWrapper->delayedDestroy(mRenderThread, 2_s, mHintSessionWrapper); } } static void setBufferCount(ANativeWindow* window) { static void setBufferCount(ANativeWindow* window) { Loading Loading @@ -739,7 +740,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline); int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline); int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration); mHintSessionWrapper.updateTargetWorkDuration(frameDeadline - intendedVsync); mHintSessionWrapper->updateTargetWorkDuration(frameDeadline - intendedVsync); if (didDraw) { if (didDraw) { int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime); Loading @@ -747,7 +748,7 @@ void CanvasContext::draw(bool solelyTextureViewUpdates) { int64_t actualDuration = frameDuration - int64_t actualDuration = frameDuration - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - (std::min(syncDelayDuration, mLastDequeueBufferDuration)) - dequeueBufferDuration - idleDuration; dequeueBufferDuration - idleDuration; mHintSessionWrapper.reportActualWorkDuration(actualDuration); mHintSessionWrapper->reportActualWorkDuration(actualDuration); } } mLastDequeueBufferDuration = dequeueBufferDuration; mLastDequeueBufferDuration = dequeueBufferDuration; Loading Loading @@ -1081,11 +1082,11 @@ void CanvasContext::prepareSurfaceControlForWebview() { } } void CanvasContext::sendLoadResetHint() { void CanvasContext::sendLoadResetHint() { mHintSessionWrapper.sendLoadResetHint(); mHintSessionWrapper->sendLoadResetHint(); } } void CanvasContext::sendLoadIncreaseHint() { void CanvasContext::sendLoadIncreaseHint() { mHintSessionWrapper.sendLoadIncreaseHint(); mHintSessionWrapper->sendLoadIncreaseHint(); } } void CanvasContext::setSyncDelayDuration(nsecs_t duration) { void CanvasContext::setSyncDelayDuration(nsecs_t duration) { Loading @@ -1093,7 +1094,7 @@ void CanvasContext::setSyncDelayDuration(nsecs_t duration) { } } void CanvasContext::startHintSession() { void CanvasContext::startHintSession() { mHintSessionWrapper.init(); mHintSessionWrapper->init(); } } bool CanvasContext::shouldDither() { bool CanvasContext::shouldDither() { Loading
libs/hwui/renderthread/CanvasContext.h +1 −1 Original line number Original line Diff line number Diff line Loading @@ -359,7 +359,7 @@ private: std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback; std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback; std::function<void()> mPrepareSurfaceControlForWebviewCallback; std::function<void()> mPrepareSurfaceControlForWebviewCallback; HintSessionWrapper mHintSessionWrapper; std::shared_ptr<HintSessionWrapper> mHintSessionWrapper; nsecs_t mLastDequeueBufferDuration = 0; nsecs_t mLastDequeueBufferDuration = 0; nsecs_t mSyncDelayDuration = 0; nsecs_t mSyncDelayDuration = 0; nsecs_t mIdleDuration = 0; nsecs_t mIdleDuration = 0; Loading
libs/hwui/renderthread/HintSessionWrapper.cpp +56 −65 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ #include <vector> #include <vector> #include "../Properties.h" #include "../Properties.h" #include "RenderThread.h" #include "thread/CommonPool.h" #include "thread/CommonPool.h" using namespace std::chrono_literals; using namespace std::chrono_literals; Loading @@ -32,76 +33,42 @@ namespace android { namespace uirenderer { namespace uirenderer { namespace renderthread { namespace renderthread { namespace { #define BIND_APH_METHOD(name) \ name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \ LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name) typedef APerformanceHintManager* (*APH_getManager)(); void HintSessionWrapper::HintSessionBinding::init() { typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*, if (mInitialized) return; size_t, int64_t); typedef void (*APH_closeSession)(APerformanceHintSession* session); typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t); typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t); typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t); bool gAPerformanceHintBindingInitialized = false; APH_getManager gAPH_getManagerFn = nullptr; APH_createSession gAPH_createSessionFn = nullptr; APH_closeSession gAPH_closeSessionFn = nullptr; APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr; APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr; APH_sendHint gAPH_sendHintFn = nullptr; void ensureAPerformanceHintBindingInitialized() { if (gAPerformanceHintBindingInitialized) return; void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE); void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE); LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!"); LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!"); gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager"); BIND_APH_METHOD(getManager); LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr, BIND_APH_METHOD(createSession); "Failed to find required symbol APerformanceHint_getManager!"); BIND_APH_METHOD(closeSession); BIND_APH_METHOD(updateTargetWorkDuration); gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession"); BIND_APH_METHOD(reportActualWorkDuration); LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr, BIND_APH_METHOD(sendHint); "Failed to find required symbol APerformanceHint_createSession!"); gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession"); LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr, "Failed to find required symbol APerformanceHint_closeSession!"); gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym( handle_, "APerformanceHint_updateTargetWorkDuration"); LOG_ALWAYS_FATAL_IF( gAPH_updateTargetWorkDurationFn == nullptr, "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!"); gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym( mInitialized = true; handle_, "APerformanceHint_reportActualWorkDuration"); LOG_ALWAYS_FATAL_IF( gAPH_reportActualWorkDurationFn == nullptr, "Failed to find required symbol APerformanceHint_reportActualWorkDuration!"); gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint"); LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr, "Failed to find required symbol APerformanceHint_sendHint!"); gAPerformanceHintBindingInitialized = true; } } } // namespace HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId) HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId) : mUiThreadId(uiThreadId), mRenderThreadId(renderThreadId) {} : mUiThreadId(uiThreadId) , mRenderThreadId(renderThreadId) , mBinding(std::make_shared<HintSessionBinding>()) {} HintSessionWrapper::~HintSessionWrapper() { HintSessionWrapper::~HintSessionWrapper() { destroy(); destroy(); } } void HintSessionWrapper::destroy() { void HintSessionWrapper::destroy() { if (mHintSessionFuture.valid()) { if (mHintSessionFuture.has_value()) { mHintSession = mHintSessionFuture.get(); mHintSession = mHintSessionFuture->get(); mHintSessionFuture = std::nullopt; } } if (mHintSession) { if (mHintSession) { gAPH_closeSessionFn(mHintSession); mBinding->closeSession(mHintSession); mSessionValid = true; mSessionValid = true; mHintSession = nullptr; mHintSession = nullptr; } } Loading @@ -109,12 +76,12 @@ void HintSessionWrapper::destroy() { bool HintSessionWrapper::init() { bool HintSessionWrapper::init() { if (mHintSession != nullptr) return true; if (mHintSession != nullptr) return true; // If we're waiting for the session // If we're waiting for the session if (mHintSessionFuture.valid()) { if (mHintSessionFuture.has_value()) { // If the session is here // If the session is here if (mHintSessionFuture.wait_for(0s) == std::future_status::ready) { if (mHintSessionFuture->wait_for(0s) == std::future_status::ready) { mHintSession = mHintSessionFuture.get(); mHintSession = mHintSessionFuture->get(); mHintSessionFuture = std::nullopt; if (mHintSession != nullptr) { if (mHintSession != nullptr) { mSessionValid = true; mSessionValid = true; return true; return true; Loading @@ -133,9 +100,9 @@ bool HintSessionWrapper::init() { // Assume that if we return before the end, it broke // Assume that if we return before the end, it broke mSessionValid = false; mSessionValid = false; ensureAPerformanceHintBindingInitialized(); mBinding->init(); APerformanceHintManager* manager = gAPH_getManagerFn(); APerformanceHintManager* manager = mBinding->getManager(); if (!manager) return false; if (!manager) return false; std::vector<pid_t> tids = CommonPool::getThreadIds(); std::vector<pid_t> tids = CommonPool::getThreadIds(); Loading @@ -145,8 +112,9 @@ bool HintSessionWrapper::init() { // Use a placeholder target value to initialize, // Use a placeholder target value to initialize, // this will always be replaced elsewhere before it gets used // this will always be replaced elsewhere before it gets used int64_t defaultTargetDurationNanos = 16666667; int64_t defaultTargetDurationNanos = 16666667; mHintSessionFuture = CommonPool::async([=, tids = std::move(tids)] { mHintSessionFuture = CommonPool::async([=, this, tids = std::move(tids)] { return gAPH_createSessionFn(manager, tids.data(), tids.size(), defaultTargetDurationNanos); return mBinding->createSession(manager, tids.data(), tids.size(), defaultTargetDurationNanos); }); }); return false; return false; } } Loading @@ -158,7 +126,7 @@ void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) targetWorkDurationNanos > kSanityCheckLowerBound && targetWorkDurationNanos > kSanityCheckLowerBound && targetWorkDurationNanos < kSanityCheckUpperBound) { targetWorkDurationNanos < kSanityCheckUpperBound) { mLastTargetWorkDuration = targetWorkDurationNanos; mLastTargetWorkDuration = targetWorkDurationNanos; gAPH_updateTargetWorkDurationFn(mHintSession, targetWorkDurationNanos); mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos); } } mLastFrameNotification = systemTime(); mLastFrameNotification = systemTime(); } } Loading @@ -168,8 +136,9 @@ void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) { mResetsSinceLastReport = 0; mResetsSinceLastReport = 0; if (actualDurationNanos > kSanityCheckLowerBound && if (actualDurationNanos > kSanityCheckLowerBound && actualDurationNanos < kSanityCheckUpperBound) { actualDurationNanos < kSanityCheckUpperBound) { gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos); mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos); } } mLastFrameNotification = systemTime(); } } void HintSessionWrapper::sendLoadResetHint() { void HintSessionWrapper::sendLoadResetHint() { Loading @@ -179,14 +148,36 @@ void HintSessionWrapper::sendLoadResetHint() { if (now - mLastFrameNotification > kResetHintTimeout && if (now - mLastFrameNotification > kResetHintTimeout && mResetsSinceLastReport <= kMaxResetsSinceLastReport) { mResetsSinceLastReport <= kMaxResetsSinceLastReport) { ++mResetsSinceLastReport; ++mResetsSinceLastReport; gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_RESET)); mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET)); } } mLastFrameNotification = now; mLastFrameNotification = now; } } void HintSessionWrapper::sendLoadIncreaseHint() { void HintSessionWrapper::sendLoadIncreaseHint() { if (!init()) return; if (!init()) return; gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_UP)); mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP)); mLastFrameNotification = systemTime(); } bool HintSessionWrapper::alive() { return mHintSession != nullptr; } nsecs_t HintSessionWrapper::getLastUpdate() { return mLastFrameNotification; } // Requires passing in its shared_ptr since it shouldn't own a shared_ptr to itself void HintSessionWrapper::delayedDestroy(RenderThread& rt, nsecs_t delay, std::shared_ptr<HintSessionWrapper> wrapperPtr) { nsecs_t lastUpdate = wrapperPtr->getLastUpdate(); rt.queue().postDelayed(delay, [lastUpdate = lastUpdate, wrapper = wrapperPtr]() mutable { if (wrapper->getLastUpdate() == lastUpdate) { wrapper->destroy(); } // Ensure the shared_ptr is killed at the end of the method wrapper = nullptr; }); } } } /* namespace renderthread */ } /* namespace renderthread */ Loading
libs/hwui/renderthread/HintSessionWrapper.h +33 −1 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <android/performance_hint.h> #include <android/performance_hint.h> #include <future> #include <future> #include <optional> #include "utils/TimeUtils.h" #include "utils/TimeUtils.h" Loading @@ -27,8 +28,12 @@ namespace uirenderer { namespace renderthread { namespace renderthread { class RenderThread; class HintSessionWrapper { class HintSessionWrapper { public: public: friend class HintSessionWrapperTests; HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId); HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId); ~HintSessionWrapper(); ~HintSessionWrapper(); Loading @@ -38,10 +43,15 @@ public: void sendLoadIncreaseHint(); void sendLoadIncreaseHint(); bool init(); bool init(); void destroy(); void destroy(); bool alive(); nsecs_t getLastUpdate(); void delayedDestroy(renderthread::RenderThread& rt, nsecs_t delay, std::shared_ptr<HintSessionWrapper> wrapperPtr); private: private: APerformanceHintSession* mHintSession = nullptr; APerformanceHintSession* mHintSession = nullptr; std::future<APerformanceHintSession*> mHintSessionFuture; // This needs to work concurrently for testing std::optional<std::shared_future<APerformanceHintSession*>> mHintSessionFuture; int mResetsSinceLastReport = 0; int mResetsSinceLastReport = 0; nsecs_t mLastFrameNotification = 0; nsecs_t mLastFrameNotification = 0; Loading @@ -55,6 +65,28 @@ private: static constexpr nsecs_t kResetHintTimeout = 100_ms; static constexpr nsecs_t kResetHintTimeout = 100_ms; static constexpr int64_t kSanityCheckLowerBound = 100_us; static constexpr int64_t kSanityCheckLowerBound = 100_us; static constexpr int64_t kSanityCheckUpperBound = 10_s; static constexpr int64_t kSanityCheckUpperBound = 10_s; // Allows easier stub when testing class HintSessionBinding { public: virtual ~HintSessionBinding() = default; virtual void init(); APerformanceHintManager* (*getManager)(); APerformanceHintSession* (*createSession)(APerformanceHintManager* manager, const int32_t* tids, size_t tidCount, int64_t defaultTarget) = nullptr; void (*closeSession)(APerformanceHintSession* session) = nullptr; void (*updateTargetWorkDuration)(APerformanceHintSession* session, int64_t targetDuration) = nullptr; void (*reportActualWorkDuration)(APerformanceHintSession* session, int64_t actualDuration) = nullptr; void (*sendHint)(APerformanceHintSession* session, int32_t hintId) = nullptr; private: bool mInitialized = false; }; std::shared_ptr<HintSessionBinding> mBinding; }; }; } /* namespace renderthread */ } /* namespace renderthread */ Loading