blob: 883e139cca0a727aef38c0272bb6a9f170f4a630 [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>
Andy Yudffd67c2024-10-16 14:05:35 -070029#include <aidl/android/os/SessionCreationConfig.h>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000030#include <android-base/stringprintf.h>
Matt Buckley053a1df2024-06-07 02:37:59 +000031#include <android-base/thread_annotations.h>
Matt Buckley58977722024-03-11 23:32:09 +000032#include <android/binder_manager.h>
33#include <android/binder_status.h>
Bo Liu2b739bb2021-11-10 19:20:03 -050034#include <android/performance_hint.h>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000035#include <android/trace.h>
Matt Buckley854947f2024-02-07 17:30:01 +000036#include <android_os.h>
Matt Buckley151f69f2024-10-21 09:27:06 -070037#include <cutils/trace.h>
Matt Buckley854947f2024-02-07 17:30:01 +000038#include <fmq/AidlMessageQueue.h>
Peiyong Lin70de0852023-10-25 21:12:35 +000039#include <inttypes.h>
Matt Buckley87393822024-11-17 01:58:16 +000040#include <jni_wrappers.h>
Bo Liu44267722021-07-16 17:03:20 -040041#include <performance_hint_private.h>
42#include <utils/SystemClock.h>
43
Matt Buckley56093a72022-11-07 21:50:50 +000044#include <chrono>
Matt Buckley151f69f2024-10-21 09:27:06 -070045#include <format>
Matt Buckley7aac2582024-10-18 11:22:12 -070046#include <future>
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000047#include <set>
Bo Liu2b739bb2021-11-10 19:20:03 -050048#include <utility>
49#include <vector>
50
Bo Liu44267722021-07-16 17:03:20 -040051using namespace android;
Matt Buckley58977722024-03-11 23:32:09 +000052using namespace aidl::android::os;
Bo Liu44267722021-07-16 17:03:20 -040053
Matt Buckley56093a72022-11-07 21:50:50 +000054using namespace std::chrono_literals;
55
Matt Buckley7c2de582024-04-05 08:41:35 +000056// Namespace for AIDL types coming from the PowerHAL
57namespace hal = aidl::android::hardware::power;
Matt Buckley58977722024-03-11 23:32:09 +000058
Matt Buckley854947f2024-02-07 17:30:01 +000059using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
60using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
61using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
62using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
Matt Buckleye3d5c3a2023-12-01 23:10:32 +000063using android::base::StringPrintf;
Matt Buckley56093a72022-11-07 21:50:50 +000064
Bo Liu44267722021-07-16 17:03:20 -040065struct APerformanceHintSession;
66
Matt Buckley56093a72022-11-07 21:50:50 +000067constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
Matt Buckley7c2de582024-04-05 08:41:35 +000068struct AWorkDuration : public hal::WorkDuration {};
Andy Yudffd67c2024-10-16 14:05:35 -070069struct ASessionCreationConfig : public SessionCreationConfig {};
70
71bool kForceGraphicsPipeline = false;
72
73bool useGraphicsPipeline() {
74 return android::os::adpf_graphics_pipeline() || kForceGraphicsPipeline;
75}
Matt Buckley56093a72022-11-07 21:50:50 +000076
Matt Buckley151f69f2024-10-21 09:27:06 -070077// A pair of values that determine the behavior of the
78// load hint rate limiter, to only allow "X hints every Y seconds"
79constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count();
80constexpr double kMaxLoadHintsPerInterval = 20;
81constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval;
82bool kForceNewHintBehavior = false;
83
84template <class T>
85constexpr int32_t enum_size() {
86 return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
87}
88
89bool useNewLoadHintBehavior() {
90 return android::os::adpf_use_load_hints() || kForceNewHintBehavior;
91}
92
Matt Buckley1f5b95f2024-06-07 02:36:56 +000093// Shared lock for the whole PerformanceHintManager and sessions
94static std::mutex sHintMutex = std::mutex{};
Matt Buckley854947f2024-02-07 17:30:01 +000095class FMQWrapper {
96public:
97 bool isActive();
98 bool isSupported();
99 bool startChannel(IHintManager* manager);
100 void stopChannel(IHintManager* manager);
101 // Number of elements the FMQ can hold
102 bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
103 hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
104 bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
105 int64_t targetDurationNanos) REQUIRES(sHintMutex);
Matt Buckley151f69f2024-10-21 09:27:06 -0700106 bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint,
107 int64_t now) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000108 bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
109 REQUIRES(sHintMutex);
110 void setToken(ndk::SpAIBinder& token);
111 void attemptWake();
112 void setUnsupported();
113
114private:
115 template <HalChannelMessageContents::Tag T, bool urgent = false,
116 class C = HalChannelMessageContents::_at<T>>
Matt Buckley151f69f2024-10-21 09:27:06 -0700117 bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1,
118 int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000119 template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
Matt Buckley151f69f2024-10-21 09:27:06 -0700120 void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now)
121 REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000122
123 bool isActiveLocked() REQUIRES(sHintMutex);
124 bool updatePersistentTransaction() REQUIRES(sHintMutex);
125 std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
126 std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
127 // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
128 android::hardware::EventFlag* mEventFlag = nullptr;
129 int32_t mWriteMask;
130 ndk::SpAIBinder mToken = nullptr;
131 // Used to track if operating on the fmq consistently fails
132 bool mCorrupted = false;
133 // Used to keep a persistent transaction open with FMQ to reduce latency a bit
134 size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
135 bool mHalSupported = true;
136 HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
Matt Buckley7aac2582024-10-18 11:22:12 -0700137 std::future<bool> mChannelCreationFinished;
Matt Buckley854947f2024-02-07 17:30:01 +0000138};
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000139
Bo Liu44267722021-07-16 17:03:20 -0400140struct APerformanceHintManager {
141public:
142 static APerformanceHintManager* getInstance();
Matt Buckley854947f2024-02-07 17:30:01 +0000143 APerformanceHintManager(std::shared_ptr<IHintManager>& service, int64_t preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400144 APerformanceHintManager() = delete;
Matt Buckley854947f2024-02-07 17:30:01 +0000145 ~APerformanceHintManager();
Bo Liu44267722021-07-16 17:03:20 -0400146
147 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
Matt Buckleye073c732024-04-05 22:32:31 +0000148 int64_t initialTargetWorkDurationNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000149 hal::SessionTag tag = hal::SessionTag::APP,
150 bool isJava = false);
151 APerformanceHintSession* getSessionFromJava(JNIEnv* _Nonnull env, jobject _Nonnull sessionObj);
152
Andy Yudffd67c2024-10-16 14:05:35 -0700153 APerformanceHintSession* createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
154 hal::SessionTag tag = hal::SessionTag::APP,
155 bool isJava = false);
Bo Liu44267722021-07-16 17:03:20 -0400156 int64_t getPreferredRateNanos() const;
Andy Yudffd67c2024-10-16 14:05:35 -0700157 int32_t getMaxGraphicsPipelineThreadsCount();
Matt Buckley854947f2024-02-07 17:30:01 +0000158 FMQWrapper& getFMQWrapper();
Matt Buckley151f69f2024-10-21 09:27:06 -0700159 bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
Matt Buckley87393822024-11-17 01:58:16 +0000160 void initJava(JNIEnv* _Nonnull env);
Bo Liu44267722021-07-16 17:03:20 -0400161
162private:
Matt Buckley58977722024-03-11 23:32:09 +0000163 // Necessary to create an empty binder object
164 static void* tokenStubOnCreate(void*) {
165 return nullptr;
166 }
167 static void tokenStubOnDestroy(void*) {}
168 static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
169 AParcel*) {
170 return STATUS_OK;
171 }
Bo Liu44267722021-07-16 17:03:20 -0400172
Matt Buckley58977722024-03-11 23:32:09 +0000173 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
174
175 std::shared_ptr<IHintManager> mHintManager;
176 ndk::SpAIBinder mToken;
Bo Liu44267722021-07-16 17:03:20 -0400177 const int64_t mPreferredRateNanos;
Andy Yudffd67c2024-10-16 14:05:35 -0700178 std::optional<int32_t> mMaxGraphicsPipelineThreadsCount;
Matt Buckley854947f2024-02-07 17:30:01 +0000179 FMQWrapper mFMQWrapper;
Matt Buckley151f69f2024-10-21 09:27:06 -0700180 double mHintBudget = kMaxLoadHintsPerInterval;
181 int64_t mLastBudgetReplenish = 0;
Matt Buckley87393822024-11-17 01:58:16 +0000182 bool mJavaInitialized = false;
183 jclass mJavaSessionClazz;
184 jfieldID mJavaSessionNativePtr;
Bo Liu44267722021-07-16 17:03:20 -0400185};
186
187struct APerformanceHintSession {
188public:
Matt Buckley58977722024-03-11 23:32:09 +0000189 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
190 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000191 int64_t targetDurationNanos, bool isJava,
Matt Buckleye073c732024-04-05 22:32:31 +0000192 std::optional<hal::SessionConfig> sessionConfig);
Bo Liu44267722021-07-16 17:03:20 -0400193 APerformanceHintSession() = delete;
194 ~APerformanceHintSession();
195
196 int updateTargetWorkDuration(int64_t targetDurationNanos);
197 int reportActualWorkDuration(int64_t actualDurationNanos);
Matt Buckley151f69f2024-10-21 09:27:06 -0700198 int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName);
199 int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName);
200 int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName);
Peiyong Lin095de762022-11-11 18:28:12 +0000201 int setThreads(const int32_t* threadIds, size_t size);
202 int getThreadIds(int32_t* const threadIds, size_t* size);
Matt Buckley423c1b32023-06-28 19:13:42 +0000203 int setPreferPowerEfficiency(bool enabled);
Peiyong Lin70de0852023-10-25 21:12:35 +0000204 int reportActualWorkDuration(AWorkDuration* workDuration);
Matt Buckley87393822024-11-17 01:58:16 +0000205 bool isJava();
Bo Liu44267722021-07-16 17:03:20 -0400206
207private:
208 friend struct APerformanceHintManager;
209
Matt Buckley58977722024-03-11 23:32:09 +0000210 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
Peiyong Lin70de0852023-10-25 21:12:35 +0000211
Matt Buckley58977722024-03-11 23:32:09 +0000212 std::shared_ptr<IHintManager> mHintManager;
213 std::shared_ptr<IHintSession> mHintSession;
Bo Liu44267722021-07-16 17:03:20 -0400214 // HAL preferred update rate
215 const int64_t mPreferredRateNanos;
216 // Target duration for choosing update rate
Matt Buckley053a1df2024-06-07 02:37:59 +0000217 int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700218 // First target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000219 int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
Wei Wang00feb502022-10-18 10:56:59 -0700220 // Last target hit timestamp
Matt Buckley053a1df2024-06-07 02:37:59 +0000221 int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
Matt Buckley56093a72022-11-07 21:50:50 +0000222 // Last hint reported from sendHint indexed by hint value
Matt Buckley151f69f2024-10-21 09:27:06 -0700223 // This is only used by the old rate limiter impl and is replaced
224 // with the new rate limiter under a flag
Matt Buckley053a1df2024-06-07 02:37:59 +0000225 std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
Bo Liu44267722021-07-16 17:03:20 -0400226 // Cached samples
Matt Buckley053a1df2024-06-07 02:37:59 +0000227 std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
Matt Buckley87393822024-11-17 01:58:16 +0000228 // Is this session backing an SDK wrapper object
229 const bool mIsJava;
Matt Buckley854947f2024-02-07 17:30:01 +0000230 std::string mSessionName;
Matt Buckley053a1df2024-06-07 02:37:59 +0000231 static int64_t sIDCounter GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000232 // The most recent set of thread IDs
Matt Buckley053a1df2024-06-07 02:37:59 +0000233 std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
234 std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000235 // Tracing helpers
Andy Yudffd67c2024-10-16 14:05:35 -0700236 void traceThreads(const std::vector<int32_t>& tids) REQUIRES(sHintMutex);
Matt Buckley854947f2024-02-07 17:30:01 +0000237 void tracePowerEfficient(bool powerEfficient);
Andy Yudffd67c2024-10-16 14:05:35 -0700238 void traceGraphicsPipeline(bool graphicsPipeline);
239 void traceModes(const std::vector<hal::SessionMode>& modesToEnable);
Matt Buckley854947f2024-02-07 17:30:01 +0000240 void traceActualDuration(int64_t actualDuration);
241 void traceBatchSize(size_t batchSize);
242 void traceTargetDuration(int64_t targetDuration);
Bo Liu44267722021-07-16 17:03:20 -0400243};
244
Matt Buckley58977722024-03-11 23:32:09 +0000245static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000246static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
247
248static std::optional<bool> gForceFMQEnabled = std::nullopt;
249
Matt Buckleye073c732024-04-05 22:32:31 +0000250// Start above the int32 range so we don't collide with config sessions
251int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
Bo Liu44267722021-07-16 17:03:20 -0400252
Matt Buckley854947f2024-02-07 17:30:01 +0000253static FMQWrapper& getFMQ() {
254 return APerformanceHintManager::getInstance()->getFMQWrapper();
255}
256
Bo Liu44267722021-07-16 17:03:20 -0400257// ===================================== APerformanceHintManager implementation
Matt Buckley854947f2024-02-07 17:30:01 +0000258APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
Bo Liu44267722021-07-16 17:03:20 -0400259 int64_t preferredRateNanos)
Matt Buckley58977722024-03-11 23:32:09 +0000260 : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
261 static AIBinder_Class* tokenBinderClass =
262 AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
263 tokenStubOnTransact);
264 mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
Matt Buckley854947f2024-02-07 17:30:01 +0000265 if (mFMQWrapper.isSupported()) {
266 mFMQWrapper.setToken(mToken);
267 mFMQWrapper.startChannel(mHintManager.get());
268 }
269}
270
271APerformanceHintManager::~APerformanceHintManager() {
272 mFMQWrapper.stopChannel(mHintManager.get());
Matt Buckley58977722024-03-11 23:32:09 +0000273}
Bo Liu44267722021-07-16 17:03:20 -0400274
275APerformanceHintManager* APerformanceHintManager::getInstance() {
Matt Buckley7aac2582024-10-18 11:22:12 -0700276 static std::once_flag creationFlag;
277 static APerformanceHintManager* instance = nullptr;
Matt Buckley854947f2024-02-07 17:30:01 +0000278 if (gHintManagerForTesting) {
279 return gHintManagerForTesting.get();
280 }
Bo Liu44267722021-07-16 17:03:20 -0400281 if (gIHintManagerForTesting) {
Matt Buckley854947f2024-02-07 17:30:01 +0000282 gHintManagerForTesting =
283 std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
284 return gHintManagerForTesting.get();
Bo Liu44267722021-07-16 17:03:20 -0400285 }
Matt Buckley7aac2582024-10-18 11:22:12 -0700286 std::call_once(creationFlag, []() { instance = create(nullptr); });
Bo Liu44267722021-07-16 17:03:20 -0400287 return instance;
288}
289
Matt Buckley58977722024-03-11 23:32:09 +0000290APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
Bo Liu44267722021-07-16 17:03:20 -0400291 if (!manager) {
Matt Buckley58977722024-03-11 23:32:09 +0000292 manager = IHintManager::fromBinder(
293 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
Bo Liu44267722021-07-16 17:03:20 -0400294 }
295 if (manager == nullptr) {
296 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
297 return nullptr;
298 }
299 int64_t preferredRateNanos = -1L;
Matt Buckley58977722024-03-11 23:32:09 +0000300 ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400301 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000302 ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400303 return nullptr;
304 }
305 if (preferredRateNanos <= 0) {
Bo Liud6a09602021-07-26 14:48:41 -0400306 preferredRateNanos = -1L;
Bo Liu44267722021-07-16 17:03:20 -0400307 }
Matt Buckley854947f2024-02-07 17:30:01 +0000308 return new APerformanceHintManager(manager, preferredRateNanos);
Bo Liu44267722021-07-16 17:03:20 -0400309}
310
Matt Buckley151f69f2024-10-21 09:27:06 -0700311bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
312 mHintBudget =
313 std::max(kMaxLoadHintsPerInterval,
314 mHintBudget +
315 static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate);
316 mLastBudgetReplenish = now;
317
318 // If this youngest timestamp isn't older than the timeout time, we can't send
319 if (hints.size() > mHintBudget) {
320 return false;
321 }
322 mHintBudget -= hints.size();
323 return true;
324}
325
Bo Liu44267722021-07-16 17:03:20 -0400326APerformanceHintSession* APerformanceHintManager::createSession(
Matt Buckleye073c732024-04-05 22:32:31 +0000327 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000328 hal::SessionTag tag, bool isJava) {
Matt Buckleye073c732024-04-05 22:32:31 +0000329 ndk::ScopedAStatus ret;
Matt Buckley854947f2024-02-07 17:30:01 +0000330 hal::SessionConfig sessionConfig{.id = -1};
Andy Yudffd67c2024-10-16 14:05:35 -0700331
332 SessionCreationConfig creationConfig{
333 .tids = std::vector<int32_t>(threadIds, threadIds + size),
334 .targetWorkDurationNanos = initialTargetWorkDurationNanos,
335 };
336
337 return APerformanceHintManager::createSessionUsingConfig(static_cast<ASessionCreationConfig*>(
338 &creationConfig),
339 tag, isJava);
340}
341
342APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
343 ASessionCreationConfig* sessionCreationConfig, hal::SessionTag tag, bool isJava) {
344 std::shared_ptr<IHintSession> session;
345 hal::SessionConfig sessionConfig{.id = -1};
346 ndk::ScopedAStatus ret;
347
348 ret = mHintManager->createHintSessionWithConfig(mToken, tag,
349 *static_cast<SessionCreationConfig*>(
350 sessionCreationConfig),
351 &sessionConfig, &session);
Matt Buckleye073c732024-04-05 22:32:31 +0000352
Bo Liu44267722021-07-16 17:03:20 -0400353 if (!ret.isOk() || !session) {
Matt Buckley854947f2024-02-07 17:30:01 +0000354 ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400355 return nullptr;
356 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000357 auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
Andy Yudffd67c2024-10-16 14:05:35 -0700358 sessionCreationConfig->targetWorkDurationNanos, isJava,
Matt Buckley854947f2024-02-07 17:30:01 +0000359 sessionConfig.id == -1
360 ? std::nullopt
361 : std::make_optional<hal::SessionConfig>(
362 std::move(sessionConfig)));
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000363 std::scoped_lock lock(sHintMutex);
Andy Yudffd67c2024-10-16 14:05:35 -0700364 out->traceThreads(sessionCreationConfig->tids);
365 out->traceTargetDuration(sessionCreationConfig->targetWorkDurationNanos);
366 out->traceModes(sessionCreationConfig->modesToEnable);
367
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000368 return out;
Bo Liu44267722021-07-16 17:03:20 -0400369}
370
Matt Buckley87393822024-11-17 01:58:16 +0000371APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env,
372 jobject sessionObj) {
373 initJava(env);
374 LOG_ALWAYS_FATAL_IF(!env->IsInstanceOf(sessionObj, mJavaSessionClazz),
375 "Wrong java type passed to APerformanceHint_getSessionFromJava");
376 APerformanceHintSession* out = reinterpret_cast<APerformanceHintSession*>(
377 env->GetLongField(sessionObj, mJavaSessionNativePtr));
378 LOG_ALWAYS_FATAL_IF(out == nullptr, "Java-wrapped native hint session is nullptr");
379 LOG_ALWAYS_FATAL_IF(!out->isJava(), "Unmanaged native hint session returned from Java SDK");
380 return out;
381}
382
Bo Liu44267722021-07-16 17:03:20 -0400383int64_t APerformanceHintManager::getPreferredRateNanos() const {
384 return mPreferredRateNanos;
385}
386
Andy Yudffd67c2024-10-16 14:05:35 -0700387int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() {
388 if (!mMaxGraphicsPipelineThreadsCount.has_value()) {
389 int32_t threadsCount = -1;
390 ndk::ScopedAStatus ret = mHintManager->getMaxGraphicsPipelineThreadsCount(&threadsCount);
391 if (!ret.isOk()) {
392 ALOGE("%s: PerformanceHint cannot get max graphics pipeline threads count. %s",
393 __FUNCTION__, ret.getMessage());
394 return -1;
395 }
396 if (threadsCount <= 0) {
397 threadsCount = -1;
398 }
399 mMaxGraphicsPipelineThreadsCount.emplace(threadsCount);
400 }
401 return mMaxGraphicsPipelineThreadsCount.value();
402}
403
Matt Buckley854947f2024-02-07 17:30:01 +0000404FMQWrapper& APerformanceHintManager::getFMQWrapper() {
405 return mFMQWrapper;
406}
407
Matt Buckley87393822024-11-17 01:58:16 +0000408void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) {
409 if (mJavaInitialized) {
410 return;
411 }
412 jclass sessionClazz = FindClassOrDie(env, "android/os/PerformanceHintManager$Session");
413 mJavaSessionClazz = MakeGlobalRefOrDie(env, sessionClazz);
414 mJavaSessionNativePtr = GetFieldIDOrDie(env, mJavaSessionClazz, "mNativeSessionPtr", "J");
415 mJavaInitialized = true;
416}
417
Bo Liu44267722021-07-16 17:03:20 -0400418// ===================================== APerformanceHintSession implementation
419
Matt Buckley151f69f2024-10-21 09:27:06 -0700420constexpr int kNumEnums = enum_size<hal::SessionHint>();
Matt Buckley58977722024-03-11 23:32:09 +0000421APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
422 std::shared_ptr<IHintSession> session,
Bo Liu44267722021-07-16 17:03:20 -0400423 int64_t preferredRateNanos,
Matt Buckley87393822024-11-17 01:58:16 +0000424 int64_t targetDurationNanos, bool isJava,
Matt Buckleye073c732024-04-05 22:32:31 +0000425 std::optional<hal::SessionConfig> sessionConfig)
Peiyong Lin095de762022-11-11 18:28:12 +0000426 : mHintManager(hintManager),
427 mHintSession(std::move(session)),
Bo Liu44267722021-07-16 17:03:20 -0400428 mPreferredRateNanos(preferredRateNanos),
429 mTargetDurationNanos(targetDurationNanos),
Wei Wang00feb502022-10-18 10:56:59 -0700430 mFirstTargetMetTimestamp(0),
Matt Buckleye073c732024-04-05 22:32:31 +0000431 mLastTargetMetTimestamp(0),
Matt Buckley854947f2024-02-07 17:30:01 +0000432 mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
Matt Buckley87393822024-11-17 01:58:16 +0000433 mIsJava(isJava),
Matt Buckleye073c732024-04-05 22:32:31 +0000434 mSessionConfig(sessionConfig) {
435 if (sessionConfig->id > INT32_MAX) {
436 ALOGE("Session ID too large, must fit 32-bit integer");
437 }
Matt Buckleye073c732024-04-05 22:32:31 +0000438 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
439 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
Matt Buckley56093a72022-11-07 21:50:50 +0000440}
Bo Liu44267722021-07-16 17:03:20 -0400441
442APerformanceHintSession::~APerformanceHintSession() {
Matt Buckley58977722024-03-11 23:32:09 +0000443 ndk::ScopedAStatus ret = mHintSession->close();
Bo Liu44267722021-07-16 17:03:20 -0400444 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000445 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
Bo Liu44267722021-07-16 17:03:20 -0400446 }
447}
448
449int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
450 if (targetDurationNanos <= 0) {
451 ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
452 return EINVAL;
453 }
Matt Buckley854947f2024-02-07 17:30:01 +0000454 std::scoped_lock lock(sHintMutex);
455 if (mTargetDurationNanos == targetDurationNanos) {
456 return 0;
457 }
458 if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
459 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
460 if (!ret.isOk()) {
461 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
462 ret.getMessage());
463 return EPIPE;
Xiang Wange16ad282024-06-26 14:31:34 -0700464 }
465 }
Bo Liu44267722021-07-16 17:03:20 -0400466 mTargetDurationNanos = targetDurationNanos;
467 /**
468 * Most of the workload is target_duration dependent, so now clear the cached samples
469 * as they are most likely obsolete.
470 */
Peiyong Lin70de0852023-10-25 21:12:35 +0000471 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000472 traceBatchSize(0);
473 traceTargetDuration(targetDurationNanos);
Wei Wang00feb502022-10-18 10:56:59 -0700474 mFirstTargetMetTimestamp = 0;
475 mLastTargetMetTimestamp = 0;
Bo Liu44267722021-07-16 17:03:20 -0400476 return 0;
477}
478
479int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
Matt Buckley7c2de582024-04-05 08:41:35 +0000480 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
481 .workPeriodStartTimestampNanos = 0,
482 .cpuDurationNanos = actualDurationNanos,
483 .gpuDurationNanos = 0};
Bo Liu44267722021-07-16 17:03:20 -0400484
Matt Buckley58977722024-03-11 23:32:09 +0000485 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
Bo Liu44267722021-07-16 17:03:20 -0400486}
487
Matt Buckley87393822024-11-17 01:58:16 +0000488bool APerformanceHintSession::isJava() {
489 return mIsJava;
490}
491
Matt Buckley151f69f2024-10-21 09:27:06 -0700492int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
493 const char*) {
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000494 std::scoped_lock lock(sHintMutex);
Matt Buckley151f69f2024-10-21 09:27:06 -0700495 if (hints.empty()) {
Matt Buckley354cc0a2022-09-28 20:54:46 +0000496 return EINVAL;
497 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700498 for (auto&& hint : hints) {
499 if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) {
500 ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
501 return EINVAL;
Matt Buckley854947f2024-02-07 17:30:01 +0000502 }
Matt Buckley354cc0a2022-09-28 20:54:46 +0000503 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700504
505 if (useNewLoadHintBehavior()) {
506 if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) {
507 return EBUSY;
508 }
509 }
510 // keep old rate limiter behavior for legacy flag
511 else {
512 for (auto&& hint : hints) {
513 if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) {
514 return EBUSY;
515 }
516 }
517 }
518
519 if (!getFMQ().sendHints(mSessionConfig, hints, now)) {
520 for (auto&& hint : hints) {
521 ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint));
522
523 if (!ret.isOk()) {
524 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
525 return EPIPE;
526 }
527 }
528 }
529
530 if (!useNewLoadHintBehavior()) {
531 for (auto&& hint : hints) {
532 mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now;
533 }
534 }
535
536 if (ATrace_isEnabled()) {
537 ATRACE_INSTANT("Sending load hint");
538 }
539
Matt Buckley354cc0a2022-09-28 20:54:46 +0000540 return 0;
541}
542
Matt Buckley151f69f2024-10-21 09:27:06 -0700543int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) {
544 std::vector<hal::SessionHint> hints(2);
545 hints.clear();
546 if (cpu) {
547 hints.push_back(hal::SessionHint::CPU_LOAD_UP);
548 }
549 if (gpu) {
550 hints.push_back(hal::SessionHint::GPU_LOAD_UP);
551 }
552 int64_t now = ::android::uptimeNanos();
553 return sendHints(hints, now, debugName);
554}
555
556int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) {
557 std::vector<hal::SessionHint> hints(2);
558 hints.clear();
559 if (cpu) {
560 hints.push_back(hal::SessionHint::CPU_LOAD_RESET);
561 }
562 if (gpu) {
563 hints.push_back(hal::SessionHint::GPU_LOAD_RESET);
564 }
565 int64_t now = ::android::uptimeNanos();
566 return sendHints(hints, now, debugName);
567}
568
Peiyong Lin095de762022-11-11 18:28:12 +0000569int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
570 if (size == 0) {
571 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
572 return EINVAL;
573 }
574 std::vector<int32_t> tids(threadIds, threadIds + size);
Matt Buckley58977722024-03-11 23:32:09 +0000575 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000576 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000577 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
578 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
Peiyong Lin095de762022-11-11 18:28:12 +0000579 return EINVAL;
Matt Buckley58977722024-03-11 23:32:09 +0000580 } else if (ret.getExceptionCode() == EX_SECURITY) {
Xiang Wangbee6f162023-07-18 17:58:10 -0700581 return EPERM;
Peiyong Lin095de762022-11-11 18:28:12 +0000582 }
583 return EPIPE;
584 }
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000585
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000586 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000587 traceThreads(tids);
588
Peiyong Lin095de762022-11-11 18:28:12 +0000589 return 0;
590}
591
592int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
593 std::vector<int32_t> tids;
Matt Buckley58977722024-03-11 23:32:09 +0000594 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
Peiyong Lin095de762022-11-11 18:28:12 +0000595 if (!ret.isOk()) {
Matt Buckley58977722024-03-11 23:32:09 +0000596 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
Peiyong Lin095de762022-11-11 18:28:12 +0000597 return EPIPE;
598 }
599
600 // When threadIds is nullptr, this is the first call to determine the size
601 // of the thread ids list.
602 if (threadIds == nullptr) {
603 *size = tids.size();
604 return 0;
605 }
606
607 // Second call to return the actual list of thread ids.
608 *size = tids.size();
609 for (size_t i = 0; i < *size; ++i) {
610 threadIds[i] = tids[i];
611 }
612 return 0;
613}
614
Matt Buckley423c1b32023-06-28 19:13:42 +0000615int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
Matt Buckley58977722024-03-11 23:32:09 +0000616 ndk::ScopedAStatus ret =
Matt Buckley7c2de582024-04-05 08:41:35 +0000617 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
618 enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000619
620 if (!ret.isOk()) {
621 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
Matt Buckley58977722024-03-11 23:32:09 +0000622 ret.getMessage());
Matt Buckley423c1b32023-06-28 19:13:42 +0000623 return EPIPE;
624 }
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000625 std::scoped_lock lock(sHintMutex);
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000626 tracePowerEfficient(enabled);
Matt Buckley423c1b32023-06-28 19:13:42 +0000627 return OK;
628}
629
Matt Buckley58977722024-03-11 23:32:09 +0000630int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
Peiyong Lin70de0852023-10-25 21:12:35 +0000631 return reportActualWorkDurationInternal(workDuration);
632}
633
Matt Buckley58977722024-03-11 23:32:09 +0000634int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
635 int64_t actualTotalDurationNanos = workDuration->durationNanos;
Matt Buckley854947f2024-02-07 17:30:01 +0000636 traceActualDuration(workDuration->durationNanos);
Peiyong Lin70de0852023-10-25 21:12:35 +0000637 int64_t now = uptimeNanos();
Matt Buckley58977722024-03-11 23:32:09 +0000638 workDuration->timeStampNanos = now;
Matt Buckley1f5b95f2024-06-07 02:36:56 +0000639 std::scoped_lock lock(sHintMutex);
Peiyong Lin70de0852023-10-25 21:12:35 +0000640 mActualWorkDurations.push_back(std::move(*workDuration));
641
642 if (actualTotalDurationNanos >= mTargetDurationNanos) {
643 // Reset timestamps if we are equal or over the target.
644 mFirstTargetMetTimestamp = 0;
645 } else {
646 // Set mFirstTargetMetTimestamp for first time meeting target.
647 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
648 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
649 mFirstTargetMetTimestamp = now;
650 }
651 /**
652 * Rate limit the change if the update is over mPreferredRateNanos since first
653 * meeting target and less than mPreferredRateNanos since last meeting target.
654 */
655 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
656 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000657 traceBatchSize(mActualWorkDurations.size());
Peiyong Lin70de0852023-10-25 21:12:35 +0000658 return 0;
659 }
660 mLastTargetMetTimestamp = now;
661 }
662
Matt Buckley854947f2024-02-07 17:30:01 +0000663 if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
664 mActualWorkDurations.size())) {
665 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
666 if (!ret.isOk()) {
667 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
668 ret.getMessage());
669 mFirstTargetMetTimestamp = 0;
670 mLastTargetMetTimestamp = 0;
671 traceBatchSize(mActualWorkDurations.size());
672 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
673 }
Peiyong Lin70de0852023-10-25 21:12:35 +0000674 }
Matt Buckley854947f2024-02-07 17:30:01 +0000675
Peiyong Lin70de0852023-10-25 21:12:35 +0000676 mActualWorkDurations.clear();
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000677 traceBatchSize(0);
Peiyong Lin70de0852023-10-25 21:12:35 +0000678
679 return 0;
680}
Matt Buckley854947f2024-02-07 17:30:01 +0000681
682// ===================================== FMQ wrapper implementation
683
684bool FMQWrapper::isActive() {
685 std::scoped_lock lock{sHintMutex};
686 return isActiveLocked();
687}
688
689bool FMQWrapper::isActiveLocked() {
690 return mQueue != nullptr;
691}
692
693void FMQWrapper::setUnsupported() {
694 mHalSupported = false;
695}
696
697bool FMQWrapper::isSupported() {
698 if (!mHalSupported) {
699 return false;
700 }
701 // Used for testing
702 if (gForceFMQEnabled.has_value()) {
703 return *gForceFMQEnabled;
704 }
705 return android::os::adpf_use_fmq_channel_fixed();
706}
707
708bool FMQWrapper::startChannel(IHintManager* manager) {
Matt Buckley7aac2582024-10-18 11:22:12 -0700709 if (isSupported() && !isActive() && manager->isRemote()) {
710 mChannelCreationFinished = std::async(std::launch::async, [&, this, manager]() {
711 std::optional<hal::ChannelConfig> config;
712 auto ret = manager->getSessionChannel(mToken, &config);
713 if (ret.isOk() && config.has_value()) {
714 std::scoped_lock lock{sHintMutex};
715 mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
716 if (config->eventFlagDescriptor.has_value()) {
717 mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
718 android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
719 &mEventFlag);
720 mWriteMask = config->writeFlagBitmask;
721 }
722 updatePersistentTransaction();
723 } else if (ret.isOk() && !config.has_value()) {
724 ALOGV("FMQ channel enabled but unsupported.");
725 setUnsupported();
726 } else {
727 ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
Matt Buckley854947f2024-02-07 17:30:01 +0000728 }
Matt Buckley7aac2582024-10-18 11:22:12 -0700729 return true;
730 });
Matt Buckley854947f2024-02-07 17:30:01 +0000731 }
732 return isActive();
733}
734
735void FMQWrapper::stopChannel(IHintManager* manager) {
736 {
737 std::scoped_lock lock{sHintMutex};
738 if (!isActiveLocked()) {
739 return;
740 }
741 mFlagQueue = nullptr;
742 mQueue = nullptr;
743 }
744 manager->closeSessionChannel();
745}
746
747template <HalChannelMessageContents::Tag T, class C>
Matt Buckley151f69f2024-10-21 09:27:06 -0700748void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) {
749 for (size_t i = 0; i < count; ++i) {
750 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
751 .sessionID = static_cast<int32_t>(config.id),
752 .timeStampNanos = now,
753 .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))),
754 };
755 }
Matt Buckley854947f2024-02-07 17:30:01 +0000756}
757
758template <>
759void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
760 hal::SessionConfig& config,
Matt Buckley151f69f2024-10-21 09:27:06 -0700761 size_t count, int64_t now) {
Matt Buckley854947f2024-02-07 17:30:01 +0000762 for (size_t i = 0; i < count; ++i) {
763 hal::WorkDuration& message = messages[i];
764 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
765 .sessionID = static_cast<int32_t>(config.id),
Matt Buckley151f69f2024-10-21 09:27:06 -0700766 .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos,
Matt Buckley854947f2024-02-07 17:30:01 +0000767 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
768 hal::WorkDurationFixedV1>({
769 .durationNanos = message.cpuDurationNanos,
770 .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
771 .cpuDurationNanos = message.cpuDurationNanos,
772 .gpuDurationNanos = message.gpuDurationNanos,
773 }),
774 };
775 }
776}
777
778template <HalChannelMessageContents::Tag T, bool urgent, class C>
Matt Buckley151f69f2024-10-21 09:27:06 -0700779bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count,
780 int64_t now) {
Matt Buckley854947f2024-02-07 17:30:01 +0000781 if (!isActiveLocked() || !config.has_value() || mCorrupted) {
782 return false;
783 }
784 // If we didn't reserve enough space, try re-creating the transaction
785 if (count > mAvailableSlots) {
786 if (!updatePersistentTransaction()) {
787 return false;
788 }
789 // If we actually don't have enough space, give up
790 if (count > mAvailableSlots) {
791 return false;
792 }
793 }
Matt Buckley151f69f2024-10-21 09:27:06 -0700794 writeBuffer<T, C>(message, *config, count, now);
Matt Buckley854947f2024-02-07 17:30:01 +0000795 mQueue->commitWrite(count);
796 mEventFlag->wake(mWriteMask);
797 // Re-create the persistent transaction after writing
798 updatePersistentTransaction();
799 return true;
800}
801
802void FMQWrapper::setToken(ndk::SpAIBinder& token) {
803 mToken = token;
804}
805
806bool FMQWrapper::updatePersistentTransaction() {
807 mAvailableSlots = mQueue->availableToWrite();
808 if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
809 ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
810 mCorrupted = true;
811 return false;
812 }
813 return true;
814}
815
816bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
817 hal::WorkDuration* durations, size_t count) {
818 return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
819}
820
821bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
822 int64_t targetDurationNanos) {
823 return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
824}
825
Matt Buckley151f69f2024-10-21 09:27:06 -0700826bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config,
827 std::vector<hal::SessionHint>& hints, int64_t now) {
828 return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now);
Matt Buckley854947f2024-02-07 17:30:01 +0000829}
830
831bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
832 bool enabled) {
833 hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
834 .enabled = enabled};
835 return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
836}
837
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000838// ===================================== Tracing helpers
839
Andy Yudffd67c2024-10-16 14:05:35 -0700840void APerformanceHintSession::traceThreads(const std::vector<int32_t>& tids) {
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000841 std::set<int32_t> tidSet{tids.begin(), tids.end()};
842
843 // Disable old TID tracing
844 for (int32_t tid : mLastThreadIDs) {
845 if (!tidSet.count(tid)) {
846 std::string traceName =
847 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
848 ATrace_setCounter(traceName.c_str(), 0);
849 }
850 }
851
852 // Add new TID tracing
853 for (int32_t tid : tids) {
854 std::string traceName =
855 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
856 ATrace_setCounter(traceName.c_str(), 1);
857 }
858
859 mLastThreadIDs = std::move(tids);
860}
861
862void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
863 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
864}
865
Andy Yudffd67c2024-10-16 14:05:35 -0700866void APerformanceHintSession::traceGraphicsPipeline(bool graphicsPipeline) {
867 ATrace_setCounter((mSessionName + " graphics pipeline mode").c_str(), graphicsPipeline);
868}
869
870void APerformanceHintSession::traceModes(const std::vector<hal::SessionMode>& modesToEnable) {
871 // Iterate through all modes to trace, set to enable for all modes in modesToEnable,
872 // and set to disable for those are not.
873 for (hal::SessionMode mode :
874 {hal::SessionMode::POWER_EFFICIENCY, hal::SessionMode::GRAPHICS_PIPELINE}) {
875 bool isEnabled =
876 find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
877 switch (mode) {
878 case hal::SessionMode::POWER_EFFICIENCY:
879 tracePowerEfficient(isEnabled);
880 break;
881 case hal::SessionMode::GRAPHICS_PIPELINE:
882 traceGraphicsPipeline(isEnabled);
883 break;
Matt Buckleya3b8c142024-11-19 20:43:25 -0800884 default:
885 break;
Andy Yudffd67c2024-10-16 14:05:35 -0700886 }
887 }
888}
889
Matt Buckleye3d5c3a2023-12-01 23:10:32 +0000890void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
891 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
892}
893
894void APerformanceHintSession::traceBatchSize(size_t batchSize) {
895 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
896 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
897}
898
899void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
900 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
901}
Peiyong Lin70de0852023-10-25 21:12:35 +0000902
Bo Liu44267722021-07-16 17:03:20 -0400903// ===================================== C API
904APerformanceHintManager* APerformanceHint_getManager() {
905 return APerformanceHintManager::getInstance();
906}
907
Matt Buckley83f77092024-01-18 19:57:29 +0000908#define VALIDATE_PTR(ptr) \
909 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
910
911#define VALIDATE_INT(value, cmp) \
912 if (!(value cmp)) { \
913 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
914 __FUNCTION__, value); \
915 return EINVAL; \
916 }
917
918#define WARN_INT(value, cmp) \
919 if (!(value cmp)) { \
920 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
921 __FUNCTION__, value); \
922 }
923
Bo Liu44267722021-07-16 17:03:20 -0400924APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
925 const int32_t* threadIds, size_t size,
926 int64_t initialTargetWorkDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000927 VALIDATE_PTR(manager)
928 VALIDATE_PTR(threadIds)
Bo Liu44267722021-07-16 17:03:20 -0400929 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
930}
931
Andy Yudffd67c2024-10-16 14:05:35 -0700932APerformanceHintSession* APerformanceHint_createSessionUsingConfig(
933 APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig) {
934 VALIDATE_PTR(manager);
935 VALIDATE_PTR(sessionCreationConfig);
936 return manager->createSessionUsingConfig(sessionCreationConfig);
937}
938
939APerformanceHintSession* APerformanceHint_createSessionUsingConfigInternal(
940 APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig,
941 SessionTag tag) {
942 VALIDATE_PTR(manager);
943 VALIDATE_PTR(sessionCreationConfig);
944 return manager->createSessionUsingConfig(sessionCreationConfig,
945 static_cast<hal::SessionTag>(tag));
946}
947
Matt Buckley27da1342024-04-05 23:10:48 +0000948APerformanceHintSession* APerformanceHint_createSessionInternal(
949 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
950 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
951 VALIDATE_PTR(manager)
952 VALIDATE_PTR(threadIds)
953 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
954 static_cast<hal::SessionTag>(tag));
955}
956
Matt Buckley87393822024-11-17 01:58:16 +0000957APerformanceHintSession* APerformanceHint_createSessionFromJava(
958 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
959 int64_t initialTargetWorkDurationNanos) {
960 VALIDATE_PTR(manager)
961 VALIDATE_PTR(threadIds)
962 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
963 hal::SessionTag::APP, true);
964}
965
966APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env,
967 jobject sessionObj) {
968 VALIDATE_PTR(env)
969 VALIDATE_PTR(sessionObj)
970 return APerformanceHintManager::getInstance()->getSessionFromJava(env, sessionObj);
971}
972
Bo Liu44267722021-07-16 17:03:20 -0400973int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
Matt Buckley83f77092024-01-18 19:57:29 +0000974 VALIDATE_PTR(manager)
Bo Liu44267722021-07-16 17:03:20 -0400975 return manager->getPreferredRateNanos();
976}
977
Andy Yudffd67c2024-10-16 14:05:35 -0700978int APerformanceHint_getMaxGraphicsPipelineThreadsCount(APerformanceHintManager* manager) {
979 VALIDATE_PTR(manager);
980 return manager->getMaxGraphicsPipelineThreadsCount();
981}
982
Bo Liu44267722021-07-16 17:03:20 -0400983int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
984 int64_t targetDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000985 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -0400986 return session->updateTargetWorkDuration(targetDurationNanos);
987}
988
989int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
990 int64_t actualDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +0000991 VALIDATE_PTR(session)
992 VALIDATE_INT(actualDurationNanos, > 0)
Bo Liu44267722021-07-16 17:03:20 -0400993 return session->reportActualWorkDuration(actualDurationNanos);
994}
995
Bo Liu44267722021-07-16 17:03:20 -0400996void APerformanceHint_closeSession(APerformanceHintSession* session) {
Matt Buckley83f77092024-01-18 19:57:29 +0000997 VALIDATE_PTR(session)
Matt Buckley87393822024-11-17 01:58:16 +0000998 if (session->isJava()) {
999 LOG_ALWAYS_FATAL("%s: Java-owned PerformanceHintSession cannot be closed in native",
1000 __FUNCTION__);
1001 return;
1002 }
1003 delete session;
1004}
1005
1006void APerformanceHint_closeSessionFromJava(APerformanceHintSession* session) {
1007 VALIDATE_PTR(session)
Bo Liu44267722021-07-16 17:03:20 -04001008 delete session;
1009}
1010
Matt Buckley27da1342024-04-05 23:10:48 +00001011int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
Matt Buckley83f77092024-01-18 19:57:29 +00001012 VALIDATE_PTR(session)
Matt Buckley151f69f2024-10-21 09:27:06 -07001013 std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)};
1014 int64_t now = ::android::uptimeNanos();
1015 return session->sendHints(hints, now, "HWUI hint");
Matt Buckley61726a32022-12-06 23:44:45 +00001016}
1017
Peiyong Lin7ed6de32023-01-26 00:52:54 +00001018int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +00001019 size_t size) {
Matt Buckley83f77092024-01-18 19:57:29 +00001020 VALIDATE_PTR(session)
1021 VALIDATE_PTR(threadIds)
Peiyong Lin095de762022-11-11 18:28:12 +00001022 return session->setThreads(threadIds, size);
1023}
1024
Matt Buckley27da1342024-04-05 23:10:48 +00001025int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
Peiyong Lin095de762022-11-11 18:28:12 +00001026 size_t* const size) {
Matt Buckley27da1342024-04-05 23:10:48 +00001027 VALIDATE_PTR(session)
1028 return session->getThreadIds(threadIds, size);
Peiyong Lin095de762022-11-11 18:28:12 +00001029}
1030
Matt Buckley423c1b32023-06-28 19:13:42 +00001031int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
Matt Buckley83f77092024-01-18 19:57:29 +00001032 VALIDATE_PTR(session)
Matt Buckley423c1b32023-06-28 19:13:42 +00001033 return session->setPreferPowerEfficiency(enabled);
1034}
1035
Peiyong Lin70de0852023-10-25 21:12:35 +00001036int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
Matt Buckley83f77092024-01-18 19:57:29 +00001037 AWorkDuration* workDurationPtr) {
1038 VALIDATE_PTR(session)
1039 VALIDATE_PTR(workDurationPtr)
Matt Buckley58977722024-03-11 23:32:09 +00001040 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
1041 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
1042 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
1043 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
1044 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
Matt Buckley83f77092024-01-18 19:57:29 +00001045 return session->reportActualWorkDuration(workDurationPtr);
Peiyong Lin70de0852023-10-25 21:12:35 +00001046}
1047
Matt Buckley151f69f2024-10-21 09:27:06 -07001048int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu,
1049 const char* debugName) {
1050 VALIDATE_PTR(session)
1051 VALIDATE_PTR(debugName)
1052 if (!useNewLoadHintBehavior()) {
1053 return ENOTSUP;
1054 }
1055 return session->notifyWorkloadIncrease(cpu, gpu, debugName);
1056}
1057
1058int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu,
1059 const char* debugName) {
1060 VALIDATE_PTR(session)
1061 VALIDATE_PTR(debugName)
1062 if (!useNewLoadHintBehavior()) {
1063 return ENOTSUP;
1064 }
1065 return session->notifyWorkloadReset(cpu, gpu, debugName);
1066}
1067
Peiyong Lin70de0852023-10-25 21:12:35 +00001068AWorkDuration* AWorkDuration_create() {
Matt Buckley58977722024-03-11 23:32:09 +00001069 return new AWorkDuration();
Peiyong Lin70de0852023-10-25 21:12:35 +00001070}
1071
1072void AWorkDuration_release(AWorkDuration* aWorkDuration) {
Matt Buckley83f77092024-01-18 19:57:29 +00001073 VALIDATE_PTR(aWorkDuration)
Peiyong Lin70de0852023-10-25 21:12:35 +00001074 delete aWorkDuration;
1075}
1076
Peiyong Lin70de0852023-10-25 21:12:35 +00001077void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
1078 int64_t actualTotalDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +00001079 VALIDATE_PTR(aWorkDuration)
1080 WARN_INT(actualTotalDurationNanos, > 0)
Matt Buckley58977722024-03-11 23:32:09 +00001081 aWorkDuration->durationNanos = actualTotalDurationNanos;
1082}
1083
1084void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
1085 int64_t workPeriodStartTimestampNanos) {
1086 VALIDATE_PTR(aWorkDuration)
1087 WARN_INT(workPeriodStartTimestampNanos, > 0)
1088 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +00001089}
1090
1091void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
1092 int64_t actualCpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +00001093 VALIDATE_PTR(aWorkDuration)
Matt Buckleya115b122024-01-31 20:57:49 +00001094 WARN_INT(actualCpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +00001095 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +00001096}
1097
1098void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
1099 int64_t actualGpuDurationNanos) {
Matt Buckley83f77092024-01-18 19:57:29 +00001100 VALIDATE_PTR(aWorkDuration)
1101 WARN_INT(actualGpuDurationNanos, >= 0)
Matt Buckley58977722024-03-11 23:32:09 +00001102 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
Peiyong Lin70de0852023-10-25 21:12:35 +00001103}
1104
Bo Liu44267722021-07-16 17:03:20 -04001105void APerformanceHint_setIHintManagerForTesting(void* iManager) {
Matt Buckley854947f2024-02-07 17:30:01 +00001106 if (iManager == nullptr) {
1107 gHintManagerForTesting = nullptr;
1108 }
Matt Buckley58977722024-03-11 23:32:09 +00001109 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
Bo Liu44267722021-07-16 17:03:20 -04001110}
Matt Buckley854947f2024-02-07 17:30:01 +00001111
1112void APerformanceHint_setUseFMQForTesting(bool enabled) {
1113 gForceFMQEnabled = enabled;
1114}
Matt Buckley151f69f2024-10-21 09:27:06 -07001115
Andy Yudffd67c2024-10-16 14:05:35 -07001116ASessionCreationConfig* ASessionCreationConfig_create() {
1117 return new ASessionCreationConfig();
1118}
1119
1120void ASessionCreationConfig_release(ASessionCreationConfig* config) {
1121 VALIDATE_PTR(config)
1122
1123 delete config;
1124}
1125
1126int ASessionCreationConfig_setTids(ASessionCreationConfig* config, const pid_t* tids, size_t size) {
1127 VALIDATE_PTR(config)
1128 VALIDATE_PTR(tids)
1129
1130 if (!useGraphicsPipeline()) {
1131 return ENOTSUP;
1132 }
1133
1134 if (size <= 0) {
1135 LOG_ALWAYS_FATAL_IF(size <= 0,
1136 "%s: Invalid value. Thread id list size should be greater than zero.",
1137 __FUNCTION__);
1138 return EINVAL;
1139 }
1140 config->tids = std::vector<int32_t>(tids, tids + size);
1141 return 0;
1142}
1143
1144int ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig* config,
1145 int64_t targetWorkDurationNanos) {
1146 VALIDATE_PTR(config)
1147 VALIDATE_INT(targetWorkDurationNanos, >= 0)
1148
1149 if (!useGraphicsPipeline()) {
1150 return ENOTSUP;
1151 }
1152
1153 config->targetWorkDurationNanos = targetWorkDurationNanos;
1154 return 0;
1155}
1156
1157int ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig* config, bool enabled) {
1158 VALIDATE_PTR(config)
1159
1160 if (!useGraphicsPipeline()) {
1161 return ENOTSUP;
1162 }
1163
1164 if (enabled) {
1165 config->modesToEnable.push_back(hal::SessionMode::POWER_EFFICIENCY);
1166 } else {
1167 std::erase(config->modesToEnable, hal::SessionMode::POWER_EFFICIENCY);
1168 }
1169 return 0;
1170}
1171
1172int ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, bool enabled) {
1173 VALIDATE_PTR(config)
1174
1175 if (!useGraphicsPipeline()) {
1176 return ENOTSUP;
1177 }
1178
1179 if (enabled) {
1180 config->modesToEnable.push_back(hal::SessionMode::GRAPHICS_PIPELINE);
1181 } else {
1182 std::erase(config->modesToEnable, hal::SessionMode::GRAPHICS_PIPELINE);
1183 }
1184 return 0;
1185}
1186
1187void APerformanceHint_setUseGraphicsPipelineForTesting(bool enabled) {
1188 kForceGraphicsPipeline = enabled;
1189}
1190
Matt Buckley151f69f2024-10-21 09:27:06 -07001191void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
1192 int64_t* loadHintInterval) {
1193 *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval;
1194 *loadHintInterval = kLoadHintInterval;
1195}
1196
1197void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
1198 kForceNewHintBehavior = newBehavior;
1199}