blob: d627984c7ffff83c1606735958092629e0d891f9 [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);
64
65private:
66 friend struct APerformanceHintManager;
67
68 sp<IHintSession> mHintSession;
69 // HAL preferred update rate
70 const int64_t mPreferredRateNanos;
71 // Target duration for choosing update rate
72 int64_t mTargetDurationNanos;
73 // Last update timestamp
74 int64_t mLastUpdateTimestamp;
75 // Cached samples
76 std::vector<int64_t> mActualDurationsNanos;
77 std::vector<int64_t> mTimestampsNanos;
78};
79
80static IHintManager* gIHintManagerForTesting = nullptr;
81static APerformanceHintManager* gHintManagerForTesting = nullptr;
82
83// ===================================== APerformanceHintManager implementation
84APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager,
85 int64_t preferredRateNanos)
86 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {}
87
88APerformanceHintManager* APerformanceHintManager::getInstance() {
89 if (gHintManagerForTesting) return gHintManagerForTesting;
90 if (gIHintManagerForTesting) {
91 APerformanceHintManager* manager = create(gIHintManagerForTesting);
92 gIHintManagerForTesting = nullptr;
93 return manager;
94 }
95 static APerformanceHintManager* instance = create(nullptr);
96 return instance;
97}
98
99APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manager) {
100 if (!manager) {
101 manager = interface_cast<IHintManager>(
102 defaultServiceManager()->checkService(String16("performance_hint")));
103 }
104 if (manager == nullptr) {
105 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
106 return nullptr;
107 }
108 int64_t preferredRateNanos = -1L;
109 binder::Status ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
110 if (!ret.isOk()) {
111 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__,
112 ret.exceptionMessage().c_str());
113 return nullptr;
114 }
115 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400116 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400117 }
118 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
119}
120
121APerformanceHintSession* APerformanceHintManager::createSession(
122 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
Bo Liu44267722021-07-16 17:03:20 -0400123 std::vector<int32_t> tids(threadIds, threadIds + size);
124 sp<IHintSession> session;
125 binder::Status ret =
Bo Liu9acc5582022-02-17 16:47:32 -0500126 mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
Bo Liu44267722021-07-16 17:03:20 -0400127 if (!ret.isOk() || !session) {
128 return nullptr;
129 }
130 return new APerformanceHintSession(std::move(session), mPreferredRateNanos,
131 initialTargetWorkDurationNanos);
132}
133
134int64_t APerformanceHintManager::getPreferredRateNanos() const {
135 return mPreferredRateNanos;
136}
137
138// ===================================== APerformanceHintSession implementation
139
140APerformanceHintSession::APerformanceHintSession(sp<IHintSession> session,
141 int64_t preferredRateNanos,
142 int64_t targetDurationNanos)
143 : mHintSession(std::move(session)),
144 mPreferredRateNanos(preferredRateNanos),
145 mTargetDurationNanos(targetDurationNanos),
146 mLastUpdateTimestamp(elapsedRealtimeNano()) {}
147
148APerformanceHintSession::~APerformanceHintSession() {
149 binder::Status ret = mHintSession->close();
150 if (!ret.isOk()) {
151 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
152 }
153}
154
155int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
156 if (targetDurationNanos <= 0) {
157 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
158 return EINVAL;
159 }
160 binder::Status ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
161 if (!ret.isOk()) {
162 ALOGE("%s: HintSessionn updateTargetWorkDuration failed: %s", __FUNCTION__,
163 ret.exceptionMessage().c_str());
164 return EPIPE;
165 }
166 mTargetDurationNanos = targetDurationNanos;
167 /**
168 * Most of the workload is target_duration dependent, so now clear the cached samples
169 * as they are most likely obsolete.
170 */
171 mActualDurationsNanos.clear();
172 mTimestampsNanos.clear();
173 mLastUpdateTimestamp = elapsedRealtimeNano();
174 return 0;
175}
176
177int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
178 if (actualDurationNanos <= 0) {
179 ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__);
180 return EINVAL;
181 }
182 int64_t now = elapsedRealtimeNano();
183 mActualDurationsNanos.push_back(actualDurationNanos);
184 mTimestampsNanos.push_back(now);
185
186 /**
Wei Wang9f174f42021-11-11 22:56:05 -0800187 * Cache the hint if the hint is not overtime and the mLastUpdateTimestamp is
188 * still in the mPreferredRateNanos duration.
Bo Liu44267722021-07-16 17:03:20 -0400189 */
Wei Wang9f174f42021-11-11 22:56:05 -0800190 if (actualDurationNanos < mTargetDurationNanos &&
191 now - mLastUpdateTimestamp <= mPreferredRateNanos) {
192 return 0;
193 }
Bo Liu44267722021-07-16 17:03:20 -0400194
195 binder::Status ret =
196 mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
197 mActualDurationsNanos.clear();
198 mTimestampsNanos.clear();
199 if (!ret.isOk()) {
200 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
201 ret.exceptionMessage().c_str());
202 return EPIPE;
203 }
204 mLastUpdateTimestamp = now;
205 return 0;
206}
207
208// ===================================== C API
209APerformanceHintManager* APerformanceHint_getManager() {
210 return APerformanceHintManager::getInstance();
211}
212
213APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
214 const int32_t* threadIds, size_t size,
215 int64_t initialTargetWorkDurationNanos) {
216 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
217}
218
219int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
220 return manager->getPreferredRateNanos();
221}
222
223int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
224 int64_t targetDurationNanos) {
225 return session->updateTargetWorkDuration(targetDurationNanos);
226}
227
228int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
229 int64_t actualDurationNanos) {
230 return session->reportActualWorkDuration(actualDurationNanos);
231}
232
233void APerformanceHint_closeSession(APerformanceHintSession* session) {
234 delete session;
235}
236
237void APerformanceHint_setIHintManagerForTesting(void* iManager) {
238 delete gHintManagerForTesting;
239 gHintManagerForTesting = nullptr;
240 gIHintManagerForTesting = static_cast<IHintManager*>(iManager);
241}