blob: a0e434ed08b7cdcc70fb61fc69ca433a3e1ace80 [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>
Matt Buckley58977722024-03-11 23:32:09 +000021#include <aidl/android/hardware/power/SessionTag.h>
22#include <aidl/android/hardware/power/WorkDuration.h>
23#include <aidl/android/os/IHintManager.h>
24#include <aidl/android/os/IHintSession.h>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000025#include <android-base/stringprintf.h>
Matt Buckley053a1df2024-06-07 02:37:59 +000026#include <android-base/thread_annotations.h>
Matt Buckley58977722024-03-11 23:32:09 +000027#include <android/binder_manager.h>
28#include <android/binder_status.h>
Bo Liu2b739bb2021-11-10 19:20:03 -050029#include <android/performance_hint.h>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000030#include <android/trace.h>
Peiyong Lin70de0852023-10-25 21:12:35 +000031#include <inttypes.h>
Bo Liu44267722021-07-16 17:03:20 -040032#include <performance_hint_private.h>
33#include <utils/SystemClock.h>
34
Matt Buckley56093a72022-11-07 21:50:50 +000035#include <chrono>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000036#include <set>
Bo Liu2b739bb2021-11-10 19:20:03 -050037#include <utility>
38#include <vector>
39
Bo Liu44267722021-07-16 17:03:20 -040040using namespace android;
Matt Buckley58977722024-03-11 23:32:09 +000041using namespace aidl::android::os;
Bo Liu44267722021-07-16 17:03:20 -040042
Matt Buckley56093a72022-11-07 21:50:50 +000043using namespace std::chrono_literals;
44
Matt Buckley7c2de582024-04-05 08:41:35 +000045// Namespace for AIDL types coming from the PowerHAL
46namespace hal = aidl::android::hardware::power;
Matt Buckley58977722024-03-11 23:32:09 +000047
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000048using android::base::StringPrintf;
Matt Buckley56093a72022-11-07 21:50:50 +000049
Bo Liu44267722021-07-16 17:03:20 -040050struct APerformanceHintSession;
51
Matt Buckley56093a72022-11-07 21:50:50 +000052constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
Matt Buckley7c2de582024-04-05 08:41:35 +000053struct AWorkDuration : public hal::WorkDuration {};
Matt Buckley56093a72022-11-07 21:50:50 +000054
Matt Buckley1f5b95f2024-06-07 02:36:56 +000055// Shared lock for the whole PerformanceHintManager and sessions
56static std::mutex sHintMutex = std::mutex{};
57
Bo Liu44267722021-07-16 17:03:20 -040058struct APerformanceHintManager {
59public:
60 static APerformanceHintManager* getInstance();
Matt Buckley58977722024-03-11 23:32:09 +000061 APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -040062 APerformanceHintManager() = delete;
63 ~APerformanceHintManager() = default;
64
65 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
Matt Buckleye073c732024-04-05 22:32:31 +000066 int64_t initialTargetWorkDurationNanos,
67 hal::SessionTag tag = hal::SessionTag::OTHER);
Bo Liu44267722021-07-16 17:03:20 -040068 int64_t getPreferredRateNanos() const;
69
70private:
Matt Buckley58977722024-03-11 23:32:09 +000071 // Necessary to create an empty binder object
72 static void* tokenStubOnCreate(void*) {
73 return nullptr;
74 }
75 static void tokenStubOnDestroy(void*) {}
76 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
77 AParcel*) {
78 return STATUS_OK;
79 }
Bo Liu44267722021-07-16 17:03:20 -040080
Matt Buckley58977722024-03-11 23:32:09 +000081 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
82
83 std::shared_ptr<IHintManager> mHintManager;
84 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -040085 const int64_t mPreferredRateNanos;
86};
87
88struct APerformanceHintSession {
89public:
Matt Buckley58977722024-03-11 23:32:09 +000090 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
91 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +000092 int64_t targetDurationNanos,
93 std::optional<hal::SessionConfig> sessionConfig);
Bo Liu44267722021-07-16 17:03:20 -040094 APerformanceHintSession() = delete;
95 ~APerformanceHintSession();
96
97 int updateTargetWorkDuration(int64_t targetDurationNanos);
98 int reportActualWorkDuration(int64_t actualDurationNanos);
Steven Moreland42a8cce2023-03-03 23:31:17 +000099 int sendHint(SessionHint hint);
Peiyong Lin095de762022-11-11 18:28:12 +0000100 int setThreads(const int32_t* threadIds, size_t size);
101 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +0000102 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +0000103 int reportActualWorkDuration(AWorkDuration* workDuration);
Bo Liu44267722021-07-16 17:03:20 -0400104
105private:
106 friend struct APerformanceHintManager;
107
Matt Buckley58977722024-03-11 23:32:09 +0000108 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000109
Matt Buckley58977722024-03-11 23:32:09 +0000110 std::shared_ptr<IHintManager> mHintManager;
111 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400112 // HAL preferred update rate
113 const int64_t mPreferredRateNanos;
114 // Target duration for choosing update rate
Matt Buckley053a1df2024-06-07 02:37:59 +0000115 int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700116 // First target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000117 int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700118 // Last target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000119 int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000120 // Last hint reported from sendHint indexed by hint value
Matt Buckley053a1df2024-06-07 02:37:59 +0000121 std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400122 // Cached samples
Matt Buckley053a1df2024-06-07 02:37:59 +0000123 std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
124 std::string mSessionName GUARDED_BY(sHintMutex);
125 static int64_t sIDCounter GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000126 // The most recent set of thread IDs
Matt Buckley053a1df2024-06-07 02:37:59 +0000127 std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
128 std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000129 // Tracing helpers
Matt Buckley053a1df2024-06-07 02:37:59 +0000130 void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
131 void tracePowerEfficient(bool powerEfficient) REQUIRES(sHintMutex);
132 void traceActualDuration(int64_t actualDuration) REQUIRES(sHintMutex);
133 void traceBatchSize(size_t batchSize) REQUIRES(sHintMutex);
134 void traceTargetDuration(int64_t targetDuration) REQUIRES(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400135};
136
Matt Buckley58977722024-03-11 23:32:09 +0000137static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Bo Liu44267722021-07-16 17:03:20 -0400138static APerformanceHintManager* gHintManagerForTesting = nullptr;
Matt Buckleye073c732024-04-05 22:32:31 +0000139// Start above the int32 range so we don't collide with config sessions
140int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
Bo Liu44267722021-07-16 17:03:20 -0400141
142// ===================================== APerformanceHintManager implementation
Matt Buckley58977722024-03-11 23:32:09 +0000143APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
Bo Liu44267722021-07-16 17:03:20 -0400144 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000145 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
146 static AIBinder_Class* tokenBinderClass =
147 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
148 tokenStubOnTransact);
149 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
150}
Bo Liu44267722021-07-16 17:03:20 -0400151
152APerformanceHintManager* APerformanceHintManager::getInstance() {
153 if (gHintManagerForTesting) return gHintManagerForTesting;
154 if (gIHintManagerForTesting) {
Matt Buckley58977722024-03-11 23:32:09 +0000155 APerformanceHintManager* manager = create(*gIHintManagerForTesting);
Bo Liu44267722021-07-16 17:03:20 -0400156 gIHintManagerForTesting = nullptr;
157 return manager;
158 }
159 static APerformanceHintManager* instance = create(nullptr);
160 return instance;
161}
162
Matt Buckley58977722024-03-11 23:32:09 +0000163APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400164 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000165 manager = IHintManager::fromBinder(
166 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400167 }
168 if (manager == nullptr) {
169 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
170 return nullptr;
171 }
172 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000173 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400174 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000175 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400176 return nullptr;
177 }
178 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400179 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400180 }
181 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
182}
183
184APerformanceHintSession* APerformanceHintManager::createSession(
Matt Buckleye073c732024-04-05 22:32:31 +0000185 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
186 hal::SessionTag tag) {
Bo Liu44267722021-07-16 17:03:20 -0400187 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000188 std::shared_ptr<IHintSession> session;
Matt Buckleye073c732024-04-05 22:32:31 +0000189 ndk::ScopedAStatus ret;
190 std::optional<hal::SessionConfig> sessionConfig;
191 ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
192 tag, &sessionConfig, &session);
193
Bo Liu44267722021-07-16 17:03:20 -0400194 if (!ret.isOk() || !session) {
195 return nullptr;
196 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000197 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000198 initialTargetWorkDurationNanos, sessionConfig);
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000199 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000200 out->traceThreads(tids);
201 out->traceTargetDuration(initialTargetWorkDurationNanos);
202 out->tracePowerEfficient(false);
203 return out;
Bo Liu44267722021-07-16 17:03:20 -0400204}
205
206int64_t APerformanceHintManager::getPreferredRateNanos() const {
207 return mPreferredRateNanos;
208}
209
210// ===================================== APerformanceHintSession implementation
211
Matt Buckley58977722024-03-11 23:32:09 +0000212APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
213 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400214 int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000215 int64_t targetDurationNanos,
216 std::optional<hal::SessionConfig> sessionConfig)
Peiyong Lin095de762022-11-11 18:28:12 +0000217 : mHintManager(hintManager),
218 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400219 mPreferredRateNanos(preferredRateNanos),
220 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700221 mFirstTargetMetTimestamp(0),
Matt Buckleye073c732024-04-05 22:32:31 +0000222 mLastTargetMetTimestamp(0),
223 mSessionConfig(sessionConfig) {
224 if (sessionConfig->id > INT32_MAX) {
225 ALOGE("Session ID too large, must fit 32-bit integer");
226 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000227 std::scoped_lock lock(sHintMutex);
Matt Buckleye073c732024-04-05 22:32:31 +0000228 constexpr int numEnums =
229 ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
230 mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
231 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
232 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
Matt Buckley56093a72022-11-07 21:50:50 +0000233}
Bo Liu44267722021-07-16 17:03:20 -0400234
235APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000236 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400237 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000238 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400239 }
240}
241
242int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
243 if (targetDurationNanos <= 0) {
244 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
245 return EINVAL;
246 }
Matt Buckley58977722024-03-11 23:32:09 +0000247 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
Bo Liu44267722021-07-16 17:03:20 -0400248 if (!ret.isOk()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000249 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000250 ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400251 return EPIPE;
252 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000253 std::scoped_lock lock(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400254 mTargetDurationNanos = targetDurationNanos;
255 /**
256 * Most of the workload is target_duration dependent, so now clear the cached samples
257 * as they are most likely obsolete.
258 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000259 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000260 traceBatchSize(0);
261 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700262 mFirstTargetMetTimestamp = 0;
263 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400264 return 0;
265}
266
267int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000268 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
269 .workPeriodStartTimestampNanos = 0,
270 .cpuDurationNanos = actualDurationNanos,
271 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400272
Matt Buckley58977722024-03-11 23:32:09 +0000273 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400274}
275
Steven Moreland42a8cce2023-03-03 23:31:17 +0000276int APerformanceHintSession::sendHint(SessionHint hint) {
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000277 std::scoped_lock lock(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000278 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
279 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000280 return EINVAL;
281 }
Matt Buckley58977722024-03-11 23:32:09 +0000282 int64_t now = uptimeNanos();
Matt Buckley56093a72022-11-07 21:50:50 +0000283
284 // Limit sendHint to a pre-detemined rate for safety
285 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
286 return 0;
287 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000288
Matt Buckley58977722024-03-11 23:32:09 +0000289 ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000290
291 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000292 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley354cc0a2022-09-28 20:54:46 +0000293 return EPIPE;
294 }
Matt Buckley56093a72022-11-07 21:50:50 +0000295 mLastHintSentTimestamp[hint] = now;
Matt Buckley354cc0a2022-09-28 20:54:46 +0000296 return 0;
297}
298
Peiyong Lin095de762022-11-11 18:28:12 +0000299int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
300 if (size == 0) {
301 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
302 return EINVAL;
303 }
304 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000305 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000306 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000307 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
308 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000309 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000310 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700311 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000312 }
313 return EPIPE;
314 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000315
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000316 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000317 traceThreads(tids);
318
Peiyong Lin095de762022-11-11 18:28:12 +0000319 return 0;
320}
321
322int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
323 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000324 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000325 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000326 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000327 return EPIPE;
328 }
329
330 // When threadIds is nullptr, this is the first call to determine the size
331 // of the thread ids list.
332 if (threadIds == nullptr) {
333 *size = tids.size();
334 return 0;
335 }
336
337 // Second call to return the actual list of thread ids.
338 *size = tids.size();
339 for (size_t i = 0; i < *size; ++i) {
340 threadIds[i] = tids[i];
341 }
342 return 0;
343}
344
Matt Buckley423c1b32023-06-28 19:13:42 +0000345int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000346 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000347 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
348 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000349
350 if (!ret.isOk()) {
351 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000352 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000353 return EPIPE;
354 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000355 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000356 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000357 return OK;
358}
359
Matt Buckley58977722024-03-11 23:32:09 +0000360int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000361 return reportActualWorkDurationInternal(workDuration);
362}
363
Matt Buckley58977722024-03-11 23:32:09 +0000364int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
365 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000366 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000367 workDuration->timeStampNanos = now;
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000368 std::scoped_lock lock(sHintMutex);
Matt Buckley58977722024-03-11 23:32:09 +0000369 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000370 mActualWorkDurations.push_back(std::move(*workDuration));
371
372 if (actualTotalDurationNanos >= mTargetDurationNanos) {
373 // Reset timestamps if we are equal or over the target.
374 mFirstTargetMetTimestamp = 0;
375 } else {
376 // Set mFirstTargetMetTimestamp for first time meeting target.
377 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
378 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
379 mFirstTargetMetTimestamp = now;
380 }
381 /**
382 * Rate limit the change if the update is over mPreferredRateNanos since first
383 * meeting target and less than mPreferredRateNanos since last meeting target.
384 */
385 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
386 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000387 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000388 return 0;
389 }
390 mLastTargetMetTimestamp = now;
391 }
392
Matt Buckley58977722024-03-11 23:32:09 +0000393 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
Peiyong Lin70de0852023-10-25 21:12:35 +0000394 if (!ret.isOk()) {
395 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000396 ret.getMessage());
Peiyong Lin70de0852023-10-25 21:12:35 +0000397 mFirstTargetMetTimestamp = 0;
398 mLastTargetMetTimestamp = 0;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000399 traceBatchSize(mActualWorkDurations.size());
Matt Buckley58977722024-03-11 23:32:09 +0000400 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
Peiyong Lin70de0852023-10-25 21:12:35 +0000401 }
402 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000403 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000404
405 return 0;
406}
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000407// ===================================== Tracing helpers
408
409void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
410 std::set<int32_t> tidSet{tids.begin(), tids.end()};
411
412 // Disable old TID tracing
413 for (int32_t tid : mLastThreadIDs) {
414 if (!tidSet.count(tid)) {
415 std::string traceName =
416 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
417 ATrace_setCounter(traceName.c_str(), 0);
418 }
419 }
420
421 // Add new TID tracing
422 for (int32_t tid : tids) {
423 std::string traceName =
424 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
425 ATrace_setCounter(traceName.c_str(), 1);
426 }
427
428 mLastThreadIDs = std::move(tids);
429}
430
431void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
432 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
433}
434
435void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
436 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
437}
438
439void APerformanceHintSession::traceBatchSize(size_t batchSize) {
440 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
441 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
442}
443
444void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
445 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
446}
Peiyong Lin70de0852023-10-25 21:12:35 +0000447
Bo Liu44267722021-07-16 17:03:20 -0400448// ===================================== C API
449APerformanceHintManager* APerformanceHint_getManager() {
450 return APerformanceHintManager::getInstance();
451}
452
Matt Buckley83f77092024-01-18 19:57:29 +0000453#define VALIDATE_PTR(ptr) \
454 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
455
456#define VALIDATE_INT(value, cmp) \
457 if (!(value cmp)) { \
458 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
459 __FUNCTION__, value); \
460 return EINVAL; \
461 }
462
463#define WARN_INT(value, cmp) \
464 if (!(value cmp)) { \
465 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
466 __FUNCTION__, value); \
467 }
468
Bo Liu44267722021-07-16 17:03:20 -0400469APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
470 const int32_t* threadIds, size_t size,
471 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000472 VALIDATE_PTR(manager)
473 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400474 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
475}
476
Matt Buckley27da1342024-04-05 23:10:48 +0000477APerformanceHintSession* APerformanceHint_createSessionInternal(
478 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
479 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
480 VALIDATE_PTR(manager)
481 VALIDATE_PTR(threadIds)
482 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
483 static_cast<hal::SessionTag>(tag));
484}
485
Bo Liu44267722021-07-16 17:03:20 -0400486int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000487 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400488 return manager->getPreferredRateNanos();
489}
490
491int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
492 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000493 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400494 return session->updateTargetWorkDuration(targetDurationNanos);
495}
496
497int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
498 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000499 VALIDATE_PTR(session)
500 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400501 return session->reportActualWorkDuration(actualDurationNanos);
502}
503
Bo Liu44267722021-07-16 17:03:20 -0400504void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000505 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400506 delete session;
507}
508
Matt Buckley27da1342024-04-05 23:10:48 +0000509int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000510 VALIDATE_PTR(session)
Matt Buckley27da1342024-04-05 23:10:48 +0000511 return session->sendHint(hint);
Matt Buckley61726a32022-12-06 23:44:45 +0000512}
513
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000514int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000515 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000516 VALIDATE_PTR(session)
517 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000518 return session->setThreads(threadIds, size);
519}
520
Matt Buckley27da1342024-04-05 23:10:48 +0000521int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000522 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +0000523 VALIDATE_PTR(session)
524 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +0000525}
526
Matt Buckley423c1b32023-06-28 19:13:42 +0000527int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000528 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000529 return session->setPreferPowerEfficiency(enabled);
530}
531
Peiyong Lin70de0852023-10-25 21:12:35 +0000532int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000533 AWorkDuration* workDurationPtr) {
534 VALIDATE_PTR(session)
535 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000536 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
537 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
538 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
539 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
540 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000541 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000542}
543
544AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000545 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000546}
547
548void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000549 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000550 delete aWorkDuration;
551}
552
Peiyong Lin70de0852023-10-25 21:12:35 +0000553void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
554 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000555 VALIDATE_PTR(aWorkDuration)
556 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000557 aWorkDuration->durationNanos = actualTotalDurationNanos;
558}
559
560void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
561 int64_t workPeriodStartTimestampNanos) {
562 VALIDATE_PTR(aWorkDuration)
563 WARN_INT(workPeriodStartTimestampNanos, > 0)
564 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000565}
566
567void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
568 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000569 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000570 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000571 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000572}
573
574void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
575 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000576 VALIDATE_PTR(aWorkDuration)
577 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000578 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000579}
580
Bo Liu44267722021-07-16 17:03:20 -0400581void APerformanceHint_setIHintManagerForTesting(void* iManager) {
582 delete gHintManagerForTesting;
583 gHintManagerForTesting = nullptr;
Matt Buckley58977722024-03-11 23:32:09 +0000584 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400585}