diff options
| author | 2021-04-11 00:16:23 +0000 | |
|---|---|---|
| committer | 2021-04-11 00:16:23 +0000 | |
| commit | 080abd80f4f648f2e45fb4eb1e409bca1b128d4f (patch) | |
| tree | 98cea2c2e704763cdcc44f61e4f94960382d275b /libs/hwui | |
| parent | 84f96c845ba75c43d7ad4679065086b79d773175 (diff) | |
| parent | 027b2188473bd48c34cdafad1705abac7fff9356 (diff) | |
Merge changes from topic "android_dynamic_performance_framework" into sc-dev
* changes:
Integrate HWUI with PerformanceHintManager
ADPF: Add HintManagerService
ADPF: PerformanceHintManager API implementation
Diffstat (limited to 'libs/hwui')
| -rw-r--r-- | libs/hwui/FrameInfo.cpp | 29 | ||||
| -rw-r--r-- | libs/hwui/FrameInfo.h | 3 | ||||
| -rw-r--r-- | libs/hwui/Properties.cpp | 7 | ||||
| -rw-r--r-- | libs/hwui/Properties.h | 17 | ||||
| -rw-r--r-- | libs/hwui/jni/android_graphics_HardwareRenderer.cpp | 95 | ||||
| -rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 29 | ||||
| -rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.h | 6 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderProxy.cpp | 6 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderProxy.h | 2 | ||||
| -rw-r--r-- | libs/hwui/thread/CommonPool.cpp | 26 | ||||
| -rw-r--r-- | libs/hwui/thread/CommonPool.h | 5 |
11 files changed, 201 insertions, 24 deletions
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp index 2448cc904104..51fbf363f51c 100644 --- a/libs/hwui/FrameInfo.cpp +++ b/libs/hwui/FrameInfo.cpp @@ -21,29 +21,16 @@ namespace android { namespace uirenderer { const std::array FrameInfoNames{ - "Flags", - "FrameTimelineVsyncId", - "IntendedVsync", - "Vsync", - "InputEventId", - "HandleInputStart", - "AnimationStart", - "PerformTraversalsStart", - "DrawStart", - "FrameDeadline", - "SyncQueued", - "SyncStart", - "IssueDrawCommandsStart", - "SwapBuffers", - "FrameCompleted", - "DequeueBufferDuration", - "QueueBufferDuration", - "GpuCompleted", - "SwapBuffersCompleted", - "DisplayPresentTime", + "Flags", "FrameTimelineVsyncId", "IntendedVsync", + "Vsync", "InputEventId", "HandleInputStart", + "AnimationStart", "PerformTraversalsStart", "DrawStart", + "FrameDeadline", "FrameStartTime", "SyncQueued", + "SyncStart", "IssueDrawCommandsStart", "SwapBuffers", + "FrameCompleted", "DequeueBufferDuration", "QueueBufferDuration", + "GpuCompleted", "SwapBuffersCompleted", "DisplayPresentTime", }; -static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 20, +static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 21, "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)"); void FrameInfo::importUiThreadInfo(int64_t* info) { diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h index e9b2f4a9bb3b..62ac4ca5fdad 100644 --- a/libs/hwui/FrameInfo.h +++ b/libs/hwui/FrameInfo.h @@ -28,7 +28,7 @@ namespace android { namespace uirenderer { -static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 10; +static constexpr size_t UI_THREAD_FRAME_INFO_SIZE = 11; enum class FrameInfoIndex { Flags = 0, @@ -41,6 +41,7 @@ enum class FrameInfoIndex { PerformTraversalsStart, DrawStart, FrameDeadline, + FrameStartTime, // End of UI frame info SyncQueued, diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp index e58f31fd15eb..7af0a221d228 100644 --- a/libs/hwui/Properties.cpp +++ b/libs/hwui/Properties.cpp @@ -81,6 +81,9 @@ bool Properties::isolatedProcess = false; int Properties::contextPriority = 0; float Properties::defaultSdrWhitePoint = 200.f; +bool Properties::useHintManager = true; +int Properties::targetCpuTimePercentage = 70; + bool Properties::load() { bool prevDebugLayersUpdates = debugLayersUpdates; bool prevDebugOverdraw = debugOverdraw; @@ -128,6 +131,10 @@ bool Properties::load() { runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false); + useHintManager = base::GetBoolProperty(PROPERTY_USE_HINT_MANAGER, true); + targetCpuTimePercentage = base::GetIntProperty(PROPERTY_TARGET_CPU_TIME_PERCENTAGE, 70); + if (targetCpuTimePercentage <= 0 || targetCpuTimePercentage > 100) targetCpuTimePercentage = 70; + return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw); } diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index ea9cbd592d29..1cb87be98051 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -158,6 +158,20 @@ enum DebugLevel { #define PROPERTY_CAPTURE_SKP_FILENAME "debug.hwui.skp_filename" /** + * Controls whether HWUI will send timing hints to HintManager for + * better CPU scheduling. Accepted values are "true" and "false". + */ +#define PROPERTY_USE_HINT_MANAGER "debug.hwui.use_hint_manager" + +/** + * Percentage of frame time that's used for CPU work. The rest is + * reserved for GPU work. This is used with use_hint_manager to + * provide timing hints to HintManager. Accepted values are + * integer from 1-100. + */ +#define PROPERTY_TARGET_CPU_TIME_PERCENTAGE "debug.hwui.target_cpu_time_percent" + +/** * Property for whether this is running in the emulator. */ #define PROPERTY_IS_EMULATOR "ro.boot.qemu" @@ -253,6 +267,9 @@ public: static float defaultSdrWhitePoint; + static bool useHintManager; + static int targetCpuTimePercentage; + private: static ProfileType sProfileType; static bool sDisableProfileBars; diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp index f24ba5c1c878..bd1da985a33e 100644 --- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp +++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp @@ -34,14 +34,18 @@ #include <renderthread/RenderProxy.h> #include <renderthread/RenderTask.h> #include <renderthread/RenderThread.h> +#include <thread/CommonPool.h> #include <utils/Color.h> #include <utils/RefBase.h> #include <utils/StrongPointer.h> #include <utils/Timers.h> #include <utils/TraceUtils.h> +#include <pthread.h> + #include <algorithm> #include <atomic> +#include <vector> #include "android_graphics_HardwareRendererObserver.h" @@ -53,6 +57,10 @@ using namespace android::uirenderer::renderthread; struct { jclass clazz; jmethodID invokePictureCapturedCallback; + jmethodID createHintSession; + jmethodID updateTargetWorkDuration; + jmethodID reportActualWorkDuration; + jmethodID closeHintSession; } gHardwareRenderer; struct { @@ -71,6 +79,14 @@ static JNIEnv* getenv(JavaVM* vm) { return env; } +static bool hasExceptionAndClear(JNIEnv* env) { + if (GraphicsJNI::hasException(env)) { + env->ExceptionClear(); + return true; + } + return false; +} + typedef ANativeWindow* (*ANW_fromSurface)(JNIEnv* env, jobject surface); ANW_fromSurface fromSurface; @@ -120,6 +136,67 @@ private: } }; +class HintSessionWrapper : public LightRefBase<HintSessionWrapper> { +public: + static sp<HintSessionWrapper> create(JNIEnv* env, RenderProxy* proxy) { + if (!Properties::useHintManager) return nullptr; + + // Include UI thread (self), render thread, and thread pool. + std::vector<int> tids = CommonPool::getThreadIds(); + tids.push_back(proxy->getRenderThreadTid()); + tids.push_back(pthread_gettid_np(pthread_self())); + + jintArray tidsArray = env->NewIntArray(tids.size()); + if (hasExceptionAndClear(env)) return nullptr; + env->SetIntArrayRegion(tidsArray, 0, tids.size(), reinterpret_cast<jint*>(tids.data())); + if (hasExceptionAndClear(env)) return nullptr; + jobject session = env->CallStaticObjectMethod( + gHardwareRenderer.clazz, gHardwareRenderer.createHintSession, tidsArray); + if (hasExceptionAndClear(env) || !session) return nullptr; + return new HintSessionWrapper(env, session); + } + + ~HintSessionWrapper() { + if (!mSession) return; + JNIEnv* env = getenv(mVm); + env->CallStaticVoidMethod(gHardwareRenderer.clazz, gHardwareRenderer.closeHintSession, + mSession); + hasExceptionAndClear(env); + env->DeleteGlobalRef(mSession); + mSession = nullptr; + } + + void updateTargetWorkDuration(long targetDurationNanos) { + if (!mSession) return; + JNIEnv* env = getenv(mVm); + env->CallStaticVoidMethod(gHardwareRenderer.clazz, + gHardwareRenderer.updateTargetWorkDuration, mSession, + static_cast<jlong>(targetDurationNanos)); + hasExceptionAndClear(env); + } + + void reportActualWorkDuration(long actualDurationNanos) { + if (!mSession) return; + JNIEnv* env = getenv(mVm); + env->CallStaticVoidMethod(gHardwareRenderer.clazz, + gHardwareRenderer.reportActualWorkDuration, mSession, + static_cast<jlong>(actualDurationNanos)); + hasExceptionAndClear(env); + } + +private: + HintSessionWrapper(JNIEnv* env, jobject jobject) { + env->GetJavaVM(&mVm); + if (jobject) { + mSession = env->NewGlobalRef(jobject); + LOG_ALWAYS_FATAL_IF(!mSession, "Failed to make global ref"); + } + } + + JavaVM* mVm = nullptr; + jobject mSession = nullptr; +}; + static void android_view_ThreadedRenderer_rotateProcessStatsBuffer(JNIEnv* env, jobject clazz) { RenderProxy::rotateProcessStatsBuffer(); } @@ -147,6 +224,12 @@ static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject claz RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr); ContextFactoryImpl factory(rootRenderNode); RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory); + sp<HintSessionWrapper> wrapper = HintSessionWrapper::create(env, proxy); + if (wrapper) { + proxy->setHintSessionCallbacks( + [wrapper](int64_t nanos) { wrapper->updateTargetWorkDuration(nanos); }, + [wrapper](int64_t nanos) { wrapper->reportActualWorkDuration(nanos); }); + } return (jlong) proxy; } @@ -769,6 +852,18 @@ int register_android_view_ThreadedRenderer(JNIEnv* env) { gHardwareRenderer.invokePictureCapturedCallback = GetStaticMethodIDOrDie(env, hardwareRenderer, "invokePictureCapturedCallback", "(JLandroid/graphics/HardwareRenderer$PictureCapturedCallback;)V"); + gHardwareRenderer.createHintSession = + GetStaticMethodIDOrDie(env, hardwareRenderer, "createHintSession", + "([I)Landroid/os/PerformanceHintManager$Session;"); + gHardwareRenderer.updateTargetWorkDuration = + GetStaticMethodIDOrDie(env, hardwareRenderer, "updateTargetWorkDuration", + "(Landroid/os/PerformanceHintManager$Session;J)V"); + gHardwareRenderer.reportActualWorkDuration = + GetStaticMethodIDOrDie(env, hardwareRenderer, "reportActualWorkDuration", + "(Landroid/os/PerformanceHintManager$Session;J)V"); + gHardwareRenderer.closeHintSession = + GetStaticMethodIDOrDie(env, hardwareRenderer, "closeHintSession", + "(Landroid/os/PerformanceHintManager$Session;)V"); jclass frameCallbackClass = FindClassOrDie(env, "android/graphics/HardwareRenderer$FrameDrawingCallback"); diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 3408ffda3f9d..7a38a3bc9c05 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -21,6 +21,7 @@ #include "../DeferredLayerUpdater.h" #include "../DisplayList.h" +#include "../Properties.h" #include "../RenderNode.h" #include "CanvasContext.h" #include "RenderThread.h" @@ -44,6 +45,12 @@ void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, mTargetNode = targetNode; } +void DrawFrameTask::setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration, + std::function<void(int64_t)> reportActualWorkDuration) { + mUpdateTargetWorkDuration = std::move(updateTargetWorkDuration); + mReportActualWorkDuration = std::move(reportActualWorkDuration); +} + void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) { LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!"); @@ -102,6 +109,9 @@ void DrawFrameTask::run() { CanvasContext* context = mContext; std::function<void(int64_t)> callback = std::move(mFrameCallback); mFrameCallback = nullptr; + int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)]; + int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)]; + int64_t frameStartTime = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameStartTime)]; // From this point on anything in "this" is *UNSAFE TO ACCESS* if (canUnblockUiThread) { @@ -124,6 +134,25 @@ void DrawFrameTask::run() { if (!canUnblockUiThread) { unblockUiThread(); } + + // These member callbacks are effectively const as they are set once during init, so it's safe + // to use these directly instead of making local copies. + if (mUpdateTargetWorkDuration && mReportActualWorkDuration) { + constexpr int64_t kSanityCheckLowerBound = 100000; // 0.1ms + constexpr int64_t kSanityCheckUpperBound = 10000000000; // 10s + int64_t targetWorkDuration = frameDeadline - intendedVsync; + targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100; + if (targetWorkDuration > kSanityCheckLowerBound && + targetWorkDuration < kSanityCheckUpperBound && + targetWorkDuration != mLastTargetWorkDuration) { + mLastTargetWorkDuration = targetWorkDuration; + mUpdateTargetWorkDuration(targetWorkDuration); + } + int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime; + if (frameDuration > kSanityCheckLowerBound && frameDuration < kSanityCheckUpperBound) { + mReportActualWorkDuration(frameDuration); + } + } } bool DrawFrameTask::syncFrameState(TreeInfo& info) { diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h index 696cfaef3cd7..3bb574aff59b 100644 --- a/libs/hwui/renderthread/DrawFrameTask.h +++ b/libs/hwui/renderthread/DrawFrameTask.h @@ -61,6 +61,8 @@ public: virtual ~DrawFrameTask(); void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode); + void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration, + std::function<void(int64_t)> reportActualWorkDuration); void setContentDrawBounds(int left, int top, int right, int bottom) { mContentDrawBounds.set(left, top, right, bottom); } @@ -107,6 +109,10 @@ private: std::function<void(int64_t)> mFrameCallback; std::function<void(int64_t)> mFrameCompleteCallback; + + nsecs_t mLastTargetWorkDuration = 0; + std::function<void(int64_t)> mUpdateTargetWorkDuration; + std::function<void(int64_t)> mReportActualWorkDuration; }; } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 423cc08189ca..9361abd20852 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -76,6 +76,12 @@ void RenderProxy::setName(const char* name) { mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); }); } +void RenderProxy::setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration, + std::function<void(int64_t)> reportActualWorkDuration) { + mDrawFrameTask.setHintSessionCallbacks(std::move(updateTargetWorkDuration), + std::move(reportActualWorkDuration)); +} + void RenderProxy::setSurface(ANativeWindow* window, bool enableTimeout) { if (window) { ANativeWindow_acquire(window); } mRenderThread.queue().post([this, win = window, enableTimeout]() mutable { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 366d6b5a172c..8d55d3c55570 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -71,6 +71,8 @@ public: void setSwapBehavior(SwapBehavior swapBehavior); bool loadSystemProperties(); void setName(const char* name); + void setHintSessionCallbacks(std::function<void(int64_t)> updateTargetWorkDuration, + std::function<void(int64_t)> reportActualWorkDuration); void setSurface(ANativeWindow* window, bool enableTimeout = true); void setSurfaceControl(ASurfaceControl* surfaceControl); diff --git a/libs/hwui/thread/CommonPool.cpp b/libs/hwui/thread/CommonPool.cpp index d011bdfe945e..dc92f9f0d39a 100644 --- a/libs/hwui/thread/CommonPool.cpp +++ b/libs/hwui/thread/CommonPool.cpp @@ -29,14 +29,23 @@ CommonPool::CommonPool() { ATRACE_CALL(); CommonPool* pool = this; + std::mutex mLock; + std::vector<int> tids(THREAD_COUNT); + std::vector<std::condition_variable> tidConditionVars(THREAD_COUNT); + // Create 2 workers for (int i = 0; i < THREAD_COUNT; i++) { - std::thread worker([pool, i] { + std::thread worker([pool, i, &mLock, &tids, &tidConditionVars] { { std::array<char, 20> name{"hwuiTask"}; snprintf(name.data(), name.size(), "hwuiTask%d", i); auto self = pthread_self(); pthread_setname_np(self, name.data()); + { + std::unique_lock lock(mLock); + tids[i] = pthread_gettid_np(self); + tidConditionVars[i].notify_one(); + } setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND); auto startHook = renderthread::RenderThread::getOnStartHook(); if (startHook) { @@ -47,6 +56,15 @@ CommonPool::CommonPool() { }); worker.detach(); } + { + std::unique_lock lock(mLock); + for (int i = 0; i < THREAD_COUNT; i++) { + while (!tids[i]) { + tidConditionVars[i].wait(lock); + } + } + } + mWorkerThreadIds = std::move(tids); } CommonPool& CommonPool::instance() { @@ -58,6 +76,10 @@ void CommonPool::post(Task&& task) { instance().enqueue(std::move(task)); } +std::vector<int> CommonPool::getThreadIds() { + return instance().mWorkerThreadIds; +} + void CommonPool::enqueue(Task&& task) { std::unique_lock lock(mLock); while (!mWorkQueue.hasSpace()) { @@ -104,4 +126,4 @@ void CommonPool::doWaitForIdle() { } } // namespace uirenderer -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/hwui/thread/CommonPool.h b/libs/hwui/thread/CommonPool.h index 7603eeef4692..74f852bd1413 100644 --- a/libs/hwui/thread/CommonPool.h +++ b/libs/hwui/thread/CommonPool.h @@ -25,6 +25,7 @@ #include <functional> #include <future> #include <mutex> +#include <vector> namespace android { namespace uirenderer { @@ -97,6 +98,8 @@ public: return task.get_future().get(); }; + static std::vector<int> getThreadIds(); + // For testing purposes only, blocks until all worker threads are parked. static void waitForIdle(); @@ -111,6 +114,8 @@ private: void workerLoop(); + std::vector<int> mWorkerThreadIds; + std::mutex mLock; std::condition_variable mCondition; int mWaitingThreads = 0; |