blob: bc1945e3707243fb70627fbd71ca5d726bb0f80d [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>
Matt Buckley87393822024-11-17 01:58:16 +000039#include <jni_wrappers.h>
Bo Liu44267722021-07-16 17:03:20 -040040#include <performance_hint_private.h>
41#include <utils/SystemClock.h>
42
Matt Buckley56093a72022-11-07 21:50:50 +000043#include <chrono>
Matt Buckley151f69f2024-10-21 09:27:06 -070044#include <format>
Matt Buckley7aac2582024-10-18 11:22:12 -070045#include <future>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000046#include <set>
Bo Liu2b739bb2021-11-10 19:20:03 -050047#include <utility>
48#include <vector>
49
Bo Liu44267722021-07-16 17:03:20 -040050using namespace android;
Matt Buckley58977722024-03-11 23:32:09 +000051using namespace aidl::android::os;
Bo Liu44267722021-07-16 17:03:20 -040052
Matt Buckley56093a72022-11-07 21:50:50 +000053using namespace std::chrono_literals;
54
Matt Buckley7c2de582024-04-05 08:41:35 +000055// Namespace for AIDL types coming from the PowerHAL
56namespace hal = aidl::android::hardware::power;
Matt Buckley58977722024-03-11 23:32:09 +000057
Matt Buckley854947f2024-02-07 17:30:01 +000058using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
59using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
60using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
61using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000062using android::base::StringPrintf;
Matt Buckley56093a72022-11-07 21:50:50 +000063
Bo Liu44267722021-07-16 17:03:20 -040064struct APerformanceHintSession;
65
Matt Buckley56093a72022-11-07 21:50:50 +000066constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
Matt Buckley7c2de582024-04-05 08:41:35 +000067struct AWorkDuration : public hal::WorkDuration {};
Matt Buckley56093a72022-11-07 21:50:50 +000068
Matt Buckley151f69f2024-10-21 09:27:06 -070069// A pair of values that determine the behavior of the
70// load hint rate limiter, to only allow "X hints every Y seconds"
71constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count();
72constexpr double kMaxLoadHintsPerInterval = 20;
73constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval;
74bool kForceNewHintBehavior = false;
75
76template <class T>
77constexpr int32_t enum_size() {
78 return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
79}
80
81bool useNewLoadHintBehavior() {
82 return android::os::adpf_use_load_hints() || kForceNewHintBehavior;
83}
84
Matt Buckley1f5b95f2024-06-07 02:36:56 +000085// Shared lock for the whole PerformanceHintManager and sessions
86static std::mutex sHintMutex = std::mutex{};
Matt Buckley854947f2024-02-07 17:30:01 +000087class FMQWrapper {
88public:
89 bool isActive();
90 bool isSupported();
91 bool startChannel(IHintManager* manager);
92 void stopChannel(IHintManager* manager);
93 // Number of elements the FMQ can hold
94 bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
95 hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
96 bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
97 int64_t targetDurationNanos) REQUIRES(sHintMutex);
Matt Buckley151f69f2024-10-21 09:27:06 -070098 bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint,
99 int64_t now) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000100 bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
101 REQUIRES(sHintMutex);
102 void setToken(ndk::SpAIBinder& token);
103 void attemptWake();
104 void setUnsupported();
105
106private:
107 template <HalChannelMessageContents::Tag T, bool urgent = false,
108 class C = HalChannelMessageContents::_at<T>>
Matt Buckley151f69f2024-10-21 09:27:06 -0700109 bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1,
110 int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000111 template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
Matt Buckley151f69f2024-10-21 09:27:06 -0700112 void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now)
113 REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000114
115 bool isActiveLocked() REQUIRES(sHintMutex);
116 bool updatePersistentTransaction() REQUIRES(sHintMutex);
117 std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
118 std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
119 // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
120 android::hardware::EventFlag* mEventFlag = nullptr;
121 int32_t mWriteMask;
122 ndk::SpAIBinder mToken = nullptr;
123 // Used to track if operating on the fmq consistently fails
124 bool mCorrupted = false;
125 // Used to keep a persistent transaction open with FMQ to reduce latency a bit
126 size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
127 bool mHalSupported = true;
128 HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
Matt Buckley7aac2582024-10-18 11:22:12 -0700129 std::future<bool> mChannelCreationFinished;
Matt Buckley854947f2024-02-07 17:30:01 +0000130};
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000131
Bo Liu44267722021-07-16 17:03:20 -0400132struct APerformanceHintManager {
133public:
134 static APerformanceHintManager* getInstance();
Matt Buckley854947f2024-02-07 17:30:01 +0000135 APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400136 APerformanceHintManager() = delete;
Matt Buckley854947f2024-02-07 17:30:01 +0000137 ~APerformanceHintManager();
Bo Liu44267722021-07-16 17:03:20 -0400138
139 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
Matt Buckleye073c732024-04-05 22:32:31 +0000140 int64_t initialTargetWorkDurationNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000141 hal::SessionTag tag = hal::SessionTag::APP,
142 bool isJava = false);
143 APerformanceHintSession* getSessionFromJava(JNIEnv* _Nonnull env, jobject _Nonnull sessionObj);
144
Bo Liu44267722021-07-16 17:03:20 -0400145 int64_t getPreferredRateNanos() const;
Matt Buckley854947f2024-02-07 17:30:01 +0000146 FMQWrapper& getFMQWrapper();
Matt Buckley151f69f2024-10-21 09:27:06 -0700147 bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
Matt Buckley87393822024-11-17 01:58:16 +0000148 void initJava(JNIEnv* _Nonnull env);
Bo Liu44267722021-07-16 17:03:20 -0400149
150private:
Matt Buckley58977722024-03-11 23:32:09 +0000151 // Necessary to create an empty binder object
152 static void* tokenStubOnCreate(void*) {
153 return nullptr;
154 }
155 static void tokenStubOnDestroy(void*) {}
156 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
157 AParcel*) {
158 return STATUS_OK;
159 }
Bo Liu44267722021-07-16 17:03:20 -0400160
Matt Buckley58977722024-03-11 23:32:09 +0000161 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
162
163 std::shared_ptr<IHintManager> mHintManager;
164 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -0400165 const int64_t mPreferredRateNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000166 FMQWrapper mFMQWrapper;
Matt Buckley151f69f2024-10-21 09:27:06 -0700167 double mHintBudget = kMaxLoadHintsPerInterval;
168 int64_t mLastBudgetReplenish = 0;
Matt Buckley87393822024-11-17 01:58:16 +0000169 bool mJavaInitialized = false;
170 jclass mJavaSessionClazz;
171 jfieldID mJavaSessionNativePtr;
Bo Liu44267722021-07-16 17:03:20 -0400172};
173
174struct APerformanceHintSession {
175public:
Matt Buckley58977722024-03-11 23:32:09 +0000176 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
177 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000178 int64_t targetDurationNanos, bool isJava,
Matt Buckleye073c732024-04-05 22:32:31 +0000179 std::optional<hal::SessionConfig> sessionConfig);
Bo Liu44267722021-07-16 17:03:20 -0400180 APerformanceHintSession() = delete;
181 ~APerformanceHintSession();
182
183 int updateTargetWorkDuration(int64_t targetDurationNanos);
184 int reportActualWorkDuration(int64_t actualDurationNanos);
Matt Buckley151f69f2024-10-21 09:27:06 -0700185 int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName);
186 int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName);
187 int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName);
Peiyong Lin095de762022-11-11 18:28:12 +0000188 int setThreads(const int32_t* threadIds, size_t size);
189 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +0000190 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +0000191 int reportActualWorkDuration(AWorkDuration* workDuration);
Matt Buckley87393822024-11-17 01:58:16 +0000192 bool isJava();
Bo Liu44267722021-07-16 17:03:20 -0400193
194private:
195 friend struct APerformanceHintManager;
196
Matt Buckley58977722024-03-11 23:32:09 +0000197 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000198
Matt Buckley58977722024-03-11 23:32:09 +0000199 std::shared_ptr<IHintManager> mHintManager;
200 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400201 // HAL preferred update rate
202 const int64_t mPreferredRateNanos;
203 // Target duration for choosing update rate
Matt Buckley053a1df2024-06-07 02:37:59 +0000204 int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700205 // First target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000206 int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700207 // Last target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000208 int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000209 // Last hint reported from sendHint indexed by hint value
Matt Buckley151f69f2024-10-21 09:27:06 -0700210 // This is only used by the old rate limiter impl and is replaced
211 // with the new rate limiter under a flag
Matt Buckley053a1df2024-06-07 02:37:59 +0000212 std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400213 // Cached samples
Matt Buckley053a1df2024-06-07 02:37:59 +0000214 std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
Matt Buckley87393822024-11-17 01:58:16 +0000215 // Is this session backing an SDK wrapper object
216 const bool mIsJava;
Matt Buckley854947f2024-02-07 17:30:01 +0000217 std::string mSessionName;
Matt Buckley053a1df2024-06-07 02:37:59 +0000218 static int64_t sIDCounter GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000219 // The most recent set of thread IDs
Matt Buckley053a1df2024-06-07 02:37:59 +0000220 std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
221 std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000222 // Tracing helpers
Matt Buckley053a1df2024-06-07 02:37:59 +0000223 void traceThreads(std::vector<int32_t>& tids) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000224 void tracePowerEfficient(bool powerEfficient);
225 void traceActualDuration(int64_t actualDuration);
226 void traceBatchSize(size_t batchSize);
227 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400228};
229
Matt Buckley58977722024-03-11 23:32:09 +0000230static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000231static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
232
233static std::optional<bool> gForceFMQEnabled = std::nullopt;
234
Matt Buckleye073c732024-04-05 22:32:31 +0000235// Start above the int32 range so we don't collide with config sessions
236int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
Bo Liu44267722021-07-16 17:03:20 -0400237
Matt Buckley854947f2024-02-07 17:30:01 +0000238static FMQWrapper& getFMQ() {
239 return APerformanceHintManager::getInstance()->getFMQWrapper();
240}
241
Bo Liu44267722021-07-16 17:03:20 -0400242// ===================================== APerformanceHintManager implementation
Matt Buckley854947f2024-02-07 17:30:01 +0000243APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
Bo Liu44267722021-07-16 17:03:20 -0400244 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000245 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
246 static AIBinder_Class* tokenBinderClass =
247 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
248 tokenStubOnTransact);
249 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
Matt Buckley854947f2024-02-07 17:30:01 +0000250 if (mFMQWrapper.isSupported()) {
251 mFMQWrapper.setToken(mToken);
252 mFMQWrapper.startChannel(mHintManager.get());
253 }
254}
255
256APerformanceHintManager::~APerformanceHintManager() {
257 mFMQWrapper.stopChannel(mHintManager.get());
Matt Buckley58977722024-03-11 23:32:09 +0000258}
Bo Liu44267722021-07-16 17:03:20 -0400259
260APerformanceHintManager* APerformanceHintManager::getInstance() {
Matt Buckley7aac2582024-10-18 11:22:12 -0700261 static std::once_flag creationFlag;
262 static APerformanceHintManager* instance = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000263 if (gHintManagerForTesting) {
264 return gHintManagerForTesting.get();
265 }
Bo Liu44267722021-07-16 17:03:20 -0400266 if (gIHintManagerForTesting) {
Matt Buckley854947f2024-02-07 17:30:01 +0000267 gHintManagerForTesting =
268 std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
269 return gHintManagerForTesting.get();
Bo Liu44267722021-07-16 17:03:20 -0400270 }
Matt Buckley7aac2582024-10-18 11:22:12 -0700271 std::call_once(creationFlag, []() { instance = create(nullptr); });
Bo Liu44267722021-07-16 17:03:20 -0400272 return instance;
273}
274
Matt Buckley58977722024-03-11 23:32:09 +0000275APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400276 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000277 manager = IHintManager::fromBinder(
278 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400279 }
280 if (manager == nullptr) {
281 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
282 return nullptr;
283 }
284 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000285 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400286 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000287 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400288 return nullptr;
289 }
290 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400291 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400292 }
Matt Buckley854947f2024-02-07 17:30:01 +0000293 return new APerformanceHintManager(manager, preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400294}
295
Matt Buckley151f69f2024-10-21 09:27:06 -0700296bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
297 mHintBudget =
298 std::max(kMaxLoadHintsPerInterval,
299 mHintBudget +
300 static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate);
301 mLastBudgetReplenish = now;
302
303 // If this youngest timestamp isn't older than the timeout time, we can't send
304 if (hints.size() > mHintBudget) {
305 return false;
306 }
307 mHintBudget -= hints.size();
308 return true;
309}
310
Bo Liu44267722021-07-16 17:03:20 -0400311APerformanceHintSession* APerformanceHintManager::createSession(
Matt Buckleye073c732024-04-05 22:32:31 +0000312 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000313 hal::SessionTag tag, bool isJava) {
Bo Liu44267722021-07-16 17:03:20 -0400314 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000315 std::shared_ptr<IHintSession> session;
Matt Buckleye073c732024-04-05 22:32:31 +0000316 ndk::ScopedAStatus ret;
Matt Buckley854947f2024-02-07 17:30:01 +0000317 hal::SessionConfig sessionConfig{.id = -1};
Matt Buckleye073c732024-04-05 22:32:31 +0000318 ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
319 tag, &sessionConfig, &session);
320
Bo Liu44267722021-07-16 17:03:20 -0400321 if (!ret.isOk() || !session) {
Matt Buckley854947f2024-02-07 17:30:01 +0000322 ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400323 return nullptr;
324 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000325 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000326 initialTargetWorkDurationNanos, isJava,
Matt Buckley854947f2024-02-07 17:30:01 +0000327 sessionConfig.id == -1
328 ? std::nullopt
329 : std::make_optional<hal::SessionConfig>(
330 std::move(sessionConfig)));
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000331 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000332 out->traceThreads(tids);
333 out->traceTargetDuration(initialTargetWorkDurationNanos);
334 out->tracePowerEfficient(false);
335 return out;
Bo Liu44267722021-07-16 17:03:20 -0400336}
337
Matt Buckley87393822024-11-17 01:58:16 +0000338APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env,
339 jobject sessionObj) {
340 initJava(env);
341 LOG_ALWAYS_FATAL_IF(!env->IsInstanceOf(sessionObj, mJavaSessionClazz),
342 "Wrong java type passed to APerformanceHint_getSessionFromJava");
343 APerformanceHintSession* out = reinterpret_cast<APerformanceHintSession*>(
344 env->GetLongField(sessionObj, mJavaSessionNativePtr));
345 LOG_ALWAYS_FATAL_IF(out == nullptr, "Java-wrapped native hint session is nullptr");
346 LOG_ALWAYS_FATAL_IF(!out->isJava(), "Unmanaged native hint session returned from Java SDK");
347 return out;
348}
349
Bo Liu44267722021-07-16 17:03:20 -0400350int64_t APerformanceHintManager::getPreferredRateNanos() const {
351 return mPreferredRateNanos;
352}
353
Matt Buckley854947f2024-02-07 17:30:01 +0000354FMQWrapper& APerformanceHintManager::getFMQWrapper() {
355 return mFMQWrapper;
356}
357
Matt Buckley87393822024-11-17 01:58:16 +0000358void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) {
359 if (mJavaInitialized) {
360 return;
361 }
362 jclass sessionClazz = FindClassOrDie(env, "android/os/PerformanceHintManager$Session");
363 mJavaSessionClazz = MakeGlobalRefOrDie(env, sessionClazz);
364 mJavaSessionNativePtr = GetFieldIDOrDie(env, mJavaSessionClazz, "mNativeSessionPtr", "J");
365 mJavaInitialized = true;
366}
367
Bo Liu44267722021-07-16 17:03:20 -0400368// ===================================== APerformanceHintSession implementation
369
Matt Buckley151f69f2024-10-21 09:27:06 -0700370constexpr int kNumEnums = enum_size<hal::SessionHint>();
Matt Buckley58977722024-03-11 23:32:09 +0000371APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
372 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400373 int64_t preferredRateNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000374 int64_t targetDurationNanos, bool isJava,
Matt Buckleye073c732024-04-05 22:32:31 +0000375 std::optional<hal::SessionConfig> sessionConfig)
Peiyong Lin095de762022-11-11 18:28:12 +0000376 : mHintManager(hintManager),
377 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400378 mPreferredRateNanos(preferredRateNanos),
379 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700380 mFirstTargetMetTimestamp(0),
Matt Buckleye073c732024-04-05 22:32:31 +0000381 mLastTargetMetTimestamp(0),
Matt Buckley854947f2024-02-07 17:30:01 +0000382 mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
Matt Buckley87393822024-11-17 01:58:16 +0000383 mIsJava(isJava),
Matt Buckleye073c732024-04-05 22:32:31 +0000384 mSessionConfig(sessionConfig) {
385 if (sessionConfig->id > INT32_MAX) {
386 ALOGE("Session ID too large, must fit 32-bit integer");
387 }
Matt Buckleye073c732024-04-05 22:32:31 +0000388 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
389 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
Matt Buckley56093a72022-11-07 21:50:50 +0000390}
Bo Liu44267722021-07-16 17:03:20 -0400391
392APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000393 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400394 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000395 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400396 }
397}
398
399int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
400 if (targetDurationNanos <= 0) {
401 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
402 return EINVAL;
403 }
Matt Buckley854947f2024-02-07 17:30:01 +0000404 std::scoped_lock lock(sHintMutex);
405 if (mTargetDurationNanos == targetDurationNanos) {
406 return 0;
407 }
408 if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
409 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
410 if (!ret.isOk()) {
411 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
412 ret.getMessage());
413 return EPIPE;
Xiang Wange16ad282024-06-26 14:31:34 -0700414 }
415 }
Bo Liu44267722021-07-16 17:03:20 -0400416 mTargetDurationNanos = targetDurationNanos;
417 /**
418 * Most of the workload is target_duration dependent, so now clear the cached samples
419 * as they are most likely obsolete.
420 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000421 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000422 traceBatchSize(0);
423 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700424 mFirstTargetMetTimestamp = 0;
425 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400426 return 0;
427}
428
429int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000430 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
431 .workPeriodStartTimestampNanos = 0,
432 .cpuDurationNanos = actualDurationNanos,
433 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400434
Matt Buckley58977722024-03-11 23:32:09 +0000435 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400436}
437
Matt Buckley87393822024-11-17 01:58:16 +0000438bool APerformanceHintSession::isJava() {
439 return mIsJava;
440}
441
Matt Buckley151f69f2024-10-21 09:27:06 -0700442int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
443 const char*) {
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000444 std::scoped_lock lock(sHintMutex);
Matt Buckley151f69f2024-10-21 09:27:06 -0700445 if (hints.empty()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000446 return EINVAL;
447 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700448 for (auto&& hint : hints) {
449 if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) {
450 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
451 return EINVAL;
Matt Buckley854947f2024-02-07 17:30:01 +0000452 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000453 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700454
455 if (useNewLoadHintBehavior()) {
456 if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) {
457 return EBUSY;
458 }
459 }
460 // keep old rate limiter behavior for legacy flag
461 else {
462 for (auto&& hint : hints) {
463 if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) {
464 return EBUSY;
465 }
466 }
467 }
468
469 if (!getFMQ().sendHints(mSessionConfig, hints, now)) {
470 for (auto&& hint : hints) {
471 ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint));
472
473 if (!ret.isOk()) {
474 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
475 return EPIPE;
476 }
477 }
478 }
479
480 if (!useNewLoadHintBehavior()) {
481 for (auto&& hint : hints) {
482 mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now;
483 }
484 }
485
486 if (ATrace_isEnabled()) {
487 ATRACE_INSTANT("Sending load hint");
488 }
489
Matt Buckley354cc0a2022-09-28 20:54:46 +0000490 return 0;
491}
492
Matt Buckley151f69f2024-10-21 09:27:06 -0700493int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) {
494 std::vector<hal::SessionHint> hints(2);
495 hints.clear();
496 if (cpu) {
497 hints.push_back(hal::SessionHint::CPU_LOAD_UP);
498 }
499 if (gpu) {
500 hints.push_back(hal::SessionHint::GPU_LOAD_UP);
501 }
502 int64_t now = ::android::uptimeNanos();
503 return sendHints(hints, now, debugName);
504}
505
506int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) {
507 std::vector<hal::SessionHint> hints(2);
508 hints.clear();
509 if (cpu) {
510 hints.push_back(hal::SessionHint::CPU_LOAD_RESET);
511 }
512 if (gpu) {
513 hints.push_back(hal::SessionHint::GPU_LOAD_RESET);
514 }
515 int64_t now = ::android::uptimeNanos();
516 return sendHints(hints, now, debugName);
517}
518
Peiyong Lin095de762022-11-11 18:28:12 +0000519int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
520 if (size == 0) {
521 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
522 return EINVAL;
523 }
524 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000525 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000526 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000527 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
528 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000529 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000530 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700531 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000532 }
533 return EPIPE;
534 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000535
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000536 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000537 traceThreads(tids);
538
Peiyong Lin095de762022-11-11 18:28:12 +0000539 return 0;
540}
541
542int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
543 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000544 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000545 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000546 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000547 return EPIPE;
548 }
549
550 // When threadIds is nullptr, this is the first call to determine the size
551 // of the thread ids list.
552 if (threadIds == nullptr) {
553 *size = tids.size();
554 return 0;
555 }
556
557 // Second call to return the actual list of thread ids.
558 *size = tids.size();
559 for (size_t i = 0; i < *size; ++i) {
560 threadIds[i] = tids[i];
561 }
562 return 0;
563}
564
Matt Buckley423c1b32023-06-28 19:13:42 +0000565int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000566 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000567 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
568 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000569
570 if (!ret.isOk()) {
571 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000572 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000573 return EPIPE;
574 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000575 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000576 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000577 return OK;
578}
579
Matt Buckley58977722024-03-11 23:32:09 +0000580int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000581 return reportActualWorkDurationInternal(workDuration);
582}
583
Matt Buckley58977722024-03-11 23:32:09 +0000584int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
585 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000586 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000587 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000588 workDuration->timeStampNanos = now;
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000589 std::scoped_lock lock(sHintMutex);
Peiyong Lin70de0852023-10-25 21:12:35 +0000590 mActualWorkDurations.push_back(std::move(*workDuration));
591
592 if (actualTotalDurationNanos >= mTargetDurationNanos) {
593 // Reset timestamps if we are equal or over the target.
594 mFirstTargetMetTimestamp = 0;
595 } else {
596 // Set mFirstTargetMetTimestamp for first time meeting target.
597 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
598 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
599 mFirstTargetMetTimestamp = now;
600 }
601 /**
602 * Rate limit the change if the update is over mPreferredRateNanos since first
603 * meeting target and less than mPreferredRateNanos since last meeting target.
604 */
605 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
606 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000607 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000608 return 0;
609 }
610 mLastTargetMetTimestamp = now;
611 }
612
Matt Buckley854947f2024-02-07 17:30:01 +0000613 if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
614 mActualWorkDurations.size())) {
615 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
616 if (!ret.isOk()) {
617 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
618 ret.getMessage());
619 mFirstTargetMetTimestamp = 0;
620 mLastTargetMetTimestamp = 0;
621 traceBatchSize(mActualWorkDurations.size());
622 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
623 }
Peiyong Lin70de0852023-10-25 21:12:35 +0000624 }
Matt Buckley854947f2024-02-07 17:30:01 +0000625
Peiyong Lin70de0852023-10-25 21:12:35 +0000626 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000627 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000628
629 return 0;
630}
Matt Buckley854947f2024-02-07 17:30:01 +0000631
632// ===================================== FMQ wrapper implementation
633
634bool FMQWrapper::isActive() {
635 std::scoped_lock lock{sHintMutex};
636 return isActiveLocked();
637}
638
639bool FMQWrapper::isActiveLocked() {
640 return mQueue != nullptr;
641}
642
643void FMQWrapper::setUnsupported() {
644 mHalSupported = false;
645}
646
647bool FMQWrapper::isSupported() {
648 if (!mHalSupported) {
649 return false;
650 }
651 // Used for testing
652 if (gForceFMQEnabled.has_value()) {
653 return *gForceFMQEnabled;
654 }
655 return android::os::adpf_use_fmq_channel_fixed();
656}
657
658bool FMQWrapper::startChannel(IHintManager* manager) {
Matt Buckley7aac2582024-10-18 11:22:12 -0700659 if (isSupported() && !isActive() && manager->isRemote()) {
660 mChannelCreationFinished = std::async(std::launch::async, [&, this, manager]() {
661 std::optional<hal::ChannelConfig> config;
662 auto ret = manager->getSessionChannel(mToken, &config);
663 if (ret.isOk() && config.has_value()) {
664 std::scoped_lock lock{sHintMutex};
665 mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
666 if (config->eventFlagDescriptor.has_value()) {
667 mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
668 android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
669 &mEventFlag);
670 mWriteMask = config->writeFlagBitmask;
671 }
672 updatePersistentTransaction();
673 } else if (ret.isOk() && !config.has_value()) {
674 ALOGV("FMQ channel enabled but unsupported.");
675 setUnsupported();
676 } else {
677 ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley854947f2024-02-07 17:30:01 +0000678 }
Matt Buckley7aac2582024-10-18 11:22:12 -0700679 return true;
680 });
Matt Buckley854947f2024-02-07 17:30:01 +0000681 }
682 return isActive();
683}
684
685void FMQWrapper::stopChannel(IHintManager* manager) {
686 {
687 std::scoped_lock lock{sHintMutex};
688 if (!isActiveLocked()) {
689 return;
690 }
691 mFlagQueue = nullptr;
692 mQueue = nullptr;
693 }
694 manager->closeSessionChannel();
695}
696
697template <HalChannelMessageContents::Tag T, class C>
Matt Buckley151f69f2024-10-21 09:27:06 -0700698void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) {
699 for (size_t i = 0; i < count; ++i) {
700 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
701 .sessionID = static_cast<int32_t>(config.id),
702 .timeStampNanos = now,
703 .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))),
704 };
705 }
Matt Buckley854947f2024-02-07 17:30:01 +0000706}
707
708template <>
709void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
710 hal::SessionConfig& config,
Matt Buckley151f69f2024-10-21 09:27:06 -0700711 size_t count, int64_t now) {
Matt Buckley854947f2024-02-07 17:30:01 +0000712 for (size_t i = 0; i < count; ++i) {
713 hal::WorkDuration& message = messages[i];
714 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
715 .sessionID = static_cast<int32_t>(config.id),
Matt Buckley151f69f2024-10-21 09:27:06 -0700716 .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos,
Matt Buckley854947f2024-02-07 17:30:01 +0000717 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
718 hal::WorkDurationFixedV1>({
719 .durationNanos = message.cpuDurationNanos,
720 .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
721 .cpuDurationNanos = message.cpuDurationNanos,
722 .gpuDurationNanos = message.gpuDurationNanos,
723 }),
724 };
725 }
726}
727
728template <HalChannelMessageContents::Tag T, bool urgent, class C>
Matt Buckley151f69f2024-10-21 09:27:06 -0700729bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count,
730 int64_t now) {
Matt Buckley854947f2024-02-07 17:30:01 +0000731 if (!isActiveLocked() || !config.has_value() || mCorrupted) {
732 return false;
733 }
734 // If we didn't reserve enough space, try re-creating the transaction
735 if (count > mAvailableSlots) {
736 if (!updatePersistentTransaction()) {
737 return false;
738 }
739 // If we actually don't have enough space, give up
740 if (count > mAvailableSlots) {
741 return false;
742 }
743 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700744 writeBuffer<T, C>(message, *config, count, now);
Matt Buckley854947f2024-02-07 17:30:01 +0000745 mQueue->commitWrite(count);
746 mEventFlag->wake(mWriteMask);
747 // Re-create the persistent transaction after writing
748 updatePersistentTransaction();
749 return true;
750}
751
752void FMQWrapper::setToken(ndk::SpAIBinder& token) {
753 mToken = token;
754}
755
756bool FMQWrapper::updatePersistentTransaction() {
757 mAvailableSlots = mQueue->availableToWrite();
758 if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
759 ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
760 mCorrupted = true;
761 return false;
762 }
763 return true;
764}
765
766bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
767 hal::WorkDuration* durations, size_t count) {
768 return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
769}
770
771bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
772 int64_t targetDurationNanos) {
773 return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
774}
775
Matt Buckley151f69f2024-10-21 09:27:06 -0700776bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config,
777 std::vector<hal::SessionHint>& hints, int64_t now) {
778 return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now);
Matt Buckley854947f2024-02-07 17:30:01 +0000779}
780
781bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
782 bool enabled) {
783 hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
784 .enabled = enabled};
785 return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
786}
787
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000788// ===================================== Tracing helpers
789
790void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
791 std::set<int32_t> tidSet{tids.begin(), tids.end()};
792
793 // Disable old TID tracing
794 for (int32_t tid : mLastThreadIDs) {
795 if (!tidSet.count(tid)) {
796 std::string traceName =
797 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
798 ATrace_setCounter(traceName.c_str(), 0);
799 }
800 }
801
802 // Add new TID tracing
803 for (int32_t tid : tids) {
804 std::string traceName =
805 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
806 ATrace_setCounter(traceName.c_str(), 1);
807 }
808
809 mLastThreadIDs = std::move(tids);
810}
811
812void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
813 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
814}
815
816void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
817 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
818}
819
820void APerformanceHintSession::traceBatchSize(size_t batchSize) {
821 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
822 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
823}
824
825void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
826 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
827}
Peiyong Lin70de0852023-10-25 21:12:35 +0000828
Bo Liu44267722021-07-16 17:03:20 -0400829// ===================================== C API
830APerformanceHintManager* APerformanceHint_getManager() {
831 return APerformanceHintManager::getInstance();
832}
833
Matt Buckley83f77092024-01-18 19:57:29 +0000834#define VALIDATE_PTR(ptr) \
835 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
836
837#define VALIDATE_INT(value, cmp) \
838 if (!(value cmp)) { \
839 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
840 __FUNCTION__, value); \
841 return EINVAL; \
842 }
843
844#define WARN_INT(value, cmp) \
845 if (!(value cmp)) { \
846 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
847 __FUNCTION__, value); \
848 }
849
Bo Liu44267722021-07-16 17:03:20 -0400850APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
851 const int32_t* threadIds, size_t size,
852 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000853 VALIDATE_PTR(manager)
854 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400855 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
856}
857
Matt Buckley27da1342024-04-05 23:10:48 +0000858APerformanceHintSession* APerformanceHint_createSessionInternal(
859 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
860 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
861 VALIDATE_PTR(manager)
862 VALIDATE_PTR(threadIds)
863 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
864 static_cast<hal::SessionTag>(tag));
865}
866
Matt Buckley87393822024-11-17 01:58:16 +0000867APerformanceHintSession* APerformanceHint_createSessionFromJava(
868 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
869 int64_t initialTargetWorkDurationNanos) {
870 VALIDATE_PTR(manager)
871 VALIDATE_PTR(threadIds)
872 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
873 hal::SessionTag::APP, true);
874}
875
876APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env,
877 jobject sessionObj) {
878 VALIDATE_PTR(env)
879 VALIDATE_PTR(sessionObj)
880 return APerformanceHintManager::getInstance()->getSessionFromJava(env, sessionObj);
881}
882
Bo Liu44267722021-07-16 17:03:20 -0400883int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000884 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400885 return manager->getPreferredRateNanos();
886}
887
888int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
889 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000890 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400891 return session->updateTargetWorkDuration(targetDurationNanos);
892}
893
894int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
895 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000896 VALIDATE_PTR(session)
897 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400898 return session->reportActualWorkDuration(actualDurationNanos);
899}
900
Bo Liu44267722021-07-16 17:03:20 -0400901void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000902 VALIDATE_PTR(session)
Matt Buckley87393822024-11-17 01:58:16 +0000903 if (session->isJava()) {
904 LOG_ALWAYS_FATAL("%s: Java-owned PerformanceHintSession cannot be closed in native",
905 __FUNCTION__);
906 return;
907 }
908 delete session;
909}
910
911void APerformanceHint_closeSessionFromJava(APerformanceHintSession* session) {
912 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400913 delete session;
914}
915
Matt Buckley27da1342024-04-05 23:10:48 +0000916int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +0000917 VALIDATE_PTR(session)
Matt Buckley151f69f2024-10-21 09:27:06 -0700918 std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)};
919 int64_t now = ::android::uptimeNanos();
920 return session->sendHints(hints, now, "HWUI hint");
Matt Buckley61726a32022-12-06 23:44:45 +0000921}
922
Peiyong Lin7ed6de32023-01-26 00:52:54 +0000923int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000924 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +0000925 VALIDATE_PTR(session)
926 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +0000927 return session->setThreads(threadIds, size);
928}
929
Matt Buckley27da1342024-04-05 23:10:48 +0000930int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +0000931 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +0000932 VALIDATE_PTR(session)
933 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +0000934}
935
Matt Buckley423c1b32023-06-28 19:13:42 +0000936int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +0000937 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +0000938 return session->setPreferPowerEfficiency(enabled);
939}
940
Peiyong Lin70de0852023-10-25 21:12:35 +0000941int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +0000942 AWorkDuration* workDurationPtr) {
943 VALIDATE_PTR(session)
944 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +0000945 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
946 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
947 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
948 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
949 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +0000950 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +0000951}
952
Matt Buckley151f69f2024-10-21 09:27:06 -0700953int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu,
954 const char* debugName) {
955 VALIDATE_PTR(session)
956 VALIDATE_PTR(debugName)
957 if (!useNewLoadHintBehavior()) {
958 return ENOTSUP;
959 }
960 return session->notifyWorkloadIncrease(cpu, gpu, debugName);
961}
962
963int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu,
964 const char* debugName) {
965 VALIDATE_PTR(session)
966 VALIDATE_PTR(debugName)
967 if (!useNewLoadHintBehavior()) {
968 return ENOTSUP;
969 }
970 return session->notifyWorkloadReset(cpu, gpu, debugName);
971}
972
Peiyong Lin70de0852023-10-25 21:12:35 +0000973AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +0000974 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +0000975}
976
977void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +0000978 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +0000979 delete aWorkDuration;
980}
981
Peiyong Lin70de0852023-10-25 21:12:35 +0000982void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
983 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000984 VALIDATE_PTR(aWorkDuration)
985 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +0000986 aWorkDuration->durationNanos = actualTotalDurationNanos;
987}
988
989void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
990 int64_t workPeriodStartTimestampNanos) {
991 VALIDATE_PTR(aWorkDuration)
992 WARN_INT(workPeriodStartTimestampNanos, > 0)
993 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +0000994}
995
996void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
997 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000998 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +0000999 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +00001000 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +00001001}
1002
1003void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
1004 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +00001005 VALIDATE_PTR(aWorkDuration)
1006 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +00001007 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +00001008}
1009
Bo Liu44267722021-07-16 17:03:20 -04001010void APerformanceHint_setIHintManagerForTesting(void* iManager) {
Matt Buckley854947f2024-02-07 17:30:01 +00001011 if (iManager == nullptr) {
1012 gHintManagerForTesting = nullptr;
1013 }
Matt Buckley58977722024-03-11 23:32:09 +00001014 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -04001015}
Matt Buckley854947f2024-02-07 17:30:01 +00001016
1017void APerformanceHint_setUseFMQForTesting(bool enabled) {
1018 gForceFMQEnabled = enabled;
1019}
Matt Buckley151f69f2024-10-21 09:27:06 -07001020
1021void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
1022 int64_t* loadHintInterval) {
1023 *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval;
1024 *loadHintInterval = kLoadHintInterval;
1025}
1026
1027void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
1028 kForceNewHintBehavior = newBehavior;
1029}