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 <utility> 20 #include <vector> 21 22 #include <android/os/IHintManager.h> 23 #include <android/os/IHintSession.h> 24 #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 30 using namespace android; 31 using namespace android::os; 32 33 struct APerformanceHintSession; 34 35 struct APerformanceHintManager { 36 public: 37 static APerformanceHintManager* getInstance(); 38 APerformanceHintManager(sp<IHintManager> service, int64_t preferredRateNanos); 39 APerformanceHintManager() = delete; 40 ~APerformanceHintManager() = default; 41 42 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size, 43 int64_t initialTargetWorkDurationNanos); 44 int64_t getPreferredRateNanos() const; 45 46 private: 47 static APerformanceHintManager* create(sp<IHintManager> iHintManager); 48 49 sp<IHintManager> mHintManager; 50 const int64_t mPreferredRateNanos; 51 }; 52 53 struct APerformanceHintSession { 54 public: 55 APerformanceHintSession(sp<IHintSession> session, int64_t preferredRateNanos, 56 int64_t targetDurationNanos); 57 APerformanceHintSession() = delete; 58 ~APerformanceHintSession(); 59 60 int updateTargetWorkDuration(int64_t targetDurationNanos); 61 int reportActualWorkDuration(int64_t actualDurationNanos); 62 63 private: 64 friend struct APerformanceHintManager; 65 66 sp<IHintSession> mHintSession; 67 // HAL preferred update rate 68 const int64_t mPreferredRateNanos; 69 // Target duration for choosing update rate 70 int64_t mTargetDurationNanos; 71 // Last update timestamp 72 int64_t mLastUpdateTimestamp; 73 // Cached samples 74 std::vector<int64_t> mActualDurationsNanos; 75 std::vector<int64_t> mTimestampsNanos; 76 }; 77 78 static IHintManager* gIHintManagerForTesting = nullptr; 79 static APerformanceHintManager* gHintManagerForTesting = nullptr; 80 81 // ===================================== APerformanceHintManager implementation 82 APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager, 83 int64_t preferredRateNanos) 84 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {} 85 86 APerformanceHintManager* APerformanceHintManager::getInstance() { 87 if (gHintManagerForTesting) return gHintManagerForTesting; 88 if (gIHintManagerForTesting) { 89 APerformanceHintManager* manager = create(gIHintManagerForTesting); 90 gIHintManagerForTesting = nullptr; 91 return manager; 92 } 93 static APerformanceHintManager* instance = create(nullptr); 94 return instance; 95 } 96 97 APerformanceHintManager* APerformanceHintManager::create(sp<IHintManager> manager) { 98 if (!manager) { 99 manager = interface_cast<IHintManager>( 100 defaultServiceManager()->checkService(String16("performance_hint"))); 101 } 102 if (manager == nullptr) { 103 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__); 104 return nullptr; 105 } 106 int64_t preferredRateNanos = -1L; 107 binder::Status ret = manager->getHintSessionPreferredRate(&preferredRateNanos); 108 if (!ret.isOk()) { 109 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, 110 ret.exceptionMessage().c_str()); 111 return nullptr; 112 } 113 if (preferredRateNanos <= 0) { 114 preferredRateNanos = -1L; 115 } 116 return new APerformanceHintManager(std::move(manager), preferredRateNanos); 117 } 118 119 APerformanceHintSession* APerformanceHintManager::createSession( 120 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) { 121 sp<IBinder> token = sp<BBinder>::make(); 122 std::vector<int32_t> tids(threadIds, threadIds + size); 123 sp<IHintSession> session; 124 binder::Status ret = 125 mHintManager->createHintSession(token, tids, initialTargetWorkDurationNanos, &session); 126 if (!ret.isOk() || !session) { 127 return nullptr; 128 } 129 return new APerformanceHintSession(std::move(session), mPreferredRateNanos, 130 initialTargetWorkDurationNanos); 131 } 132 133 int64_t APerformanceHintManager::getPreferredRateNanos() const { 134 return mPreferredRateNanos; 135 } 136 137 // ===================================== APerformanceHintSession implementation 138 139 APerformanceHintSession::APerformanceHintSession(sp<IHintSession> session, 140 int64_t preferredRateNanos, 141 int64_t targetDurationNanos) 142 : mHintSession(std::move(session)), 143 mPreferredRateNanos(preferredRateNanos), 144 mTargetDurationNanos(targetDurationNanos), 145 mLastUpdateTimestamp(elapsedRealtimeNano()) {} 146 147 APerformanceHintSession::~APerformanceHintSession() { 148 binder::Status ret = mHintSession->close(); 149 if (!ret.isOk()) { 150 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.exceptionMessage().c_str()); 151 } 152 } 153 154 int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) { 155 if (targetDurationNanos <= 0) { 156 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__); 157 return EINVAL; 158 } 159 binder::Status ret = mHintSession->updateTargetWorkDuration(targetDurationNanos); 160 if (!ret.isOk()) { 161 ALOGE("%s: HintSessionn updateTargetWorkDuration failed: %s", __FUNCTION__, 162 ret.exceptionMessage().c_str()); 163 return EPIPE; 164 } 165 mTargetDurationNanos = targetDurationNanos; 166 /** 167 * Most of the workload is target_duration dependent, so now clear the cached samples 168 * as they are most likely obsolete. 169 */ 170 mActualDurationsNanos.clear(); 171 mTimestampsNanos.clear(); 172 mLastUpdateTimestamp = elapsedRealtimeNano(); 173 return 0; 174 } 175 176 int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) { 177 if (actualDurationNanos <= 0) { 178 ALOGE("%s: actualDurationNanos must be positive", __FUNCTION__); 179 return EINVAL; 180 } 181 int64_t now = elapsedRealtimeNano(); 182 mActualDurationsNanos.push_back(actualDurationNanos); 183 mTimestampsNanos.push_back(now); 184 185 /** 186 * Use current sample to determine the rate limit. We can pick a shorter rate limit 187 * if any sample underperformed, however, it could be the lower level system is slow 188 * to react. So here we explicitly choose the rate limit with the latest sample. 189 */ 190 int64_t rateLimit = actualDurationNanos > mTargetDurationNanos ? mPreferredRateNanos 191 : 10 * mPreferredRateNanos; 192 if (now - mLastUpdateTimestamp <= rateLimit) return 0; 193 194 binder::Status ret = 195 mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos); 196 mActualDurationsNanos.clear(); 197 mTimestampsNanos.clear(); 198 if (!ret.isOk()) { 199 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__, 200 ret.exceptionMessage().c_str()); 201 return EPIPE; 202 } 203 mLastUpdateTimestamp = now; 204 return 0; 205 } 206 207 // ===================================== C API 208 APerformanceHintManager* APerformanceHint_getManager() { 209 return APerformanceHintManager::getInstance(); 210 } 211 212 APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager, 213 const int32_t* threadIds, size_t size, 214 int64_t initialTargetWorkDurationNanos) { 215 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos); 216 } 217 218 int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) { 219 return manager->getPreferredRateNanos(); 220 } 221 222 int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session, 223 int64_t targetDurationNanos) { 224 return session->updateTargetWorkDuration(targetDurationNanos); 225 } 226 227 int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session, 228 int64_t actualDurationNanos) { 229 return session->reportActualWorkDuration(actualDurationNanos); 230 } 231 232 void APerformanceHint_closeSession(APerformanceHintSession* session) { 233 delete session; 234 } 235 236 void APerformanceHint_setIHintManagerForTesting(void* iManager) { 237 delete gHintManagerForTesting; 238 gHintManagerForTesting = nullptr; 239 gIHintManagerForTesting = static_cast<IHintManager*>(iManager); 240 } 241