blob: e91c7a9ecda8c90cb5b380e4109e14e98a9b84b2 [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,
Matt Buckley31974132024-05-21 19:54:39 +000067 hal::SessionTag tag = hal::SessionTag::APP);
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 }
Xiang Wange16ad282024-06-26 14:31:34 -0700247 {
248 std::scoped_lock lock(sHintMutex);
249 if (mTargetDurationNanos == targetDurationNanos) {
250 return 0;
251 }
252 }
Matt Buckley58977722024-03-11 23:32:09 +0000253 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
Bo Liu44267722021-07-16 17:03:20 -0400254 if (!ret.isOk()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000255 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000256 ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400257 return EPIPE;
258 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000259 std::scoped_lock lock(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400260 mTargetDurationNanos = targetDurationNanos;
261 /**
262 * Most of the workload is target_duration dependent, so now clear the cached samples
263 * as they are most likely obsolete.
264 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000265 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000266 traceBatchSize(0);
267 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700268 mFirstTargetMetTimestamp = 0;
269 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400270 return 0;
271}
272
273int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000274 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
275 .workPeriodStartTimestampNanos = 0,
276 .cpuDurationNanos = actualDurationNanos,
277 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400278
Matt Buckley58977722024-03-11 23:32:09 +0000279 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400280}
281
Steven Moreland42a8cce2023-03-03 23:31:17 +0000282int APerformanceHintSession::sendHint(SessionHint hint) {
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000283 std::scoped_lock lock(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000284 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
285 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000286 return EINVAL;
287 }
Matt Buckley58977722024-03-11 23:32:09 +0000288 int64_t now = uptimeNanos();
Matt Buckley56093a72022-11-07 21:50:50 +0000289
290 // Limit sendHint to a pre-detemined rate for safety
291 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
292 return 0;
293 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000294
Matt Buckley58977722024-03-11 23:32:09 +0000295 ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000296
297 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000298 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley354cc0a2022-09-28 20:54:46 +0000299 return EPIPE;
300 }
Matt Buckley56093a72022-11-07 21:50:50 +0000301 mLastHintSentTimestamp[hint] = now;
Matt Buckley354cc0a2022-09-28 20:54:46 +0000302 return 0;
303}
304
Peiyong Lin095de762022-11-11 18:28:12 +0000305int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
306 if (size == 0) {
307 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
308 return EINVAL;
309 }
310 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000311 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000312 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000313 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
314 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000315 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000316 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700317 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000318 }
319 return EPIPE;
320 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000321
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000322 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000323 traceThreads(tids);
324
Peiyong Lin095de762022-11-11 18:28:12 +0000325 return 0;
326}
327
328int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
329 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000330 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000331 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000332 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000333 return EPIPE;
334 }
335
336 // When threadIds is nullptr, this is the first call to determine the size
337 // of the thread ids list.
338 if (threadIds == nullptr) {
339 *size = tids.size();
340 return 0;
341 }
342
343 // Second call to return the actual list of thread ids.
344 *size = tids.size();
345 for (size_t i = 0; i < *size; ++i) {
346 threadIds[i] = tids[i];
347 }
348 return 0;
349}
350
Matt Buckley423c1b32023-06-28 19:13:42 +0000351int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000352 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000353 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
354 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000355
356 if (!ret.isOk()) {
357 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000358 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000359 return EPIPE;
360 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000361 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000362 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000363 return OK;
364}
365
Matt Buckley58977722024-03-11 23:32:09 +0000366int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000367 return reportActualWorkDurationInternal(workDuration);
368}
369
Matt Buckley58977722024-03-11 23:32:09 +0000370int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
371 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000372 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000373 workDuration->timeStampNanos = now;
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000374 std::scoped_lock lock(sHintMutex);
Matt Buckley58977722024-03-11 23:32:09 +0000375 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000376 mActualWorkDurations.push_back(std::move(*workDuration));
377
378 if (actualTotalDurationNanos >= mTargetDurationNanos) {
379 // Reset timestamps if we are equal or over the target.
380 mFirstTargetMetTimestamp = 0;
381 } else {
382 // Set mFirstTargetMetTimestamp for first time meeting target.
383 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
384 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
385 mFirstTargetMetTimestamp = now;
386 }
387 /**
388 * Rate limit the change if the update is over mPreferredRateNanos since first
389 * meeting target and less than mPreferredRateNanos since last meeting target.
390 */
391 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
392 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000393 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000394 return 0;
395 }
396 mLastTargetMetTimestamp = now;
397 }
398
Matt Buckley58977722024-03-11 23:32:09 +0000399 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
Peiyong Lin70de0852023-10-25 21:12:35 +0000400 if (!ret.isOk()) {
401 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000402 ret.getMessage());
Peiyong Lin70de0852023-10-25 21:12:35 +0000403 mFirstTargetMetTimestamp = 0;
404 mLastTargetMetTimestamp = 0;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000405 traceBatchSize(mActualWorkDurations.size());
Matt Buckley58977722024-03-11 23:32:09 +0000406 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
Peiyong Lin70de0852023-10-25 21:12:35 +0000407 }
408 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000409 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000410
411 return 0;
412}
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000413// ===================================== Tracing helpers
414
415void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
416 std::set<int32_t> tidSet{tids.begin(), tids.end()};
417
418 // Disable old TID tracing
419 for (int32_t tid : mLastThreadIDs) {
420 if (!tidSet.count(tid)) {
421 std::string traceName =
422 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
423 ATrace_setCounter(traceName.c_str(), 0);
424 }
425 }
426
427 // Add new TID tracing
428 for (int32_t tid : tids) {
429 std::string traceName =
430 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
431 ATrace_setCounter(traceName.c_str(), 1);
432 }
433
434 mLastThreadIDs = std::move(tids);
435}
436
437void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
438 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
439}
440
441void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
442 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
443}
444
445void APerformanceHintSession::traceBatchSize(size_t batchSize) {
446 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
447 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
448}
449
450void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
451 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
452}
Peiyong Lin70de0852023-10-25 21:12:35 +0000453
Bo Liu44267722021-07-16 17:03:20 -0400454// ===================================== C API
455APerformanceHintManager* APerformanceHint_getManager() {
456 return APerformanceHintManager::getInstance();
457}
458
Matt Buckley83f77092024-01-18 19:57:29 +0000459#define VALIDATE_PTR(ptr) \
460 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
461
462#define VALIDATE_INT(value, cmp) \
463 if (!(value cmp)) { \
464 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
465 __FUNCTION__, value); \
466 return EINVAL; \
467 }
468
469#define WARN_INT(value, cmp) \
470 if (!(value cmp)) { \
471 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
472 __FUNCTION__, value); \
473 }
474
Bo Liu44267722021-07-16 17:03:20 -0400475APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
476 const int32_t* threadIds, size_t size,
477 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000478 VALIDATE_PTR(manager)
479 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400480 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
481}
482
Matt Buckley27da1342024-04-05 23:10:48 +0000483APerformanceHintSession* APerformanceHint_createSessionInternal(
484 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
485 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
486 VALIDATE_PTR(manager)
487 VALIDATE_PTR(threadIds)
488 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
489 static_cast<hal::SessionTag>(tag));
490}
491
Bo Liu44267722021-07-16 17:03:20 -0400492int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000493 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400494 return manager->getPreferredRateNanos();
495}
496
497int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
498 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000499 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400500 return session->updateTargetWorkDuration(targetDurationNanos);
501}
502
503int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
504 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000505 VALIDATE_PTR(session)
506 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400507 return session->reportActualWorkDuration(actualDurationNanos);
508}
509
Bo Liu44267722021-07-16 17:03:20 -0400510void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000511 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400512 delete session;
513}
514
Matt Buckley27da1342024-04-05 23:10:48 +0000515int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000516 VALIDATE_PTR(session)
Matt Buckley27da1342024-04-05 23:10:48 +0000517 return session->sendHint(hint);
Matt Buckley61726a32022-12-06 23:44:45 +0000518}
519
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000520int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000521 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000522 VALIDATE_PTR(session)
523 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000524 return session->setThreads(threadIds, size);
525}
526
Matt Buckley27da1342024-04-05 23:10:48 +0000527int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000528 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +0000529 VALIDATE_PTR(session)
530 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +0000531}
532
Matt Buckley423c1b32023-06-28 19:13:42 +0000533int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000534 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000535 return session->setPreferPowerEfficiency(enabled);
536}
537
Peiyong Lin70de0852023-10-25 21:12:35 +0000538int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000539 AWorkDuration* workDurationPtr) {
540 VALIDATE_PTR(session)
541 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000542 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
543 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
544 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
545 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
546 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000547 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000548}
549
550AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000551 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000552}
553
554void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000555 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000556 delete aWorkDuration;
557}
558
Peiyong Lin70de0852023-10-25 21:12:35 +0000559void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
560 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000561 VALIDATE_PTR(aWorkDuration)
562 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000563 aWorkDuration->durationNanos = actualTotalDurationNanos;
564}
565
566void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
567 int64_t workPeriodStartTimestampNanos) {
568 VALIDATE_PTR(aWorkDuration)
569 WARN_INT(workPeriodStartTimestampNanos, > 0)
570 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000571}
572
573void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
574 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000575 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000576 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000577 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000578}
579
580void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
581 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000582 VALIDATE_PTR(aWorkDuration)
583 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000584 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000585}
586
Bo Liu44267722021-07-16 17:03:20 -0400587void APerformanceHint_setIHintManagerForTesting(void* iManager) {
588 delete gHintManagerForTesting;
589 gHintManagerForTesting = nullptr;
Matt Buckley58977722024-03-11 23:32:09 +0000590 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400591}