blob: c571b742d2d1a5219a9320c96f089d1b418ec625 [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
Matt Buckley56093a72022-11-07 21:50:50 +000019#include <aidl/android/hardware/power/SessionHint.h>
Matt Buckley423c1b32023-06-28 19:13:42 +000020#include <aidl/android/hardware/power/SessionMode.h>
Bo Liu44267722021-07-16 17:03:20 -040021#include <android/os/IHintManager.h>
22#include <android/os/IHintSession.h>
Bo Liu2b739bb2021-11-10 19:20:03 -050023#include <android/performance_hint.h>
Bo Liu44267722021-07-16 17:03:20 -040024#include <binder/Binder.h>
25#include <binder/IBinder.h>
26#include <binder/IServiceManager.h>
27#include <performance_hint_private.h>
28#include <utils/SystemClock.h>
29
Matt Buckley56093a72022-11-07 21:50:50 +000030#include <chrono>
Bo Liu2b739bb2021-11-10 19:20:03 -050031#include <utility>
32#include <vector>
33
Bo Liu44267722021-07-16 17:03:20 -040034using namespace android;
35using namespace android::os;
36
Matt Buckley56093a72022-11-07 21:50:50 +000037using namespace std::chrono_literals;
38
39using AidlSessionHint = aidl::android::hardware::power::SessionHint;
Matt Buckley423c1b32023-06-28 19:13:42 +000040using AidlSessionMode = aidl::android::hardware::power::SessionMode;
Matt Buckley56093a72022-11-07 21:50:50 +000041
Bo Liu44267722021-07-16 17:03:20 -040042struct APerformanceHintSession;
43
Matt Buckley56093a72022-11-07 21:50:50 +000044constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
45
Bo Liu44267722021-07-16 17:03:20 -040046struct APerformanceHintManager {
47public:
48 static APerformanceHintManager* getInstance();
49 APerformanceHintManager(sp<IHintManager> service, int64_t preferredRateNanos);
50 APerformanceHintManager() = delete;
51 ~APerformanceHintManager() = default;
52
53 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
54 int64_t initialTargetWorkDurationNanos);
55 int64_t getPreferredRateNanos() const;
56
57private:
58 static APerformanceHintManager* create(sp<IHintManager> iHintManager);
59
60 sp<IHintManager> mHintManager;
Bo Liu9acc5582022-02-17 16:47:32 -050061 const sp<IBinder> mToken = sp<BBinder>::make();
Bo Liu44267722021-07-16 17:03:20 -040062 const int64_t mPreferredRateNanos;
63};
64
65struct APerformanceHintSession {
66public:
Peiyong Lin095de762022-11-11 18:28:12 +000067 APerformanceHintSession(sp<IHintManager> hintManager, sp<IHintSession> session,
68 int64_t preferredRateNanos, int64_t targetDurationNanos);
Bo Liu44267722021-07-16 17:03:20 -040069 APerformanceHintSession() = delete;
70 ~APerformanceHintSession();
71
72 int updateTargetWorkDuration(int64_t targetDurationNanos);
73 int reportActualWorkDuration(int64_t actualDurationNanos);
Steven Moreland42a8cce2023-03-03 23:31:17 +000074 int sendHint(SessionHint hint);
Peiyong Lin095de762022-11-11 18:28:12 +000075 int setThreads(const int32_t* threadIds, size_t size);
76 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +000077 int setPreferPowerEfficiency(bool enabled);
Bo Liu44267722021-07-16 17:03:20 -040078
79private:
80 friend struct APerformanceHintManager;
81
Peiyong Lin095de762022-11-11 18:28:12 +000082 sp<IHintManager> mHintManager;
Bo Liu44267722021-07-16 17:03:20 -040083 sp<IHintSession> mHintSession;
84 // HAL preferred update rate
85 const int64_t mPreferredRateNanos;
86 // Target duration for choosing update rate
87 int64_t mTargetDurationNanos;
Wei Wang00feb502022-10-18 10:56:59 -070088 // First target hit timestamp
89 int64_t mFirstTargetMetTimestamp;
90 // Last target hit timestamp
91 int64_t mLastTargetMetTimestamp;
Matt Buckley56093a72022-11-07 21:50:50 +000092 // Last hint reported from sendHint indexed by hint value
93 std::vector<int64_t> mLastHintSentTimestamp;
Bo Liu44267722021-07-16 17:03:20 -040094 // Cached samples
95 std::vector<int64_t> mActualDurationsNanos;
96 std::vector<int64_t> mTimestampsNanos;
97};
98
99static IHintManager* gIHintManagerForTesting = nullptr;
100static APerformanceHintManager* gHintManagerForTesting = nullptr;
101
102// ===================================== APerformanceHintManager implementation
103APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager,
104 int64_t preferredRateNanos)
105 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {}
106
107APerformanceHintManager* APerformanceHintManager::getInstance() {
108 if (gHintManagerForTesting) return gHintManagerForTesting;
109 if (gIHintManagerForTesting) {
110 APerformanceHintManager* manager = create(gIHintManagerForTesting);
111 gIHintManagerForTesting = nullptr;
112 return manager;
113 }
114 static APerformanceHintManager* instance = create(nullptr);
115 return instance;
116}
117
118APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manager) {
119 if (!manager) {
120 manager = interface_cast<IHintManager>(
121 defaultServiceManager()->checkService(String16("performance_hint")));
122 }
123 if (manager == nullptr) {
124 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
125 return nullptr;
126 }
127 int64_t preferredRateNanos = -1L;
128 binder::Status ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
129 if (!ret.isOk()) {
130 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__,
131 ret.exceptionMessage().c_str());
132 return nullptr;
133 }
134 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400135 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400136 }
137 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
138}
139
140APerformanceHintSession* APerformanceHintManager::createSession(
141 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
Bo Liu44267722021-07-16 17:03:20 -0400142 std::vector<int32_t> tids(threadIds, threadIds + size);
143 sp<IHintSession> session;
144 binder::Status ret =
Bo Liu9acc5582022-02-17 16:47:32 -0500145 mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
Bo Liu44267722021-07-16 17:03:20 -0400146 if (!ret.isOk() || !session) {
Xiang Wang883ee642023-08-17 16:49:16 -0700147 ALOGE("%s: PerformanceHint cannot create hint session. %s", __FUNCTION__,
148 ret.exceptionMessage().c_str());
Bo Liu44267722021-07-16 17:03:20 -0400149 return nullptr;
150 }
Peiyong Lin095de762022-11-11 18:28:12 +0000151 return new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Bo Liu44267722021-07-16 17:03:20 -0400152 initialTargetWorkDurationNanos);
153}
154
155int64_t APerformanceHintManager::getPreferredRateNanos() const {
156 return mPreferredRateNanos;
157}
158
159// ===================================== APerformanceHintSession implementation
160
Peiyong Lin095de762022-11-11 18:28:12 +0000161APerformanceHintSession::APerformanceHintSession(sp<IHintManager> hintManager,
162 sp<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400163 int64_t preferredRateNanos,
164 int64_t targetDurationNanos)
Peiyong Lin095de762022-11-11 18:28:12 +0000165 : mHintManager(hintManager),
166 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400167 mPreferredRateNanos(preferredRateNanos),
168 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700169 mFirstTargetMetTimestamp(0),
Matt Buckley56093a72022-11-07 21:50:50 +0000170 mLastTargetMetTimestamp(0) {
171 const std::vector<AidlSessionHint> sessionHintRange{ndk::enum_range<AidlSessionHint>().begin(),
172 ndk::enum_range<AidlSessionHint>().end()};
173
174 mLastHintSentTimestamp = std::vector<int64_t>(sessionHintRange.size(), 0);
175}
Bo Liu44267722021-07-16 17:03:20 -0400176
177APerformanceHintSession::~APerformanceHintSession() {
178 binder::Status ret = mHintSession->close();
179 if (!ret.isOk()) {
180 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
181 }
182}
183
184int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
185 if (targetDurationNanos <= 0) {
186 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
187 return EINVAL;
188 }
189 binder::Status ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
190 if (!ret.isOk()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000191 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
Bo Liu44267722021-07-16 17:03:20 -0400192 ret.exceptionMessage().c_str());
193 return EPIPE;
194 }
195 mTargetDurationNanos = targetDurationNanos;
196 /**
197 * Most of the workload is target_duration dependent, so now clear the cached samples
198 * as they are most likely obsolete.
199 */
200 mActualDurationsNanos.clear();
201 mTimestampsNanos.clear();
Wei Wang00feb502022-10-18 10:56:59 -0700202 mFirstTargetMetTimestamp = 0;
203 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400204 return 0;
205}
206
207int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
208 if (actualDurationNanos <= 0) {
209 ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__);
210 return EINVAL;
211 }
212 int64_t now = elapsedRealtimeNano();
213 mActualDurationsNanos.push_back(actualDurationNanos);
214 mTimestampsNanos.push_back(now);
215
Wei Wang00feb502022-10-18 10:56:59 -0700216 if (actualDurationNanos >= mTargetDurationNanos) {
217 // Reset timestamps if we are equal or over the target.
218 mFirstTargetMetTimestamp = 0;
219 } else {
220 // Set mFirstTargetMetTimestamp for first time meeting target.
221 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
222 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
223 mFirstTargetMetTimestamp = now;
224 }
225 /**
226 * Rate limit the change if the update is over mPreferredRateNanos since first
227 * meeting target and less than mPreferredRateNanos since last meeting target.
228 */
229 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
230 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
231 return 0;
232 }
233 mLastTargetMetTimestamp = now;
Wei Wang9f174f42021-11-11 22:56:05 -0800234 }
Bo Liu44267722021-07-16 17:03:20 -0400235
236 binder::Status ret =
237 mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
Bo Liu44267722021-07-16 17:03:20 -0400238 if (!ret.isOk()) {
239 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
240 ret.exceptionMessage().c_str());
Wei Wang00feb502022-10-18 10:56:59 -0700241 mFirstTargetMetTimestamp = 0;
242 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400243 return EPIPE;
244 }
Wei Wang00feb502022-10-18 10:56:59 -0700245 mActualDurationsNanos.clear();
246 mTimestampsNanos.clear();
247
Bo Liu44267722021-07-16 17:03:20 -0400248 return 0;
249}
250
Steven Moreland42a8cce2023-03-03 23:31:17 +0000251int APerformanceHintSession::sendHint(SessionHint hint) {
Matt Buckley56093a72022-11-07 21:50:50 +0000252 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
253 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000254 return EINVAL;
255 }
Matt Buckley56093a72022-11-07 21:50:50 +0000256 int64_t now = elapsedRealtimeNano();
257
258 // Limit sendHint to a pre-detemined rate for safety
259 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
260 return 0;
261 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000262
263 binder::Status ret = mHintSession->sendHint(hint);
264
265 if (!ret.isOk()) {
266 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
267 return EPIPE;
268 }
Matt Buckley56093a72022-11-07 21:50:50 +0000269 mLastHintSentTimestamp[hint] = now;
Matt Buckley354cc0a2022-09-28 20:54:46 +0000270 return 0;
271}
272
Peiyong Lin095de762022-11-11 18:28:12 +0000273int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
274 if (size == 0) {
275 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
276 return EINVAL;
277 }
278 std::vector<int32_t> tids(threadIds, threadIds + size);
279 binder::Status ret = mHintManager->setHintSessionThreads(mHintSession, tids);
280 if (!ret.isOk()) {
281 ALOGE("%s: failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
Xiang Wangbee6f162023-07-18 17:58:10 -0700282 if (ret.exceptionCode() == binder::Status::Exception::EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000283 return EINVAL;
Xiang Wangbee6f162023-07-18 17:58:10 -0700284 } else if (ret.exceptionCode() == binder::Status::Exception::EX_SECURITY) {
285 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000286 }
287 return EPIPE;
288 }
289 return 0;
290}
291
292int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
293 std::vector<int32_t> tids;
294 binder::Status ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
295 if (!ret.isOk()) {
296 ALOGE("%s: failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
297 return EPIPE;
298 }
299
300 // When threadIds is nullptr, this is the first call to determine the size
301 // of the thread ids list.
302 if (threadIds == nullptr) {
303 *size = tids.size();
304 return 0;
305 }
306
307 // Second call to return the actual list of thread ids.
308 *size = tids.size();
309 for (size_t i = 0; i < *size; ++i) {
310 threadIds[i] = tids[i];
311 }
312 return 0;
313}
314
Matt Buckley423c1b32023-06-28 19:13:42 +0000315int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
316 binder::Status ret =
317 mHintSession->setMode(static_cast<int32_t>(AidlSessionMode::POWER_EFFICIENCY), enabled);
318
319 if (!ret.isOk()) {
320 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
321 ret.exceptionMessage().c_str());
322 return EPIPE;
323 }
324 return OK;
325}
326
Bo Liu44267722021-07-16 17:03:20 -0400327// ===================================== C API
328APerformanceHintManager* APerformanceHint_getManager() {
329 return APerformanceHintManager::getInstance();
330}
331
332APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
333 const int32_t* threadIds, size_t size,
334 int64_t initialTargetWorkDurationNanos) {
335 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
336}
337
338int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
339 return manager->getPreferredRateNanos();
340}
341
342int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
343 int64_t targetDurationNanos) {
344 return session->updateTargetWorkDuration(targetDurationNanos);
345}
346
347int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
348 int64_t actualDurationNanos) {
349 return session->reportActualWorkDuration(actualDurationNanos);
350}
351
Bo Liu44267722021-07-16 17:03:20 -0400352void APerformanceHint_closeSession(APerformanceHintSession* session) {
353 delete session;
354}
355
Steven Moreland42a8cce2023-03-03 23:31:17 +0000356int APerformanceHint_sendHint(void* session, SessionHint hint) {
Matt Buckley61726a32022-12-06 23:44:45 +0000357 return reinterpret_cast<APerformanceHintSession*>(session)->sendHint(hint);
358}
359
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000360int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000361 size_t size) {
362 if (session == nullptr) {
363 return EINVAL;
364 }
365 return session->setThreads(threadIds, size);
366}
367
368int APerformanceHint_getThreadIds(void* aPerformanceHintSession, int32_t* const threadIds,
369 size_t* const size) {
370 if (aPerformanceHintSession == nullptr) {
371 return EINVAL;
372 }
373 return static_cast<APerformanceHintSession*>(aPerformanceHintSession)
374 ->getThreadIds(threadIds, size);
375}
376
Matt Buckley423c1b32023-06-28 19:13:42 +0000377int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
378 return session->setPreferPowerEfficiency(enabled);
379}
380
Bo Liu44267722021-07-16 17:03:20 -0400381void APerformanceHint_setIHintManagerForTesting(void* iManager) {
382 delete gHintManagerForTesting;
383 gHintManagerForTesting = nullptr;
384 gIHintManagerForTesting = static_cast<IHintManager*>(iManager);
385}