blob: 8227bdbd14a7d088fde7efb1bd2038d1f1b281a9 [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 Buckley58977722024-03-11 23:32:09 +000044using HalSessionHint = aidl::android::hardware::power::SessionHint;
45using HalSessionMode = aidl::android::hardware::power::SessionMode;
46using HalWorkDuration = aidl::android::hardware::power::WorkDuration;
47
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 Buckley58977722024-03-11 23:32:09 +000053struct AWorkDuration : public HalWorkDuration {};
Matt Buckley56093a72022-11-07 21:50:50 +000054
Bo Liu44267722021-07-16 17:03:20 -040055struct APerformanceHintManager {
56public:
57 static APerformanceHintManager* getInstance();
Matt Buckley58977722024-03-11 23:32:09 +000058 APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -040059 APerformanceHintManager() = delete;
60 ~APerformanceHintManager() = default;
61
62 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
63 int64_t initialTargetWorkDurationNanos);
64 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,
88 int64_t targetDurationNanos);
Bo Liu44267722021-07-16 17:03:20 -040089 APerformanceHintSession() = delete;
90 ~APerformanceHintSession();
91
92 int updateTargetWorkDuration(int64_t targetDurationNanos);
93 int reportActualWorkDuration(int64_t actualDurationNanos);
Steven Moreland42a8cce2023-03-03 23:31:17 +000094 int sendHint(SessionHint hint);
Peiyong Lin095de762022-11-11 18:28:12 +000095 int setThreads(const int32_t* threadIds, size_t size);
96 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +000097 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +000098 int reportActualWorkDuration(AWorkDuration* workDuration);
Bo Liu44267722021-07-16 17:03:20 -040099
100private:
101 friend struct APerformanceHintManager;
102
Matt Buckley58977722024-03-11 23:32:09 +0000103 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000104
Matt Buckley58977722024-03-11 23:32:09 +0000105 std::shared_ptr<IHintManager> mHintManager;
106 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400107 // HAL preferred update rate
108 const int64_t mPreferredRateNanos;
109 // Target duration for choosing update rate
110 int64_t mTargetDurationNanos;
Wei Wang00feb502022-10-18 10:56:59 -0700111 // First target hit timestamp
112 int64_t mFirstTargetMetTimestamp;
113 // Last target hit timestamp
114 int64_t mLastTargetMetTimestamp;
Matt Buckley56093a72022-11-07 21:50:50 +0000115 // Last hint reported from sendHint indexed by hint value
116 std::vector<int64_t> mLastHintSentTimestamp;
Bo Liu44267722021-07-16 17:03:20 -0400117 // Cached samples
Matt Buckley58977722024-03-11 23:32:09 +0000118 std::vector<HalWorkDuration> mActualWorkDurations;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000119 std::string mSessionName;
120 static int32_t sIDCounter;
121 // The most recent set of thread IDs
122 std::vector<int32_t> mLastThreadIDs;
123 // Tracing helpers
124 void traceThreads(std::vector<int32_t>& tids);
125 void tracePowerEfficient(bool powerEfficient);
126 void traceActualDuration(int64_t actualDuration);
127 void traceBatchSize(size_t batchSize);
128 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400129};
130
Matt Buckley58977722024-03-11 23:32:09 +0000131static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Bo Liu44267722021-07-16 17:03:20 -0400132static APerformanceHintManager* gHintManagerForTesting = nullptr;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000133int32_t APerformanceHintSession::sIDCounter = 0;
Bo Liu44267722021-07-16 17:03:20 -0400134
135// ===================================== APerformanceHintManager implementation
Matt Buckley58977722024-03-11 23:32:09 +0000136APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
Bo Liu44267722021-07-16 17:03:20 -0400137 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000138 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
139 static AIBinder_Class* tokenBinderClass =
140 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
141 tokenStubOnTransact);
142 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
143}
Bo Liu44267722021-07-16 17:03:20 -0400144
145APerformanceHintManager* APerformanceHintManager::getInstance() {
146 if (gHintManagerForTesting) return gHintManagerForTesting;
147 if (gIHintManagerForTesting) {
Matt Buckley58977722024-03-11 23:32:09 +0000148 APerformanceHintManager* manager = create(*gIHintManagerForTesting);
Bo Liu44267722021-07-16 17:03:20 -0400149 gIHintManagerForTesting = nullptr;
150 return manager;
151 }
152 static APerformanceHintManager* instance = create(nullptr);
153 return instance;
154}
155
Matt Buckley58977722024-03-11 23:32:09 +0000156APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400157 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000158 manager = IHintManager::fromBinder(
159 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400160 }
161 if (manager == nullptr) {
162 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
163 return nullptr;
164 }
165 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000166 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400167 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000168 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400169 return nullptr;
170 }
171 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400172 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400173 }
174 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
175}
176
177APerformanceHintSession* APerformanceHintManager::createSession(
178 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
Bo Liu44267722021-07-16 17:03:20 -0400179 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000180 std::shared_ptr<IHintSession> session;
181 ndk::ScopedAStatus ret =
Bo Liu9acc5582022-02-17 16:47:32 -0500182 mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
Bo Liu44267722021-07-16 17:03:20 -0400183 if (!ret.isOk() || !session) {
184 return nullptr;
185 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000186 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
187 initialTargetWorkDurationNanos);
188 out->traceThreads(tids);
189 out->traceTargetDuration(initialTargetWorkDurationNanos);
190 out->tracePowerEfficient(false);
191 return out;
Bo Liu44267722021-07-16 17:03:20 -0400192}
193
194int64_t APerformanceHintManager::getPreferredRateNanos() const {
195 return mPreferredRateNanos;
196}
197
198// ===================================== APerformanceHintSession implementation
199
Matt Buckley58977722024-03-11 23:32:09 +0000200APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
201 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400202 int64_t preferredRateNanos,
203 int64_t targetDurationNanos)
Peiyong Lin095de762022-11-11 18:28:12 +0000204 : mHintManager(hintManager),
205 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400206 mPreferredRateNanos(preferredRateNanos),
207 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700208 mFirstTargetMetTimestamp(0),
Matt Buckley56093a72022-11-07 21:50:50 +0000209 mLastTargetMetTimestamp(0) {
Matt Buckley58977722024-03-11 23:32:09 +0000210 const std::vector<HalSessionHint> sessionHintRange{ndk::enum_range<HalSessionHint>().begin(),
211 ndk::enum_range<HalSessionHint>().end()};
Matt Buckley56093a72022-11-07 21:50:50 +0000212
213 mLastHintSentTimestamp = std::vector<int64_t>(sessionHintRange.size(), 0);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000214 mSessionName = android::base::StringPrintf("ADPF Session %" PRId32, ++sIDCounter);
Matt Buckley56093a72022-11-07 21:50:50 +0000215}
Bo Liu44267722021-07-16 17:03:20 -0400216
217APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000218 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400219 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000220 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400221 }
222}
223
224int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
225 if (targetDurationNanos <= 0) {
226 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
227 return EINVAL;
228 }
Matt Buckley58977722024-03-11 23:32:09 +0000229 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
Bo Liu44267722021-07-16 17:03:20 -0400230 if (!ret.isOk()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000231 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000232 ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400233 return EPIPE;
234 }
235 mTargetDurationNanos = targetDurationNanos;
236 /**
237 * Most of the workload is target_duration dependent, so now clear the cached samples
238 * as they are most likely obsolete.
239 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000240 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000241 traceBatchSize(0);
242 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700243 mFirstTargetMetTimestamp = 0;
244 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400245 return 0;
246}
247
248int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley58977722024-03-11 23:32:09 +0000249 HalWorkDuration workDuration{.durationNanos = actualDurationNanos,
250 .workPeriodStartTimestampNanos = 0,
251 .cpuDurationNanos = actualDurationNanos,
252 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400253
Matt Buckley58977722024-03-11 23:32:09 +0000254 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400255}
256
Steven Moreland42a8cce2023-03-03 23:31:17 +0000257int APerformanceHintSession::sendHint(SessionHint hint) {
Matt Buckley56093a72022-11-07 21:50:50 +0000258 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
259 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000260 return EINVAL;
261 }
Matt Buckley58977722024-03-11 23:32:09 +0000262 int64_t now = uptimeNanos();
Matt Buckley56093a72022-11-07 21:50:50 +0000263
264 // Limit sendHint to a pre-detemined rate for safety
265 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
266 return 0;
267 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000268
Matt Buckley58977722024-03-11 23:32:09 +0000269 ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000270
271 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000272 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley354cc0a2022-09-28 20:54:46 +0000273 return EPIPE;
274 }
Matt Buckley56093a72022-11-07 21:50:50 +0000275 mLastHintSentTimestamp[hint] = now;
Matt Buckley354cc0a2022-09-28 20:54:46 +0000276 return 0;
277}
278
Peiyong Lin095de762022-11-11 18:28:12 +0000279int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
280 if (size == 0) {
281 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
282 return EINVAL;
283 }
284 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000285 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000286 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000287 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
288 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000289 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000290 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700291 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000292 }
293 return EPIPE;
294 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000295
296 traceThreads(tids);
297
Peiyong Lin095de762022-11-11 18:28:12 +0000298 return 0;
299}
300
301int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
302 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000303 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000304 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000305 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000306 return EPIPE;
307 }
308
309 // When threadIds is nullptr, this is the first call to determine the size
310 // of the thread ids list.
311 if (threadIds == nullptr) {
312 *size = tids.size();
313 return 0;
314 }
315
316 // Second call to return the actual list of thread ids.
317 *size = tids.size();
318 for (size_t i = 0; i < *size; ++i) {
319 threadIds[i] = tids[i];
320 }
321 return 0;
322}
323
Matt Buckley423c1b32023-06-28 19:13:42 +0000324int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000325 ndk::ScopedAStatus ret =
326 mHintSession->setMode(static_cast<int32_t>(HalSessionMode::POWER_EFFICIENCY), enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000327
328 if (!ret.isOk()) {
329 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000330 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000331 return EPIPE;
332 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000333 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000334 return OK;
335}
336
Matt Buckley58977722024-03-11 23:32:09 +0000337int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000338 return reportActualWorkDurationInternal(workDuration);
339}
340
Matt Buckley58977722024-03-11 23:32:09 +0000341int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
342 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000343 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000344 workDuration->timeStampNanos = now;
345 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000346 mActualWorkDurations.push_back(std::move(*workDuration));
347
348 if (actualTotalDurationNanos >= mTargetDurationNanos) {
349 // Reset timestamps if we are equal or over the target.
350 mFirstTargetMetTimestamp = 0;
351 } else {
352 // Set mFirstTargetMetTimestamp for first time meeting target.
353 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
354 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
355 mFirstTargetMetTimestamp = now;
356 }
357 /**
358 * Rate limit the change if the update is over mPreferredRateNanos since first
359 * meeting target and less than mPreferredRateNanos since last meeting target.
360 */
361 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
362 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000363 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000364 return 0;
365 }
366 mLastTargetMetTimestamp = now;
367 }
368
Matt Buckley58977722024-03-11 23:32:09 +0000369 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
Peiyong Lin70de0852023-10-25 21:12:35 +0000370 if (!ret.isOk()) {
371 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000372 ret.getMessage());
Peiyong Lin70de0852023-10-25 21:12:35 +0000373 mFirstTargetMetTimestamp = 0;
374 mLastTargetMetTimestamp = 0;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000375 traceBatchSize(mActualWorkDurations.size());
Matt Buckley58977722024-03-11 23:32:09 +0000376 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
Peiyong Lin70de0852023-10-25 21:12:35 +0000377 }
378 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000379 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000380
381 return 0;
382}
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000383// ===================================== Tracing helpers
384
385void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
386 std::set<int32_t> tidSet{tids.begin(), tids.end()};
387
388 // Disable old TID tracing
389 for (int32_t tid : mLastThreadIDs) {
390 if (!tidSet.count(tid)) {
391 std::string traceName =
392 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
393 ATrace_setCounter(traceName.c_str(), 0);
394 }
395 }
396
397 // Add new TID tracing
398 for (int32_t tid : tids) {
399 std::string traceName =
400 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
401 ATrace_setCounter(traceName.c_str(), 1);
402 }
403
404 mLastThreadIDs = std::move(tids);
405}
406
407void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
408 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
409}
410
411void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
412 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
413}
414
415void APerformanceHintSession::traceBatchSize(size_t batchSize) {
416 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
417 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
418}
419
420void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
421 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
422}
Peiyong Lin70de0852023-10-25 21:12:35 +0000423
Bo Liu44267722021-07-16 17:03:20 -0400424// ===================================== C API
425APerformanceHintManager* APerformanceHint_getManager() {
426 return APerformanceHintManager::getInstance();
427}
428
Matt Buckley83f77092024-01-18 19:57:29 +0000429#define VALIDATE_PTR(ptr) \
430 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
431
432#define VALIDATE_INT(value, cmp) \
433 if (!(value cmp)) { \
434 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
435 __FUNCTION__, value); \
436 return EINVAL; \
437 }
438
439#define WARN_INT(value, cmp) \
440 if (!(value cmp)) { \
441 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
442 __FUNCTION__, value); \
443 }
444
Bo Liu44267722021-07-16 17:03:20 -0400445APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
446 const int32_t* threadIds, size_t size,
447 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000448 VALIDATE_PTR(manager)
449 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400450 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
451}
452
453int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000454 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400455 return manager->getPreferredRateNanos();
456}
457
458int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
459 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000460 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400461 return session->updateTargetWorkDuration(targetDurationNanos);
462}
463
464int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
465 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000466 VALIDATE_PTR(session)
467 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400468 return session->reportActualWorkDuration(actualDurationNanos);
469}
470
Bo Liu44267722021-07-16 17:03:20 -0400471void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000472 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400473 delete session;
474}
475
Steven Moreland42a8cce2023-03-03 23:31:17 +0000476int APerformanceHint_sendHint(void* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000477 VALIDATE_PTR(session)
Matt Buckley61726a32022-12-06 23:44:45 +0000478 return reinterpret_cast<APerformanceHintSession*>(session)->sendHint(hint);
479}
480
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000481int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000482 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000483 VALIDATE_PTR(session)
484 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000485 return session->setThreads(threadIds, size);
486}
487
488int APerformanceHint_getThreadIds(void* aPerformanceHintSession, int32_t* const threadIds,
489 size_t* const size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000490 VALIDATE_PTR(aPerformanceHintSession)
Peiyong Lin095de762022-11-11 18:28:12 +0000491 return static_cast<APerformanceHintSession*>(aPerformanceHintSession)
492 ->getThreadIds(threadIds, size);
493}
494
Matt Buckley423c1b32023-06-28 19:13:42 +0000495int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000496 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000497 return session->setPreferPowerEfficiency(enabled);
498}
499
Peiyong Lin70de0852023-10-25 21:12:35 +0000500int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000501 AWorkDuration* workDurationPtr) {
502 VALIDATE_PTR(session)
503 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000504 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
505 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
506 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
507 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
508 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000509 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000510}
511
512AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000513 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000514}
515
516void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000517 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000518 delete aWorkDuration;
519}
520
Peiyong Lin70de0852023-10-25 21:12:35 +0000521void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
522 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000523 VALIDATE_PTR(aWorkDuration)
524 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000525 aWorkDuration->durationNanos = actualTotalDurationNanos;
526}
527
528void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
529 int64_t workPeriodStartTimestampNanos) {
530 VALIDATE_PTR(aWorkDuration)
531 WARN_INT(workPeriodStartTimestampNanos, > 0)
532 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000533}
534
535void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
536 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000537 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000538 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000539 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000540}
541
542void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
543 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000544 VALIDATE_PTR(aWorkDuration)
545 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000546 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000547}
548
Bo Liu44267722021-07-16 17:03:20 -0400549void APerformanceHint_setIHintManagerForTesting(void* iManager) {
550 delete gHintManagerForTesting;
551 gHintManagerForTesting = nullptr;
Matt Buckley58977722024-03-11 23:32:09 +0000552 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400553}