blob: 15f77cebf3ba7d8dafeac5aacf8360efed4bb1dc [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 Buckley7aac2582024-10-18 11:22:12 -070042#include <future>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000043#include <set>
Bo Liu2b739bb2021-11-10 19:20:03 -050044#include <utility>
45#include <vector>
46
Bo Liu44267722021-07-16 17:03:20 -040047using namespace android;
Matt Buckley58977722024-03-11 23:32:09 +000048using namespace aidl::android::os;
Bo Liu44267722021-07-16 17:03:20 -040049
Matt Buckley56093a72022-11-07 21:50:50 +000050using namespace std::chrono_literals;
51
Matt Buckley7c2de582024-04-05 08:41:35 +000052// Namespace for AIDL types coming from the PowerHAL
53namespace hal = aidl::android::hardware::power;
Matt Buckley58977722024-03-11 23:32:09 +000054
Matt Buckley854947f2024-02-07 17:30:01 +000055using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
56using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
57using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
58using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000059using android::base::StringPrintf;
Matt Buckley56093a72022-11-07 21:50:50 +000060
Bo Liu44267722021-07-16 17:03:20 -040061struct APerformanceHintSession;
62
Matt Buckley56093a72022-11-07 21:50:50 +000063constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
Matt Buckley7c2de582024-04-05 08:41:35 +000064struct AWorkDuration : public hal::WorkDuration {};
Matt Buckley56093a72022-11-07 21:50:50 +000065
Matt Buckley1f5b95f2024-06-07 02:36:56 +000066// Shared lock for the whole PerformanceHintManager and sessions
67static std::mutex sHintMutex = std::mutex{};
Matt Buckley854947f2024-02-07 17:30:01 +000068class FMQWrapper {
69public:
70 bool isActive();
71 bool isSupported();
72 bool startChannel(IHintManager* manager);
73 void stopChannel(IHintManager* manager);
74 // Number of elements the FMQ can hold
75 bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
76 hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
77 bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
78 int64_t targetDurationNanos) REQUIRES(sHintMutex);
79 bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex);
80 bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
81 REQUIRES(sHintMutex);
82 void setToken(ndk::SpAIBinder& token);
83 void attemptWake();
84 void setUnsupported();
85
86private:
87 template <HalChannelMessageContents::Tag T, bool urgent = false,
88 class C = HalChannelMessageContents::_at<T>>
89 bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1)
90 REQUIRES(sHintMutex);
91 template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
92 void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex);
93
94 bool isActiveLocked() REQUIRES(sHintMutex);
95 bool updatePersistentTransaction() REQUIRES(sHintMutex);
96 std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
97 std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
98 // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
99 android::hardware::EventFlag* mEventFlag = nullptr;
100 int32_t mWriteMask;
101 ndk::SpAIBinder mToken = nullptr;
102 // Used to track if operating on the fmq consistently fails
103 bool mCorrupted = false;
104 // Used to keep a persistent transaction open with FMQ to reduce latency a bit
105 size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
106 bool mHalSupported = true;
107 HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
Matt Buckley7aac2582024-10-18 11:22:12 -0700108 std::future<bool> mChannelCreationFinished;
Matt Buckley854947f2024-02-07 17:30:01 +0000109};
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000110
Bo Liu44267722021-07-16 17:03:20 -0400111struct APerformanceHintManager {
112public:
113 static APerformanceHintManager* getInstance();
Matt Buckley854947f2024-02-07 17:30:01 +0000114 APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400115 APerformanceHintManager() = delete;
Matt Buckley854947f2024-02-07 17:30:01 +0000116 ~APerformanceHintManager();
Bo Liu44267722021-07-16 17:03:20 -0400117
118 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
Matt Buckleye073c732024-04-05 22:32:31 +0000119 int64_t initialTargetWorkDurationNanos,
Matt Buckley31974132024-05-21 19:54:39 +0000120 hal::SessionTag tag = hal::SessionTag::APP);
Bo Liu44267722021-07-16 17:03:20 -0400121 int64_t getPreferredRateNanos() const;
Matt Buckley854947f2024-02-07 17:30:01 +0000122 FMQWrapper& getFMQWrapper();
Bo Liu44267722021-07-16 17:03:20 -0400123
124private:
Matt Buckley58977722024-03-11 23:32:09 +0000125 // Necessary to create an empty binder object
126 static void* tokenStubOnCreate(void*) {
127 return nullptr;
128 }
129 static void tokenStubOnDestroy(void*) {}
130 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
131 AParcel*) {
132 return STATUS_OK;
133 }
Bo Liu44267722021-07-16 17:03:20 -0400134
Matt Buckley58977722024-03-11 23:32:09 +0000135 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
136
137 std::shared_ptr<IHintManager> mHintManager;
138 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -0400139 const int64_t mPreferredRateNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000140 FMQWrapper mFMQWrapper;
Bo Liu44267722021-07-16 17:03:20 -0400141};
142
143struct APerformanceHintSession {
144public:
Matt Buckley58977722024-03-11 23:32:09 +0000145 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
146 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000147 int64_t targetDurationNanos,
148 std::optional<hal::SessionConfig> sessionConfig);
Bo Liu44267722021-07-16 17:03:20 -0400149 APerformanceHintSession() = delete;
150 ~APerformanceHintSession();
151
152 int updateTargetWorkDuration(int64_t targetDurationNanos);
153 int reportActualWorkDuration(int64_t actualDurationNanos);
Steven Moreland42a8cce2023-03-03 23:31:17 +0000154 int sendHint(SessionHint hint);
Peiyong Lin095de762022-11-11 18:28:12 +0000155 int setThreads(const int32_t* threadIds, size_t size);
156 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +0000157 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +0000158 int reportActualWorkDuration(AWorkDuration* workDuration);
Bo Liu44267722021-07-16 17:03:20 -0400159
160private:
161 friend struct APerformanceHintManager;
162
Matt Buckley58977722024-03-11 23:32:09 +0000163 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000164
Matt Buckley58977722024-03-11 23:32:09 +0000165 std::shared_ptr<IHintManager> mHintManager;
166 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400167 // HAL preferred update rate
168 const int64_t mPreferredRateNanos;
169 // Target duration for choosing update rate
Matt Buckley053a1df2024-06-07 02:37:59 +0000170 int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700171 // First target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000172 int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700173 // Last target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000174 int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000175 // Last hint reported from sendHint indexed by hint value
Matt Buckley053a1df2024-06-07 02:37:59 +0000176 std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400177 // Cached samples
Matt Buckley053a1df2024-06-07 02:37:59 +0000178 std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000179 std::string mSessionName;
Matt Buckley053a1df2024-06-07 02:37:59 +0000180 static int64_t sIDCounter GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000181 // The most recent set of thread IDs
Matt Buckley053a1df2024-06-07 02:37:59 +0000182 std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
183 std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000184 // Tracing helpers
Matt Buckley053a1df2024-06-07 02:37:59 +0000185 void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000186 void tracePowerEfficient(bool powerEfficient);
187 void traceActualDuration(int64_t actualDuration);
188 void traceBatchSize(size_t batchSize);
189 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400190};
191
Matt Buckley58977722024-03-11 23:32:09 +0000192static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000193static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
194
195static std::optional<bool> gForceFMQEnabled = std::nullopt;
196
Matt Buckleye073c732024-04-05 22:32:31 +0000197// Start above the int32 range so we don't collide with config sessions
198int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
Bo Liu44267722021-07-16 17:03:20 -0400199
Matt Buckley854947f2024-02-07 17:30:01 +0000200static FMQWrapper& getFMQ() {
201 return APerformanceHintManager::getInstance()->getFMQWrapper();
202}
203
Bo Liu44267722021-07-16 17:03:20 -0400204// ===================================== APerformanceHintManager implementation
Matt Buckley854947f2024-02-07 17:30:01 +0000205APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
Bo Liu44267722021-07-16 17:03:20 -0400206 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000207 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
208 static AIBinder_Class* tokenBinderClass =
209 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
210 tokenStubOnTransact);
211 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
Matt Buckley854947f2024-02-07 17:30:01 +0000212 if (mFMQWrapper.isSupported()) {
213 mFMQWrapper.setToken(mToken);
214 mFMQWrapper.startChannel(mHintManager.get());
215 }
216}
217
218APerformanceHintManager::~APerformanceHintManager() {
219 mFMQWrapper.stopChannel(mHintManager.get());
Matt Buckley58977722024-03-11 23:32:09 +0000220}
Bo Liu44267722021-07-16 17:03:20 -0400221
222APerformanceHintManager* APerformanceHintManager::getInstance() {
Matt Buckley7aac2582024-10-18 11:22:12 -0700223 static std::once_flag creationFlag;
224 static APerformanceHintManager* instance = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000225 if (gHintManagerForTesting) {
226 return gHintManagerForTesting.get();
227 }
Bo Liu44267722021-07-16 17:03:20 -0400228 if (gIHintManagerForTesting) {
Matt Buckley854947f2024-02-07 17:30:01 +0000229 gHintManagerForTesting =
230 std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
231 return gHintManagerForTesting.get();
Bo Liu44267722021-07-16 17:03:20 -0400232 }
Matt Buckley7aac2582024-10-18 11:22:12 -0700233 std::call_once(creationFlag, []() { instance = create(nullptr); });
Bo Liu44267722021-07-16 17:03:20 -0400234 return instance;
235}
236
Matt Buckley58977722024-03-11 23:32:09 +0000237APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400238 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000239 manager = IHintManager::fromBinder(
240 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400241 }
242 if (manager == nullptr) {
243 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
244 return nullptr;
245 }
246 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000247 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400248 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000249 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400250 return nullptr;
251 }
252 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400253 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400254 }
Matt Buckley854947f2024-02-07 17:30:01 +0000255 return new APerformanceHintManager(manager, preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400256}
257
258APerformanceHintSession* APerformanceHintManager::createSession(
Matt Buckleye073c732024-04-05 22:32:31 +0000259 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
260 hal::SessionTag tag) {
Bo Liu44267722021-07-16 17:03:20 -0400261 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000262 std::shared_ptr<IHintSession> session;
Matt Buckleye073c732024-04-05 22:32:31 +0000263 ndk::ScopedAStatus ret;
Matt Buckley854947f2024-02-07 17:30:01 +0000264 hal::SessionConfig sessionConfig{.id = -1};
Matt Buckleye073c732024-04-05 22:32:31 +0000265 ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
266 tag, &sessionConfig, &session);
267
Bo Liu44267722021-07-16 17:03:20 -0400268 if (!ret.isOk() || !session) {
Matt Buckley854947f2024-02-07 17:30:01 +0000269 ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400270 return nullptr;
271 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000272 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Matt Buckley854947f2024-02-07 17:30:01 +0000273 initialTargetWorkDurationNanos,
274 sessionConfig.id == -1
275 ? std::nullopt
276 : std::make_optional<hal::SessionConfig>(
277 std::move(sessionConfig)));
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000278 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000279 out->traceThreads(tids);
280 out->traceTargetDuration(initialTargetWorkDurationNanos);
281 out->tracePowerEfficient(false);
282 return out;
Bo Liu44267722021-07-16 17:03:20 -0400283}
284
285int64_t APerformanceHintManager::getPreferredRateNanos() const {
286 return mPreferredRateNanos;
287}
288
Matt Buckley854947f2024-02-07 17:30:01 +0000289FMQWrapper& APerformanceHintManager::getFMQWrapper() {
290 return mFMQWrapper;
291}
292
Bo Liu44267722021-07-16 17:03:20 -0400293// ===================================== APerformanceHintSession implementation
294
Matt Buckley854947f2024-02-07 17:30:01 +0000295constexpr int kNumEnums =
296 ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
297
Matt Buckley58977722024-03-11 23:32:09 +0000298APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
299 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400300 int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000301 int64_t targetDurationNanos,
302 std::optional<hal::SessionConfig> sessionConfig)
Peiyong Lin095de762022-11-11 18:28:12 +0000303 : mHintManager(hintManager),
304 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400305 mPreferredRateNanos(preferredRateNanos),
306 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700307 mFirstTargetMetTimestamp(0),
Matt Buckleye073c732024-04-05 22:32:31 +0000308 mLastTargetMetTimestamp(0),
Matt Buckley854947f2024-02-07 17:30:01 +0000309 mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
Matt Buckleye073c732024-04-05 22:32:31 +0000310 mSessionConfig(sessionConfig) {
311 if (sessionConfig->id > INT32_MAX) {
312 ALOGE("Session ID too large, must fit 32-bit integer");
313 }
Matt Buckleye073c732024-04-05 22:32:31 +0000314 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
315 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
Matt Buckley56093a72022-11-07 21:50:50 +0000316}
Bo Liu44267722021-07-16 17:03:20 -0400317
318APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000319 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400320 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000321 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400322 }
323}
324
325int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
326 if (targetDurationNanos <= 0) {
327 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
328 return EINVAL;
329 }
Matt Buckley854947f2024-02-07 17:30:01 +0000330 std::scoped_lock lock(sHintMutex);
331 if (mTargetDurationNanos == targetDurationNanos) {
332 return 0;
333 }
334 if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
335 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
336 if (!ret.isOk()) {
337 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
338 ret.getMessage());
339 return EPIPE;
Xiang Wange16ad282024-06-26 14:31:34 -0700340 }
341 }
Bo Liu44267722021-07-16 17:03:20 -0400342 mTargetDurationNanos = targetDurationNanos;
343 /**
344 * Most of the workload is target_duration dependent, so now clear the cached samples
345 * as they are most likely obsolete.
346 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000347 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000348 traceBatchSize(0);
349 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700350 mFirstTargetMetTimestamp = 0;
351 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400352 return 0;
353}
354
355int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000356 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
357 .workPeriodStartTimestampNanos = 0,
358 .cpuDurationNanos = actualDurationNanos,
359 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400360
Matt Buckley58977722024-03-11 23:32:09 +0000361 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400362}
363
Steven Moreland42a8cce2023-03-03 23:31:17 +0000364int APerformanceHintSession::sendHint(SessionHint hint) {
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000365 std::scoped_lock lock(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000366 if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
367 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000368 return EINVAL;
369 }
Matt Buckley58977722024-03-11 23:32:09 +0000370 int64_t now = uptimeNanos();
Matt Buckley56093a72022-11-07 21:50:50 +0000371
372 // Limit sendHint to a pre-detemined rate for safety
373 if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
374 return 0;
375 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000376
Matt Buckley854947f2024-02-07 17:30:01 +0000377 if (!getFMQ().sendHint(mSessionConfig, hint)) {
378 ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
Matt Buckley354cc0a2022-09-28 20:54:46 +0000379
Matt Buckley854947f2024-02-07 17:30:01 +0000380 if (!ret.isOk()) {
381 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
382 return EPIPE;
383 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000384 }
Matt Buckley56093a72022-11-07 21:50:50 +0000385 mLastHintSentTimestamp[hint] = now;
Matt Buckley354cc0a2022-09-28 20:54:46 +0000386 return 0;
387}
388
Peiyong Lin095de762022-11-11 18:28:12 +0000389int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
390 if (size == 0) {
391 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
392 return EINVAL;
393 }
394 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000395 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000396 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000397 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
398 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000399 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000400 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700401 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000402 }
403 return EPIPE;
404 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000405
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000406 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000407 traceThreads(tids);
408
Peiyong Lin095de762022-11-11 18:28:12 +0000409 return 0;
410}
411
412int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
413 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000414 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000415 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000416 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000417 return EPIPE;
418 }
419
420 // When threadIds is nullptr, this is the first call to determine the size
421 // of the thread ids list.
422 if (threadIds == nullptr) {
423 *size = tids.size();
424 return 0;
425 }
426
427 // Second call to return the actual list of thread ids.
428 *size = tids.size();
429 for (size_t i = 0; i < *size; ++i) {
430 threadIds[i] = tids[i];
431 }
432 return 0;
433}
434
Matt Buckley423c1b32023-06-28 19:13:42 +0000435int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000436 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000437 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
438 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000439
440 if (!ret.isOk()) {
441 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000442 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000443 return EPIPE;
444 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000445 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000446 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000447 return OK;
448}
449
Matt Buckley58977722024-03-11 23:32:09 +0000450int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000451 return reportActualWorkDurationInternal(workDuration);
452}
453
Matt Buckley58977722024-03-11 23:32:09 +0000454int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
455 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000456 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000457 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000458 workDuration->timeStampNanos = now;
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000459 std::scoped_lock lock(sHintMutex);
Peiyong Lin70de0852023-10-25 21:12:35 +0000460 mActualWorkDurations.push_back(std::move(*workDuration));
461
462 if (actualTotalDurationNanos >= mTargetDurationNanos) {
463 // Reset timestamps if we are equal or over the target.
464 mFirstTargetMetTimestamp = 0;
465 } else {
466 // Set mFirstTargetMetTimestamp for first time meeting target.
467 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
468 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
469 mFirstTargetMetTimestamp = now;
470 }
471 /**
472 * Rate limit the change if the update is over mPreferredRateNanos since first
473 * meeting target and less than mPreferredRateNanos since last meeting target.
474 */
475 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
476 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000477 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000478 return 0;
479 }
480 mLastTargetMetTimestamp = now;
481 }
482
Matt Buckley854947f2024-02-07 17:30:01 +0000483 if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
484 mActualWorkDurations.size())) {
485 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
486 if (!ret.isOk()) {
487 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
488 ret.getMessage());
489 mFirstTargetMetTimestamp = 0;
490 mLastTargetMetTimestamp = 0;
491 traceBatchSize(mActualWorkDurations.size());
492 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
493 }
Peiyong Lin70de0852023-10-25 21:12:35 +0000494 }
Matt Buckley854947f2024-02-07 17:30:01 +0000495
Peiyong Lin70de0852023-10-25 21:12:35 +0000496 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000497 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000498
499 return 0;
500}
Matt Buckley854947f2024-02-07 17:30:01 +0000501
502// ===================================== FMQ wrapper implementation
503
504bool FMQWrapper::isActive() {
505 std::scoped_lock lock{sHintMutex};
506 return isActiveLocked();
507}
508
509bool FMQWrapper::isActiveLocked() {
510 return mQueue != nullptr;
511}
512
513void FMQWrapper::setUnsupported() {
514 mHalSupported = false;
515}
516
517bool FMQWrapper::isSupported() {
518 if (!mHalSupported) {
519 return false;
520 }
521 // Used for testing
522 if (gForceFMQEnabled.has_value()) {
523 return *gForceFMQEnabled;
524 }
525 return android::os::adpf_use_fmq_channel_fixed();
526}
527
528bool FMQWrapper::startChannel(IHintManager* manager) {
Matt Buckley7aac2582024-10-18 11:22:12 -0700529 if (isSupported() && !isActive() && manager->isRemote()) {
530 mChannelCreationFinished = std::async(std::launch::async, [&, this, manager]() {
531 std::optional<hal::ChannelConfig> config;
532 auto ret = manager->getSessionChannel(mToken, &config);
533 if (ret.isOk() && config.has_value()) {
534 std::scoped_lock lock{sHintMutex};
535 mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
536 if (config->eventFlagDescriptor.has_value()) {
537 mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
538 android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
539 &mEventFlag);
540 mWriteMask = config->writeFlagBitmask;
541 }
542 updatePersistentTransaction();
543 } else if (ret.isOk() && !config.has_value()) {
544 ALOGV("FMQ channel enabled but unsupported.");
545 setUnsupported();
546 } else {
547 ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley854947f2024-02-07 17:30:01 +0000548 }
Matt Buckley7aac2582024-10-18 11:22:12 -0700549 return true;
550 });
Matt Buckley854947f2024-02-07 17:30:01 +0000551 }
552 return isActive();
553}
554
555void FMQWrapper::stopChannel(IHintManager* manager) {
556 {
557 std::scoped_lock lock{sHintMutex};
558 if (!isActiveLocked()) {
559 return;
560 }
561 mFlagQueue = nullptr;
562 mQueue = nullptr;
563 }
564 manager->closeSessionChannel();
565}
566
567template <HalChannelMessageContents::Tag T, class C>
568void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) {
569 new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{
570 .sessionID = static_cast<int32_t>(config.id),
571 .timeStampNanos = ::android::uptimeNanos(),
572 .data = HalChannelMessageContents::make<T, C>(std::move(*message)),
573 };
574}
575
576template <>
577void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
578 hal::SessionConfig& config,
579 size_t count) {
580 for (size_t i = 0; i < count; ++i) {
581 hal::WorkDuration& message = messages[i];
582 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
583 .sessionID = static_cast<int32_t>(config.id),
584 .timeStampNanos =
585 (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos,
586 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
587 hal::WorkDurationFixedV1>({
588 .durationNanos = message.cpuDurationNanos,
589 .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
590 .cpuDurationNanos = message.cpuDurationNanos,
591 .gpuDurationNanos = message.gpuDurationNanos,
592 }),
593 };
594 }
595}
596
597template <HalChannelMessageContents::Tag T, bool urgent, class C>
598bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) {
599 if (!isActiveLocked() || !config.has_value() || mCorrupted) {
600 return false;
601 }
602 // If we didn't reserve enough space, try re-creating the transaction
603 if (count > mAvailableSlots) {
604 if (!updatePersistentTransaction()) {
605 return false;
606 }
607 // If we actually don't have enough space, give up
608 if (count > mAvailableSlots) {
609 return false;
610 }
611 }
612 writeBuffer<T, C>(message, *config, count);
613 mQueue->commitWrite(count);
614 mEventFlag->wake(mWriteMask);
615 // Re-create the persistent transaction after writing
616 updatePersistentTransaction();
617 return true;
618}
619
620void FMQWrapper::setToken(ndk::SpAIBinder& token) {
621 mToken = token;
622}
623
624bool FMQWrapper::updatePersistentTransaction() {
625 mAvailableSlots = mQueue->availableToWrite();
626 if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
627 ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
628 mCorrupted = true;
629 return false;
630 }
631 return true;
632}
633
634bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
635 hal::WorkDuration* durations, size_t count) {
636 return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
637}
638
639bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
640 int64_t targetDurationNanos) {
641 return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
642}
643
644bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) {
645 return sendMessages<HalChannelMessageContents::hint>(config,
646 reinterpret_cast<hal::SessionHint*>(
647 &hint));
648}
649
650bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
651 bool enabled) {
652 hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
653 .enabled = enabled};
654 return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
655}
656
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000657// ===================================== Tracing helpers
658
659void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
660 std::set<int32_t> tidSet{tids.begin(), tids.end()};
661
662 // Disable old TID tracing
663 for (int32_t tid : mLastThreadIDs) {
664 if (!tidSet.count(tid)) {
665 std::string traceName =
666 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
667 ATrace_setCounter(traceName.c_str(), 0);
668 }
669 }
670
671 // Add new TID tracing
672 for (int32_t tid : tids) {
673 std::string traceName =
674 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
675 ATrace_setCounter(traceName.c_str(), 1);
676 }
677
678 mLastThreadIDs = std::move(tids);
679}
680
681void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
682 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
683}
684
685void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
686 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
687}
688
689void APerformanceHintSession::traceBatchSize(size_t batchSize) {
690 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
691 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
692}
693
694void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
695 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
696}
Peiyong Lin70de0852023-10-25 21:12:35 +0000697
Bo Liu44267722021-07-16 17:03:20 -0400698// ===================================== C API
699APerformanceHintManager* APerformanceHint_getManager() {
700 return APerformanceHintManager::getInstance();
701}
702
Matt Buckley83f77092024-01-18 19:57:29 +0000703#define VALIDATE_PTR(ptr) \
704 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
705
706#define VALIDATE_INT(value, cmp) \
707 if (!(value cmp)) { \
708 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
709 __FUNCTION__, value); \
710 return EINVAL; \
711 }
712
713#define WARN_INT(value, cmp) \
714 if (!(value cmp)) { \
715 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
716 __FUNCTION__, value); \
717 }
718
Bo Liu44267722021-07-16 17:03:20 -0400719APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
720 const int32_t* threadIds, size_t size,
721 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000722 VALIDATE_PTR(manager)
723 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400724 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
725}
726
Matt Buckley27da1342024-04-05 23:10:48 +0000727APerformanceHintSession* APerformanceHint_createSessionInternal(
728 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
729 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
730 VALIDATE_PTR(manager)
731 VALIDATE_PTR(threadIds)
732 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
733 static_cast<hal::SessionTag>(tag));
734}
735
Bo Liu44267722021-07-16 17:03:20 -0400736int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000737 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400738 return manager->getPreferredRateNanos();
739}
740
741int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
742 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000743 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400744 return session->updateTargetWorkDuration(targetDurationNanos);
745}
746
747int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
748 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000749 VALIDATE_PTR(session)
750 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400751 return session->reportActualWorkDuration(actualDurationNanos);
752}
753
Bo Liu44267722021-07-16 17:03:20 -0400754void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000755 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400756 delete session;
757}
758
Matt Buckley27da1342024-04-05 23:10:48 +0000759int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000760 VALIDATE_PTR(session)
Matt Buckley27da1342024-04-05 23:10:48 +0000761 return session->sendHint(hint);
Matt Buckley61726a32022-12-06 23:44:45 +0000762}
763
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000764int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000765 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000766 VALIDATE_PTR(session)
767 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000768 return session->setThreads(threadIds, size);
769}
770
Matt Buckley27da1342024-04-05 23:10:48 +0000771int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000772 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +0000773 VALIDATE_PTR(session)
774 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +0000775}
776
Matt Buckley423c1b32023-06-28 19:13:42 +0000777int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000778 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000779 return session->setPreferPowerEfficiency(enabled);
780}
781
Peiyong Lin70de0852023-10-25 21:12:35 +0000782int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000783 AWorkDuration* workDurationPtr) {
784 VALIDATE_PTR(session)
785 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000786 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
787 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
788 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
789 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
790 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000791 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000792}
793
794AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000795 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000796}
797
798void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000799 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000800 delete aWorkDuration;
801}
802
Peiyong Lin70de0852023-10-25 21:12:35 +0000803void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
804 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000805 VALIDATE_PTR(aWorkDuration)
806 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000807 aWorkDuration->durationNanos = actualTotalDurationNanos;
808}
809
810void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
811 int64_t workPeriodStartTimestampNanos) {
812 VALIDATE_PTR(aWorkDuration)
813 WARN_INT(workPeriodStartTimestampNanos, > 0)
814 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000815}
816
817void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
818 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000819 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000820 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000821 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000822}
823
824void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
825 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000826 VALIDATE_PTR(aWorkDuration)
827 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000828 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000829}
830
Bo Liu44267722021-07-16 17:03:20 -0400831void APerformanceHint_setIHintManagerForTesting(void* iManager) {
Matt Buckley854947f2024-02-07 17:30:01 +0000832 if (iManager == nullptr) {
833 gHintManagerForTesting = nullptr;
834 }
Matt Buckley58977722024-03-11 23:32:09 +0000835 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400836}
Matt Buckley854947f2024-02-07 17:30:01 +0000837
838void APerformanceHint_setUseFMQForTesting(bool enabled) {
839 gForceFMQEnabled = enabled;
840}