blob: 095d7d1145aefc262fe5e8125e8b628566bf7392 [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 Buckley854947f2024-02-07 17:30:01 +000019#include <aidl/android/hardware/power/ChannelConfig.h>
20#include <aidl/android/hardware/power/ChannelMessage.h>
21#include <aidl/android/hardware/power/SessionConfig.h>
Matt Buckley56093a72022-11-07 21:50:50 +000022#include <aidl/android/hardware/power/SessionHint.h>
Matt Buckley423c1b32023-06-28 19:13:42 +000023#include <aidl/android/hardware/power/SessionMode.h>
Matt Buckley58977722024-03-11 23:32:09 +000024#include <aidl/android/hardware/power/SessionTag.h>
25#include <aidl/android/hardware/power/WorkDuration.h>
Matt Buckley854947f2024-02-07 17:30:01 +000026#include <aidl/android/hardware/power/WorkDurationFixedV1.h>
Matt Buckley58977722024-03-11 23:32:09 +000027#include <aidl/android/os/IHintManager.h>
28#include <aidl/android/os/IHintSession.h>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000029#include <android-base/stringprintf.h>
Matt Buckley053a1df2024-06-07 02:37:59 +000030#include <android-base/thread_annotations.h>
Matt Buckley58977722024-03-11 23:32:09 +000031#include <android/binder_manager.h>
32#include <android/binder_status.h>
Bo Liu2b739bb2021-11-10 19:20:03 -050033#include <android/performance_hint.h>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000034#include <android/trace.h>
Matt Buckley854947f2024-02-07 17:30:01 +000035#include <android_os.h>
36#include <fmq/AidlMessageQueue.h>
Peiyong Lin70de0852023-10-25 21:12:35 +000037#include <inttypes.h>
Bo Liu44267722021-07-16 17:03:20 -040038#include <performance_hint_private.h>
39#include <utils/SystemClock.h>
40
Matt Buckley56093a72022-11-07 21:50:50 +000041#include <chrono>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000042#include <set>
Bo Liu2b739bb2021-11-10 19:20:03 -050043#include <utility>
44#include <vector>
45
Bo Liu44267722021-07-16 17:03:20 -040046using namespace android;
Matt Buckley58977722024-03-11 23:32:09 +000047using namespace aidl::android::os;
Bo Liu44267722021-07-16 17:03:20 -040048
Matt Buckley56093a72022-11-07 21:50:50 +000049using namespace std::chrono_literals;
50
Matt Buckley7c2de582024-04-05 08:41:35 +000051// Namespace for AIDL types coming from the PowerHAL
52namespace hal = aidl::android::hardware::power;
Matt Buckley58977722024-03-11 23:32:09 +000053
Matt Buckley854947f2024-02-07 17:30:01 +000054using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
55using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
56using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
57using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000058using android::base::StringPrintf;
Matt Buckley56093a72022-11-07 21:50:50 +000059
Bo Liu44267722021-07-16 17:03:20 -040060struct APerformanceHintSession;
61
Matt Buckley56093a72022-11-07 21:50:50 +000062constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
Matt Buckley7c2de582024-04-05 08:41:35 +000063struct AWorkDuration : public hal::WorkDuration {};
Matt Buckley56093a72022-11-07 21:50:50 +000064
Matt Buckley1f5b95f2024-06-07 02:36:56 +000065// Shared lock for the whole PerformanceHintManager and sessions
66static std::mutex sHintMutex = std::mutex{};
Matt Buckley854947f2024-02-07 17:30:01 +000067class FMQWrapper {
68public:
69 bool isActive();
70 bool isSupported();
71 bool startChannel(IHintManager* manager);
72 void stopChannel(IHintManager* manager);
73 // Number of elements the FMQ can hold
74 bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
75 hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
76 bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
77 int64_t targetDurationNanos) REQUIRES(sHintMutex);
78 bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex);
79 bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
80 REQUIRES(sHintMutex);
81 void setToken(ndk::SpAIBinder& token);
82 void attemptWake();
83 void setUnsupported();
84
85private:
86 template <HalChannelMessageContents::Tag T, bool urgent = false,
87 class C = HalChannelMessageContents::_at<T>>
88 bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1)
89 REQUIRES(sHintMutex);
90 template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
91 void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex);
92
93 bool isActiveLocked() REQUIRES(sHintMutex);
94 bool updatePersistentTransaction() REQUIRES(sHintMutex);
95 std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
96 std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
97 // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
98 android::hardware::EventFlag* mEventFlag = nullptr;
99 int32_t mWriteMask;
100 ndk::SpAIBinder mToken = nullptr;
101 // Used to track if operating on the fmq consistently fails
102 bool mCorrupted = false;
103 // Used to keep a persistent transaction open with FMQ to reduce latency a bit
104 size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
105 bool mHalSupported = true;
106 HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
107};
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000108
Bo Liu44267722021-07-16 17:03:20 -0400109struct APerformanceHintManager {
110public:
111 static APerformanceHintManager* getInstance();
Matt Buckley854947f2024-02-07 17:30:01 +0000112 APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400113 APerformanceHintManager() = delete;
Matt Buckley854947f2024-02-07 17:30:01 +0000114 ~APerformanceHintManager();
Bo Liu44267722021-07-16 17:03:20 -0400115
116 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
Matt Buckleye073c732024-04-05 22:32:31 +0000117 int64_t initialTargetWorkDurationNanos,
Matt Buckley31974132024-05-21 19:54:39 +0000118 hal::SessionTag tag = hal::SessionTag::APP);
Bo Liu44267722021-07-16 17:03:20 -0400119 int64_t getPreferredRateNanos() const;
Matt Buckley854947f2024-02-07 17:30:01 +0000120 FMQWrapper& getFMQWrapper();
Bo Liu44267722021-07-16 17:03:20 -0400121
122private:
Matt Buckley58977722024-03-11 23:32:09 +0000123 // Necessary to create an empty binder object
124 static void* tokenStubOnCreate(void*) {
125 return nullptr;
126 }
127 static void tokenStubOnDestroy(void*) {}
128 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
129 AParcel*) {
130 return STATUS_OK;
131 }
Bo Liu44267722021-07-16 17:03:20 -0400132
Matt Buckley58977722024-03-11 23:32:09 +0000133 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
134
135 std::shared_ptr<IHintManager> mHintManager;
136 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -0400137 const int64_t mPreferredRateNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000138 FMQWrapper mFMQWrapper;
Bo Liu44267722021-07-16 17:03:20 -0400139};
140
141struct APerformanceHintSession {
142public:
Matt Buckley58977722024-03-11 23:32:09 +0000143 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
144 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000145 int64_t targetDurationNanos,
146 std::optional<hal::SessionConfig> sessionConfig);
Bo Liu44267722021-07-16 17:03:20 -0400147 APerformanceHintSession() = delete;
148 ~APerformanceHintSession();
149
150 int updateTargetWorkDuration(int64_t targetDurationNanos);
151 int reportActualWorkDuration(int64_t actualDurationNanos);
Steven Moreland42a8cce2023-03-03 23:31:17 +0000152 int sendHint(SessionHint hint);
Peiyong Lin095de762022-11-11 18:28:12 +0000153 int setThreads(const int32_t* threadIds, size_t size);
154 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +0000155 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +0000156 int reportActualWorkDuration(AWorkDuration* workDuration);
Bo Liu44267722021-07-16 17:03:20 -0400157
158private:
159 friend struct APerformanceHintManager;
160
Matt Buckley58977722024-03-11 23:32:09 +0000161 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000162
Matt Buckley58977722024-03-11 23:32:09 +0000163 std::shared_ptr<IHintManager> mHintManager;
164 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400165 // HAL preferred update rate
166 const int64_t mPreferredRateNanos;
167 // Target duration for choosing update rate
Matt Buckley053a1df2024-06-07 02:37:59 +0000168 int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700169 // First target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000170 int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700171 // Last target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000172 int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000173 // Last hint reported from sendHint indexed by hint value
Matt Buckley053a1df2024-06-07 02:37:59 +0000174 std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400175 // Cached samples
Matt Buckley053a1df2024-06-07 02:37:59 +0000176 std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000177 std::string mSessionName;
Matt Buckley053a1df2024-06-07 02:37:59 +0000178 static int64_t sIDCounter GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000179 // The most recent set of thread IDs
Matt Buckley053a1df2024-06-07 02:37:59 +0000180 std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
181 std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000182 // Tracing helpers
Matt Buckley053a1df2024-06-07 02:37:59 +0000183 void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000184 void tracePowerEfficient(bool powerEfficient);
185 void traceActualDuration(int64_t actualDuration);
186 void traceBatchSize(size_t batchSize);
187 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400188};
189
Matt Buckley58977722024-03-11 23:32:09 +0000190static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000191static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
192
193static std::optional<bool> gForceFMQEnabled = std::nullopt;
194
Matt Buckleye073c732024-04-05 22:32:31 +0000195// Start above the int32 range so we don't collide with config sessions
196int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
Bo Liu44267722021-07-16 17:03:20 -0400197
Matt Buckley854947f2024-02-07 17:30:01 +0000198static FMQWrapper& getFMQ() {
199 return APerformanceHintManager::getInstance()->getFMQWrapper();
200}
201
Bo Liu44267722021-07-16 17:03:20 -0400202// ===================================== APerformanceHintManager implementation
Matt Buckley854947f2024-02-07 17:30:01 +0000203APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
Bo Liu44267722021-07-16 17:03:20 -0400204 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000205 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
206 static AIBinder_Class* tokenBinderClass =
207 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
208 tokenStubOnTransact);
209 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
Matt Buckley854947f2024-02-07 17:30:01 +0000210 if (mFMQWrapper.isSupported()) {
211 mFMQWrapper.setToken(mToken);
212 mFMQWrapper.startChannel(mHintManager.get());
213 }
214}
215
216APerformanceHintManager::~APerformanceHintManager() {
217 mFMQWrapper.stopChannel(mHintManager.get());
Matt Buckley58977722024-03-11 23:32:09 +0000218}
Bo Liu44267722021-07-16 17:03:20 -0400219
220APerformanceHintManager* APerformanceHintManager::getInstance() {
Matt Buckley854947f2024-02-07 17:30:01 +0000221 if (gHintManagerForTesting) {
222 return gHintManagerForTesting.get();
223 }
Bo Liu44267722021-07-16 17:03:20 -0400224 if (gIHintManagerForTesting) {
Matt Buckley854947f2024-02-07 17:30:01 +0000225 gHintManagerForTesting =
226 std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
227 return gHintManagerForTesting.get();
Bo Liu44267722021-07-16 17:03:20 -0400228 }
229 static APerformanceHintManager* instance = create(nullptr);
230 return instance;
231}
232
Matt Buckley58977722024-03-11 23:32:09 +0000233APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400234 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000235 manager = IHintManager::fromBinder(
236 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400237 }
238 if (manager == nullptr) {
239 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
240 return nullptr;
241 }
242 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000243 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400244 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000245 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400246 return nullptr;
247 }
248 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400249 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400250 }
Matt Buckley854947f2024-02-07 17:30:01 +0000251 return new APerformanceHintManager(manager, preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400252}
253
254APerformanceHintSession* APerformanceHintManager::createSession(
Matt Buckleye073c732024-04-05 22:32:31 +0000255 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
256 hal::SessionTag tag) {
Bo Liu44267722021-07-16 17:03:20 -0400257 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000258 std::shared_ptr<IHintSession> session;
Matt Buckleye073c732024-04-05 22:32:31 +0000259 ndk::ScopedAStatus ret;
Matt Buckley854947f2024-02-07 17:30:01 +0000260 hal::SessionConfig sessionConfig{.id = -1};
Matt Buckleye073c732024-04-05 22:32:31 +0000261 ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
262 tag, &sessionConfig, &session);
263
Bo Liu44267722021-07-16 17:03:20 -0400264 if (!ret.isOk() || !session) {
Matt Buckley854947f2024-02-07 17:30:01 +0000265 ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400266 return nullptr;
267 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000268 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Matt Buckley854947f2024-02-07 17:30:01 +0000269 initialTargetWorkDurationNanos,
270 sessionConfig.id == -1
271 ? std::nullopt
272 : std::make_optional<hal::SessionConfig>(
273 std::move(sessionConfig)));
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000274 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000275 out->traceThreads(tids);
276 out->traceTargetDuration(initialTargetWorkDurationNanos);
277 out->tracePowerEfficient(false);
278 return out;
Bo Liu44267722021-07-16 17:03:20 -0400279}
280
281int64_t APerformanceHintManager::getPreferredRateNanos() const {
282 return mPreferredRateNanos;
283}
284
Matt Buckley854947f2024-02-07 17:30:01 +0000285FMQWrapper& APerformanceHintManager::getFMQWrapper() {
286 return mFMQWrapper;
287}
288
Bo Liu44267722021-07-16 17:03:20 -0400289// ===================================== APerformanceHintSession implementation
290
Matt Buckley854947f2024-02-07 17:30:01 +0000291constexpr int kNumEnums =
292 ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
293
Matt Buckley58977722024-03-11 23:32:09 +0000294APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
295 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400296 int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000297 int64_t targetDurationNanos,
298 std::optional<hal::SessionConfig> sessionConfig)
Peiyong Lin095de762022-11-11 18:28:12 +0000299 : mHintManager(hintManager),
300 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400301 mPreferredRateNanos(preferredRateNanos),
302 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700303 mFirstTargetMetTimestamp(0),
Matt Buckleye073c732024-04-05 22:32:31 +0000304 mLastTargetMetTimestamp(0),
Matt Buckley854947f2024-02-07 17:30:01 +0000305 mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
Matt Buckleye073c732024-04-05 22:32:31 +0000306 mSessionConfig(sessionConfig) {
307 if (sessionConfig->id > INT32_MAX) {
308 ALOGE("Session ID too large, must fit 32-bit integer");
309 }
Matt Buckleye073c732024-04-05 22:32:31 +0000310 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
311 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
Matt Buckley56093a72022-11-07 21:50:50 +0000312}
Bo Liu44267722021-07-16 17:03:20 -0400313
314APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000315 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400316 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000317 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400318 }
319}
320
321int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
322 if (targetDurationNanos <= 0) {
323 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
324 return EINVAL;
325 }
Matt Buckley854947f2024-02-07 17:30:01 +0000326 std::scoped_lock lock(sHintMutex);
327 if (mTargetDurationNanos == targetDurationNanos) {
328 return 0;
329 }
330 if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
331 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
332 if (!ret.isOk()) {
333 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
334 ret.getMessage());
335 return EPIPE;
Xiang Wange16ad282024-06-26 14:31:34 -0700336 }
337 }
Bo Liu44267722021-07-16 17:03:20 -0400338 mTargetDurationNanos = targetDurationNanos;
339 /**
340 * Most of the workload is target_duration dependent, so now clear the cached samples
341 * as they are most likely obsolete.
342 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000343 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000344 traceBatchSize(0);
345 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700346 mFirstTargetMetTimestamp = 0;
347 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400348 return 0;
349}
350
351int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000352 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
353 .workPeriodStartTimestampNanos = 0,
354 .cpuDurationNanos = actualDurationNanos,
355 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400356
Matt Buckley58977722024-03-11 23:32:09 +0000357 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400358}
359
Steven Moreland42a8cce2023-03-03 23:31:17 +0000360int APerformanceHintSession::sendHint(SessionHint hint) {
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000361 std::scoped_lock lock(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000362 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
363 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000364 return EINVAL;
365 }
Matt Buckley58977722024-03-11 23:32:09 +0000366 int64_t now = uptimeNanos();
Matt Buckley56093a72022-11-07 21:50:50 +0000367
368 // Limit sendHint to a pre-detemined rate for safety
369 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
370 return 0;
371 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000372
Matt Buckley854947f2024-02-07 17:30:01 +0000373 if (!getFMQ().sendHint(mSessionConfig, hint)) {
374 ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000375
Matt Buckley854947f2024-02-07 17:30:01 +0000376 if (!ret.isOk()) {
377 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
378 return EPIPE;
379 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000380 }
Matt Buckley56093a72022-11-07 21:50:50 +0000381 mLastHintSentTimestamp[hint] = now;
Matt Buckley354cc0a2022-09-28 20:54:46 +0000382 return 0;
383}
384
Peiyong Lin095de762022-11-11 18:28:12 +0000385int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
386 if (size == 0) {
387 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
388 return EINVAL;
389 }
390 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000391 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000392 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000393 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
394 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000395 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000396 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700397 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000398 }
399 return EPIPE;
400 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000401
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000402 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000403 traceThreads(tids);
404
Peiyong Lin095de762022-11-11 18:28:12 +0000405 return 0;
406}
407
408int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
409 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000410 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000411 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000412 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000413 return EPIPE;
414 }
415
416 // When threadIds is nullptr, this is the first call to determine the size
417 // of the thread ids list.
418 if (threadIds == nullptr) {
419 *size = tids.size();
420 return 0;
421 }
422
423 // Second call to return the actual list of thread ids.
424 *size = tids.size();
425 for (size_t i = 0; i < *size; ++i) {
426 threadIds[i] = tids[i];
427 }
428 return 0;
429}
430
Matt Buckley423c1b32023-06-28 19:13:42 +0000431int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000432 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000433 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
434 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000435
436 if (!ret.isOk()) {
437 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000438 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000439 return EPIPE;
440 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000441 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000442 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000443 return OK;
444}
445
Matt Buckley58977722024-03-11 23:32:09 +0000446int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000447 return reportActualWorkDurationInternal(workDuration);
448}
449
Matt Buckley58977722024-03-11 23:32:09 +0000450int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
451 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000452 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000453 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000454 workDuration->timeStampNanos = now;
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000455 std::scoped_lock lock(sHintMutex);
Peiyong Lin70de0852023-10-25 21:12:35 +0000456 mActualWorkDurations.push_back(std::move(*workDuration));
457
458 if (actualTotalDurationNanos >= mTargetDurationNanos) {
459 // Reset timestamps if we are equal or over the target.
460 mFirstTargetMetTimestamp = 0;
461 } else {
462 // Set mFirstTargetMetTimestamp for first time meeting target.
463 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
464 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
465 mFirstTargetMetTimestamp = now;
466 }
467 /**
468 * Rate limit the change if the update is over mPreferredRateNanos since first
469 * meeting target and less than mPreferredRateNanos since last meeting target.
470 */
471 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
472 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000473 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000474 return 0;
475 }
476 mLastTargetMetTimestamp = now;
477 }
478
Matt Buckley854947f2024-02-07 17:30:01 +0000479 if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
480 mActualWorkDurations.size())) {
481 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
482 if (!ret.isOk()) {
483 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
484 ret.getMessage());
485 mFirstTargetMetTimestamp = 0;
486 mLastTargetMetTimestamp = 0;
487 traceBatchSize(mActualWorkDurations.size());
488 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
489 }
Peiyong Lin70de0852023-10-25 21:12:35 +0000490 }
Matt Buckley854947f2024-02-07 17:30:01 +0000491
Peiyong Lin70de0852023-10-25 21:12:35 +0000492 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000493 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000494
495 return 0;
496}
Matt Buckley854947f2024-02-07 17:30:01 +0000497
498// ===================================== FMQ wrapper implementation
499
500bool FMQWrapper::isActive() {
501 std::scoped_lock lock{sHintMutex};
502 return isActiveLocked();
503}
504
505bool FMQWrapper::isActiveLocked() {
506 return mQueue != nullptr;
507}
508
509void FMQWrapper::setUnsupported() {
510 mHalSupported = false;
511}
512
513bool FMQWrapper::isSupported() {
514 if (!mHalSupported) {
515 return false;
516 }
517 // Used for testing
518 if (gForceFMQEnabled.has_value()) {
519 return *gForceFMQEnabled;
520 }
521 return android::os::adpf_use_fmq_channel_fixed();
522}
523
524bool FMQWrapper::startChannel(IHintManager* manager) {
525 if (isSupported() && !isActive()) {
526 std::optional<hal::ChannelConfig> config;
527 auto ret = manager->getSessionChannel(mToken, &config);
528 if (ret.isOk() && config.has_value()) {
529 std::scoped_lock lock{sHintMutex};
530 mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
531 if (config->eventFlagDescriptor.has_value()) {
532 mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
533 android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
534 &mEventFlag);
535 mWriteMask = config->writeFlagBitmask;
536 }
537 updatePersistentTransaction();
538 } else if (ret.isOk() && !config.has_value()) {
539 ALOGV("FMQ channel enabled but unsupported.");
540 setUnsupported();
541 } else {
542 ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
543 }
544 }
545 return isActive();
546}
547
548void FMQWrapper::stopChannel(IHintManager* manager) {
549 {
550 std::scoped_lock lock{sHintMutex};
551 if (!isActiveLocked()) {
552 return;
553 }
554 mFlagQueue = nullptr;
555 mQueue = nullptr;
556 }
557 manager->closeSessionChannel();
558}
559
560template <HalChannelMessageContents::Tag T, class C>
561void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) {
562 new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{
563 .sessionID = static_cast<int32_t>(config.id),
564 .timeStampNanos = ::android::uptimeNanos(),
565 .data = HalChannelMessageContents::make<T, C>(std::move(*message)),
566 };
567}
568
569template <>
570void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
571 hal::SessionConfig& config,
572 size_t count) {
573 for (size_t i = 0; i < count; ++i) {
574 hal::WorkDuration& message = messages[i];
575 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
576 .sessionID = static_cast<int32_t>(config.id),
577 .timeStampNanos =
578 (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos,
579 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
580 hal::WorkDurationFixedV1>({
581 .durationNanos = message.cpuDurationNanos,
582 .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
583 .cpuDurationNanos = message.cpuDurationNanos,
584 .gpuDurationNanos = message.gpuDurationNanos,
585 }),
586 };
587 }
588}
589
590template <HalChannelMessageContents::Tag T, bool urgent, class C>
591bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) {
592 if (!isActiveLocked() || !config.has_value() || mCorrupted) {
593 return false;
594 }
595 // If we didn't reserve enough space, try re-creating the transaction
596 if (count > mAvailableSlots) {
597 if (!updatePersistentTransaction()) {
598 return false;
599 }
600 // If we actually don't have enough space, give up
601 if (count > mAvailableSlots) {
602 return false;
603 }
604 }
605 writeBuffer<T, C>(message, *config, count);
606 mQueue->commitWrite(count);
607 mEventFlag->wake(mWriteMask);
608 // Re-create the persistent transaction after writing
609 updatePersistentTransaction();
610 return true;
611}
612
613void FMQWrapper::setToken(ndk::SpAIBinder& token) {
614 mToken = token;
615}
616
617bool FMQWrapper::updatePersistentTransaction() {
618 mAvailableSlots = mQueue->availableToWrite();
619 if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
620 ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
621 mCorrupted = true;
622 return false;
623 }
624 return true;
625}
626
627bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
628 hal::WorkDuration* durations, size_t count) {
629 return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
630}
631
632bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
633 int64_t targetDurationNanos) {
634 return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
635}
636
637bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) {
638 return sendMessages<HalChannelMessageContents::hint>(config,
639 reinterpret_cast<hal::SessionHint*>(
640 &hint));
641}
642
643bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
644 bool enabled) {
645 hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
646 .enabled = enabled};
647 return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
648}
649
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000650// ===================================== Tracing helpers
651
652void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
653 std::set<int32_t> tidSet{tids.begin(), tids.end()};
654
655 // Disable old TID tracing
656 for (int32_t tid : mLastThreadIDs) {
657 if (!tidSet.count(tid)) {
658 std::string traceName =
659 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
660 ATrace_setCounter(traceName.c_str(), 0);
661 }
662 }
663
664 // Add new TID tracing
665 for (int32_t tid : tids) {
666 std::string traceName =
667 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
668 ATrace_setCounter(traceName.c_str(), 1);
669 }
670
671 mLastThreadIDs = std::move(tids);
672}
673
674void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
675 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
676}
677
678void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
679 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
680}
681
682void APerformanceHintSession::traceBatchSize(size_t batchSize) {
683 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
684 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
685}
686
687void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
688 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
689}
Peiyong Lin70de0852023-10-25 21:12:35 +0000690
Bo Liu44267722021-07-16 17:03:20 -0400691// ===================================== C API
692APerformanceHintManager* APerformanceHint_getManager() {
693 return APerformanceHintManager::getInstance();
694}
695
Matt Buckley83f77092024-01-18 19:57:29 +0000696#define VALIDATE_PTR(ptr) \
697 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
698
699#define VALIDATE_INT(value, cmp) \
700 if (!(value cmp)) { \
701 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
702 __FUNCTION__, value); \
703 return EINVAL; \
704 }
705
706#define WARN_INT(value, cmp) \
707 if (!(value cmp)) { \
708 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
709 __FUNCTION__, value); \
710 }
711
Bo Liu44267722021-07-16 17:03:20 -0400712APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
713 const int32_t* threadIds, size_t size,
714 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000715 VALIDATE_PTR(manager)
716 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400717 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
718}
719
Matt Buckley27da1342024-04-05 23:10:48 +0000720APerformanceHintSession* APerformanceHint_createSessionInternal(
721 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
722 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
723 VALIDATE_PTR(manager)
724 VALIDATE_PTR(threadIds)
725 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
726 static_cast<hal::SessionTag>(tag));
727}
728
Bo Liu44267722021-07-16 17:03:20 -0400729int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000730 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400731 return manager->getPreferredRateNanos();
732}
733
734int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
735 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000736 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400737 return session->updateTargetWorkDuration(targetDurationNanos);
738}
739
740int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
741 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000742 VALIDATE_PTR(session)
743 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400744 return session->reportActualWorkDuration(actualDurationNanos);
745}
746
Bo Liu44267722021-07-16 17:03:20 -0400747void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000748 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400749 delete session;
750}
751
Matt Buckley27da1342024-04-05 23:10:48 +0000752int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000753 VALIDATE_PTR(session)
Matt Buckley27da1342024-04-05 23:10:48 +0000754 return session->sendHint(hint);
Matt Buckley61726a32022-12-06 23:44:45 +0000755}
756
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000757int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000758 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000759 VALIDATE_PTR(session)
760 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000761 return session->setThreads(threadIds, size);
762}
763
Matt Buckley27da1342024-04-05 23:10:48 +0000764int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000765 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +0000766 VALIDATE_PTR(session)
767 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +0000768}
769
Matt Buckley423c1b32023-06-28 19:13:42 +0000770int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000771 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000772 return session->setPreferPowerEfficiency(enabled);
773}
774
Peiyong Lin70de0852023-10-25 21:12:35 +0000775int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000776 AWorkDuration* workDurationPtr) {
777 VALIDATE_PTR(session)
778 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000779 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
780 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
781 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
782 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
783 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000784 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000785}
786
787AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000788 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000789}
790
791void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000792 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000793 delete aWorkDuration;
794}
795
Peiyong Lin70de0852023-10-25 21:12:35 +0000796void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
797 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000798 VALIDATE_PTR(aWorkDuration)
799 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000800 aWorkDuration->durationNanos = actualTotalDurationNanos;
801}
802
803void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
804 int64_t workPeriodStartTimestampNanos) {
805 VALIDATE_PTR(aWorkDuration)
806 WARN_INT(workPeriodStartTimestampNanos, > 0)
807 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000808}
809
810void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
811 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000812 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000813 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000814 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000815}
816
817void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
818 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000819 VALIDATE_PTR(aWorkDuration)
820 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000821 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000822}
823
Bo Liu44267722021-07-16 17:03:20 -0400824void APerformanceHint_setIHintManagerForTesting(void* iManager) {
Matt Buckley854947f2024-02-07 17:30:01 +0000825 if (iManager == nullptr) {
826 gHintManagerForTesting = nullptr;
827 }
Matt Buckley58977722024-03-11 23:32:09 +0000828 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400829}
Matt Buckley854947f2024-02-07 17:30:01 +0000830
831void APerformanceHint_setUseFMQForTesting(bool enabled) {
832 gForceFMQEnabled = enabled;
833}