blob: f64b84782aa42052722a892008c2d3096028704f [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
Matt Buckley1f5b95f2024-06-07 02:36:56 +000054// Shared lock for the whole PerformanceHintManager and sessions
55static std::mutex sHintMutex = std::mutex{};
56
Bo Liu44267722021-07-16 17:03:20 -040057struct APerformanceHintManager {
58public:
59 static APerformanceHintManager* getInstance();
Matt Buckley58977722024-03-11 23:32:09 +000060 APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -040061 APerformanceHintManager() = delete;
62 ~APerformanceHintManager() = default;
63
64 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
Matt Buckleye073c732024-04-05 22:32:31 +000065 int64_t initialTargetWorkDurationNanos,
66 hal::SessionTag tag = hal::SessionTag::OTHER);
Bo Liu44267722021-07-16 17:03:20 -040067 int64_t getPreferredRateNanos() const;
68
69private:
Matt Buckley58977722024-03-11 23:32:09 +000070 // Necessary to create an empty binder object
71 static void* tokenStubOnCreate(void*) {
72 return nullptr;
73 }
74 static void tokenStubOnDestroy(void*) {}
75 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
76 AParcel*) {
77 return STATUS_OK;
78 }
Bo Liu44267722021-07-16 17:03:20 -040079
Matt Buckley58977722024-03-11 23:32:09 +000080 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
81
82 std::shared_ptr<IHintManager> mHintManager;
83 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -040084 const int64_t mPreferredRateNanos;
85};
86
87struct APerformanceHintSession {
88public:
Matt Buckley58977722024-03-11 23:32:09 +000089 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
90 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +000091 int64_t targetDurationNanos,
92 std::optional<hal::SessionConfig> sessionConfig);
Bo Liu44267722021-07-16 17:03:20 -040093 APerformanceHintSession() = delete;
94 ~APerformanceHintSession();
95
96 int updateTargetWorkDuration(int64_t targetDurationNanos);
97 int reportActualWorkDuration(int64_t actualDurationNanos);
Steven Moreland42a8cce2023-03-03 23:31:17 +000098 int sendHint(SessionHint hint);
Peiyong Lin095de762022-11-11 18:28:12 +000099 int setThreads(const int32_t* threadIds, size_t size);
100 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +0000101 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +0000102 int reportActualWorkDuration(AWorkDuration* workDuration);
Bo Liu44267722021-07-16 17:03:20 -0400103
104private:
105 friend struct APerformanceHintManager;
106
Matt Buckley58977722024-03-11 23:32:09 +0000107 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000108
Matt Buckley58977722024-03-11 23:32:09 +0000109 std::shared_ptr<IHintManager> mHintManager;
110 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400111 // HAL preferred update rate
112 const int64_t mPreferredRateNanos;
113 // Target duration for choosing update rate
114 int64_t mTargetDurationNanos;
Wei Wang00feb502022-10-18 10:56:59 -0700115 // First target hit timestamp
116 int64_t mFirstTargetMetTimestamp;
117 // Last target hit timestamp
118 int64_t mLastTargetMetTimestamp;
Matt Buckley56093a72022-11-07 21:50:50 +0000119 // Last hint reported from sendHint indexed by hint value
120 std::vector<int64_t> mLastHintSentTimestamp;
Bo Liu44267722021-07-16 17:03:20 -0400121 // Cached samples
Matt Buckley7c2de582024-04-05 08:41:35 +0000122 std::vector<hal::WorkDuration> mActualWorkDurations;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000123 std::string mSessionName;
Matt Buckleye073c732024-04-05 22:32:31 +0000124 static int64_t sIDCounter;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000125 // The most recent set of thread IDs
126 std::vector<int32_t> mLastThreadIDs;
Matt Buckleye073c732024-04-05 22:32:31 +0000127 std::optional<hal::SessionConfig> mSessionConfig;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000128 // Tracing helpers
129 void traceThreads(std::vector<int32_t>& tids);
130 void tracePowerEfficient(bool powerEfficient);
131 void traceActualDuration(int64_t actualDuration);
132 void traceBatchSize(size_t batchSize);
133 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400134};
135
Matt Buckley58977722024-03-11 23:32:09 +0000136static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Bo Liu44267722021-07-16 17:03:20 -0400137static APerformanceHintManager* gHintManagerForTesting = nullptr;
Matt Buckleye073c732024-04-05 22:32:31 +0000138// Start above the int32 range so we don't collide with config sessions
139int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
Bo Liu44267722021-07-16 17:03:20 -0400140
141// ===================================== APerformanceHintManager implementation
Matt Buckley58977722024-03-11 23:32:09 +0000142APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
Bo Liu44267722021-07-16 17:03:20 -0400143 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000144 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
145 static AIBinder_Class* tokenBinderClass =
146 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
147 tokenStubOnTransact);
148 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
149}
Bo Liu44267722021-07-16 17:03:20 -0400150
151APerformanceHintManager* APerformanceHintManager::getInstance() {
152 if (gHintManagerForTesting) return gHintManagerForTesting;
153 if (gIHintManagerForTesting) {
Matt Buckley58977722024-03-11 23:32:09 +0000154 APerformanceHintManager* manager = create(*gIHintManagerForTesting);
Bo Liu44267722021-07-16 17:03:20 -0400155 gIHintManagerForTesting = nullptr;
156 return manager;
157 }
158 static APerformanceHintManager* instance = create(nullptr);
159 return instance;
160}
161
Matt Buckley58977722024-03-11 23:32:09 +0000162APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400163 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000164 manager = IHintManager::fromBinder(
165 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400166 }
167 if (manager == nullptr) {
168 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
169 return nullptr;
170 }
171 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000172 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400173 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000174 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400175 return nullptr;
176 }
177 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400178 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400179 }
180 return new APerformanceHintManager(std::move(manager), preferredRateNanos);
181}
182
183APerformanceHintSession* APerformanceHintManager::createSession(
Matt Buckleye073c732024-04-05 22:32:31 +0000184 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
185 hal::SessionTag tag) {
Bo Liu44267722021-07-16 17:03:20 -0400186 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000187 std::shared_ptr<IHintSession> session;
Matt Buckleye073c732024-04-05 22:32:31 +0000188 ndk::ScopedAStatus ret;
189 std::optional<hal::SessionConfig> sessionConfig;
190 ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
191 tag, &sessionConfig, &session);
192
Bo Liu44267722021-07-16 17:03:20 -0400193 if (!ret.isOk() || !session) {
194 return nullptr;
195 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000196 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000197 initialTargetWorkDurationNanos, sessionConfig);
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000198 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000199 out->traceThreads(tids);
200 out->traceTargetDuration(initialTargetWorkDurationNanos);
201 out->tracePowerEfficient(false);
202 return out;
Bo Liu44267722021-07-16 17:03:20 -0400203}
204
205int64_t APerformanceHintManager::getPreferredRateNanos() const {
206 return mPreferredRateNanos;
207}
208
209// ===================================== APerformanceHintSession implementation
210
Matt Buckley58977722024-03-11 23:32:09 +0000211APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
212 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400213 int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000214 int64_t targetDurationNanos,
215 std::optional<hal::SessionConfig> sessionConfig)
Peiyong Lin095de762022-11-11 18:28:12 +0000216 : mHintManager(hintManager),
217 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400218 mPreferredRateNanos(preferredRateNanos),
219 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700220 mFirstTargetMetTimestamp(0),
Matt Buckleye073c732024-04-05 22:32:31 +0000221 mLastTargetMetTimestamp(0),
222 mSessionConfig(sessionConfig) {
223 if (sessionConfig->id > INT32_MAX) {
224 ALOGE("Session ID too large, must fit 32-bit integer");
225 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000226 std::scoped_lock lock(sHintMutex);
Matt Buckleye073c732024-04-05 22:32:31 +0000227 constexpr int numEnums =
228 ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
229 mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
230 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
231 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
Matt Buckley56093a72022-11-07 21:50:50 +0000232}
Bo Liu44267722021-07-16 17:03:20 -0400233
234APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000235 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400236 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000237 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400238 }
239}
240
241int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
242 if (targetDurationNanos <= 0) {
243 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
244 return EINVAL;
245 }
Matt Buckley58977722024-03-11 23:32:09 +0000246 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
Bo Liu44267722021-07-16 17:03:20 -0400247 if (!ret.isOk()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000248 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000249 ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400250 return EPIPE;
251 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000252 std::scoped_lock lock(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400253 mTargetDurationNanos = targetDurationNanos;
254 /**
255 * Most of the workload is target_duration dependent, so now clear the cached samples
256 * as they are most likely obsolete.
257 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000258 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000259 traceBatchSize(0);
260 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700261 mFirstTargetMetTimestamp = 0;
262 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400263 return 0;
264}
265
266int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000267 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
268 .workPeriodStartTimestampNanos = 0,
269 .cpuDurationNanos = actualDurationNanos,
270 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400271
Matt Buckley58977722024-03-11 23:32:09 +0000272 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400273}
274
Steven Moreland42a8cce2023-03-03 23:31:17 +0000275int APerformanceHintSession::sendHint(SessionHint hint) {
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000276 std::scoped_lock lock(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000277 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
278 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000279 return EINVAL;
280 }
Matt Buckley58977722024-03-11 23:32:09 +0000281 int64_t now = uptimeNanos();
Matt Buckley56093a72022-11-07 21:50:50 +0000282
283 // Limit sendHint to a pre-detemined rate for safety
284 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
285 return 0;
286 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000287
Matt Buckley58977722024-03-11 23:32:09 +0000288 ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000289
290 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000291 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley354cc0a2022-09-28 20:54:46 +0000292 return EPIPE;
293 }
Matt Buckley56093a72022-11-07 21:50:50 +0000294 mLastHintSentTimestamp[hint] = now;
Matt Buckley354cc0a2022-09-28 20:54:46 +0000295 return 0;
296}
297
Peiyong Lin095de762022-11-11 18:28:12 +0000298int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
299 if (size == 0) {
300 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
301 return EINVAL;
302 }
303 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000304 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000305 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000306 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
307 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000308 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000309 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700310 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000311 }
312 return EPIPE;
313 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000314
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000315 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000316 traceThreads(tids);
317
Peiyong Lin095de762022-11-11 18:28:12 +0000318 return 0;
319}
320
321int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
322 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000323 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000324 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000325 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000326 return EPIPE;
327 }
328
329 // When threadIds is nullptr, this is the first call to determine the size
330 // of the thread ids list.
331 if (threadIds == nullptr) {
332 *size = tids.size();
333 return 0;
334 }
335
336 // Second call to return the actual list of thread ids.
337 *size = tids.size();
338 for (size_t i = 0; i < *size; ++i) {
339 threadIds[i] = tids[i];
340 }
341 return 0;
342}
343
Matt Buckley423c1b32023-06-28 19:13:42 +0000344int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000345 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000346 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
347 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000348
349 if (!ret.isOk()) {
350 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000351 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000352 return EPIPE;
353 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000354 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000355 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000356 return OK;
357}
358
Matt Buckley58977722024-03-11 23:32:09 +0000359int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000360 return reportActualWorkDurationInternal(workDuration);
361}
362
Matt Buckley58977722024-03-11 23:32:09 +0000363int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
364 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000365 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000366 workDuration->timeStampNanos = now;
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000367 std::scoped_lock lock(sHintMutex);
Matt Buckley58977722024-03-11 23:32:09 +0000368 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000369 mActualWorkDurations.push_back(std::move(*workDuration));
370
371 if (actualTotalDurationNanos >= mTargetDurationNanos) {
372 // Reset timestamps if we are equal or over the target.
373 mFirstTargetMetTimestamp = 0;
374 } else {
375 // Set mFirstTargetMetTimestamp for first time meeting target.
376 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
377 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
378 mFirstTargetMetTimestamp = now;
379 }
380 /**
381 * Rate limit the change if the update is over mPreferredRateNanos since first
382 * meeting target and less than mPreferredRateNanos since last meeting target.
383 */
384 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
385 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000386 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000387 return 0;
388 }
389 mLastTargetMetTimestamp = now;
390 }
391
Matt Buckley58977722024-03-11 23:32:09 +0000392 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
Peiyong Lin70de0852023-10-25 21:12:35 +0000393 if (!ret.isOk()) {
394 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000395 ret.getMessage());
Peiyong Lin70de0852023-10-25 21:12:35 +0000396 mFirstTargetMetTimestamp = 0;
397 mLastTargetMetTimestamp = 0;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000398 traceBatchSize(mActualWorkDurations.size());
Matt Buckley58977722024-03-11 23:32:09 +0000399 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
Peiyong Lin70de0852023-10-25 21:12:35 +0000400 }
401 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000402 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000403
404 return 0;
405}
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000406// ===================================== Tracing helpers
407
408void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
409 std::set<int32_t> tidSet{tids.begin(), tids.end()};
410
411 // Disable old TID tracing
412 for (int32_t tid : mLastThreadIDs) {
413 if (!tidSet.count(tid)) {
414 std::string traceName =
415 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
416 ATrace_setCounter(traceName.c_str(), 0);
417 }
418 }
419
420 // Add new TID tracing
421 for (int32_t tid : tids) {
422 std::string traceName =
423 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
424 ATrace_setCounter(traceName.c_str(), 1);
425 }
426
427 mLastThreadIDs = std::move(tids);
428}
429
430void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
431 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
432}
433
434void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
435 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
436}
437
438void APerformanceHintSession::traceBatchSize(size_t batchSize) {
439 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
440 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
441}
442
443void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
444 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
445}
Peiyong Lin70de0852023-10-25 21:12:35 +0000446
Bo Liu44267722021-07-16 17:03:20 -0400447// ===================================== C API
448APerformanceHintManager* APerformanceHint_getManager() {
449 return APerformanceHintManager::getInstance();
450}
451
Matt Buckley83f77092024-01-18 19:57:29 +0000452#define VALIDATE_PTR(ptr) \
453 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
454
455#define VALIDATE_INT(value, cmp) \
456 if (!(value cmp)) { \
457 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
458 __FUNCTION__, value); \
459 return EINVAL; \
460 }
461
462#define WARN_INT(value, cmp) \
463 if (!(value cmp)) { \
464 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
465 __FUNCTION__, value); \
466 }
467
Bo Liu44267722021-07-16 17:03:20 -0400468APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
469 const int32_t* threadIds, size_t size,
470 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000471 VALIDATE_PTR(manager)
472 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400473 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
474}
475
Matt Buckley27da1342024-04-05 23:10:48 +0000476APerformanceHintSession* APerformanceHint_createSessionInternal(
477 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
478 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
479 VALIDATE_PTR(manager)
480 VALIDATE_PTR(threadIds)
481 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
482 static_cast<hal::SessionTag>(tag));
483}
484
Bo Liu44267722021-07-16 17:03:20 -0400485int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000486 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400487 return manager->getPreferredRateNanos();
488}
489
490int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
491 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000492 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400493 return session->updateTargetWorkDuration(targetDurationNanos);
494}
495
496int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
497 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000498 VALIDATE_PTR(session)
499 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400500 return session->reportActualWorkDuration(actualDurationNanos);
501}
502
Bo Liu44267722021-07-16 17:03:20 -0400503void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000504 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400505 delete session;
506}
507
Matt Buckley27da1342024-04-05 23:10:48 +0000508int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000509 VALIDATE_PTR(session)
Matt Buckley27da1342024-04-05 23:10:48 +0000510 return session->sendHint(hint);
Matt Buckley61726a32022-12-06 23:44:45 +0000511}
512
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000513int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000514 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000515 VALIDATE_PTR(session)
516 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000517 return session->setThreads(threadIds, size);
518}
519
Matt Buckley27da1342024-04-05 23:10:48 +0000520int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000521 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +0000522 VALIDATE_PTR(session)
523 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +0000524}
525
Matt Buckley423c1b32023-06-28 19:13:42 +0000526int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000527 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000528 return session->setPreferPowerEfficiency(enabled);
529}
530
Peiyong Lin70de0852023-10-25 21:12:35 +0000531int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000532 AWorkDuration* workDurationPtr) {
533 VALIDATE_PTR(session)
534 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000535 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
536 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
537 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
538 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
539 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000540 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000541}
542
543AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000544 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000545}
546
547void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000548 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000549 delete aWorkDuration;
550}
551
Peiyong Lin70de0852023-10-25 21:12:35 +0000552void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
553 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000554 VALIDATE_PTR(aWorkDuration)
555 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000556 aWorkDuration->durationNanos = actualTotalDurationNanos;
557}
558
559void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
560 int64_t workPeriodStartTimestampNanos) {
561 VALIDATE_PTR(aWorkDuration)
562 WARN_INT(workPeriodStartTimestampNanos, > 0)
563 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000564}
565
566void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
567 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000568 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000569 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000570 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000571}
572
573void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
574 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000575 VALIDATE_PTR(aWorkDuration)
576 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000577 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000578}
579
Bo Liu44267722021-07-16 17:03:20 -0400580void APerformanceHint_setIHintManagerForTesting(void* iManager) {
581 delete gHintManagerForTesting;
582 gHintManagerForTesting = nullptr;
Matt Buckley58977722024-03-11 23:32:09 +0000583 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400584}