blob: 882afcab6290ad085dbe0809d579f8187a7c26b4 [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,
62 int64_t initialTargetWorkDurationNanos);
63 int64_t getPreferredRateNanos() const;
64
65private:
Matt Buckley58977722024-03-11 23:32:09 +000066 // Necessary to create an empty binder object
67 static void* tokenStubOnCreate(void*) {
68 return nullptr;
69 }
70 static void tokenStubOnDestroy(void*) {}
71 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
72 AParcel*) {
73 return STATUS_OK;
74 }
Bo Liu44267722021-07-16 17:03:20 -040075
Matt Buckley58977722024-03-11 23:32:09 +000076 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
77
78 std::shared_ptr<IHintManager> mHintManager;
79 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -040080 const int64_t mPreferredRateNanos;
81};
82
83struct APerformanceHintSession {
84public:
Matt Buckley58977722024-03-11 23:32:09 +000085 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
86 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
87 int64_t targetDurationNanos);
Bo Liu44267722021-07-16 17:03:20 -040088 APerformanceHintSession() = delete;
89 ~APerformanceHintSession();
90
91 int updateTargetWorkDuration(int64_t targetDurationNanos);
92 int reportActualWorkDuration(int64_t actualDurationNanos);
Steven Moreland42a8cce2023-03-03 23:31:17 +000093 int sendHint(SessionHint hint);
Peiyong Lin095de762022-11-11 18:28:12 +000094 int setThreads(const int32_t* threadIds, size_t size);
95 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +000096 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +000097 int reportActualWorkDuration(AWorkDuration* workDuration);
Bo Liu44267722021-07-16 17:03:20 -040098
99private:
100 friend struct APerformanceHintManager;
101
Matt Buckley58977722024-03-11 23:32:09 +0000102 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000103
Matt Buckley58977722024-03-11 23:32:09 +0000104 std::shared_ptr<IHintManager> mHintManager;
105 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400106 // HAL preferred update rate
107 const int64_t mPreferredRateNanos;
108 // Target duration for choosing update rate
109 int64_t mTargetDurationNanos;
Wei Wang00feb502022-10-18 10:56:59 -0700110 // First target hit timestamp
111 int64_t mFirstTargetMetTimestamp;
112 // Last target hit timestamp
113 int64_t mLastTargetMetTimestamp;
Matt Buckley56093a72022-11-07 21:50:50 +0000114 // Last hint reported from sendHint indexed by hint value
115 std::vector<int64_t> mLastHintSentTimestamp;
Bo Liu44267722021-07-16 17:03:20 -0400116 // Cached samples
Matt Buckley7c2de582024-04-05 08:41:35 +0000117 std::vector<hal::WorkDuration> mActualWorkDurations;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000118 std::string mSessionName;
119 static int32_t sIDCounter;
120 // The most recent set of thread IDs
121 std::vector<int32_t> mLastThreadIDs;
122 // Tracing helpers
123 void traceThreads(std::vector<int32_t>& tids);
124 void tracePowerEfficient(bool powerEfficient);
125 void traceActualDuration(int64_t actualDuration);
126 void traceBatchSize(size_t batchSize);
127 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400128};
129
Matt Buckley58977722024-03-11 23:32:09 +0000130static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Bo Liu44267722021-07-16 17:03:20 -0400131static APerformanceHintManager* gHintManagerForTesting = nullptr;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000132int32_t APerformanceHintSession::sIDCounter = 0;
Bo Liu44267722021-07-16 17:03:20 -0400133
134// ===================================== APerformanceHintManager implementation
Matt Buckley58977722024-03-11 23:32:09 +0000135APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
Bo Liu44267722021-07-16 17:03:20 -0400136 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000137 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
138 static AIBinder_Class* tokenBinderClass =
139 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
140 tokenStubOnTransact);
141 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
142}
Bo Liu44267722021-07-16 17:03:20 -0400143
144APerformanceHintManager* APerformanceHintManager::getInstance() {
145 if (gHintManagerForTesting) return gHintManagerForTesting;
146 if (gIHintManagerForTesting) {
Matt Buckley58977722024-03-11 23:32:09 +0000147 APerformanceHintManager* manager = create(*gIHintManagerForTesting);
Bo Liu44267722021-07-16 17:03:20 -0400148 gIHintManagerForTesting = nullptr;
149 return manager;
150 }
151 static APerformanceHintManager* instance = create(nullptr);
152 return instance;
153}
154
Matt Buckley58977722024-03-11 23:32:09 +0000155APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400156 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000157 manager = IHintManager::fromBinder(
158 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400159 }
160 if (manager == nullptr) {
161 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
162 return nullptr;
163 }
164 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000165 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400166 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000167 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400168 return nullptr;
169 }
170 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400171 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400172 }
173 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
174}
175
176APerformanceHintSession* APerformanceHintManager::createSession(
177 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos) {
Bo Liu44267722021-07-16 17:03:20 -0400178 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000179 std::shared_ptr<IHintSession> session;
180 ndk::ScopedAStatus ret =
Bo Liu9acc5582022-02-17 16:47:32 -0500181 mHintManager->createHintSession(mToken, tids, initialTargetWorkDurationNanos, &session);
Bo Liu44267722021-07-16 17:03:20 -0400182 if (!ret.isOk() || !session) {
183 return nullptr;
184 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000185 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
186 initialTargetWorkDurationNanos);
187 out->traceThreads(tids);
188 out->traceTargetDuration(initialTargetWorkDurationNanos);
189 out->tracePowerEfficient(false);
190 return out;
Bo Liu44267722021-07-16 17:03:20 -0400191}
192
193int64_t APerformanceHintManager::getPreferredRateNanos() const {
194 return mPreferredRateNanos;
195}
196
197// ===================================== APerformanceHintSession implementation
198
Matt Buckley58977722024-03-11 23:32:09 +0000199APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
200 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400201 int64_t preferredRateNanos,
202 int64_t targetDurationNanos)
Peiyong Lin095de762022-11-11 18:28:12 +0000203 : mHintManager(hintManager),
204 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400205 mPreferredRateNanos(preferredRateNanos),
206 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700207 mFirstTargetMetTimestamp(0),
Matt Buckley56093a72022-11-07 21:50:50 +0000208 mLastTargetMetTimestamp(0) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000209 const std::vector<hal::SessionHint> sessionHintRange{ndk::enum_range<hal::SessionHint>()
210 .begin(),
211 ndk::enum_range<hal::SessionHint>().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 Buckley7c2de582024-04-05 08:41:35 +0000249 hal::WorkDuration 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 =
Matt Buckley7c2de582024-04-05 08:41:35 +0000326 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
327 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000328
329 if (!ret.isOk()) {
330 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000331 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000332 return EPIPE;
333 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000334 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000335 return OK;
336}
337
Matt Buckley58977722024-03-11 23:32:09 +0000338int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000339 return reportActualWorkDurationInternal(workDuration);
340}
341
Matt Buckley58977722024-03-11 23:32:09 +0000342int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
343 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000344 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000345 workDuration->timeStampNanos = now;
346 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000347 mActualWorkDurations.push_back(std::move(*workDuration));
348
349 if (actualTotalDurationNanos >= mTargetDurationNanos) {
350 // Reset timestamps if we are equal or over the target.
351 mFirstTargetMetTimestamp = 0;
352 } else {
353 // Set mFirstTargetMetTimestamp for first time meeting target.
354 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
355 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
356 mFirstTargetMetTimestamp = now;
357 }
358 /**
359 * Rate limit the change if the update is over mPreferredRateNanos since first
360 * meeting target and less than mPreferredRateNanos since last meeting target.
361 */
362 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
363 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000364 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000365 return 0;
366 }
367 mLastTargetMetTimestamp = now;
368 }
369
Matt Buckley58977722024-03-11 23:32:09 +0000370 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
Peiyong Lin70de0852023-10-25 21:12:35 +0000371 if (!ret.isOk()) {
372 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000373 ret.getMessage());
Peiyong Lin70de0852023-10-25 21:12:35 +0000374 mFirstTargetMetTimestamp = 0;
375 mLastTargetMetTimestamp = 0;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000376 traceBatchSize(mActualWorkDurations.size());
Matt Buckley58977722024-03-11 23:32:09 +0000377 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
Peiyong Lin70de0852023-10-25 21:12:35 +0000378 }
379 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000380 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000381
382 return 0;
383}
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000384// ===================================== Tracing helpers
385
386void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
387 std::set<int32_t> tidSet{tids.begin(), tids.end()};
388
389 // Disable old TID tracing
390 for (int32_t tid : mLastThreadIDs) {
391 if (!tidSet.count(tid)) {
392 std::string traceName =
393 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
394 ATrace_setCounter(traceName.c_str(), 0);
395 }
396 }
397
398 // Add new TID tracing
399 for (int32_t tid : tids) {
400 std::string traceName =
401 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
402 ATrace_setCounter(traceName.c_str(), 1);
403 }
404
405 mLastThreadIDs = std::move(tids);
406}
407
408void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
409 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
410}
411
412void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
413 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
414}
415
416void APerformanceHintSession::traceBatchSize(size_t batchSize) {
417 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
418 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
419}
420
421void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
422 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
423}
Peiyong Lin70de0852023-10-25 21:12:35 +0000424
Bo Liu44267722021-07-16 17:03:20 -0400425// ===================================== C API
426APerformanceHintManager* APerformanceHint_getManager() {
427 return APerformanceHintManager::getInstance();
428}
429
Matt Buckley83f77092024-01-18 19:57:29 +0000430#define VALIDATE_PTR(ptr) \
431 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
432
433#define VALIDATE_INT(value, cmp) \
434 if (!(value cmp)) { \
435 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
436 __FUNCTION__, value); \
437 return EINVAL; \
438 }
439
440#define WARN_INT(value, cmp) \
441 if (!(value cmp)) { \
442 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
443 __FUNCTION__, value); \
444 }
445
Bo Liu44267722021-07-16 17:03:20 -0400446APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
447 const int32_t* threadIds, size_t size,
448 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000449 VALIDATE_PTR(manager)
450 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400451 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
452}
453
454int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000455 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400456 return manager->getPreferredRateNanos();
457}
458
459int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
460 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000461 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400462 return session->updateTargetWorkDuration(targetDurationNanos);
463}
464
465int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
466 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000467 VALIDATE_PTR(session)
468 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400469 return session->reportActualWorkDuration(actualDurationNanos);
470}
471
Bo Liu44267722021-07-16 17:03:20 -0400472void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000473 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400474 delete session;
475}
476
Steven Moreland42a8cce2023-03-03 23:31:17 +0000477int APerformanceHint_sendHint(void* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000478 VALIDATE_PTR(session)
Matt Buckley61726a32022-12-06 23:44:45 +0000479 return reinterpret_cast<APerformanceHintSession*>(session)->sendHint(hint);
480}
481
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000482int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000483 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000484 VALIDATE_PTR(session)
485 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000486 return session->setThreads(threadIds, size);
487}
488
489int APerformanceHint_getThreadIds(void* aPerformanceHintSession, int32_t* const threadIds,
490 size_t* const size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000491 VALIDATE_PTR(aPerformanceHintSession)
Peiyong Lin095de762022-11-11 18:28:12 +0000492 return static_cast<APerformanceHintSession*>(aPerformanceHintSession)
493 ->getThreadIds(threadIds, size);
494}
495
Matt Buckley423c1b32023-06-28 19:13:42 +0000496int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000497 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000498 return session->setPreferPowerEfficiency(enabled);
499}
500
Peiyong Lin70de0852023-10-25 21:12:35 +0000501int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000502 AWorkDuration* workDurationPtr) {
503 VALIDATE_PTR(session)
504 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000505 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
506 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
507 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
508 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
509 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000510 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000511}
512
513AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000514 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000515}
516
517void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000518 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000519 delete aWorkDuration;
520}
521
Peiyong Lin70de0852023-10-25 21:12:35 +0000522void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
523 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000524 VALIDATE_PTR(aWorkDuration)
525 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000526 aWorkDuration->durationNanos = actualTotalDurationNanos;
527}
528
529void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
530 int64_t workPeriodStartTimestampNanos) {
531 VALIDATE_PTR(aWorkDuration)
532 WARN_INT(workPeriodStartTimestampNanos, > 0)
533 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000534}
535
536void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
537 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000538 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000539 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000540 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000541}
542
543void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
544 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000545 VALIDATE_PTR(aWorkDuration)
546 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000547 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000548}
549
Bo Liu44267722021-07-16 17:03:20 -0400550void APerformanceHint_setIHintManagerForTesting(void* iManager) {
551 delete gHintManagerForTesting;
552 gHintManagerForTesting = nullptr;
Matt Buckley58977722024-03-11 23:32:09 +0000553 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400554}