blob: e2fa94dd39bb9dfc7f977c7fb02d5777d0cd138a [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>
Matt Buckley151f69f2024-10-21 09:27:06 -070036#include <cutils/trace.h>
Matt Buckley854947f2024-02-07 17:30:01 +000037#include <fmq/AidlMessageQueue.h>
Peiyong Lin70de0852023-10-25 21:12:35 +000038#include <inttypes.h>
Bo Liu44267722021-07-16 17:03:20 -040039#include <performance_hint_private.h>
40#include <utils/SystemClock.h>
41
Matt Buckley56093a72022-11-07 21:50:50 +000042#include <chrono>
Matt Buckley151f69f2024-10-21 09:27:06 -070043#include <format>
Matt Buckley7aac2582024-10-18 11:22:12 -070044#include <future>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000045#include <set>
Bo Liu2b739bb2021-11-10 19:20:03 -050046#include <utility>
47#include <vector>
48
Bo Liu44267722021-07-16 17:03:20 -040049using namespace android;
Matt Buckley58977722024-03-11 23:32:09 +000050using namespace aidl::android::os;
Bo Liu44267722021-07-16 17:03:20 -040051
Matt Buckley56093a72022-11-07 21:50:50 +000052using namespace std::chrono_literals;
53
Matt Buckley7c2de582024-04-05 08:41:35 +000054// Namespace for AIDL types coming from the PowerHAL
55namespace hal = aidl::android::hardware::power;
Matt Buckley58977722024-03-11 23:32:09 +000056
Matt Buckley854947f2024-02-07 17:30:01 +000057using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
58using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
59using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
60using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000061using android::base::StringPrintf;
Matt Buckley56093a72022-11-07 21:50:50 +000062
Bo Liu44267722021-07-16 17:03:20 -040063struct APerformanceHintSession;
64
Matt Buckley56093a72022-11-07 21:50:50 +000065constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
Matt Buckley7c2de582024-04-05 08:41:35 +000066struct AWorkDuration : public hal::WorkDuration {};
Matt Buckley56093a72022-11-07 21:50:50 +000067
Matt Buckley151f69f2024-10-21 09:27:06 -070068// A pair of values that determine the behavior of the
69// load hint rate limiter, to only allow "X hints every Y seconds"
70constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count();
71constexpr double kMaxLoadHintsPerInterval = 20;
72constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval;
73bool kForceNewHintBehavior = false;
74
75template <class T>
76constexpr int32_t enum_size() {
77 return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
78}
79
80bool useNewLoadHintBehavior() {
81 return android::os::adpf_use_load_hints() || kForceNewHintBehavior;
82}
83
Matt Buckley1f5b95f2024-06-07 02:36:56 +000084// Shared lock for the whole PerformanceHintManager and sessions
85static std::mutex sHintMutex = std::mutex{};
Matt Buckley854947f2024-02-07 17:30:01 +000086class FMQWrapper {
87public:
88 bool isActive();
89 bool isSupported();
90 bool startChannel(IHintManager* manager);
91 void stopChannel(IHintManager* manager);
92 // Number of elements the FMQ can hold
93 bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
94 hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
95 bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
96 int64_t targetDurationNanos) REQUIRES(sHintMutex);
Matt Buckley151f69f2024-10-21 09:27:06 -070097 bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint,
98 int64_t now) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +000099 bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
100 REQUIRES(sHintMutex);
101 void setToken(ndk::SpAIBinder& token);
102 void attemptWake();
103 void setUnsupported();
104
105private:
106 template <HalChannelMessageContents::Tag T, bool urgent = false,
107 class C = HalChannelMessageContents::_at<T>>
Matt Buckley151f69f2024-10-21 09:27:06 -0700108 bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1,
109 int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000110 template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
Matt Buckley151f69f2024-10-21 09:27:06 -0700111 void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now)
112 REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000113
114 bool isActiveLocked() REQUIRES(sHintMutex);
115 bool updatePersistentTransaction() REQUIRES(sHintMutex);
116 std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
117 std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
118 // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
119 android::hardware::EventFlag* mEventFlag = nullptr;
120 int32_t mWriteMask;
121 ndk::SpAIBinder mToken = nullptr;
122 // Used to track if operating on the fmq consistently fails
123 bool mCorrupted = false;
124 // Used to keep a persistent transaction open with FMQ to reduce latency a bit
125 size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
126 bool mHalSupported = true;
127 HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
Matt Buckley7aac2582024-10-18 11:22:12 -0700128 std::future<bool> mChannelCreationFinished;
Matt Buckley854947f2024-02-07 17:30:01 +0000129};
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000130
Bo Liu44267722021-07-16 17:03:20 -0400131struct APerformanceHintManager {
132public:
133 static APerformanceHintManager* getInstance();
Matt Buckley854947f2024-02-07 17:30:01 +0000134 APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400135 APerformanceHintManager() = delete;
Matt Buckley854947f2024-02-07 17:30:01 +0000136 ~APerformanceHintManager();
Bo Liu44267722021-07-16 17:03:20 -0400137
138 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
Matt Buckleye073c732024-04-05 22:32:31 +0000139 int64_t initialTargetWorkDurationNanos,
Matt Buckley31974132024-05-21 19:54:39 +0000140 hal::SessionTag tag = hal::SessionTag::APP);
Bo Liu44267722021-07-16 17:03:20 -0400141 int64_t getPreferredRateNanos() const;
Matt Buckley854947f2024-02-07 17:30:01 +0000142 FMQWrapper& getFMQWrapper();
Matt Buckley151f69f2024-10-21 09:27:06 -0700143 bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400144
145private:
Matt Buckley58977722024-03-11 23:32:09 +0000146 // Necessary to create an empty binder object
147 static void* tokenStubOnCreate(void*) {
148 return nullptr;
149 }
150 static void tokenStubOnDestroy(void*) {}
151 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
152 AParcel*) {
153 return STATUS_OK;
154 }
Bo Liu44267722021-07-16 17:03:20 -0400155
Matt Buckley58977722024-03-11 23:32:09 +0000156 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
157
158 std::shared_ptr<IHintManager> mHintManager;
159 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -0400160 const int64_t mPreferredRateNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000161 FMQWrapper mFMQWrapper;
Matt Buckley151f69f2024-10-21 09:27:06 -0700162 double mHintBudget = kMaxLoadHintsPerInterval;
163 int64_t mLastBudgetReplenish = 0;
Bo Liu44267722021-07-16 17:03:20 -0400164};
165
166struct APerformanceHintSession {
167public:
Matt Buckley58977722024-03-11 23:32:09 +0000168 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
169 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000170 int64_t targetDurationNanos,
171 std::optional<hal::SessionConfig> sessionConfig);
Bo Liu44267722021-07-16 17:03:20 -0400172 APerformanceHintSession() = delete;
173 ~APerformanceHintSession();
174
175 int updateTargetWorkDuration(int64_t targetDurationNanos);
176 int reportActualWorkDuration(int64_t actualDurationNanos);
Matt Buckley151f69f2024-10-21 09:27:06 -0700177 int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName);
178 int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName);
179 int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName);
Peiyong Lin095de762022-11-11 18:28:12 +0000180 int setThreads(const int32_t* threadIds, size_t size);
181 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +0000182 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +0000183 int reportActualWorkDuration(AWorkDuration* workDuration);
Bo Liu44267722021-07-16 17:03:20 -0400184
185private:
186 friend struct APerformanceHintManager;
187
Matt Buckley58977722024-03-11 23:32:09 +0000188 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000189
Matt Buckley58977722024-03-11 23:32:09 +0000190 std::shared_ptr<IHintManager> mHintManager;
191 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400192 // HAL preferred update rate
193 const int64_t mPreferredRateNanos;
194 // Target duration for choosing update rate
Matt Buckley053a1df2024-06-07 02:37:59 +0000195 int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700196 // First target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000197 int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700198 // Last target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000199 int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000200 // Last hint reported from sendHint indexed by hint value
Matt Buckley151f69f2024-10-21 09:27:06 -0700201 // This is only used by the old rate limiter impl and is replaced
202 // with the new rate limiter under a flag
Matt Buckley053a1df2024-06-07 02:37:59 +0000203 std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400204 // Cached samples
Matt Buckley053a1df2024-06-07 02:37:59 +0000205 std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000206 std::string mSessionName;
Matt Buckley053a1df2024-06-07 02:37:59 +0000207 static int64_t sIDCounter GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000208 // The most recent set of thread IDs
Matt Buckley053a1df2024-06-07 02:37:59 +0000209 std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
210 std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000211 // Tracing helpers
Matt Buckley053a1df2024-06-07 02:37:59 +0000212 void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000213 void tracePowerEfficient(bool powerEfficient);
214 void traceActualDuration(int64_t actualDuration);
215 void traceBatchSize(size_t batchSize);
216 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400217};
218
Matt Buckley58977722024-03-11 23:32:09 +0000219static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000220static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
221
222static std::optional<bool> gForceFMQEnabled = std::nullopt;
223
Matt Buckleye073c732024-04-05 22:32:31 +0000224// Start above the int32 range so we don't collide with config sessions
225int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
Bo Liu44267722021-07-16 17:03:20 -0400226
Matt Buckley854947f2024-02-07 17:30:01 +0000227static FMQWrapper& getFMQ() {
228 return APerformanceHintManager::getInstance()->getFMQWrapper();
229}
230
Bo Liu44267722021-07-16 17:03:20 -0400231// ===================================== APerformanceHintManager implementation
Matt Buckley854947f2024-02-07 17:30:01 +0000232APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
Bo Liu44267722021-07-16 17:03:20 -0400233 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000234 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
235 static AIBinder_Class* tokenBinderClass =
236 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
237 tokenStubOnTransact);
238 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
Matt Buckley854947f2024-02-07 17:30:01 +0000239 if (mFMQWrapper.isSupported()) {
240 mFMQWrapper.setToken(mToken);
241 mFMQWrapper.startChannel(mHintManager.get());
242 }
243}
244
245APerformanceHintManager::~APerformanceHintManager() {
246 mFMQWrapper.stopChannel(mHintManager.get());
Matt Buckley58977722024-03-11 23:32:09 +0000247}
Bo Liu44267722021-07-16 17:03:20 -0400248
249APerformanceHintManager* APerformanceHintManager::getInstance() {
Matt Buckley7aac2582024-10-18 11:22:12 -0700250 static std::once_flag creationFlag;
251 static APerformanceHintManager* instance = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000252 if (gHintManagerForTesting) {
253 return gHintManagerForTesting.get();
254 }
Bo Liu44267722021-07-16 17:03:20 -0400255 if (gIHintManagerForTesting) {
Matt Buckley854947f2024-02-07 17:30:01 +0000256 gHintManagerForTesting =
257 std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
258 return gHintManagerForTesting.get();
Bo Liu44267722021-07-16 17:03:20 -0400259 }
Matt Buckley7aac2582024-10-18 11:22:12 -0700260 std::call_once(creationFlag, []() { instance = create(nullptr); });
Bo Liu44267722021-07-16 17:03:20 -0400261 return instance;
262}
263
Matt Buckley58977722024-03-11 23:32:09 +0000264APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400265 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000266 manager = IHintManager::fromBinder(
267 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400268 }
269 if (manager == nullptr) {
270 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
271 return nullptr;
272 }
273 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000274 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400275 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000276 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400277 return nullptr;
278 }
279 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400280 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400281 }
Matt Buckley854947f2024-02-07 17:30:01 +0000282 return new APerformanceHintManager(manager, preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400283}
284
Matt Buckley151f69f2024-10-21 09:27:06 -0700285bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
286 mHintBudget =
287 std::max(kMaxLoadHintsPerInterval,
288 mHintBudget +
289 static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate);
290 mLastBudgetReplenish = now;
291
292 // If this youngest timestamp isn't older than the timeout time, we can't send
293 if (hints.size() > mHintBudget) {
294 return false;
295 }
296 mHintBudget -= hints.size();
297 return true;
298}
299
Bo Liu44267722021-07-16 17:03:20 -0400300APerformanceHintSession* APerformanceHintManager::createSession(
Matt Buckleye073c732024-04-05 22:32:31 +0000301 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
302 hal::SessionTag tag) {
Bo Liu44267722021-07-16 17:03:20 -0400303 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000304 std::shared_ptr<IHintSession> session;
Matt Buckleye073c732024-04-05 22:32:31 +0000305 ndk::ScopedAStatus ret;
Matt Buckley854947f2024-02-07 17:30:01 +0000306 hal::SessionConfig sessionConfig{.id = -1};
Matt Buckleye073c732024-04-05 22:32:31 +0000307 ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
308 tag, &sessionConfig, &session);
309
Bo Liu44267722021-07-16 17:03:20 -0400310 if (!ret.isOk() || !session) {
Matt Buckley854947f2024-02-07 17:30:01 +0000311 ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400312 return nullptr;
313 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000314 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Matt Buckley854947f2024-02-07 17:30:01 +0000315 initialTargetWorkDurationNanos,
316 sessionConfig.id == -1
317 ? std::nullopt
318 : std::make_optional<hal::SessionConfig>(
319 std::move(sessionConfig)));
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000320 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000321 out->traceThreads(tids);
322 out->traceTargetDuration(initialTargetWorkDurationNanos);
323 out->tracePowerEfficient(false);
324 return out;
Bo Liu44267722021-07-16 17:03:20 -0400325}
326
327int64_t APerformanceHintManager::getPreferredRateNanos() const {
328 return mPreferredRateNanos;
329}
330
Matt Buckley854947f2024-02-07 17:30:01 +0000331FMQWrapper& APerformanceHintManager::getFMQWrapper() {
332 return mFMQWrapper;
333}
334
Bo Liu44267722021-07-16 17:03:20 -0400335// ===================================== APerformanceHintSession implementation
336
Matt Buckley151f69f2024-10-21 09:27:06 -0700337constexpr int kNumEnums = enum_size<hal::SessionHint>();
Matt Buckley58977722024-03-11 23:32:09 +0000338APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
339 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400340 int64_t preferredRateNanos,
Matt Buckleye073c732024-04-05 22:32:31 +0000341 int64_t targetDurationNanos,
342 std::optional<hal::SessionConfig> sessionConfig)
Peiyong Lin095de762022-11-11 18:28:12 +0000343 : mHintManager(hintManager),
344 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400345 mPreferredRateNanos(preferredRateNanos),
346 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700347 mFirstTargetMetTimestamp(0),
Matt Buckleye073c732024-04-05 22:32:31 +0000348 mLastTargetMetTimestamp(0),
Matt Buckley854947f2024-02-07 17:30:01 +0000349 mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
Matt Buckleye073c732024-04-05 22:32:31 +0000350 mSessionConfig(sessionConfig) {
351 if (sessionConfig->id > INT32_MAX) {
352 ALOGE("Session ID too large, must fit 32-bit integer");
353 }
Matt Buckleye073c732024-04-05 22:32:31 +0000354 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
355 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
Matt Buckley56093a72022-11-07 21:50:50 +0000356}
Bo Liu44267722021-07-16 17:03:20 -0400357
358APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000359 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400360 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000361 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400362 }
363}
364
365int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
366 if (targetDurationNanos <= 0) {
367 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
368 return EINVAL;
369 }
Matt Buckley854947f2024-02-07 17:30:01 +0000370 std::scoped_lock lock(sHintMutex);
371 if (mTargetDurationNanos == targetDurationNanos) {
372 return 0;
373 }
374 if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
375 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
376 if (!ret.isOk()) {
377 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
378 ret.getMessage());
379 return EPIPE;
Xiang Wange16ad282024-06-26 14:31:34 -0700380 }
381 }
Bo Liu44267722021-07-16 17:03:20 -0400382 mTargetDurationNanos = targetDurationNanos;
383 /**
384 * Most of the workload is target_duration dependent, so now clear the cached samples
385 * as they are most likely obsolete.
386 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000387 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000388 traceBatchSize(0);
389 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700390 mFirstTargetMetTimestamp = 0;
391 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400392 return 0;
393}
394
395int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000396 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
397 .workPeriodStartTimestampNanos = 0,
398 .cpuDurationNanos = actualDurationNanos,
399 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400400
Matt Buckley58977722024-03-11 23:32:09 +0000401 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400402}
403
Matt Buckley151f69f2024-10-21 09:27:06 -0700404int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
405 const char*) {
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000406 std::scoped_lock lock(sHintMutex);
Matt Buckley151f69f2024-10-21 09:27:06 -0700407 if (hints.empty()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000408 return EINVAL;
409 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700410 for (auto&& hint : hints) {
411 if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) {
412 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
413 return EINVAL;
Matt Buckley854947f2024-02-07 17:30:01 +0000414 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000415 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700416
417 if (useNewLoadHintBehavior()) {
418 if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) {
419 return EBUSY;
420 }
421 }
422 // keep old rate limiter behavior for legacy flag
423 else {
424 for (auto&& hint : hints) {
425 if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) {
426 return EBUSY;
427 }
428 }
429 }
430
431 if (!getFMQ().sendHints(mSessionConfig, hints, now)) {
432 for (auto&& hint : hints) {
433 ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint));
434
435 if (!ret.isOk()) {
436 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
437 return EPIPE;
438 }
439 }
440 }
441
442 if (!useNewLoadHintBehavior()) {
443 for (auto&& hint : hints) {
444 mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now;
445 }
446 }
447
448 if (ATrace_isEnabled()) {
449 ATRACE_INSTANT("Sending load hint");
450 }
451
Matt Buckley354cc0a2022-09-28 20:54:46 +0000452 return 0;
453}
454
Matt Buckley151f69f2024-10-21 09:27:06 -0700455int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) {
456 std::vector<hal::SessionHint> hints(2);
457 hints.clear();
458 if (cpu) {
459 hints.push_back(hal::SessionHint::CPU_LOAD_UP);
460 }
461 if (gpu) {
462 hints.push_back(hal::SessionHint::GPU_LOAD_UP);
463 }
464 int64_t now = ::android::uptimeNanos();
465 return sendHints(hints, now, debugName);
466}
467
468int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) {
469 std::vector<hal::SessionHint> hints(2);
470 hints.clear();
471 if (cpu) {
472 hints.push_back(hal::SessionHint::CPU_LOAD_RESET);
473 }
474 if (gpu) {
475 hints.push_back(hal::SessionHint::GPU_LOAD_RESET);
476 }
477 int64_t now = ::android::uptimeNanos();
478 return sendHints(hints, now, debugName);
479}
480
Peiyong Lin095de762022-11-11 18:28:12 +0000481int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
482 if (size == 0) {
483 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
484 return EINVAL;
485 }
486 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000487 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000488 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000489 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
490 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000491 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000492 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700493 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000494 }
495 return EPIPE;
496 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000497
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000498 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000499 traceThreads(tids);
500
Peiyong Lin095de762022-11-11 18:28:12 +0000501 return 0;
502}
503
504int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
505 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000506 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000507 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000508 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000509 return EPIPE;
510 }
511
512 // When threadIds is nullptr, this is the first call to determine the size
513 // of the thread ids list.
514 if (threadIds == nullptr) {
515 *size = tids.size();
516 return 0;
517 }
518
519 // Second call to return the actual list of thread ids.
520 *size = tids.size();
521 for (size_t i = 0; i < *size; ++i) {
522 threadIds[i] = tids[i];
523 }
524 return 0;
525}
526
Matt Buckley423c1b32023-06-28 19:13:42 +0000527int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000528 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000529 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
530 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000531
532 if (!ret.isOk()) {
533 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000534 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000535 return EPIPE;
536 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000537 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000538 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000539 return OK;
540}
541
Matt Buckley58977722024-03-11 23:32:09 +0000542int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000543 return reportActualWorkDurationInternal(workDuration);
544}
545
Matt Buckley58977722024-03-11 23:32:09 +0000546int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
547 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000548 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000549 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000550 workDuration->timeStampNanos = now;
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000551 std::scoped_lock lock(sHintMutex);
Peiyong Lin70de0852023-10-25 21:12:35 +0000552 mActualWorkDurations.push_back(std::move(*workDuration));
553
554 if (actualTotalDurationNanos >= mTargetDurationNanos) {
555 // Reset timestamps if we are equal or over the target.
556 mFirstTargetMetTimestamp = 0;
557 } else {
558 // Set mFirstTargetMetTimestamp for first time meeting target.
559 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
560 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
561 mFirstTargetMetTimestamp = now;
562 }
563 /**
564 * Rate limit the change if the update is over mPreferredRateNanos since first
565 * meeting target and less than mPreferredRateNanos since last meeting target.
566 */
567 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
568 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000569 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000570 return 0;
571 }
572 mLastTargetMetTimestamp = now;
573 }
574
Matt Buckley854947f2024-02-07 17:30:01 +0000575 if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
576 mActualWorkDurations.size())) {
577 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
578 if (!ret.isOk()) {
579 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
580 ret.getMessage());
581 mFirstTargetMetTimestamp = 0;
582 mLastTargetMetTimestamp = 0;
583 traceBatchSize(mActualWorkDurations.size());
584 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
585 }
Peiyong Lin70de0852023-10-25 21:12:35 +0000586 }
Matt Buckley854947f2024-02-07 17:30:01 +0000587
Peiyong Lin70de0852023-10-25 21:12:35 +0000588 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000589 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000590
591 return 0;
592}
Matt Buckley854947f2024-02-07 17:30:01 +0000593
594// ===================================== FMQ wrapper implementation
595
596bool FMQWrapper::isActive() {
597 std::scoped_lock lock{sHintMutex};
598 return isActiveLocked();
599}
600
601bool FMQWrapper::isActiveLocked() {
602 return mQueue != nullptr;
603}
604
605void FMQWrapper::setUnsupported() {
606 mHalSupported = false;
607}
608
609bool FMQWrapper::isSupported() {
610 if (!mHalSupported) {
611 return false;
612 }
613 // Used for testing
614 if (gForceFMQEnabled.has_value()) {
615 return *gForceFMQEnabled;
616 }
617 return android::os::adpf_use_fmq_channel_fixed();
618}
619
620bool FMQWrapper::startChannel(IHintManager* manager) {
Matt Buckley7aac2582024-10-18 11:22:12 -0700621 if (isSupported() && !isActive() && manager->isRemote()) {
622 mChannelCreationFinished = std::async(std::launch::async, [&, this, manager]() {
623 std::optional<hal::ChannelConfig> config;
624 auto ret = manager->getSessionChannel(mToken, &config);
625 if (ret.isOk() && config.has_value()) {
626 std::scoped_lock lock{sHintMutex};
627 mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
628 if (config->eventFlagDescriptor.has_value()) {
629 mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
630 android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
631 &mEventFlag);
632 mWriteMask = config->writeFlagBitmask;
633 }
634 updatePersistentTransaction();
635 } else if (ret.isOk() && !config.has_value()) {
636 ALOGV("FMQ channel enabled but unsupported.");
637 setUnsupported();
638 } else {
639 ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley854947f2024-02-07 17:30:01 +0000640 }
Matt Buckley7aac2582024-10-18 11:22:12 -0700641 return true;
642 });
Matt Buckley854947f2024-02-07 17:30:01 +0000643 }
644 return isActive();
645}
646
647void FMQWrapper::stopChannel(IHintManager* manager) {
648 {
649 std::scoped_lock lock{sHintMutex};
650 if (!isActiveLocked()) {
651 return;
652 }
653 mFlagQueue = nullptr;
654 mQueue = nullptr;
655 }
656 manager->closeSessionChannel();
657}
658
659template <HalChannelMessageContents::Tag T, class C>
Matt Buckley151f69f2024-10-21 09:27:06 -0700660void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) {
661 for (size_t i = 0; i < count; ++i) {
662 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
663 .sessionID = static_cast<int32_t>(config.id),
664 .timeStampNanos = now,
665 .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))),
666 };
667 }
Matt Buckley854947f2024-02-07 17:30:01 +0000668}
669
670template <>
671void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
672 hal::SessionConfig& config,
Matt Buckley151f69f2024-10-21 09:27:06 -0700673 size_t count, int64_t now) {
Matt Buckley854947f2024-02-07 17:30:01 +0000674 for (size_t i = 0; i < count; ++i) {
675 hal::WorkDuration& message = messages[i];
676 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
677 .sessionID = static_cast<int32_t>(config.id),
Matt Buckley151f69f2024-10-21 09:27:06 -0700678 .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos,
Matt Buckley854947f2024-02-07 17:30:01 +0000679 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
680 hal::WorkDurationFixedV1>({
681 .durationNanos = message.cpuDurationNanos,
682 .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
683 .cpuDurationNanos = message.cpuDurationNanos,
684 .gpuDurationNanos = message.gpuDurationNanos,
685 }),
686 };
687 }
688}
689
690template <HalChannelMessageContents::Tag T, bool urgent, class C>
Matt Buckley151f69f2024-10-21 09:27:06 -0700691bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count,
692 int64_t now) {
Matt Buckley854947f2024-02-07 17:30:01 +0000693 if (!isActiveLocked() || !config.has_value() || mCorrupted) {
694 return false;
695 }
696 // If we didn't reserve enough space, try re-creating the transaction
697 if (count > mAvailableSlots) {
698 if (!updatePersistentTransaction()) {
699 return false;
700 }
701 // If we actually don't have enough space, give up
702 if (count > mAvailableSlots) {
703 return false;
704 }
705 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700706 writeBuffer<T, C>(message, *config, count, now);
Matt Buckley854947f2024-02-07 17:30:01 +0000707 mQueue->commitWrite(count);
708 mEventFlag->wake(mWriteMask);
709 // Re-create the persistent transaction after writing
710 updatePersistentTransaction();
711 return true;
712}
713
714void FMQWrapper::setToken(ndk::SpAIBinder& token) {
715 mToken = token;
716}
717
718bool FMQWrapper::updatePersistentTransaction() {
719 mAvailableSlots = mQueue->availableToWrite();
720 if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
721 ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
722 mCorrupted = true;
723 return false;
724 }
725 return true;
726}
727
728bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
729 hal::WorkDuration* durations, size_t count) {
730 return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
731}
732
733bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
734 int64_t targetDurationNanos) {
735 return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
736}
737
Matt Buckley151f69f2024-10-21 09:27:06 -0700738bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config,
739 std::vector<hal::SessionHint>& hints, int64_t now) {
740 return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now);
Matt Buckley854947f2024-02-07 17:30:01 +0000741}
742
743bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
744 bool enabled) {
745 hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
746 .enabled = enabled};
747 return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
748}
749
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000750// ===================================== Tracing helpers
751
752void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
753 std::set<int32_t> tidSet{tids.begin(), tids.end()};
754
755 // Disable old TID tracing
756 for (int32_t tid : mLastThreadIDs) {
757 if (!tidSet.count(tid)) {
758 std::string traceName =
759 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
760 ATrace_setCounter(traceName.c_str(), 0);
761 }
762 }
763
764 // Add new TID tracing
765 for (int32_t tid : tids) {
766 std::string traceName =
767 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
768 ATrace_setCounter(traceName.c_str(), 1);
769 }
770
771 mLastThreadIDs = std::move(tids);
772}
773
774void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
775 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
776}
777
778void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
779 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
780}
781
782void APerformanceHintSession::traceBatchSize(size_t batchSize) {
783 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
784 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
785}
786
787void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
788 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
789}
Peiyong Lin70de0852023-10-25 21:12:35 +0000790
Bo Liu44267722021-07-16 17:03:20 -0400791// ===================================== C API
792APerformanceHintManager* APerformanceHint_getManager() {
793 return APerformanceHintManager::getInstance();
794}
795
Matt Buckley83f77092024-01-18 19:57:29 +0000796#define VALIDATE_PTR(ptr) \
797 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
798
799#define VALIDATE_INT(value, cmp) \
800 if (!(value cmp)) { \
801 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
802 __FUNCTION__, value); \
803 return EINVAL; \
804 }
805
806#define WARN_INT(value, cmp) \
807 if (!(value cmp)) { \
808 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
809 __FUNCTION__, value); \
810 }
811
Bo Liu44267722021-07-16 17:03:20 -0400812APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
813 const int32_t* threadIds, size_t size,
814 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000815 VALIDATE_PTR(manager)
816 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400817 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
818}
819
Matt Buckley27da1342024-04-05 23:10:48 +0000820APerformanceHintSession* APerformanceHint_createSessionInternal(
821 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
822 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
823 VALIDATE_PTR(manager)
824 VALIDATE_PTR(threadIds)
825 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
826 static_cast<hal::SessionTag>(tag));
827}
828
Bo Liu44267722021-07-16 17:03:20 -0400829int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000830 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400831 return manager->getPreferredRateNanos();
832}
833
834int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
835 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000836 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400837 return session->updateTargetWorkDuration(targetDurationNanos);
838}
839
840int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
841 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000842 VALIDATE_PTR(session)
843 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400844 return session->reportActualWorkDuration(actualDurationNanos);
845}
846
Bo Liu44267722021-07-16 17:03:20 -0400847void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000848 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400849 delete session;
850}
851
Matt Buckley27da1342024-04-05 23:10:48 +0000852int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000853 VALIDATE_PTR(session)
Matt Buckley151f69f2024-10-21 09:27:06 -0700854 std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)};
855 int64_t now = ::android::uptimeNanos();
856 return session->sendHints(hints, now, "HWUI hint");
Matt Buckley61726a32022-12-06 23:44:45 +0000857}
858
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000859int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000860 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000861 VALIDATE_PTR(session)
862 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000863 return session->setThreads(threadIds, size);
864}
865
Matt Buckley27da1342024-04-05 23:10:48 +0000866int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000867 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +0000868 VALIDATE_PTR(session)
869 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +0000870}
871
Matt Buckley423c1b32023-06-28 19:13:42 +0000872int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000873 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000874 return session->setPreferPowerEfficiency(enabled);
875}
876
Peiyong Lin70de0852023-10-25 21:12:35 +0000877int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000878 AWorkDuration* workDurationPtr) {
879 VALIDATE_PTR(session)
880 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000881 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
882 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
883 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
884 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
885 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000886 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000887}
888
Matt Buckley151f69f2024-10-21 09:27:06 -0700889int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu,
890 const char* debugName) {
891 VALIDATE_PTR(session)
892 VALIDATE_PTR(debugName)
893 if (!useNewLoadHintBehavior()) {
894 return ENOTSUP;
895 }
896 return session->notifyWorkloadIncrease(cpu, gpu, debugName);
897}
898
899int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu,
900 const char* debugName) {
901 VALIDATE_PTR(session)
902 VALIDATE_PTR(debugName)
903 if (!useNewLoadHintBehavior()) {
904 return ENOTSUP;
905 }
906 return session->notifyWorkloadReset(cpu, gpu, debugName);
907}
908
Peiyong Lin70de0852023-10-25 21:12:35 +0000909AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000910 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000911}
912
913void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000914 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000915 delete aWorkDuration;
916}
917
Peiyong Lin70de0852023-10-25 21:12:35 +0000918void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
919 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000920 VALIDATE_PTR(aWorkDuration)
921 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000922 aWorkDuration->durationNanos = actualTotalDurationNanos;
923}
924
925void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
926 int64_t workPeriodStartTimestampNanos) {
927 VALIDATE_PTR(aWorkDuration)
928 WARN_INT(workPeriodStartTimestampNanos, > 0)
929 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000930}
931
932void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
933 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000934 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000935 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000936 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000937}
938
939void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
940 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000941 VALIDATE_PTR(aWorkDuration)
942 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +0000943 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000944}
945
Bo Liu44267722021-07-16 17:03:20 -0400946void APerformanceHint_setIHintManagerForTesting(void* iManager) {
Matt Buckley854947f2024-02-07 17:30:01 +0000947 if (iManager == nullptr) {
948 gHintManagerForTesting = nullptr;
949 }
Matt Buckley58977722024-03-11 23:32:09 +0000950 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -0400951}
Matt Buckley854947f2024-02-07 17:30:01 +0000952
953void APerformanceHint_setUseFMQForTesting(bool enabled) {
954 gForceFMQEnabled = enabled;
955}
Matt Buckley151f69f2024-10-21 09:27:06 -0700956
957void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
958 int64_t* loadHintInterval) {
959 *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval;
960 *loadHintInterval = kLoadHintInterval;
961}
962
963void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
964 kForceNewHintBehavior = newBehavior;
965}