blob: 95b7513caa306be949ef76e4dcb9a4d4220881da [file] [log] [blame]
Bo Liu44267722021-07-16 17:03:20 -04001/*
2 * Copyright (C) 2021 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#define LOG_TAG "perf_hint"
18
Bo Liu44267722021-07-16 17:03:20 -040019#include <android/os/IHintManager.h>
20#include <android/os/IHintSession.h>
Bo Liu2b739bb2021-11-10 19:20:03 -050021#include <android/performance_hint.h>
Bo Liu44267722021-07-16 17:03:20 -040022#include <binder/Binder.h>
23#include <binder/IBinder.h>
24#include <binder/IServiceManager.h>
25#include <performance_hint_private.h>
26#include <utils/SystemClock.h>
27
Bo Liu2b739bb2021-11-10 19:20:03 -050028#include <utility>
29#include <vector>
30
Bo Liu44267722021-07-16 17:03:20 -040031using namespace android;
32using namespace android::os;
33
34struct APerformanceHintSession;
35
36struct APerformanceHintManager {
37public:
38 static APerformanceHintManager* getInstance();
39 APerformanceHintManager(sp<IHintManager> service, int64_t preferredRateNanos);
40 APerformanceHintManager() = delete;
41 ~APerformanceHintManager() = default;
42
43 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
44 int64_t initialTargetWorkDurationNanos);
45 int64_t getPreferredRateNanos() const;
46
47private:
48 static APerformanceHintManager* create(sp<IHintManager> iHintManager);
49
50 sp<IHintManager> mHintManager;
Bo Liu9acc5582022-02-17 16:47:32 -050051 const sp<IBinder> mToken = sp<BBinder>::make();
Bo Liu44267722021-07-16 17:03:20 -040052 const int64_t mPreferredRateNanos;
53};
54
55struct APerformanceHintSession {
56public:
57 APerformanceHintSession(sp<IHintSession> session, int64_t preferredRateNanos,
58 int64_t targetDurationNanos);
59 APerformanceHintSession() = delete;
60 ~APerformanceHintSession();
61
62 int updateTargetWorkDuration(int64_t targetDurationNanos);
63 int reportActualWorkDuration(int64_t actualDurationNanos);
Matt Buckley354cc0a2022-09-28 20:54:46 +000064 int sendHint(int32_t hint);
Bo Liu44267722021-07-16 17:03:20 -040065
66private:
67 friend struct APerformanceHintManager;
68
69 sp<IHintSession> mHintSession;
70 // HAL preferred update rate
71 const int64_t mPreferredRateNanos;
72 // Target duration for choosing update rate
73 int64_t mTargetDurationNanos;
Wei Wang00feb502022-10-18 10:56:59 -070074 // First target hit timestamp
75 int64_t mFirstTargetMetTimestamp;
76 // Last target hit timestamp
77 int64_t mLastTargetMetTimestamp;
Bo Liu44267722021-07-16 17:03:20 -040078 // Cached samples
79 std::vector<int64_t> mActualDurationsNanos;
80 std::vector<int64_t> mTimestampsNanos;
81};
82
83static IHintManager* gIHintManagerForTesting = nullptr;
84static APerformanceHintManager* gHintManagerForTesting = nullptr;
85
86// ===================================== APerformanceHintManager implementation
87APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager,
88 int64_t preferredRateNanos)
89 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {}
90
91APerformanceHintManager* APerformanceHintManager::getInstance() {
92 if (gHintManagerForTesting) return gHintManagerForTesting;
93 if (gIHintManagerForTesting) {
94 APerformanceHintManager* manager = create(gIHintManagerForTesting);
95 gIHintManagerForTesting = nullptr;
96 return manager;
97 }
98 static APerformanceHintManager* instance = create(nullptr);
99 return instance;
100}
101
102APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manager) {
103 if (!manager) {
104 manager = interface_cast<IHintManager>(
105 defaultServiceManager()->checkService(String16("performance_hint")));
106 }
107 if (manager == nullptr) {
108 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
109 return nullptr;
110 }
111 int64_t preferredRateNanos = -1L;
112 binder::Status ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
113 if (!ret.isOk()) {
114 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__,
115 ret.exceptionMessage().c_str());
116 return nullptr;
117 }
118 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400119 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400120 }
121 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
122}
123
124APerformanceHintSession* APerformanceHintManager::createSession(
125 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
Bo Liu44267722021-07-16 17:03:20 -0400126 std::vector<int32_t> tids(threadIds, threadIds + size);
127 sp<IHintSession> session;
128 binder::Status ret =
Bo Liu9acc5582022-02-17 16:47:32 -0500129 mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
Bo Liu44267722021-07-16 17:03:20 -0400130 if (!ret.isOk() || !session) {
131 return nullptr;
132 }
133 return new APerformanceHintSession(std::move(session), mPreferredRateNanos,
134 initialTargetWorkDurationNanos);
135}
136
137int64_t APerformanceHintManager::getPreferredRateNanos() const {
138 return mPreferredRateNanos;
139}
140
141// ===================================== APerformanceHintSession implementation
142
143APerformanceHintSession::APerformanceHintSession(sp<IHintSession> session,
144 int64_t preferredRateNanos,
145 int64_t targetDurationNanos)
146 : mHintSession(std::move(session)),
147 mPreferredRateNanos(preferredRateNanos),
148 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700149 mFirstTargetMetTimestamp(0),
150 mLastTargetMetTimestamp(0) {}
Bo Liu44267722021-07-16 17:03:20 -0400151
152APerformanceHintSession::~APerformanceHintSession() {
153 binder::Status ret = mHintSession->close();
154 if (!ret.isOk()) {
155 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
156 }
157}
158
159int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
160 if (targetDurationNanos <= 0) {
161 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
162 return EINVAL;
163 }
164 binder::Status ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
165 if (!ret.isOk()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000166 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
Bo Liu44267722021-07-16 17:03:20 -0400167 ret.exceptionMessage().c_str());
168 return EPIPE;
169 }
170 mTargetDurationNanos = targetDurationNanos;
171 /**
172 * Most of the workload is target_duration dependent, so now clear the cached samples
173 * as they are most likely obsolete.
174 */
175 mActualDurationsNanos.clear();
176 mTimestampsNanos.clear();
Wei Wang00feb502022-10-18 10:56:59 -0700177 mFirstTargetMetTimestamp = 0;
178 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400179 return 0;
180}
181
182int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
183 if (actualDurationNanos <= 0) {
184 ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__);
185 return EINVAL;
186 }
187 int64_t now = elapsedRealtimeNano();
188 mActualDurationsNanos.push_back(actualDurationNanos);
189 mTimestampsNanos.push_back(now);
190
Wei Wang00feb502022-10-18 10:56:59 -0700191 if (actualDurationNanos >= mTargetDurationNanos) {
192 // Reset timestamps if we are equal or over the target.
193 mFirstTargetMetTimestamp = 0;
194 } else {
195 // Set mFirstTargetMetTimestamp for first time meeting target.
196 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
197 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
198 mFirstTargetMetTimestamp = now;
199 }
200 /**
201 * Rate limit the change if the update is over mPreferredRateNanos since first
202 * meeting target and less than mPreferredRateNanos since last meeting target.
203 */
204 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
205 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
206 return 0;
207 }
208 mLastTargetMetTimestamp = now;
Wei Wang9f174f42021-11-11 22:56:05 -0800209 }
Bo Liu44267722021-07-16 17:03:20 -0400210
211 binder::Status ret =
212 mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
Bo Liu44267722021-07-16 17:03:20 -0400213 if (!ret.isOk()) {
214 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
215 ret.exceptionMessage().c_str());
Wei Wang00feb502022-10-18 10:56:59 -0700216 mFirstTargetMetTimestamp = 0;
217 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400218 return EPIPE;
219 }
Wei Wang00feb502022-10-18 10:56:59 -0700220 mActualDurationsNanos.clear();
221 mTimestampsNanos.clear();
222
Bo Liu44267722021-07-16 17:03:20 -0400223 return 0;
224}
225
Matt Buckley354cc0a2022-09-28 20:54:46 +0000226int APerformanceHintSession::sendHint(int32_t hint) {
227 if (hint < 0) {
228 ALOGE("%s: session hint value must be greater than zero", __FUNCTION__);
229 return EINVAL;
230 }
231
232 binder::Status ret = mHintSession->sendHint(hint);
233
234 if (!ret.isOk()) {
235 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
236 return EPIPE;
237 }
238 return 0;
239}
240
Bo Liu44267722021-07-16 17:03:20 -0400241// ===================================== C API
242APerformanceHintManager* APerformanceHint_getManager() {
243 return APerformanceHintManager::getInstance();
244}
245
246APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
247 const int32_t* threadIds, size_t size,
248 int64_t initialTargetWorkDurationNanos) {
249 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
250}
251
252int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
253 return manager->getPreferredRateNanos();
254}
255
256int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
257 int64_t targetDurationNanos) {
258 return session->updateTargetWorkDuration(targetDurationNanos);
259}
260
261int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
262 int64_t actualDurationNanos) {
263 return session->reportActualWorkDuration(actualDurationNanos);
264}
265
Bo Liu44267722021-07-16 17:03:20 -0400266void APerformanceHint_closeSession(APerformanceHintSession* session) {
267 delete session;
268}
269
Matt Buckley61726a32022-12-06 23:44:45 +0000270int APerformanceHint_sendHint(void* session, int32_t hint) {
271 return reinterpret_cast<APerformanceHintSession*>(session)->sendHint(hint);
272}
273
Bo Liu44267722021-07-16 17:03:20 -0400274void APerformanceHint_setIHintManagerForTesting(void* iManager) {
275 delete gHintManagerForTesting;
276 gHintManagerForTesting = nullptr;
277 gIHintManagerForTesting = static_cast<IHintManager*>(iManager);
278}