blob: 7a155c583fd4f155c3f3e9c8a8de012629c83733 [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
Igor Kraskevich2cec1582024-03-13 11:23:40 +000023#include <algorithm>
Matt Buckley191f5cc2023-03-30 20:58:22 +000024#include <chrono>
Matt Buckleye9023cf2022-11-23 22:39:25 +000025#include <vector>
26
27#include "../Properties.h"
Matt Buckley0daae6a2023-09-14 22:56:50 +000028#include "RenderThread.h"
Matt Buckleye9023cf2022-11-23 22:39:25 +000029#include "thread/CommonPool.h"
30
Matt Buckley191f5cc2023-03-30 20:58:22 +000031using namespace std::chrono_literals;
32
Matt Buckleye9023cf2022-11-23 22:39:25 +000033namespace android {
34namespace uirenderer {
35namespace renderthread {
36
Matt Buckley0c668362023-09-07 05:52:07 +000037#define BIND_APH_METHOD(name) \
38 name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \
39 LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name)
Matt Buckleye9023cf2022-11-23 22:39:25 +000040
Matt Buckley0c668362023-09-07 05:52:07 +000041void HintSessionWrapper::HintSessionBinding::init() {
42 if (mInitialized) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +000043
44 void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
45 LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
46
Matt Buckley0c668362023-09-07 05:52:07 +000047 BIND_APH_METHOD(getManager);
Matt Buckley27da1342024-04-05 23:10:48 +000048 BIND_APH_METHOD(createSessionInternal);
Matt Buckley0c668362023-09-07 05:52:07 +000049 BIND_APH_METHOD(closeSession);
50 BIND_APH_METHOD(updateTargetWorkDuration);
51 BIND_APH_METHOD(reportActualWorkDuration);
52 BIND_APH_METHOD(sendHint);
Igor Kraskevich2cec1582024-03-13 11:23:40 +000053 BIND_APH_METHOD(setThreads);
Matt Buckleye9023cf2022-11-23 22:39:25 +000054
Matt Buckley0c668362023-09-07 05:52:07 +000055 mInitialized = true;
Matt Buckleye9023cf2022-11-23 22:39:25 +000056}
57
Matt Buckleye9023cf2022-11-23 22:39:25 +000058HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
Matt Buckley0c668362023-09-07 05:52:07 +000059 : mUiThreadId(uiThreadId)
60 , mRenderThreadId(renderThreadId)
61 , mBinding(std::make_shared<HintSessionBinding>()) {}
Matt Buckleye9023cf2022-11-23 22:39:25 +000062
63HintSessionWrapper::~HintSessionWrapper() {
Matt Buckleyac620f62023-08-24 15:56:46 +000064 destroy();
65}
66
67void HintSessionWrapper::destroy() {
Matt Buckley0daae6a2023-09-14 22:56:50 +000068 if (mHintSessionFuture.has_value()) {
69 mHintSession = mHintSessionFuture->get();
70 mHintSessionFuture = std::nullopt;
Matt Buckleyac620f62023-08-24 15:56:46 +000071 }
Igor Kraskevich2cec1582024-03-13 11:23:40 +000072 if (mSetThreadsFuture.has_value()) {
73 mSetThreadsFuture->wait();
74 mSetThreadsFuture = std::nullopt;
75 }
Matt Buckleye9023cf2022-11-23 22:39:25 +000076 if (mHintSession) {
Matt Buckley0c668362023-09-07 05:52:07 +000077 mBinding->closeSession(mHintSession);
Matt Buckleyac620f62023-08-24 15:56:46 +000078 mSessionValid = true;
79 mHintSession = nullptr;
Matt Buckleye9023cf2022-11-23 22:39:25 +000080 }
Matt Buckley1b99d782023-09-26 19:30:25 +000081 mResetsSinceLastReport = 0;
Matt Buckleye9023cf2022-11-23 22:39:25 +000082}
83
Matt Buckleye9023cf2022-11-23 22:39:25 +000084bool HintSessionWrapper::init() {
Matt Buckley191f5cc2023-03-30 20:58:22 +000085 if (mHintSession != nullptr) return true;
Matt Buckley191f5cc2023-03-30 20:58:22 +000086 // If we're waiting for the session
Matt Buckley0daae6a2023-09-14 22:56:50 +000087 if (mHintSessionFuture.has_value()) {
Matt Buckley191f5cc2023-03-30 20:58:22 +000088 // If the session is here
Matt Buckley0daae6a2023-09-14 22:56:50 +000089 if (mHintSessionFuture->wait_for(0s) == std::future_status::ready) {
90 mHintSession = mHintSessionFuture->get();
91 mHintSessionFuture = std::nullopt;
Matt Buckley191f5cc2023-03-30 20:58:22 +000092 if (mHintSession != nullptr) {
93 mSessionValid = true;
94 return true;
95 }
96 }
97 return false;
98 }
99
100 // If it broke last time we tried this, shouldn't be running, or
Matt Buckley124d0c672023-01-19 03:04:19 +0000101 // has bad argument values, don't even bother
Matt Buckley191f5cc2023-03-30 20:58:22 +0000102 if (!mSessionValid || !Properties::useHintManager || !Properties::isDrawingEnabled() ||
103 mUiThreadId < 0 || mRenderThreadId < 0) {
Matt Buckley124d0c672023-01-19 03:04:19 +0000104 return false;
105 }
Matt Buckleye9023cf2022-11-23 22:39:25 +0000106
107 // Assume that if we return before the end, it broke
108 mSessionValid = false;
109
Matt Buckley0c668362023-09-07 05:52:07 +0000110 mBinding->init();
Matt Buckleye9023cf2022-11-23 22:39:25 +0000111
Matt Buckley0c668362023-09-07 05:52:07 +0000112 APerformanceHintManager* manager = mBinding->getManager();
Matt Buckleye9023cf2022-11-23 22:39:25 +0000113 if (!manager) return false;
114
Igor Kraskevich2cec1582024-03-13 11:23:40 +0000115 mPermanentSessionTids = CommonPool::getThreadIds();
116 mPermanentSessionTids.push_back(mUiThreadId);
117 mPermanentSessionTids.push_back(mRenderThreadId);
Matt Buckleye9023cf2022-11-23 22:39:25 +0000118
Matt Buckley1b99d782023-09-26 19:30:25 +0000119 // Use the cached target value if there is one, otherwise use a default. This is to ensure
120 // the cached target and target in PowerHAL are consistent, and that it updates correctly
121 // whenever there is a change.
122 int64_t targetDurationNanos =
123 mLastTargetWorkDuration == 0 ? kDefaultTargetDuration : mLastTargetWorkDuration;
Igor Kraskevich2cec1582024-03-13 11:23:40 +0000124 mHintSessionFuture = CommonPool::async([=, this, tids = mPermanentSessionTids] {
Matt Buckley27da1342024-04-05 23:10:48 +0000125 return mBinding->createSessionInternal(manager, tids.data(), tids.size(),
126 targetDurationNanos, SessionTag::HWUI);
Matt Buckley191f5cc2023-03-30 20:58:22 +0000127 });
128 return false;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000129}
130
131void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000132 if (!init()) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000133 targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
134 if (targetWorkDurationNanos != mLastTargetWorkDuration &&
135 targetWorkDurationNanos > kSanityCheckLowerBound &&
136 targetWorkDurationNanos < kSanityCheckUpperBound) {
137 mLastTargetWorkDuration = targetWorkDurationNanos;
Matt Buckley0c668362023-09-07 05:52:07 +0000138 mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos);
Matt Buckleye9023cf2022-11-23 22:39:25 +0000139 }
140 mLastFrameNotification = systemTime();
141}
142
143void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000144 if (!init()) return;
Matt Buckley814f9fc2023-05-03 14:32:11 +0000145 mResetsSinceLastReport = 0;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000146 if (actualDurationNanos > kSanityCheckLowerBound &&
147 actualDurationNanos < kSanityCheckUpperBound) {
Matt Buckley0c668362023-09-07 05:52:07 +0000148 mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos);
Matt Buckleye9023cf2022-11-23 22:39:25 +0000149 }
Matt Buckley0daae6a2023-09-14 22:56:50 +0000150 mLastFrameNotification = systemTime();
Matt Buckleye9023cf2022-11-23 22:39:25 +0000151}
152
Igor Kraskevich2cec1582024-03-13 11:23:40 +0000153void HintSessionWrapper::setActiveFunctorThreads(std::vector<pid_t> threadIds) {
154 if (!init()) return;
155 if (!mBinding || !mHintSession) return;
156 // Sort the vector to make sure they're compared as sets.
157 std::sort(threadIds.begin(), threadIds.end());
158 if (threadIds == mActiveFunctorTids) return;
159 mActiveFunctorTids = std::move(threadIds);
160 std::vector<pid_t> combinedTids = mPermanentSessionTids;
161 std::copy(mActiveFunctorTids.begin(), mActiveFunctorTids.end(),
162 std::back_inserter(combinedTids));
163 mSetThreadsFuture = CommonPool::async([this, tids = std::move(combinedTids)] {
164 int ret = mBinding->setThreads(mHintSession, tids.data(), tids.size());
165 ALOGE_IF(ret != 0, "APerformaceHint_setThreads failed: %d", ret);
166 return ret;
167 });
168}
169
Matt Buckleye9023cf2022-11-23 22:39:25 +0000170void HintSessionWrapper::sendLoadResetHint() {
Matt Buckley814f9fc2023-05-03 14:32:11 +0000171 static constexpr int kMaxResetsSinceLastReport = 2;
Matt Buckley191f5cc2023-03-30 20:58:22 +0000172 if (!init()) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000173 nsecs_t now = systemTime();
Matt Buckley814f9fc2023-05-03 14:32:11 +0000174 if (now - mLastFrameNotification > kResetHintTimeout &&
175 mResetsSinceLastReport <= kMaxResetsSinceLastReport) {
176 ++mResetsSinceLastReport;
Matt Buckley0c668362023-09-07 05:52:07 +0000177 mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET));
Matt Buckleye9023cf2022-11-23 22:39:25 +0000178 }
179 mLastFrameNotification = now;
180}
181
Matt Buckleyac5f7552022-12-19 22:03:27 +0000182void HintSessionWrapper::sendLoadIncreaseHint() {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000183 if (!init()) return;
Matt Buckley0c668362023-09-07 05:52:07 +0000184 mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP));
Matt Buckley0daae6a2023-09-14 22:56:50 +0000185}
186
187bool HintSessionWrapper::alive() {
188 return mHintSession != nullptr;
189}
190
191nsecs_t HintSessionWrapper::getLastUpdate() {
192 return mLastFrameNotification;
193}
194
195// Requires passing in its shared_ptr since it shouldn't own a shared_ptr to itself
196void HintSessionWrapper::delayedDestroy(RenderThread& rt, nsecs_t delay,
197 std::shared_ptr<HintSessionWrapper> wrapperPtr) {
198 nsecs_t lastUpdate = wrapperPtr->getLastUpdate();
199 rt.queue().postDelayed(delay, [lastUpdate = lastUpdate, wrapper = wrapperPtr]() mutable {
200 if (wrapper->getLastUpdate() == lastUpdate) {
201 wrapper->destroy();
202 }
203 // Ensure the shared_ptr is killed at the end of the method
204 wrapper = nullptr;
205 });
Matt Buckleyac5f7552022-12-19 22:03:27 +0000206}
207
Matt Buckleye9023cf2022-11-23 22:39:25 +0000208} /* namespace renderthread */
209} /* namespace uirenderer */
210} /* namespace android */