blob: 2362331aca26337898a2c99c45ecace90a575aa1 [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"
Matt Buckley0daae6a2023-09-14 22:56:50 +000027#include "RenderThread.h"
Matt Buckleye9023cf2022-11-23 22:39:25 +000028#include "thread/CommonPool.h"
29
Matt Buckley191f5cc2023-03-30 20:58:22 +000030using namespace std::chrono_literals;
31
Matt Buckleye9023cf2022-11-23 22:39:25 +000032namespace android {
33namespace uirenderer {
34namespace renderthread {
35
Matt Buckley0c668362023-09-07 05:52:07 +000036#define BIND_APH_METHOD(name) \
37 name = (decltype(name))dlsym(handle_, "APerformanceHint_" #name); \
38 LOG_ALWAYS_FATAL_IF(name == nullptr, "Failed to find required symbol APerformanceHint_" #name)
Matt Buckleye9023cf2022-11-23 22:39:25 +000039
Matt Buckley0c668362023-09-07 05:52:07 +000040void HintSessionWrapper::HintSessionBinding::init() {
41 if (mInitialized) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +000042
43 void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
44 LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
45
Matt Buckley0c668362023-09-07 05:52:07 +000046 BIND_APH_METHOD(getManager);
47 BIND_APH_METHOD(createSession);
48 BIND_APH_METHOD(closeSession);
49 BIND_APH_METHOD(updateTargetWorkDuration);
50 BIND_APH_METHOD(reportActualWorkDuration);
51 BIND_APH_METHOD(sendHint);
Matt Buckleye9023cf2022-11-23 22:39:25 +000052
Matt Buckley0c668362023-09-07 05:52:07 +000053 mInitialized = true;
Matt Buckleye9023cf2022-11-23 22:39:25 +000054}
55
Matt Buckleye9023cf2022-11-23 22:39:25 +000056HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
Matt Buckley0c668362023-09-07 05:52:07 +000057 : mUiThreadId(uiThreadId)
58 , mRenderThreadId(renderThreadId)
59 , mBinding(std::make_shared<HintSessionBinding>()) {}
Matt Buckleye9023cf2022-11-23 22:39:25 +000060
61HintSessionWrapper::~HintSessionWrapper() {
Matt Buckleyac620f62023-08-24 15:56:46 +000062 destroy();
63}
64
65void HintSessionWrapper::destroy() {
Matt Buckley0daae6a2023-09-14 22:56:50 +000066 if (mHintSessionFuture.has_value()) {
67 mHintSession = mHintSessionFuture->get();
68 mHintSessionFuture = std::nullopt;
Matt Buckleyac620f62023-08-24 15:56:46 +000069 }
Matt Buckleye9023cf2022-11-23 22:39:25 +000070 if (mHintSession) {
Matt Buckley0c668362023-09-07 05:52:07 +000071 mBinding->closeSession(mHintSession);
Matt Buckleyac620f62023-08-24 15:56:46 +000072 mSessionValid = true;
73 mHintSession = nullptr;
Matt Buckleye9023cf2022-11-23 22:39:25 +000074 }
Matt Buckley1b99d782023-09-26 19:30:25 +000075 mResetsSinceLastReport = 0;
Matt Buckleye9023cf2022-11-23 22:39:25 +000076}
77
Matt Buckleye9023cf2022-11-23 22:39:25 +000078bool HintSessionWrapper::init() {
Matt Buckley191f5cc2023-03-30 20:58:22 +000079 if (mHintSession != nullptr) return true;
Matt Buckley191f5cc2023-03-30 20:58:22 +000080 // If we're waiting for the session
Matt Buckley0daae6a2023-09-14 22:56:50 +000081 if (mHintSessionFuture.has_value()) {
Matt Buckley191f5cc2023-03-30 20:58:22 +000082 // If the session is here
Matt Buckley0daae6a2023-09-14 22:56:50 +000083 if (mHintSessionFuture->wait_for(0s) == std::future_status::ready) {
84 mHintSession = mHintSessionFuture->get();
85 mHintSessionFuture = std::nullopt;
Matt Buckley191f5cc2023-03-30 20:58:22 +000086 if (mHintSession != nullptr) {
87 mSessionValid = true;
88 return true;
89 }
90 }
91 return false;
92 }
93
94 // If it broke last time we tried this, shouldn't be running, or
Matt Buckley124d0c672023-01-19 03:04:19 +000095 // has bad argument values, don't even bother
Matt Buckley191f5cc2023-03-30 20:58:22 +000096 if (!mSessionValid || !Properties::useHintManager || !Properties::isDrawingEnabled() ||
97 mUiThreadId < 0 || mRenderThreadId < 0) {
Matt Buckley124d0c672023-01-19 03:04:19 +000098 return false;
99 }
Matt Buckleye9023cf2022-11-23 22:39:25 +0000100
101 // Assume that if we return before the end, it broke
102 mSessionValid = false;
103
Matt Buckley0c668362023-09-07 05:52:07 +0000104 mBinding->init();
Matt Buckleye9023cf2022-11-23 22:39:25 +0000105
Matt Buckley0c668362023-09-07 05:52:07 +0000106 APerformanceHintManager* manager = mBinding->getManager();
Matt Buckleye9023cf2022-11-23 22:39:25 +0000107 if (!manager) return false;
108
109 std::vector<pid_t> tids = CommonPool::getThreadIds();
110 tids.push_back(mUiThreadId);
111 tids.push_back(mRenderThreadId);
112
Matt Buckley1b99d782023-09-26 19:30:25 +0000113 // Use the cached target value if there is one, otherwise use a default. This is to ensure
114 // the cached target and target in PowerHAL are consistent, and that it updates correctly
115 // whenever there is a change.
116 int64_t targetDurationNanos =
117 mLastTargetWorkDuration == 0 ? kDefaultTargetDuration : mLastTargetWorkDuration;
Matt Buckley0c668362023-09-07 05:52:07 +0000118 mHintSessionFuture = CommonPool::async([=, this, tids = std::move(tids)] {
Matt Buckley1b99d782023-09-26 19:30:25 +0000119 return mBinding->createSession(manager, tids.data(), tids.size(), targetDurationNanos);
Matt Buckley191f5cc2023-03-30 20:58:22 +0000120 });
121 return false;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000122}
123
124void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000125 if (!init()) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000126 targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
127 if (targetWorkDurationNanos != mLastTargetWorkDuration &&
128 targetWorkDurationNanos > kSanityCheckLowerBound &&
129 targetWorkDurationNanos < kSanityCheckUpperBound) {
130 mLastTargetWorkDuration = targetWorkDurationNanos;
Matt Buckley0c668362023-09-07 05:52:07 +0000131 mBinding->updateTargetWorkDuration(mHintSession, targetWorkDurationNanos);
Matt Buckleye9023cf2022-11-23 22:39:25 +0000132 }
133 mLastFrameNotification = systemTime();
134}
135
136void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000137 if (!init()) return;
Matt Buckley814f9fc2023-05-03 14:32:11 +0000138 mResetsSinceLastReport = 0;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000139 if (actualDurationNanos > kSanityCheckLowerBound &&
140 actualDurationNanos < kSanityCheckUpperBound) {
Matt Buckley0c668362023-09-07 05:52:07 +0000141 mBinding->reportActualWorkDuration(mHintSession, actualDurationNanos);
Matt Buckleye9023cf2022-11-23 22:39:25 +0000142 }
Matt Buckley0daae6a2023-09-14 22:56:50 +0000143 mLastFrameNotification = systemTime();
Matt Buckleye9023cf2022-11-23 22:39:25 +0000144}
145
146void HintSessionWrapper::sendLoadResetHint() {
Matt Buckley814f9fc2023-05-03 14:32:11 +0000147 static constexpr int kMaxResetsSinceLastReport = 2;
Matt Buckley191f5cc2023-03-30 20:58:22 +0000148 if (!init()) return;
Matt Buckleye9023cf2022-11-23 22:39:25 +0000149 nsecs_t now = systemTime();
Matt Buckley814f9fc2023-05-03 14:32:11 +0000150 if (now - mLastFrameNotification > kResetHintTimeout &&
151 mResetsSinceLastReport <= kMaxResetsSinceLastReport) {
152 ++mResetsSinceLastReport;
Matt Buckley0c668362023-09-07 05:52:07 +0000153 mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_RESET));
Matt Buckleye9023cf2022-11-23 22:39:25 +0000154 }
155 mLastFrameNotification = now;
156}
157
Matt Buckleyac5f7552022-12-19 22:03:27 +0000158void HintSessionWrapper::sendLoadIncreaseHint() {
Matt Buckley191f5cc2023-03-30 20:58:22 +0000159 if (!init()) return;
Matt Buckley0c668362023-09-07 05:52:07 +0000160 mBinding->sendHint(mHintSession, static_cast<int32_t>(SessionHint::CPU_LOAD_UP));
Matt Buckley0daae6a2023-09-14 22:56:50 +0000161}
162
163bool HintSessionWrapper::alive() {
164 return mHintSession != nullptr;
165}
166
167nsecs_t HintSessionWrapper::getLastUpdate() {
168 return mLastFrameNotification;
169}
170
171// Requires passing in its shared_ptr since it shouldn't own a shared_ptr to itself
172void HintSessionWrapper::delayedDestroy(RenderThread& rt, nsecs_t delay,
173 std::shared_ptr<HintSessionWrapper> wrapperPtr) {
174 nsecs_t lastUpdate = wrapperPtr->getLastUpdate();
175 rt.queue().postDelayed(delay, [lastUpdate = lastUpdate, wrapper = wrapperPtr]() mutable {
176 if (wrapper->getLastUpdate() == lastUpdate) {
177 wrapper->destroy();
178 }
179 // Ensure the shared_ptr is killed at the end of the method
180 wrapper = nullptr;
181 });
Matt Buckleyac5f7552022-12-19 22:03:27 +0000182}
183
Matt Buckleye9023cf2022-11-23 22:39:25 +0000184} /* namespace renderthread */
185} /* namespace uirenderer */
186} /* namespace android */