1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker #include "HintSessionWrapper.h"
18*d57664e9SAndroid Build Coastguard Worker
19*d57664e9SAndroid Build Coastguard Worker #include <dlfcn.h>
20*d57664e9SAndroid Build Coastguard Worker #include <private/performance_hint_private.h>
21*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
22*d57664e9SAndroid Build Coastguard Worker
23*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
24*d57664e9SAndroid Build Coastguard Worker #include <chrono>
25*d57664e9SAndroid Build Coastguard Worker #include <vector>
26*d57664e9SAndroid Build Coastguard Worker
27*d57664e9SAndroid Build Coastguard Worker #include "../Properties.h"
28*d57664e9SAndroid Build Coastguard Worker #include "RenderThread.h"
29*d57664e9SAndroid Build Coastguard Worker #include "thread/CommonPool.h"
30*d57664e9SAndroid Build Coastguard Worker
31*d57664e9SAndroid Build Coastguard Worker using namespace std::chrono_literals;
32*d57664e9SAndroid Build Coastguard Worker
33*d57664e9SAndroid Build Coastguard Worker namespace android {
34*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
35*d57664e9SAndroid Build Coastguard Worker namespace renderthread {
36*d57664e9SAndroid Build Coastguard Worker
37*d57664e9SAndroid Build Coastguard Worker #define BIND_APH_METHOD(name) \
38*d57664e9SAndroid Build Coastguard Worker name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \
39*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name)
40*d57664e9SAndroid Build Coastguard Worker
init()41*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::HintSessionBinding::init() {
42*d57664e9SAndroid Build Coastguard Worker if (mInitialized) return;
43*d57664e9SAndroid Build Coastguard Worker
44*d57664e9SAndroid Build Coastguard Worker void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
45*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
46*d57664e9SAndroid Build Coastguard Worker
47*d57664e9SAndroid Build Coastguard Worker BIND_APH_METHOD(getManager);
48*d57664e9SAndroid Build Coastguard Worker BIND_APH_METHOD(createSessionInternal);
49*d57664e9SAndroid Build Coastguard Worker BIND_APH_METHOD(closeSession);
50*d57664e9SAndroid Build Coastguard Worker BIND_APH_METHOD(updateTargetWorkDuration);
51*d57664e9SAndroid Build Coastguard Worker BIND_APH_METHOD(reportActualWorkDuration);
52*d57664e9SAndroid Build Coastguard Worker BIND_APH_METHOD(sendHint);
53*d57664e9SAndroid Build Coastguard Worker BIND_APH_METHOD(setThreads);
54*d57664e9SAndroid Build Coastguard Worker
55*d57664e9SAndroid Build Coastguard Worker mInitialized = true;
56*d57664e9SAndroid Build Coastguard Worker }
57*d57664e9SAndroid Build Coastguard Worker
HintSessionWrapper(pid_t uiThreadId,pid_t renderThreadId)58*d57664e9SAndroid Build Coastguard Worker HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
59*d57664e9SAndroid Build Coastguard Worker : mUiThreadId(uiThreadId)
60*d57664e9SAndroid Build Coastguard Worker , mRenderThreadId(renderThreadId)
61*d57664e9SAndroid Build Coastguard Worker , mBinding(std::make_shared<HintSessionBinding>()) {}
62*d57664e9SAndroid Build Coastguard Worker
~HintSessionWrapper()63*d57664e9SAndroid Build Coastguard Worker HintSessionWrapper::~HintSessionWrapper() {
64*d57664e9SAndroid Build Coastguard Worker destroy();
65*d57664e9SAndroid Build Coastguard Worker }
66*d57664e9SAndroid Build Coastguard Worker
destroy()67*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::destroy() {
68*d57664e9SAndroid Build Coastguard Worker if (mHintSessionFuture.has_value()) {
69*d57664e9SAndroid Build Coastguard Worker mHintSession = mHintSessionFuture->get();
70*d57664e9SAndroid Build Coastguard Worker mHintSessionFuture = std::nullopt;
71*d57664e9SAndroid Build Coastguard Worker }
72*d57664e9SAndroid Build Coastguard Worker if (mSetThreadsFuture.has_value()) {
73*d57664e9SAndroid Build Coastguard Worker mSetThreadsFuture->wait();
74*d57664e9SAndroid Build Coastguard Worker mSetThreadsFuture = std::nullopt;
75*d57664e9SAndroid Build Coastguard Worker }
76*d57664e9SAndroid Build Coastguard Worker if (mHintSession) {
77*d57664e9SAndroid Build Coastguard Worker mBinding->closeSession(mHintSession);
78*d57664e9SAndroid Build Coastguard Worker mSessionValid = true;
79*d57664e9SAndroid Build Coastguard Worker mHintSession = nullptr;
80*d57664e9SAndroid Build Coastguard Worker }
81*d57664e9SAndroid Build Coastguard Worker mResetsSinceLastReport = 0;
82*d57664e9SAndroid Build Coastguard Worker }
83*d57664e9SAndroid Build Coastguard Worker
init()84*d57664e9SAndroid Build Coastguard Worker bool HintSessionWrapper::init() {
85*d57664e9SAndroid Build Coastguard Worker if (mHintSession != nullptr) return true;
86*d57664e9SAndroid Build Coastguard Worker // If we're waiting for the session
87*d57664e9SAndroid Build Coastguard Worker if (mHintSessionFuture.has_value()) {
88*d57664e9SAndroid Build Coastguard Worker // If the session is here
89*d57664e9SAndroid Build Coastguard Worker if (mHintSessionFuture->wait_for(0s) == std::future_status::ready) {
90*d57664e9SAndroid Build Coastguard Worker mHintSession = mHintSessionFuture->get();
91*d57664e9SAndroid Build Coastguard Worker mHintSessionFuture = std::nullopt;
92*d57664e9SAndroid Build Coastguard Worker if (mHintSession != nullptr) {
93*d57664e9SAndroid Build Coastguard Worker mSessionValid = true;
94*d57664e9SAndroid Build Coastguard Worker return true;
95*d57664e9SAndroid Build Coastguard Worker }
96*d57664e9SAndroid Build Coastguard Worker }
97*d57664e9SAndroid Build Coastguard Worker return false;
98*d57664e9SAndroid Build Coastguard Worker }
99*d57664e9SAndroid Build Coastguard Worker
100*d57664e9SAndroid Build Coastguard Worker // If it broke last time we tried this, shouldn't be running, or
101*d57664e9SAndroid Build Coastguard Worker // has bad argument values, don't even bother
102*d57664e9SAndroid Build Coastguard Worker if (!mSessionValid || !Properties::useHintManager || !Properties::isDrawingEnabled() ||
103*d57664e9SAndroid Build Coastguard Worker mUiThreadId < 0 || mRenderThreadId < 0) {
104*d57664e9SAndroid Build Coastguard Worker return false;
105*d57664e9SAndroid Build Coastguard Worker }
106*d57664e9SAndroid Build Coastguard Worker
107*d57664e9SAndroid Build Coastguard Worker // Assume that if we return before the end, it broke
108*d57664e9SAndroid Build Coastguard Worker mSessionValid = false;
109*d57664e9SAndroid Build Coastguard Worker
110*d57664e9SAndroid Build Coastguard Worker mBinding->init();
111*d57664e9SAndroid Build Coastguard Worker
112*d57664e9SAndroid Build Coastguard Worker APerformanceHintManager* manager = mBinding->getManager();
113*d57664e9SAndroid Build Coastguard Worker if (!manager) return false;
114*d57664e9SAndroid Build Coastguard Worker
115*d57664e9SAndroid Build Coastguard Worker mPermanentSessionTids = CommonPool::getThreadIds();
116*d57664e9SAndroid Build Coastguard Worker mPermanentSessionTids.push_back(mUiThreadId);
117*d57664e9SAndroid Build Coastguard Worker mPermanentSessionTids.push_back(mRenderThreadId);
118*d57664e9SAndroid Build Coastguard Worker
119*d57664e9SAndroid Build Coastguard Worker // Use the cached target value if there is one, otherwise use a default. This is to ensure
120*d57664e9SAndroid Build Coastguard Worker // the cached target and target in PowerHAL are consistent, and that it updates correctly
121*d57664e9SAndroid Build Coastguard Worker // whenever there is a change.
122*d57664e9SAndroid Build Coastguard Worker int64_t targetDurationNanos =
123*d57664e9SAndroid Build Coastguard Worker mLastTargetWorkDuration == 0 ? kDefaultTargetDuration : mLastTargetWorkDuration;
124*d57664e9SAndroid Build Coastguard Worker mHintSessionFuture = CommonPool::async([=, this, tids = mPermanentSessionTids] {
125*d57664e9SAndroid Build Coastguard Worker return mBinding->createSessionInternal(manager, tids.data(), tids.size(),
126*d57664e9SAndroid Build Coastguard Worker targetDurationNanos, SessionTag::HWUI);
127*d57664e9SAndroid Build Coastguard Worker });
128*d57664e9SAndroid Build Coastguard Worker return false;
129*d57664e9SAndroid Build Coastguard Worker }
130*d57664e9SAndroid Build Coastguard Worker
updateTargetWorkDuration(long targetWorkDurationNanos)131*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
132*d57664e9SAndroid Build Coastguard Worker if (!init()) return;
133*d57664e9SAndroid Build Coastguard Worker targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
134*d57664e9SAndroid Build Coastguard Worker if (targetWorkDurationNanos != mLastTargetWorkDuration &&
135*d57664e9SAndroid Build Coastguard Worker targetWorkDurationNanos > kSanityCheckLowerBound &&
136*d57664e9SAndroid Build Coastguard Worker targetWorkDurationNanos < kSanityCheckUpperBound) {
137*d57664e9SAndroid Build Coastguard Worker mLastTargetWorkDuration = targetWorkDurationNanos;
138*d57664e9SAndroid Build Coastguard Worker mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos);
139*d57664e9SAndroid Build Coastguard Worker }
140*d57664e9SAndroid Build Coastguard Worker mLastFrameNotification = systemTime();
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker
reportActualWorkDuration(long actualDurationNanos)143*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
144*d57664e9SAndroid Build Coastguard Worker if (!init()) return;
145*d57664e9SAndroid Build Coastguard Worker mResetsSinceLastReport = 0;
146*d57664e9SAndroid Build Coastguard Worker if (actualDurationNanos > kSanityCheckLowerBound &&
147*d57664e9SAndroid Build Coastguard Worker actualDurationNanos < kSanityCheckUpperBound) {
148*d57664e9SAndroid Build Coastguard Worker mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos);
149*d57664e9SAndroid Build Coastguard Worker }
150*d57664e9SAndroid Build Coastguard Worker mLastFrameNotification = systemTime();
151*d57664e9SAndroid Build Coastguard Worker }
152*d57664e9SAndroid Build Coastguard Worker
setActiveFunctorThreads(std::vector<pid_t> threadIds)153*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::setActiveFunctorThreads(std::vector<pid_t> threadIds) {
154*d57664e9SAndroid Build Coastguard Worker if (!init()) return;
155*d57664e9SAndroid Build Coastguard Worker if (!mBinding || !mHintSession) return;
156*d57664e9SAndroid Build Coastguard Worker // Sort the vector to make sure they're compared as sets.
157*d57664e9SAndroid Build Coastguard Worker std::sort(threadIds.begin(), threadIds.end());
158*d57664e9SAndroid Build Coastguard Worker if (threadIds == mActiveFunctorTids) return;
159*d57664e9SAndroid Build Coastguard Worker mActiveFunctorTids = std::move(threadIds);
160*d57664e9SAndroid Build Coastguard Worker std::vector<pid_t> combinedTids = mPermanentSessionTids;
161*d57664e9SAndroid Build Coastguard Worker std::copy(mActiveFunctorTids.begin(), mActiveFunctorTids.end(),
162*d57664e9SAndroid Build Coastguard Worker std::back_inserter(combinedTids));
163*d57664e9SAndroid Build Coastguard Worker mSetThreadsFuture = CommonPool::async([this, tids = std::move(combinedTids)] {
164*d57664e9SAndroid Build Coastguard Worker int ret = mBinding->setThreads(mHintSession, tids.data(), tids.size());
165*d57664e9SAndroid Build Coastguard Worker ALOGE_IF(ret != 0, "APerformaceHint_setThreads failed: %d", ret);
166*d57664e9SAndroid Build Coastguard Worker return ret;
167*d57664e9SAndroid Build Coastguard Worker });
168*d57664e9SAndroid Build Coastguard Worker }
169*d57664e9SAndroid Build Coastguard Worker
sendLoadResetHint()170*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::sendLoadResetHint() {
171*d57664e9SAndroid Build Coastguard Worker static constexpr int kMaxResetsSinceLastReport = 2;
172*d57664e9SAndroid Build Coastguard Worker if (!init()) return;
173*d57664e9SAndroid Build Coastguard Worker nsecs_t now = systemTime();
174*d57664e9SAndroid Build Coastguard Worker if (now - mLastFrameNotification > kResetHintTimeout &&
175*d57664e9SAndroid Build Coastguard Worker mResetsSinceLastReport <= kMaxResetsSinceLastReport) {
176*d57664e9SAndroid Build Coastguard Worker ++mResetsSinceLastReport;
177*d57664e9SAndroid Build Coastguard Worker mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET));
178*d57664e9SAndroid Build Coastguard Worker }
179*d57664e9SAndroid Build Coastguard Worker mLastFrameNotification = now;
180*d57664e9SAndroid Build Coastguard Worker }
181*d57664e9SAndroid Build Coastguard Worker
sendLoadIncreaseHint()182*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::sendLoadIncreaseHint() {
183*d57664e9SAndroid Build Coastguard Worker if (!init()) return;
184*d57664e9SAndroid Build Coastguard Worker mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP));
185*d57664e9SAndroid Build Coastguard Worker }
186*d57664e9SAndroid Build Coastguard Worker
alive()187*d57664e9SAndroid Build Coastguard Worker bool HintSessionWrapper::alive() {
188*d57664e9SAndroid Build Coastguard Worker return mHintSession != nullptr;
189*d57664e9SAndroid Build Coastguard Worker }
190*d57664e9SAndroid Build Coastguard Worker
getLastUpdate()191*d57664e9SAndroid Build Coastguard Worker nsecs_t HintSessionWrapper::getLastUpdate() {
192*d57664e9SAndroid Build Coastguard Worker return mLastFrameNotification;
193*d57664e9SAndroid Build Coastguard Worker }
194*d57664e9SAndroid Build Coastguard Worker
195*d57664e9SAndroid Build Coastguard Worker // Requires passing in its shared_ptr since it shouldn't own a shared_ptr to itself
delayedDestroy(RenderThread & rt,nsecs_t delay,std::shared_ptr<HintSessionWrapper> wrapperPtr)196*d57664e9SAndroid Build Coastguard Worker void HintSessionWrapper::delayedDestroy(RenderThread& rt, nsecs_t delay,
197*d57664e9SAndroid Build Coastguard Worker std::shared_ptr<HintSessionWrapper> wrapperPtr) {
198*d57664e9SAndroid Build Coastguard Worker nsecs_t lastUpdate = wrapperPtr->getLastUpdate();
199*d57664e9SAndroid Build Coastguard Worker rt.queue().postDelayed(delay, [lastUpdate = lastUpdate, wrapper = wrapperPtr]() mutable {
200*d57664e9SAndroid Build Coastguard Worker if (wrapper->getLastUpdate() == lastUpdate) {
201*d57664e9SAndroid Build Coastguard Worker wrapper->destroy();
202*d57664e9SAndroid Build Coastguard Worker }
203*d57664e9SAndroid Build Coastguard Worker // Ensure the shared_ptr is killed at the end of the method
204*d57664e9SAndroid Build Coastguard Worker wrapper = nullptr;
205*d57664e9SAndroid Build Coastguard Worker });
206*d57664e9SAndroid Build Coastguard Worker }
207*d57664e9SAndroid Build Coastguard Worker
208*d57664e9SAndroid Build Coastguard Worker } /* namespace renderthread */
209*d57664e9SAndroid Build Coastguard Worker } /* namespace uirenderer */
210*d57664e9SAndroid Build Coastguard Worker } /* namespace android */
211