• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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