blob: 83056b2673656acbe9f0dbede576896e99dd4b7b [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 Buckley58977722024-03-11 23:32:09 +000026#include <android/binder_manager.h>
27#include <android/binder_status.h>
Bo Liu2b739bb2021-11-10 19:20:03 -050028#include <android/performance_hint.h>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000029#include <android/trace.h>
Peiyong Lin70de0852023-10-25 21:12:35 +000030#include <inttypes.h>
Bo Liu44267722021-07-16 17:03:20 -040031#include <performance_hint_private.h>
32#include <utils/SystemClock.h>
33
Matt Buckley56093a72022-11-07 21:50:50 +000034#include <chrono>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000035#include <set>
Bo Liu2b739bb2021-11-10 19:20:03 -050036#include <utility>
37#include <vector>
38
Bo Liu44267722021-07-16 17:03:20 -040039using namespace android;
Matt Buckley58977722024-03-11 23:32:09 +000040using namespace aidl::android::os;
Bo Liu44267722021-07-16 17:03:20 -040041
Matt Buckley56093a72022-11-07 21:50:50 +000042using namespace std::chrono_literals;
43
Matt Buckley7c2de582024-04-05 08:41:35 +000044// Namespace for AIDL types coming from the PowerHAL
45namespace hal = aidl::android::hardware::power;
Matt Buckley58977722024-03-11 23:32:09 +000046
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000047using android::base::StringPrintf;
Matt Buckley56093a72022-11-07 21:50:50 +000048
Bo Liu44267722021-07-16 17:03:20 -040049struct APerformanceHintSession;
50
Matt Buckley56093a72022-11-07 21:50:50 +000051constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
Matt Buckley7c2de582024-04-05 08:41:35 +000052struct AWorkDuration : public hal::WorkDuration {};
Matt Buckley56093a72022-11-07 21:50:50 +000053
Bo Liu44267722021-07-16 17:03:20 -040054struct APerformanceHintManager {
55public:
56 static APerformanceHintManager* getInstance();
Matt Buckley58977722024-03-11 23:32:09 +000057 APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -040058 APerformanceHintManager() = delete;
59 ~APerformanceHintManager() = default;
60
61 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
Matt Buckleye073c732024-04-05 22:32:31 +000062 int64_t initialTargetWorkDurationNanos,
63 hal::SessionTag tag = hal::SessionTag::OTHER);
Bo Liu44267722021-07-16 17:03:20 -040064 int64_t getPreferredRateNanos() const;
65
66private:
Matt Buckley58977722024-03-11 23:32:09 +000067 // Necessary to create an empty binder object
68 static void* tokenStubOnCreate(void*) {
69 return nullptr;
70 }
71 static void tokenStubOnDestroy(void*) {}
72 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
73 AParcel*) {
74 return STATUS_OK;
75 }
Bo Liu44267722021-07-16 17:03:20 -040076
Matt Buckley58977722024-03-11 23:32:09 +000077 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
78
79 std::shared_ptr<IHintManager> mHintManager;
80 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -040081 const int64_t mPreferredRateNanos;
82};
83
84struct APerformanceHintSession {
85public:
Matt Buckley58977722024-03-11 23:32:09 +000086 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
87 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +000088 int64_t targetDurationNanos,
89 std::optional<hal::SessionConfig> sessionConfig);
Bo Liu44267722021-07-16 17:03:20 -040090 APerformanceHintSession() = delete;
91 ~APerformanceHintSession();
92
93 int updateTargetWorkDuration(int64_t targetDurationNanos);
94 int reportActualWorkDuration(int64_t actualDurationNanos);
Steven Moreland42a8cce2023-03-03 23:31:17 +000095 int sendHint(SessionHint hint);
Peiyong Lin095de762022-11-11 18:28:12 +000096 int setThreads(const int32_t* threadIds, size_t size);
97 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +000098 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +000099 int reportActualWorkDuration(AWorkDuration* workDuration);
Bo Liu44267722021-07-16 17:03:20 -0400100
101private:
102 friend struct APerformanceHintManager;
103
Matt Buckley58977722024-03-11 23:32:09 +0000104 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000105
Matt Buckley58977722024-03-11 23:32:09 +0000106 std::shared_ptr<IHintManager> mHintManager;
107 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400108 // HAL preferred update rate
109 const int64_t mPreferredRateNanos;
110 // Target duration for choosing update rate
111 int64_t mTargetDurationNanos;
Wei Wang00feb502022-10-18 10:56:59 -0700112 // First target hit timestamp
113 int64_t mFirstTargetMetTimestamp;
114 // Last target hit timestamp
115 int64_t mLastTargetMetTimestamp;
Matt Buckley56093a72022-11-07 21:50:50 +0000116 // Last hint reported from sendHint indexed by hint value
117 std::vector<int64_t> mLastHintSentTimestamp;
Bo Liu44267722021-07-16 17:03:20 -0400118 // Cached samples
Matt Buckley7c2de582024-04-05 08:41:35 +0000119 std::vector<hal::WorkDuration> mActualWorkDurations;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000120 std::string mSessionName;
Matt Buckleye073c732024-04-05 22:32:31 +0000121 static int64_t sIDCounter;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000122 // The most recent set of thread IDs
123 std::vector<int32_t> mLastThreadIDs;
Matt Buckleye073c732024-04-05 22:32:31 +0000124 std::optional<hal::SessionConfig> mSessionConfig;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000125 // Tracing helpers
126 void traceThreads(std::vector<int32_t>& tids);
127 void tracePowerEfficient(bool powerEfficient);
128 void traceActualDuration(int64_t actualDuration);
129 void traceBatchSize(size_t batchSize);
130 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400131};
132
Matt Buckley58977722024-03-11 23:32:09 +0000133static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Bo Liu44267722021-07-16 17:03:20 -0400134static APerformanceHintManager* gHintManagerForTesting = nullptr;
Matt Buckleye073c732024-04-05 22:32:31 +0000135// Start above the int32 range so we don't collide with config sessions
136int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
Bo Liu44267722021-07-16 17:03:20 -0400137
138// ===================================== APerformanceHintManager implementation
Matt Buckley58977722024-03-11 23:32:09 +0000139APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
Bo Liu44267722021-07-16 17:03:20 -0400140 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000141 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
142 static AIBinder_Class* tokenBinderClass =
143 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
144 tokenStubOnTransact);
145 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
146}
Bo Liu44267722021-07-16 17:03:20 -0400147
148APerformanceHintManager* APerformanceHintManager::getInstance() {
149 if (gHintManagerForTesting) return gHintManagerForTesting;
150 if (gIHintManagerForTesting) {
Matt Buckley58977722024-03-11 23:32:09 +0000151 APerformanceHintManager* manager = create(*gIHintManagerForTesting);
Bo Liu44267722021-07-16 17:03:20 -0400152 gIHintManagerForTesting = nullptr;
153 return manager;
154 }
155 static APerformanceHintManager* instance = create(nullptr);
156 return instance;
157}
158
Matt Buckley58977722024-03-11 23:32:09 +0000159APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400160 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000161 manager = IHintManager::fromBinder(
162 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400163 }
164 if (manager == nullptr) {
165 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
166 return nullptr;
167 }
168 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000169 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400170 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000171 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400172 return nullptr;
173 }
174 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400175 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400176 }
177 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
178}
179
180APerformanceHintSession* APerformanceHintManager::createSession(
Matt Buckleye073c732024-04-05 22:32:31 +0000181 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
182 hal::SessionTag tag) {
Bo Liu44267722021-07-16 17:03:20 -0400183 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000184 std::shared_ptr<IHintSession> session;
Matt Buckleye073c732024-04-05 22:32:31 +0000185 ndk::ScopedAStatus ret;
186 std::optional<hal::SessionConfig> sessionConfig;
187 ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
188 tag, &sessionConfig, &session);
189
Bo Liu44267722021-07-16 17:03:20 -0400190 if (!ret.isOk() || !session) {
191 return nullptr;
192 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000193 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000194 initialTargetWorkDurationNanos, sessionConfig);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000195 out->traceThreads(tids);
196 out->traceTargetDuration(initialTargetWorkDurationNanos);
197 out->tracePowerEfficient(false);
198 return out;
Bo Liu44267722021-07-16 17:03:20 -0400199}
200
201int64_t APerformanceHintManager::getPreferredRateNanos() const {
202 return mPreferredRateNanos;
203}
204
205// ===================================== APerformanceHintSession implementation
206
Matt Buckley58977722024-03-11 23:32:09 +0000207APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
208 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400209 int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000210 int64_t targetDurationNanos,
211 std::optional<hal::SessionConfig> sessionConfig)
Peiyong Lin095de762022-11-11 18:28:12 +0000212 : mHintManager(hintManager),
213 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400214 mPreferredRateNanos(preferredRateNanos),
215 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700216 mFirstTargetMetTimestamp(0),
Matt Buckleye073c732024-04-05 22:32:31 +0000217 mLastTargetMetTimestamp(0),
218 mSessionConfig(sessionConfig) {
219 if (sessionConfig->id > INT32_MAX) {
220 ALOGE("Session ID too large, must fit 32-bit integer");
221 }
222 constexpr int numEnums =
223 ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
224 mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
225 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
226 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
Matt Buckley56093a72022-11-07 21:50:50 +0000227}
Bo Liu44267722021-07-16 17:03:20 -0400228
229APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000230 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400231 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000232 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400233 }
234}
235
236int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
237 if (targetDurationNanos <= 0) {
238 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
239 return EINVAL;
240 }
Matt Buckley58977722024-03-11 23:32:09 +0000241 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
Bo Liu44267722021-07-16 17:03:20 -0400242 if (!ret.isOk()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000243 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000244 ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400245 return EPIPE;
246 }
247 mTargetDurationNanos = targetDurationNanos;
248 /**
249 * Most of the workload is target_duration dependent, so now clear the cached samples
250 * as they are most likely obsolete.
251 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000252 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000253 traceBatchSize(0);
254 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700255 mFirstTargetMetTimestamp = 0;
256 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400257 return 0;
258}
259
260int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000261 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
262 .workPeriodStartTimestampNanos = 0,
263 .cpuDurationNanos = actualDurationNanos,
264 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400265
Matt Buckley58977722024-03-11 23:32:09 +0000266 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400267}
268
Steven Moreland42a8cce2023-03-03 23:31:17 +0000269int APerformanceHintSession::sendHint(SessionHint hint) {
Matt Buckley56093a72022-11-07 21:50:50 +0000270 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
271 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000272 return EINVAL;
273 }
Matt Buckley58977722024-03-11 23:32:09 +0000274 int64_t now = uptimeNanos();
Matt Buckley56093a72022-11-07 21:50:50 +0000275
276 // Limit sendHint to a pre-detemined rate for safety
277 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
278 return 0;
279 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000280
Matt Buckley58977722024-03-11 23:32:09 +0000281 ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000282
283 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000284 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley354cc0a2022-09-28 20:54:46 +0000285 return EPIPE;
286 }
Matt Buckley56093a72022-11-07 21:50:50 +0000287 mLastHintSentTimestamp[hint] = now;
Matt Buckley354cc0a2022-09-28 20:54:46 +0000288 return 0;
289}
290
Peiyong Lin095de762022-11-11 18:28:12 +0000291int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
292 if (size == 0) {
293 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
294 return EINVAL;
295 }
296 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000297 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000298 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000299 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
300 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000301 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000302 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700303 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000304 }
305 return EPIPE;
306 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000307
308 traceThreads(tids);
309
Peiyong Lin095de762022-11-11 18:28:12 +0000310 return 0;
311}
312
313int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
314 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000315 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000316 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000317 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000318 return EPIPE;
319 }
320
321 // When threadIds is nullptr, this is the first call to determine the size
322 // of the thread ids list.
323 if (threadIds == nullptr) {
324 *size = tids.size();
325 return 0;
326 }
327
328 // Second call to return the actual list of thread ids.
329 *size = tids.size();
330 for (size_t i = 0; i < *size; ++i) {
331 threadIds[i] = tids[i];
332 }
333 return 0;
334}
335
Matt Buckley423c1b32023-06-28 19:13:42 +0000336int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000337 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000338 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
339 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000340
341 if (!ret.isOk()) {
342 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000343 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000344 return EPIPE;
345 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000346 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000347 return OK;
348}
349
Matt Buckley58977722024-03-11 23:32:09 +0000350int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000351 return reportActualWorkDurationInternal(workDuration);
352}
353
Matt Buckley58977722024-03-11 23:32:09 +0000354int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
355 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000356 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000357 workDuration->timeStampNanos = now;
358 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000359 mActualWorkDurations.push_back(std::move(*workDuration));
360
361 if (actualTotalDurationNanos >= mTargetDurationNanos) {
362 // Reset timestamps if we are equal or over the target.
363 mFirstTargetMetTimestamp = 0;
364 } else {
365 // Set mFirstTargetMetTimestamp for first time meeting target.
366 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
367 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
368 mFirstTargetMetTimestamp = now;
369 }
370 /**
371 * Rate limit the change if the update is over mPreferredRateNanos since first
372 * meeting target and less than mPreferredRateNanos since last meeting target.
373 */
374 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
375 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000376 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000377 return 0;
378 }
379 mLastTargetMetTimestamp = now;
380 }
381
Matt Buckley58977722024-03-11 23:32:09 +0000382 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
Peiyong Lin70de0852023-10-25 21:12:35 +0000383 if (!ret.isOk()) {
384 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000385 ret.getMessage());
Peiyong Lin70de0852023-10-25 21:12:35 +0000386 mFirstTargetMetTimestamp = 0;
387 mLastTargetMetTimestamp = 0;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000388 traceBatchSize(mActualWorkDurations.size());
Matt Buckley58977722024-03-11 23:32:09 +0000389 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
Peiyong Lin70de0852023-10-25 21:12:35 +0000390 }
391 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000392 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000393
394 return 0;
395}
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000396// ===================================== Tracing helpers
397
398void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
399 std::set<int32_t> tidSet{tids.begin(), tids.end()};
400
401 // Disable old TID tracing
402 for (int32_t tid : mLastThreadIDs) {
403 if (!tidSet.count(tid)) {
404 std::string traceName =
405 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
406 ATrace_setCounter(traceName.c_str(), 0);
407 }
408 }
409
410 // Add new TID tracing
411 for (int32_t tid : tids) {
412 std::string traceName =
413 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
414 ATrace_setCounter(traceName.c_str(), 1);
415 }
416
417 mLastThreadIDs = std::move(tids);
418}
419
420void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
421 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
422}
423
424void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
425 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
426}
427
428void APerformanceHintSession::traceBatchSize(size_t batchSize) {
429 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
430 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
431}
432
433void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
434 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
435}
Peiyong Lin70de0852023-10-25 21:12:35 +0000436
Bo Liu44267722021-07-16 17:03:20 -0400437// ===================================== C API
438APerformanceHintManager* APerformanceHint_getManager() {
439 return APerformanceHintManager::getInstance();
440}
441
Matt Buckley83f77092024-01-18 19:57:29 +0000442#define VALIDATE_PTR(ptr) \
443 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
444
445#define VALIDATE_INT(value, cmp) \
446 if (!(value cmp)) { \
447 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
448 __FUNCTION__, value); \
449 return EINVAL; \
450 }
451
452#define WARN_INT(value, cmp) \
453 if (!(value cmp)) { \
454 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
455 __FUNCTION__, value); \
456 }
457
Bo Liu44267722021-07-16 17:03:20 -0400458APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
459 const int32_t* threadIds, size_t size,
460 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000461 VALIDATE_PTR(manager)
462 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400463 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
464}
465
Matt Buckley27da1342024-04-05 23:10:48 +0000466APerformanceHintSession* APerformanceHint_createSessionInternal(
467 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
468 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
469 VALIDATE_PTR(manager)
470 VALIDATE_PTR(threadIds)
471 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
472 static_cast<hal::SessionTag>(tag));
473}
474
Bo Liu44267722021-07-16 17:03:20 -0400475int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000476 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400477 return manager->getPreferredRateNanos();
478}
479
480int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
481 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000482 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400483 return session->updateTargetWorkDuration(targetDurationNanos);
484}
485
486int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
487 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000488 VALIDATE_PTR(session)
489 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400490 return session->reportActualWorkDuration(actualDurationNanos);
491}
492
Bo Liu44267722021-07-16 17:03:20 -0400493void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000494 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400495 delete session;
496}
497
Matt Buckley27da1342024-04-05 23:10:48 +0000498int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000499 VALIDATE_PTR(session)
Matt Buckley27da1342024-04-05 23:10:48 +0000500 return session->sendHint(hint);
Matt Buckley61726a32022-12-06 23:44:45 +0000501}
502
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000503int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000504 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000505 VALIDATE_PTR(session)
506 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000507 return session->setThreads(threadIds, size);
508}
509
Matt Buckley27da1342024-04-05 23:10:48 +0000510int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000511 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +0000512 VALIDATE_PTR(session)
513 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +0000514}
515
Matt Buckley423c1b32023-06-28 19:13:42 +0000516int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000517 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000518 return session->setPreferPowerEfficiency(enabled);
519}
520
Peiyong Lin70de0852023-10-25 21:12:35 +0000521int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000522 AWorkDuration* workDurationPtr) {
523 VALIDATE_PTR(session)
524 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000525 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
526 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
527 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
528 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
529 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000530 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000531}
532
533AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000534 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000535}
536
537void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000538 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000539 delete aWorkDuration;
540}
541
Peiyong Lin70de0852023-10-25 21:12:35 +0000542void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
543 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000544 VALIDATE_PTR(aWorkDuration)
545 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000546 aWorkDuration->durationNanos = actualTotalDurationNanos;
547}
548
549void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
550 int64_t workPeriodStartTimestampNanos) {
551 VALIDATE_PTR(aWorkDuration)
552 WARN_INT(workPeriodStartTimestampNanos, > 0)
553 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000554}
555
556void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
557 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000558 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000559 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000560 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000561}
562
563void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
564 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000565 VALIDATE_PTR(aWorkDuration)
566 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000567 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000568}
569
Bo Liu44267722021-07-16 17:03:20 -0400570void APerformanceHint_setIHintManagerForTesting(void* iManager) {
571 delete gHintManagerForTesting;
572 gHintManagerForTesting = nullptr;
Matt Buckley58977722024-03-11 23:32:09 +0000573 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400574}