1 /*
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
19 #include <android/os/IHintManager.h>
20 #include <android/os/IHintSession.h>
21 #include <android/performance_hint.h>
22 #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
28 #include <utility>
29 #include <vector>
30
31 using namespace android;
32 using namespace android::os;
33
34 struct APerformanceHintSession;
35
36 struct APerformanceHintManager {
37 public:
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
47 private:
48 static APerformanceHintManager* create(sp<IHintManager> iHintManager);
49
50 sp<IHintManager> mHintManager;
51 const sp<IBinder> mToken = sp<BBinder>::make();
52 const int64_t mPreferredRateNanos;
53 };
54
55 struct APerformanceHintSession {
56 public:
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
65 private:
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
80 static IHintManager* gIHintManagerForTesting = nullptr;
81 static APerformanceHintManager* gHintManagerForTesting = nullptr;
82
83 // ===================================== APerformanceHintManager implementation
APerformanceHintManager(sp<IHintManager> manager,int64_t preferredRateNanos)84 APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager,
85 int64_t preferredRateNanos)
86 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {}
87
getInstance()88 APerformanceHintManager* 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
create(sp<IHintManager> manager)99 APerformanceHintManager* 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) {
116 preferredRateNanos = -1L;
117 }
118 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
119 }
120
createSession(const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos)121 APerformanceHintSession* APerformanceHintManager::createSession(
122 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
123 std::vector<int32_t> tids(threadIds, threadIds + size);
124 sp<IHintSession> session;
125 binder::Status ret =
126 mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
127 if (!ret.isOk() || !session) {
128 return nullptr;
129 }
130 return new APerformanceHintSession(std::move(session), mPreferredRateNanos,
131 initialTargetWorkDurationNanos);
132 }
133
getPreferredRateNanos() const134 int64_t APerformanceHintManager::getPreferredRateNanos() const {
135 return mPreferredRateNanos;
136 }
137
138 // ===================================== APerformanceHintSession implementation
139
APerformanceHintSession(sp<IHintSession> session,int64_t preferredRateNanos,int64_t targetDurationNanos)140 APerformanceHintSession::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
~APerformanceHintSession()148 APerformanceHintSession::~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
updateTargetWorkDuration(int64_t targetDurationNanos)155 int 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
reportActualWorkDuration(int64_t actualDurationNanos)177 int 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 /**
187 * Cache the hint if the hint is not overtime and the mLastUpdateTimestamp is
188 * still in the mPreferredRateNanos duration.
189 */
190 if (actualDurationNanos < mTargetDurationNanos &&
191 now - mLastUpdateTimestamp <= mPreferredRateNanos) {
192 return 0;
193 }
194
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
APerformanceHint_getManager()209 APerformanceHintManager* APerformanceHint_getManager() {
210 return APerformanceHintManager::getInstance();
211 }
212
APerformanceHint_createSession(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos)213 APerformanceHintSession* 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
APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager * manager)219 int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
220 return manager->getPreferredRateNanos();
221 }
222
APerformanceHint_updateTargetWorkDuration(APerformanceHintSession * session,int64_t targetDurationNanos)223 int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
224 int64_t targetDurationNanos) {
225 return session->updateTargetWorkDuration(targetDurationNanos);
226 }
227
APerformanceHint_reportActualWorkDuration(APerformanceHintSession * session,int64_t actualDurationNanos)228 int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
229 int64_t actualDurationNanos) {
230 return session->reportActualWorkDuration(actualDurationNanos);
231 }
232
APerformanceHint_closeSession(APerformanceHintSession * session)233 void APerformanceHint_closeSession(APerformanceHintSession* session) {
234 delete session;
235 }
236
APerformanceHint_setIHintManagerForTesting(void * iManager)237 void APerformanceHint_setIHintManagerForTesting(void* iManager) {
238 delete gHintManagerForTesting;
239 gHintManagerForTesting = nullptr;
240 gIHintManagerForTesting = static_cast<IHintManager*>(iManager);
241 }
242