blob: b34da5153a723bf584be6dfbffa1d73462b06d33 [file] [log] [blame]
Matt Buckleye9023cf2022-11-23 22:39:25 +00001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "HintSessionWrapper.h"
18
19#include <dlfcn.h>
Matt Buckley61726a32022-12-06 23:44:45 +000020#include <private/performance_hint_private.h>
Matt Buckleye9023cf2022-11-23 22:39:25 +000021#include <utils/Log.h>
22
Matt Buckley191f5cc2023-03-30 20:58:22 +000023#include <chrono>
Matt Buckleye9023cf2022-11-23 22:39:25 +000024#include <vector>
25
26#include "../Properties.h"
27#include "thread/CommonPool.h"
28
Matt Buckley191f5cc2023-03-30 20:58:22 +000029using namespace std::chrono_literals;
30
Matt Buckleye9023cf2022-11-23 22:39:25 +000031namespace android {
32namespace uirenderer {
33namespace renderthread {
34
Matt Buckley87765572023-09-07 05:52:07 +000035#define BIND_APH_METHOD(name) \
36 name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \
37 LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name)
Matt Buckleye9023cf2022-11-23 22:39:25 +000038
Matt Buckley87765572023-09-07 05:52:07 +000039void HintSessionWrapper::HintSessionBinding::init() {
40 if (mInitialized) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +000041
42 void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
43 LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
44
Matt Buckley87765572023-09-07 05:52:07 +000045 BIND_APH_METHOD(getManager);
46 BIND_APH_METHOD(createSession);
47 BIND_APH_METHOD(closeSession);
48 BIND_APH_METHOD(updateTargetWorkDuration);
49 BIND_APH_METHOD(reportActualWorkDuration);
50 BIND_APH_METHOD(sendHint);
Matt Buckleye9023cf2022-11-23 22:39:25 +000051
Matt Buckley87765572023-09-07 05:52:07 +000052 mInitialized = true;
Matt Buckleye9023cf2022-11-23 22:39:25 +000053}
54
Matt Buckleye9023cf2022-11-23 22:39:25 +000055HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
Matt Buckley87765572023-09-07 05:52:07 +000056 : mUiThreadId(uiThreadId)
57 , mRenderThreadId(renderThreadId)
58 , mBinding(std::make_shared<HintSessionBinding>()) {}
Matt Buckleye9023cf2022-11-23 22:39:25 +000059
60HintSessionWrapper::~HintSessionWrapper() {
Matt Buckley10d75fc2023-08-24 15:56:46 +000061 destroy();
62}
63
64void HintSessionWrapper::destroy() {
Matt Buckleybe9bd5d2023-10-12 19:37:36 +000065 if (mHintSessionFuture.valid()) {
66 mHintSession = mHintSessionFuture.get();
Matt Buckley10d75fc2023-08-24 15:56:46 +000067 }
Matt Buckleye9023cf2022-11-23 22:39:25 +000068 if (mHintSession) {
Matt Buckley87765572023-09-07 05:52:07 +000069 mBinding->closeSession(mHintSession);
Matt Buckley10d75fc2023-08-24 15:56:46 +000070 mSessionValid = true;
71 mHintSession = nullptr;
Matt Buckleye9023cf2022-11-23 22:39:25 +000072 }
73}
74
Matt Buckleye9023cf2022-11-23 22:39:25 +000075bool HintSessionWrapper::init() {
Matt Buckley191f5cc2023-03-30 20:58:22 +000076 if (mHintSession != nullptr) return true;
Matt Buckleybe9bd5d2023-10-12 19:37:36 +000077
Matt Buckley191f5cc2023-03-30 20:58:22 +000078 // If we're waiting for the session
Matt Buckleybe9bd5d2023-10-12 19:37:36 +000079 if (mHintSessionFuture.valid()) {
Matt Buckley191f5cc2023-03-30 20:58:22 +000080 // If the session is here
Matt Buckleybe9bd5d2023-10-12 19:37:36 +000081 if (mHintSessionFuture.wait_for(0s) == std::future_status::ready) {
82 mHintSession = mHintSessionFuture.get();
Matt Buckley191f5cc2023-03-30 20:58:22 +000083 if (mHintSession != nullptr) {
84 mSessionValid = true;
85 return true;
86 }
87 }
88 return false;
89 }
90
91 // If it broke last time we tried this, shouldn't be running, or
Matt Buckley124d0c672023-01-19 03:04:19 +000092 // has bad argument values, don't even bother
Matt Buckley191f5cc2023-03-30 20:58:22 +000093 if (!mSessionValid || !Properties::useHintManager || !Properties::isDrawingEnabled() ||
94 mUiThreadId < 0 || mRenderThreadId < 0) {
Matt Buckley124d0c672023-01-19 03:04:19 +000095 return false;
96 }
Matt Buckleye9023cf2022-11-23 22:39:25 +000097
98 // Assume that if we return before the end, it broke
99 mSessionValid = false;
100
Matt Buckley87765572023-09-07 05:52:07 +0000101 mBinding->init();
Matt Buckleye9023cf2022-11-23 22:39:25 +0000102
Matt Buckley87765572023-09-07 05:52:07 +0000103 APerformanceHintManager* manager = mBinding->getManager();
Matt Buckleye9023cf2022-11-23 22:39:25 +0000104 if (!manager) return false;
105
106 std::vector<pid_t> tids = CommonPool::getThreadIds();
107 tids.push_back(mUiThreadId);
108 tids.push_back(mRenderThreadId);
109
110 // Use a placeholder target value to initialize,
111 // this will always be replaced elsewhere before it gets used
Matt Buckleya25ad052023-10-12 19:42:23 +0000112 int64_t defaultTargetDurationNanos = 16666667;
Matt Buckley87765572023-09-07 05:52:07 +0000113 mHintSessionFuture = CommonPool::async([=, this, tids = std::move(tids)] {
Matt Buckleya25ad052023-10-12 19:42:23 +0000114 return mBinding->createSession(manager, tids.data(), tids.size(),
115 defaultTargetDurationNanos);
Matt Buckley191f5cc2023-03-30 20:58:22 +0000116 });
117 return false;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000118}
119
120void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000121 if (!init()) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000122 targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
123 if (targetWorkDurationNanos != mLastTargetWorkDuration &&
124 targetWorkDurationNanos > kSanityCheckLowerBound &&
125 targetWorkDurationNanos < kSanityCheckUpperBound) {
126 mLastTargetWorkDuration = targetWorkDurationNanos;
Matt Buckley87765572023-09-07 05:52:07 +0000127 mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos);
Matt Buckleye9023cf2022-11-23 22:39:25 +0000128 }
129 mLastFrameNotification = systemTime();
130}
131
132void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000133 if (!init()) return;
Matt Buckley814f9fc2023-05-03 14:32:11 +0000134 mResetsSinceLastReport = 0;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000135 if (actualDurationNanos > kSanityCheckLowerBound &&
136 actualDurationNanos < kSanityCheckUpperBound) {
Matt Buckley87765572023-09-07 05:52:07 +0000137 mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos);
Matt Buckleye9023cf2022-11-23 22:39:25 +0000138 }
139}
140
141void HintSessionWrapper::sendLoadResetHint() {
Matt Buckley814f9fc2023-05-03 14:32:11 +0000142 static constexpr int kMaxResetsSinceLastReport = 2;
Matt Buckley191f5cc2023-03-30 20:58:22 +0000143 if (!init()) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000144 nsecs_t now = systemTime();
Matt Buckley814f9fc2023-05-03 14:32:11 +0000145 if (now - mLastFrameNotification > kResetHintTimeout &&
146 mResetsSinceLastReport <= kMaxResetsSinceLastReport) {
147 ++mResetsSinceLastReport;
Matt Buckley87765572023-09-07 05:52:07 +0000148 mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET));
Matt Buckleye9023cf2022-11-23 22:39:25 +0000149 }
150 mLastFrameNotification = now;
151}
152
Matt Buckleyac5f7552022-12-19 22:03:27 +0000153void HintSessionWrapper::sendLoadIncreaseHint() {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000154 if (!init()) return;
Matt Buckley87765572023-09-07 05:52:07 +0000155 mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP));
Matt Buckleyac5f7552022-12-19 22:03:27 +0000156}
157
Matt Buckleye9023cf2022-11-23 22:39:25 +0000158} /* namespace renderthread */
159} /* namespace uirenderer */
160} /* namespace android */