1 /*
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
19 #include <aidl/android/hardware/power/ChannelConfig.h>
20 #include <aidl/android/hardware/power/ChannelMessage.h>
21 #include <aidl/android/hardware/power/SessionConfig.h>
22 #include <aidl/android/hardware/power/SessionHint.h>
23 #include <aidl/android/hardware/power/SessionMode.h>
24 #include <aidl/android/hardware/power/SessionTag.h>
25 #include <aidl/android/hardware/power/SupportInfo.h>
26 #include <aidl/android/hardware/power/WorkDuration.h>
27 #include <aidl/android/hardware/power/WorkDurationFixedV1.h>
28 #include <aidl/android/os/IHintManager.h>
29 #include <aidl/android/os/IHintSession.h>
30 #include <aidl/android/os/SessionCreationConfig.h>
31 #include <android-base/stringprintf.h>
32 #include <android-base/thread_annotations.h>
33 #include <android/binder_libbinder.h>
34 #include <android/binder_manager.h>
35 #include <android/binder_status.h>
36 #include <android/native_window.h>
37 #include <android/performance_hint.h>
38 #include <android/surface_control.h>
39 #include <android/trace.h>
40 #include <android_os.h>
41 #include <cutils/trace.h>
42 #include <fmq/AidlMessageQueue.h>
43 #include <gui/Surface.h>
44 #include <gui/SurfaceComposerClient.h>
45 #include <gui/SurfaceControl.h>
46 #include <inttypes.h>
47 #include <jni_wrappers.h>
48 #include <performance_hint_private.h>
49 #include <utils/SystemClock.h>
50
51 #include <chrono>
52 #include <format>
53 #include <future>
54 #include <set>
55 #include <utility>
56 #include <vector>
57
58 using namespace android;
59 using namespace aidl::android::os;
60
61 using namespace std::chrono_literals;
62
63 // Namespace for AIDL types coming from the PowerHAL
64 namespace hal = aidl::android::hardware::power;
65
66 using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
67 using HalChannelMessageContents = hal::ChannelMessage::ChannelMessageContents;
68 using HalMessageQueue = ::android::AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>;
69 using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
70 using android::base::StringPrintf;
71
72 struct APerformanceHintSession;
73
74 struct AWorkDuration : public hal::WorkDuration {};
75 struct ASessionCreationConfig : public SessionCreationConfig {
76 std::vector<wp<IBinder>> layers{};
hasModeASessionCreationConfig77 bool hasMode(hal::SessionMode mode) {
78 return std::find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
79 }
setModeASessionCreationConfig80 void setMode(hal::SessionMode mode, bool enabled) {
81 if (hasMode(mode)) {
82 if (!enabled) {
83 std::erase(modesToEnable, mode);
84 }
85 } else if (enabled) {
86 modesToEnable.push_back(mode);
87 }
88 }
89 };
90
91 // A pair of values that determine the behavior of the
92 // load hint rate limiter, to only allow "X hints every Y seconds"
93 constexpr int64_t kLoadHintInterval = std::chrono::nanoseconds(2s).count();
94 constexpr double kMaxLoadHintsPerInterval = 20;
95 // Replenish rate is used for new rate limiting behavior, it currently replenishes at a rate of
96 // 20 / 2s = 1 per 100us, which is the same limit as before, just enforced differently
97 constexpr double kReplenishRate = kMaxLoadHintsPerInterval / static_cast<double>(kLoadHintInterval);
98 constexpr int64_t kSendHintTimeout = kLoadHintInterval / kMaxLoadHintsPerInterval;
99 bool kForceNewHintBehavior = false;
100
101 template <class T>
enum_size()102 constexpr int32_t enum_size() {
103 return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1;
104 }
105
useNewLoadHintBehavior()106 bool useNewLoadHintBehavior() {
107 return android::os::adpf_use_load_hints() || kForceNewHintBehavior;
108 }
109
110 // Shared lock for the whole PerformanceHintManager and sessions
111 static std::mutex sHintMutex = std::mutex{};
112 class FMQWrapper {
113 public:
114 bool isActive();
115 bool isSupported();
116 bool startChannel(IHintManager* manager);
117 void stopChannel(IHintManager* manager);
118 // Number of elements the FMQ can hold
119 bool reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
120 hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex);
121 bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
122 int64_t targetDurationNanos) REQUIRES(sHintMutex);
123 bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint,
124 int64_t now) REQUIRES(sHintMutex);
125 bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled)
126 REQUIRES(sHintMutex);
127 void setToken(ndk::SpAIBinder& token);
128 void attemptWake();
129 void setUnsupported();
130
131 private:
132 template <HalChannelMessageContents::Tag T, bool urgent = false,
133 class C = HalChannelMessageContents::_at<T>>
134 bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1,
135 int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex);
136 template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>>
137 void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now)
138 REQUIRES(sHintMutex);
139
140 bool isActiveLocked() REQUIRES(sHintMutex);
141 bool updatePersistentTransaction() REQUIRES(sHintMutex);
142 std::shared_ptr<HalMessageQueue> mQueue GUARDED_BY(sHintMutex) = nullptr;
143 std::shared_ptr<HalFlagQueue> mFlagQueue GUARDED_BY(sHintMutex) = nullptr;
144 // android::hardware::EventFlag* mEventFlag GUARDED_BY(sHintMutex) = nullptr;
145 android::hardware::EventFlag* mEventFlag = nullptr;
146 int32_t mWriteMask;
147 ndk::SpAIBinder mToken = nullptr;
148 // Used to track if operating on the fmq consistently fails
149 bool mCorrupted = false;
150 // Used to keep a persistent transaction open with FMQ to reduce latency a bit
151 size_t mAvailableSlots GUARDED_BY(sHintMutex) = 0;
152 bool mHalSupported = true;
153 HalMessageQueue::MemTransaction mFmqTransaction GUARDED_BY(sHintMutex);
154 std::future<bool> mChannelCreationFinished;
155 };
156
157 struct SupportInfoWrapper : public hal::SupportInfo {
158 bool isSessionModeSupported(hal::SessionMode mode);
159 bool isSessionHintSupported(hal::SessionHint hint);
160
161 private:
162 template <class T>
getEnumSupportFromBitfieldSupportInfoWrapper163 bool getEnumSupportFromBitfield(T& enumValue, int64_t& supportBitfield) {
164 // extract the bit corresponding to the enum by shifting the bitfield
165 // over that much and cutting off any extra values
166 return (supportBitfield >> static_cast<int>(enumValue)) % 2;
167 }
168 };
169
170 class HintManagerClient : public IHintManager::BnHintManagerClient {
171 public:
172 // Currently a no-op that exists for FMQ init to call in the future
receiveChannelConfig(const hal::ChannelConfig &)173 ndk::ScopedAStatus receiveChannelConfig(const hal::ChannelConfig&) {
174 return ndk::ScopedAStatus::ok();
175 }
176 };
177
178 struct APerformanceHintManager {
179 public:
180 static APerformanceHintManager* getInstance();
181 APerformanceHintManager(std::shared_ptr<IHintManager>& service,
182 IHintManager::HintManagerClientData&& clientData,
183 std::shared_ptr<HintManagerClient> callbackClient);
184 APerformanceHintManager() = delete;
185 ~APerformanceHintManager();
186
187 APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
188 int64_t initialTargetWorkDurationNanos,
189 hal::SessionTag tag = hal::SessionTag::APP,
190 bool isJava = false);
191 APerformanceHintSession* getSessionFromJava(JNIEnv* _Nonnull env, jobject _Nonnull sessionObj);
192
193 int createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
194 APerformanceHintSession** sessionPtr,
195 hal::SessionTag tag = hal::SessionTag::APP, bool isJava = false);
196 int64_t getPreferredRateNanos() const;
197 int32_t getMaxGraphicsPipelineThreadsCount();
198 FMQWrapper& getFMQWrapper();
199 bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex);
200 void initJava(JNIEnv* _Nonnull env);
201 template <class T>
202 static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows,
203 ASurfaceControl** controls, int numSurfaceControls,
204 std::vector<T>& out);
205 ndk::SpAIBinder& getToken();
206 SupportInfoWrapper& getSupportInfo();
207 bool isFeatureSupported(APerformanceHintFeature feature);
208
209 private:
210 static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
211
212 std::shared_ptr<IHintManager> mHintManager;
213 std::shared_ptr<HintManagerClient> mCallbackClient;
214 IHintManager::HintManagerClientData mClientData;
215 SupportInfoWrapper mSupportInfoWrapper;
216 ndk::SpAIBinder mToken;
217 FMQWrapper mFMQWrapper;
218 double mHintBudget = kMaxLoadHintsPerInterval;
219 int64_t mLastBudgetReplenish = 0;
220 bool mJavaInitialized = false;
221 jclass mJavaSessionClazz;
222 jfieldID mJavaSessionNativePtr;
223 };
224
225 struct APerformanceHintSession {
226 public:
227 APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
228 std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
229 int64_t targetDurationNanos, bool isJava,
230 std::optional<hal::SessionConfig> sessionConfig);
231 APerformanceHintSession() = delete;
232 ~APerformanceHintSession();
233
234 int updateTargetWorkDuration(int64_t targetDurationNanos);
235 int reportActualWorkDuration(int64_t actualDurationNanos);
236 int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName);
237 int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName);
238 int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName);
239 int notifyWorkloadSpike(bool cpu, bool gpu, const char* debugName);
240 int setThreads(const int32_t* threadIds, size_t size);
241 int getThreadIds(int32_t* const threadIds, size_t* size);
242 int setPreferPowerEfficiency(bool enabled);
243 int reportActualWorkDuration(AWorkDuration* workDuration);
244 bool isJava();
245 status_t setNativeSurfaces(ANativeWindow** windows, size_t numWindows,
246 ASurfaceControl** controls, size_t numSurfaceControls);
247
248 private:
249 friend struct APerformanceHintManager;
250
251 int reportActualWorkDurationInternal(AWorkDuration* workDuration);
252
253 std::shared_ptr<IHintManager> mHintManager;
254 std::shared_ptr<IHintSession> mHintSession;
255 // HAL preferred update rate
256 const int64_t mPreferredRateNanos;
257 // Target duration for choosing update rate
258 int64_t mTargetDurationNanos GUARDED_BY(sHintMutex);
259 // First target hit timestamp
260 int64_t mFirstTargetMetTimestamp GUARDED_BY(sHintMutex);
261 // Last target hit timestamp
262 int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex);
263 // Last hint reported from sendHint indexed by hint value
264 // This is only used by the old rate limiter impl and is replaced
265 // with the new rate limiter under a flag
266 std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex);
267 // Cached samples
268 std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex);
269 // Is this session backing an SDK wrapper object
270 const bool mIsJava;
271 std::string mSessionName;
272 static int64_t sIDCounter GUARDED_BY(sHintMutex);
273 // The most recent set of thread IDs
274 std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex);
275 std::optional<hal::SessionConfig> mSessionConfig;
276 // Tracing helpers
277 void traceThreads(const std::vector<int32_t>& tids) REQUIRES(sHintMutex);
278 void tracePowerEfficient(bool powerEfficient);
279 void traceGraphicsPipeline(bool graphicsPipeline);
280 void traceModes(const std::vector<hal::SessionMode>& modesToEnable);
281 void traceActualDuration(int64_t actualDuration);
282 void traceBatchSize(size_t batchSize);
283 void traceTargetDuration(int64_t targetDuration);
284 };
285
286 static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
287 static std::shared_ptr<APerformanceHintManager> gHintManagerForTesting = nullptr;
288
289 static std::optional<bool> gForceFMQEnabled = std::nullopt;
290
291 // Start above the int32 range so we don't collide with config sessions
292 int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
293
getFMQ()294 static FMQWrapper& getFMQ() {
295 return APerformanceHintManager::getInstance()->getFMQWrapper();
296 }
297
298 // ===================================== SupportInfoWrapper implementation
299
isSessionHintSupported(hal::SessionHint hint)300 bool SupportInfoWrapper::isSessionHintSupported(hal::SessionHint hint) {
301 return getEnumSupportFromBitfield(hint, sessionHints);
302 }
303
isSessionModeSupported(hal::SessionMode mode)304 bool SupportInfoWrapper::isSessionModeSupported(hal::SessionMode mode) {
305 return getEnumSupportFromBitfield(mode, sessionModes);
306 }
307
308 // ===================================== APerformanceHintManager implementation
APerformanceHintManager(std::shared_ptr<IHintManager> & manager,IHintManager::HintManagerClientData && clientData,std::shared_ptr<HintManagerClient> callbackClient)309 APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager>& manager,
310 IHintManager::HintManagerClientData&& clientData,
311 std::shared_ptr<HintManagerClient> callbackClient)
312 : mHintManager(std::move(manager)),
313 mCallbackClient(callbackClient),
314 mClientData(clientData),
315 mSupportInfoWrapper(clientData.supportInfo),
316 mToken(callbackClient->asBinder()) {
317 if (mFMQWrapper.isSupported()) {
318 mFMQWrapper.setToken(mToken);
319 mFMQWrapper.startChannel(mHintManager.get());
320 }
321 }
322
~APerformanceHintManager()323 APerformanceHintManager::~APerformanceHintManager() {
324 mFMQWrapper.stopChannel(mHintManager.get());
325 }
326
getInstance()327 APerformanceHintManager* APerformanceHintManager::getInstance() {
328 static std::once_flag creationFlag;
329 static APerformanceHintManager* instance = nullptr;
330 if (gHintManagerForTesting) {
331 return gHintManagerForTesting.get();
332 }
333 if (gIHintManagerForTesting) {
334 gHintManagerForTesting =
335 std::shared_ptr<APerformanceHintManager>(create(*gIHintManagerForTesting));
336 return gHintManagerForTesting.get();
337 }
338 std::call_once(creationFlag, []() { instance = create(nullptr); });
339 return instance;
340 }
341
create(std::shared_ptr<IHintManager> manager)342 APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
343 if (!manager) {
344 manager = IHintManager::fromBinder(
345 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
346 }
347 if (manager == nullptr) {
348 ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
349 return nullptr;
350 }
351 std::shared_ptr<HintManagerClient> client = ndk::SharedRefBase::make<HintManagerClient>();
352 IHintManager::HintManagerClientData clientData;
353 ndk::ScopedAStatus ret = manager->registerClient(client, &clientData);
354 if (!ret.isOk()) {
355 ALOGE("%s: PerformanceHint is not supported. %s", __FUNCTION__, ret.getMessage());
356 return nullptr;
357 }
358 if (clientData.preferredRateNanos <= 0) {
359 clientData.preferredRateNanos = -1L;
360 }
361 return new APerformanceHintManager(manager, std::move(clientData), client);
362 }
363
canSendLoadHints(std::vector<hal::SessionHint> & hints,int64_t now)364 bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) {
365 mHintBudget =
366 std::min(kMaxLoadHintsPerInterval,
367 mHintBudget +
368 static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate);
369 mLastBudgetReplenish = now;
370
371 // If this youngest timestamp isn't older than the timeout time, we can't send
372 if (hints.size() > mHintBudget) {
373 return false;
374 }
375 mHintBudget -= hints.size();
376 return true;
377 }
378
createSession(const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos,hal::SessionTag tag,bool isJava)379 APerformanceHintSession* APerformanceHintManager::createSession(
380 const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
381 hal::SessionTag tag, bool isJava) {
382 ndk::ScopedAStatus ret;
383 hal::SessionConfig sessionConfig{.id = -1};
384
385 ASessionCreationConfig creationConfig{{
386 .tids = std::vector<int32_t>(threadIds, threadIds + size),
387 .targetWorkDurationNanos = initialTargetWorkDurationNanos,
388 }};
389
390 APerformanceHintSession* sessionOut;
391 APerformanceHintManager::createSessionUsingConfig(&creationConfig, &sessionOut, tag, isJava);
392 return sessionOut;
393 }
394
createSessionUsingConfig(ASessionCreationConfig * sessionCreationConfig,APerformanceHintSession ** sessionOut,hal::SessionTag tag,bool isJava)395 int APerformanceHintManager::createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
396 APerformanceHintSession** sessionOut,
397 hal::SessionTag tag, bool isJava) {
398 hal::SessionConfig sessionConfig{.id = -1};
399 ndk::ScopedAStatus ret;
400
401 // Hold the tokens weakly until we actually need them,
402 // then promote them, then drop all strong refs after
403 if (!sessionCreationConfig->layers.empty()) {
404 for (auto&& layerIter = sessionCreationConfig->layers.begin();
405 layerIter != sessionCreationConfig->layers.end();) {
406 sp<IBinder> promoted = layerIter->promote();
407 if (promoted == nullptr) {
408 layerIter = sessionCreationConfig->layers.erase(layerIter);
409 } else {
410 sessionCreationConfig->layerTokens.push_back(
411 ndk::SpAIBinder(AIBinder_fromPlatformBinder(promoted.get())));
412 ++layerIter;
413 }
414 }
415 }
416
417 bool autoCpu = sessionCreationConfig->hasMode(hal::SessionMode::AUTO_CPU);
418 bool autoGpu = sessionCreationConfig->hasMode(hal::SessionMode::AUTO_GPU);
419
420 if (autoCpu || autoGpu) {
421 LOG_ALWAYS_FATAL_IF(!sessionCreationConfig->hasMode(hal::SessionMode::GRAPHICS_PIPELINE),
422 "Automatic session timing enabled without graphics pipeline mode");
423 }
424
425 if (autoCpu && !mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::AUTO_CPU)) {
426 ALOGE("Automatic CPU timing enabled but not supported");
427 return ENOTSUP;
428 }
429
430 if (autoGpu && !mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::AUTO_GPU)) {
431 ALOGE("Automatic GPU timing enabled but not supported");
432 return ENOTSUP;
433 }
434
435 IHintManager::SessionCreationReturn returnValue;
436 ret = mHintManager->createHintSessionWithConfig(mToken, tag,
437 *static_cast<SessionCreationConfig*>(
438 sessionCreationConfig),
439 &sessionConfig, &returnValue);
440
441 sessionCreationConfig->layerTokens.clear();
442
443 if (!ret.isOk() || !returnValue.session) {
444 ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
445 switch (ret.getExceptionCode()) {
446 case binder::Status::EX_UNSUPPORTED_OPERATION:
447 return ENOTSUP;
448 case binder::Status::EX_ILLEGAL_ARGUMENT:
449 return EINVAL;
450 default:
451 return EPIPE;
452 }
453 }
454
455 auto out = new APerformanceHintSession(mHintManager, std::move(returnValue.session),
456 mClientData.preferredRateNanos,
457 sessionCreationConfig->targetWorkDurationNanos, isJava,
458 sessionConfig.id == -1
459 ? std::nullopt
460 : std::make_optional<hal::SessionConfig>(
461 std::move(sessionConfig)));
462
463 *sessionOut = out;
464
465 std::scoped_lock lock(sHintMutex);
466 out->traceThreads(sessionCreationConfig->tids);
467 out->traceTargetDuration(sessionCreationConfig->targetWorkDurationNanos);
468 out->traceModes(sessionCreationConfig->modesToEnable);
469
470 if (returnValue.pipelineThreadLimitExceeded) {
471 ALOGE("Graphics pipeline session thread limit exceeded!");
472 return EBUSY;
473 }
474
475 return 0;
476 }
477
getSessionFromJava(JNIEnv * env,jobject sessionObj)478 APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env,
479 jobject sessionObj) {
480 initJava(env);
481 LOG_ALWAYS_FATAL_IF(!env->IsInstanceOf(sessionObj, mJavaSessionClazz),
482 "Wrong java type passed to APerformanceHint_getSessionFromJava");
483 APerformanceHintSession* out = reinterpret_cast<APerformanceHintSession*>(
484 env->GetLongField(sessionObj, mJavaSessionNativePtr));
485 LOG_ALWAYS_FATAL_IF(out == nullptr, "Java-wrapped native hint session is nullptr");
486 LOG_ALWAYS_FATAL_IF(!out->isJava(), "Unmanaged native hint session returned from Java SDK");
487 return out;
488 }
489
getPreferredRateNanos() const490 int64_t APerformanceHintManager::getPreferredRateNanos() const {
491 return mClientData.preferredRateNanos;
492 }
493
getMaxGraphicsPipelineThreadsCount()494 int32_t APerformanceHintManager::getMaxGraphicsPipelineThreadsCount() {
495 return mClientData.maxGraphicsPipelineThreads;
496 }
497
getFMQWrapper()498 FMQWrapper& APerformanceHintManager::getFMQWrapper() {
499 return mFMQWrapper;
500 }
501
initJava(JNIEnv * _Nonnull env)502 void APerformanceHintManager::initJava(JNIEnv* _Nonnull env) {
503 if (mJavaInitialized) {
504 return;
505 }
506 jclass sessionClazz = FindClassOrDie(env, "android/os/PerformanceHintManager$Session");
507 mJavaSessionClazz = MakeGlobalRefOrDie(env, sessionClazz);
508 mJavaSessionNativePtr = GetFieldIDOrDie(env, mJavaSessionClazz, "mNativeSessionPtr", "J");
509 mJavaInitialized = true;
510 }
511
getToken()512 ndk::SpAIBinder& APerformanceHintManager::getToken() {
513 return mToken;
514 }
515
getSupportInfo()516 SupportInfoWrapper& APerformanceHintManager::getSupportInfo() {
517 return mSupportInfoWrapper;
518 }
519
isFeatureSupported(APerformanceHintFeature feature)520 bool APerformanceHintManager::isFeatureSupported(APerformanceHintFeature feature) {
521 switch (feature) {
522 case (APERF_HINT_SESSIONS):
523 return mSupportInfoWrapper.usesSessions;
524 case (APERF_HINT_POWER_EFFICIENCY):
525 return mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::POWER_EFFICIENCY);
526 case (APERF_HINT_SURFACE_BINDING):
527 return mSupportInfoWrapper.compositionData.isSupported;
528 case (APERF_HINT_GRAPHICS_PIPELINE):
529 return mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::GRAPHICS_PIPELINE);
530 case (APERF_HINT_AUTO_CPU):
531 return mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::AUTO_CPU);
532 case (APERF_HINT_AUTO_GPU):
533 return mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::AUTO_GPU);
534 default:
535 return false;
536 }
537 }
538
539 // ===================================== APerformanceHintSession implementation
540
541 constexpr int kNumEnums = enum_size<hal::SessionHint>();
APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,std::shared_ptr<IHintSession> session,int64_t preferredRateNanos,int64_t targetDurationNanos,bool isJava,std::optional<hal::SessionConfig> sessionConfig)542 APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
543 std::shared_ptr<IHintSession> session,
544 int64_t preferredRateNanos,
545 int64_t targetDurationNanos, bool isJava,
546 std::optional<hal::SessionConfig> sessionConfig)
547 : mHintManager(hintManager),
548 mHintSession(std::move(session)),
549 mPreferredRateNanos(preferredRateNanos),
550 mTargetDurationNanos(targetDurationNanos),
551 mFirstTargetMetTimestamp(0),
552 mLastTargetMetTimestamp(0),
553 mLastHintSentTimestamp(std::vector<int64_t>(kNumEnums, 0)),
554 mIsJava(isJava),
555 mSessionConfig(sessionConfig) {
556 if (sessionConfig->id > INT32_MAX) {
557 ALOGE("Session ID too large, must fit 32-bit integer");
558 }
559 int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
560 mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
561 }
562
~APerformanceHintSession()563 APerformanceHintSession::~APerformanceHintSession() {
564 ndk::ScopedAStatus ret = mHintSession->close();
565 if (!ret.isOk()) {
566 ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
567 }
568 }
569
updateTargetWorkDuration(int64_t targetDurationNanos)570 int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
571 std::scoped_lock lock(sHintMutex);
572 if (mTargetDurationNanos == targetDurationNanos) {
573 return 0;
574 }
575 if (!getFMQ().updateTargetWorkDuration(mSessionConfig, targetDurationNanos)) {
576 ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
577 if (!ret.isOk()) {
578 ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
579 ret.getMessage());
580 return EPIPE;
581 }
582 }
583 mTargetDurationNanos = targetDurationNanos;
584 /**
585 * Most of the workload is target_duration dependent, so now clear the cached samples
586 * as they are most likely obsolete.
587 */
588 mActualWorkDurations.clear();
589 traceBatchSize(0);
590 traceTargetDuration(targetDurationNanos);
591 mFirstTargetMetTimestamp = 0;
592 mLastTargetMetTimestamp = 0;
593 return 0;
594 }
595
reportActualWorkDuration(int64_t actualDurationNanos)596 int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
597 hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
598 .workPeriodStartTimestampNanos = 0,
599 .cpuDurationNanos = actualDurationNanos,
600 .gpuDurationNanos = 0};
601 return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
602 }
603
isJava()604 bool APerformanceHintSession::isJava() {
605 return mIsJava;
606 }
607
sendHints(std::vector<hal::SessionHint> & hints,int64_t now,const char *)608 int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
609 const char*) {
610 auto& supportInfo = APerformanceHintManager::getInstance()->getSupportInfo();
611
612 // Drop all unsupported hints, there's not much point reporting errors or warnings for this
613 std::erase_if(hints,
614 [&](hal::SessionHint hint) { return !supportInfo.isSessionHintSupported(hint); });
615
616 if (hints.empty()) {
617 // We successfully sent all hints we were able to, technically
618 return 0;
619 }
620
621 for (auto&& hint : hints) {
622 LOG_ALWAYS_FATAL_IF(static_cast<int32_t>(hint) < 0 ||
623 static_cast<int32_t>(hint) >= kNumEnums,
624 "%s: invalid session hint %d", __FUNCTION__, hint);
625 }
626
627 std::scoped_lock lock(sHintMutex);
628 if (useNewLoadHintBehavior()) {
629 if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) {
630 return EBUSY;
631 }
632 }
633 // keep old rate limiter behavior for legacy flag
634 else {
635 for (auto&& hint : hints) {
636 if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + kSendHintTimeout)) {
637 return EBUSY;
638 }
639 }
640 }
641
642 if (!getFMQ().sendHints(mSessionConfig, hints, now)) {
643 for (auto&& hint : hints) {
644 ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint));
645
646 if (!ret.isOk()) {
647 ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
648 return EPIPE;
649 }
650 }
651 }
652
653 if (!useNewLoadHintBehavior()) {
654 for (auto&& hint : hints) {
655 mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now;
656 }
657 }
658
659 if (ATrace_isEnabled()) {
660 ATRACE_INSTANT("Sending load hint");
661 }
662
663 return 0;
664 }
665
notifyWorkloadIncrease(bool cpu,bool gpu,const char * debugName)666 int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) {
667 std::vector<hal::SessionHint> hints(2);
668 hints.clear();
669 if (cpu) {
670 hints.push_back(hal::SessionHint::CPU_LOAD_UP);
671 }
672 if (gpu) {
673 hints.push_back(hal::SessionHint::GPU_LOAD_UP);
674 }
675 int64_t now = ::android::uptimeNanos();
676 return sendHints(hints, now, debugName);
677 }
678
notifyWorkloadReset(bool cpu,bool gpu,const char * debugName)679 int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) {
680 std::vector<hal::SessionHint> hints(2);
681 hints.clear();
682 if (cpu) {
683 hints.push_back(hal::SessionHint::CPU_LOAD_RESET);
684 }
685 if (gpu) {
686 hints.push_back(hal::SessionHint::GPU_LOAD_RESET);
687 }
688 int64_t now = ::android::uptimeNanos();
689 return sendHints(hints, now, debugName);
690 }
691
notifyWorkloadSpike(bool cpu,bool gpu,const char * debugName)692 int APerformanceHintSession::notifyWorkloadSpike(bool cpu, bool gpu, const char* debugName) {
693 std::vector<hal::SessionHint> hints(2);
694 hints.clear();
695 if (cpu) {
696 hints.push_back(hal::SessionHint::CPU_LOAD_SPIKE);
697 }
698 if (gpu) {
699 hints.push_back(hal::SessionHint::GPU_LOAD_SPIKE);
700 }
701 int64_t now = ::android::uptimeNanos();
702 return sendHints(hints, now, debugName);
703 }
704
setThreads(const int32_t * threadIds,size_t size)705 int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
706 if (size == 0) {
707 ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
708 return EINVAL;
709 }
710 std::vector<int32_t> tids(threadIds, threadIds + size);
711 ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
712
713 // Illegal state means there were too many graphics pipeline threads
714 if (!ret.isOk() && ret.getExceptionCode() != EX_SERVICE_SPECIFIC) {
715 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
716 if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
717 return EINVAL;
718 } else if (ret.getExceptionCode() == EX_SECURITY) {
719 return EPERM;
720 }
721 return EPIPE;
722 }
723
724 std::scoped_lock lock(sHintMutex);
725 traceThreads(tids);
726 bool tooManyThreads =
727 ret.getExceptionCode() == EX_SERVICE_SPECIFIC && ret.getServiceSpecificError() == 5;
728
729 return tooManyThreads ? EBUSY : 0;
730 }
731
getThreadIds(int32_t * const threadIds,size_t * size)732 int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
733 std::vector<int32_t> tids;
734 ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
735 if (!ret.isOk()) {
736 ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
737 return EPIPE;
738 }
739
740 // When threadIds is nullptr, this is the first call to determine the size
741 // of the thread ids list.
742 if (threadIds == nullptr) {
743 *size = tids.size();
744 return 0;
745 }
746
747 // Second call to return the actual list of thread ids.
748 *size = tids.size();
749 for (size_t i = 0; i < *size; ++i) {
750 threadIds[i] = tids[i];
751 }
752 return 0;
753 }
754
setPreferPowerEfficiency(bool enabled)755 int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
756 ndk::ScopedAStatus ret =
757 mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
758 enabled);
759
760 if (!ret.isOk()) {
761 ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
762 ret.getMessage());
763 return EPIPE;
764 }
765 std::scoped_lock lock(sHintMutex);
766 tracePowerEfficient(enabled);
767 return OK;
768 }
769
reportActualWorkDuration(AWorkDuration * workDuration)770 int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
771 return reportActualWorkDurationInternal(workDuration);
772 }
773
reportActualWorkDurationInternal(AWorkDuration * workDuration)774 int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
775 int64_t actualTotalDurationNanos = workDuration->durationNanos;
776 int64_t now = uptimeNanos();
777 workDuration->timeStampNanos = now;
778 std::scoped_lock lock(sHintMutex);
779
780 if (mTargetDurationNanos <= 0) {
781 ALOGE("Cannot report work durations if the target duration is not positive.");
782 return EINVAL;
783 }
784
785 traceActualDuration(actualTotalDurationNanos);
786 mActualWorkDurations.push_back(std::move(*workDuration));
787
788 if (actualTotalDurationNanos >= mTargetDurationNanos) {
789 // Reset timestamps if we are equal or over the target.
790 mFirstTargetMetTimestamp = 0;
791 } else {
792 // Set mFirstTargetMetTimestamp for first time meeting target.
793 if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
794 (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
795 mFirstTargetMetTimestamp = now;
796 }
797 /**
798 * Rate limit the change if the update is over mPreferredRateNanos since first
799 * meeting target and less than mPreferredRateNanos since last meeting target.
800 */
801 if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
802 now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
803 traceBatchSize(mActualWorkDurations.size());
804 return 0;
805 }
806 mLastTargetMetTimestamp = now;
807 }
808
809 if (!getFMQ().reportActualWorkDurations(mSessionConfig, mActualWorkDurations.data(),
810 mActualWorkDurations.size())) {
811 ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
812 if (!ret.isOk()) {
813 ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
814 ret.getMessage());
815 mFirstTargetMetTimestamp = 0;
816 mLastTargetMetTimestamp = 0;
817 traceBatchSize(mActualWorkDurations.size());
818 return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
819 }
820 }
821
822 mActualWorkDurations.clear();
823 traceBatchSize(0);
824
825 return 0;
826 }
827
setNativeSurfaces(ANativeWindow ** windows,size_t numWindows,ASurfaceControl ** controls,size_t numSurfaceControls)828 status_t APerformanceHintSession::setNativeSurfaces(ANativeWindow** windows, size_t numWindows,
829 ASurfaceControl** controls,
830 size_t numSurfaceControls) {
831 if (!mSessionConfig.has_value()) {
832 return ENOTSUP;
833 }
834
835 std::vector<sp<IBinder>> layerHandles;
836 APerformanceHintManager::layersFromNativeSurfaces<sp<IBinder>>(windows, numWindows, controls,
837 numSurfaceControls,
838 layerHandles);
839
840 std::vector<ndk::SpAIBinder> ndkLayerHandles;
841 for (auto&& handle : layerHandles) {
842 ndkLayerHandles.emplace_back(ndk::SpAIBinder(AIBinder_fromPlatformBinder(handle)));
843 }
844
845 auto ret = mHintSession->associateToLayers(ndkLayerHandles);
846 if (!ret.isOk()) {
847 return EPIPE;
848 }
849 return 0;
850 }
851
852 template <class T>
layersFromNativeSurfaces(ANativeWindow ** windows,int numWindows,ASurfaceControl ** controls,int numSurfaceControls,std::vector<T> & out)853 void APerformanceHintManager::layersFromNativeSurfaces(ANativeWindow** windows, int numWindows,
854 ASurfaceControl** controls,
855 int numSurfaceControls,
856 std::vector<T>& out) {
857 std::scoped_lock lock(sHintMutex);
858 if (windows != nullptr) {
859 std::vector<ANativeWindow*> windowVec(windows, windows + numWindows);
860 for (auto&& window : windowVec) {
861 Surface* surface = static_cast<Surface*>(window);
862 if (surface != nullptr) {
863 const sp<IBinder>& handle = surface->getSurfaceControlHandle();
864 if (handle != nullptr) {
865 out.push_back(handle);
866 }
867 }
868 }
869 }
870
871 if (controls != nullptr) {
872 std::vector<ASurfaceControl*> controlVec(controls, controls + numSurfaceControls);
873 for (auto&& aSurfaceControl : controlVec) {
874 SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl);
875 if (control->isValid()) {
876 out.push_back(control->getHandle());
877 }
878 }
879 }
880 }
881
882 // ===================================== FMQ wrapper implementation
883
isActive()884 bool FMQWrapper::isActive() {
885 std::scoped_lock lock{sHintMutex};
886 return isActiveLocked();
887 }
888
isActiveLocked()889 bool FMQWrapper::isActiveLocked() {
890 return mQueue != nullptr;
891 }
892
setUnsupported()893 void FMQWrapper::setUnsupported() {
894 mHalSupported = false;
895 }
896
isSupported()897 bool FMQWrapper::isSupported() {
898 if (!mHalSupported) {
899 return false;
900 }
901 // Used for testing
902 if (gForceFMQEnabled.has_value()) {
903 return *gForceFMQEnabled;
904 }
905 return android::os::adpf_use_fmq_channel_fixed();
906 }
907
startChannel(IHintManager * manager)908 bool FMQWrapper::startChannel(IHintManager* manager) {
909 if (isSupported() && !isActive() && manager->isRemote()) {
910 mChannelCreationFinished = std::async(std::launch::async, [&, this, manager]() {
911 std::optional<hal::ChannelConfig> config;
912 auto ret = manager->getSessionChannel(mToken, &config);
913 if (ret.isOk() && config.has_value()) {
914 std::scoped_lock lock{sHintMutex};
915 mQueue = std::make_shared<HalMessageQueue>(config->channelDescriptor, true);
916 if (config->eventFlagDescriptor.has_value()) {
917 mFlagQueue = std::make_shared<HalFlagQueue>(*config->eventFlagDescriptor, true);
918 android::hardware::EventFlag::createEventFlag(mFlagQueue->getEventFlagWord(),
919 &mEventFlag);
920 mWriteMask = config->writeFlagBitmask;
921 }
922 updatePersistentTransaction();
923 } else if (ret.isOk() && !config.has_value()) {
924 ALOGV("FMQ channel enabled but unsupported.");
925 setUnsupported();
926 } else {
927 ALOGE("%s: FMQ channel initialization failed: %s", __FUNCTION__, ret.getMessage());
928 }
929 return true;
930 });
931
932 // If we're unit testing the FMQ, we should block for it to finish completing
933 if (gForceFMQEnabled.has_value()) {
934 mChannelCreationFinished.wait();
935 }
936 }
937 return isActive();
938 }
939
stopChannel(IHintManager * manager)940 void FMQWrapper::stopChannel(IHintManager* manager) {
941 {
942 std::scoped_lock lock{sHintMutex};
943 if (!isActiveLocked()) {
944 return;
945 }
946 mFlagQueue = nullptr;
947 mQueue = nullptr;
948 }
949 manager->closeSessionChannel();
950 }
951
952 template <HalChannelMessageContents::Tag T, class C>
writeBuffer(C * message,hal::SessionConfig & config,size_t count,int64_t now)953 void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) {
954 for (size_t i = 0; i < count; ++i) {
955 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
956 .sessionID = static_cast<int32_t>(config.id),
957 .timeStampNanos = now,
958 .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))),
959 };
960 }
961 }
962
963 template <>
writeBuffer(hal::WorkDuration * messages,hal::SessionConfig & config,size_t count,int64_t now)964 void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages,
965 hal::SessionConfig& config,
966 size_t count, int64_t now) {
967 for (size_t i = 0; i < count; ++i) {
968 hal::WorkDuration& message = messages[i];
969 new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{
970 .sessionID = static_cast<int32_t>(config.id),
971 .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos,
972 .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration,
973 hal::WorkDurationFixedV1>({
974 .durationNanos = message.durationNanos,
975 .workPeriodStartTimestampNanos = message.workPeriodStartTimestampNanos,
976 .cpuDurationNanos = message.cpuDurationNanos,
977 .gpuDurationNanos = message.gpuDurationNanos,
978 }),
979 };
980 }
981 }
982
983 template <HalChannelMessageContents::Tag T, bool urgent, class C>
sendMessages(std::optional<hal::SessionConfig> & config,C * message,size_t count,int64_t now)984 bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count,
985 int64_t now) {
986 if (!isActiveLocked() || !config.has_value() || mCorrupted) {
987 return false;
988 }
989 // If we didn't reserve enough space, try re-creating the transaction
990 if (count > mAvailableSlots) {
991 if (!updatePersistentTransaction()) {
992 return false;
993 }
994 // If we actually don't have enough space, give up
995 if (count > mAvailableSlots) {
996 return false;
997 }
998 }
999 writeBuffer<T, C>(message, *config, count, now);
1000 mQueue->commitWrite(count);
1001 mEventFlag->wake(mWriteMask);
1002 // Re-create the persistent transaction after writing
1003 updatePersistentTransaction();
1004 return true;
1005 }
1006
setToken(ndk::SpAIBinder & token)1007 void FMQWrapper::setToken(ndk::SpAIBinder& token) {
1008 mToken = token;
1009 }
1010
updatePersistentTransaction()1011 bool FMQWrapper::updatePersistentTransaction() {
1012 mAvailableSlots = mQueue->availableToWrite();
1013 if (mAvailableSlots > 0 && !mQueue->beginWrite(mAvailableSlots, &mFmqTransaction)) {
1014 ALOGE("ADPF FMQ became corrupted, falling back to binder calls!");
1015 mCorrupted = true;
1016 return false;
1017 }
1018 return true;
1019 }
1020
reportActualWorkDurations(std::optional<hal::SessionConfig> & config,hal::WorkDuration * durations,size_t count)1021 bool FMQWrapper::reportActualWorkDurations(std::optional<hal::SessionConfig>& config,
1022 hal::WorkDuration* durations, size_t count) {
1023 return sendMessages<HalChannelMessageContents::workDuration>(config, durations, count);
1024 }
1025
updateTargetWorkDuration(std::optional<hal::SessionConfig> & config,int64_t targetDurationNanos)1026 bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& config,
1027 int64_t targetDurationNanos) {
1028 return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos);
1029 }
1030
sendHints(std::optional<hal::SessionConfig> & config,std::vector<hal::SessionHint> & hints,int64_t now)1031 bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config,
1032 std::vector<hal::SessionHint>& hints, int64_t now) {
1033 return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now);
1034 }
1035
setMode(std::optional<hal::SessionConfig> & config,hal::SessionMode mode,bool enabled)1036 bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode,
1037 bool enabled) {
1038 hal::ChannelMessage::ChannelMessageContents::SessionModeSetter modeObj{.modeInt = mode,
1039 .enabled = enabled};
1040 return sendMessages<HalChannelMessageContents::mode, true>(config, &modeObj);
1041 }
1042
1043 // ===================================== Tracing helpers
1044
traceThreads(const std::vector<int32_t> & tids)1045 void APerformanceHintSession::traceThreads(const std::vector<int32_t>& tids) {
1046 std::set<int32_t> tidSet{tids.begin(), tids.end()};
1047
1048 // Disable old TID tracing
1049 for (int32_t tid : mLastThreadIDs) {
1050 if (!tidSet.count(tid)) {
1051 std::string traceName =
1052 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
1053 ATrace_setCounter(traceName.c_str(), 0);
1054 }
1055 }
1056
1057 // Add new TID tracing
1058 for (int32_t tid : tids) {
1059 std::string traceName =
1060 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
1061 ATrace_setCounter(traceName.c_str(), 1);
1062 }
1063
1064 mLastThreadIDs = std::move(tids);
1065 }
1066
tracePowerEfficient(bool powerEfficient)1067 void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
1068 ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
1069 }
1070
traceGraphicsPipeline(bool graphicsPipeline)1071 void APerformanceHintSession::traceGraphicsPipeline(bool graphicsPipeline) {
1072 ATrace_setCounter((mSessionName + " graphics pipeline mode").c_str(), graphicsPipeline);
1073 }
1074
traceModes(const std::vector<hal::SessionMode> & modesToEnable)1075 void APerformanceHintSession::traceModes(const std::vector<hal::SessionMode>& modesToEnable) {
1076 // Iterate through all modes to trace, set to enable for all modes in modesToEnable,
1077 // and set to disable for those are not.
1078 for (hal::SessionMode mode :
1079 {hal::SessionMode::POWER_EFFICIENCY, hal::SessionMode::GRAPHICS_PIPELINE}) {
1080 bool isEnabled =
1081 find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
1082 switch (mode) {
1083 case hal::SessionMode::POWER_EFFICIENCY:
1084 tracePowerEfficient(isEnabled);
1085 break;
1086 case hal::SessionMode::GRAPHICS_PIPELINE:
1087 traceGraphicsPipeline(isEnabled);
1088 break;
1089 default:
1090 break;
1091 }
1092 }
1093 }
1094
traceActualDuration(int64_t actualDuration)1095 void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
1096 ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
1097 }
1098
traceBatchSize(size_t batchSize)1099 void APerformanceHintSession::traceBatchSize(size_t batchSize) {
1100 std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
1101 ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
1102 }
1103
traceTargetDuration(int64_t targetDuration)1104 void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
1105 ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
1106 }
1107
1108 // ===================================== Start of C API
1109
APerformanceHint_getManager()1110 APerformanceHintManager* APerformanceHint_getManager() {
1111 return APerformanceHintManager::getInstance();
1112 }
1113
1114 #define VALIDATE_PTR(ptr) \
1115 LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
1116
1117 #define HARD_VALIDATE_INT(value, cmp) \
1118 LOG_ALWAYS_FATAL_IF(!(value cmp), \
1119 "%s: Invalid value. Check failed: (" #value " " #cmp \
1120 ") with value: %" PRIi64, \
1121 __FUNCTION__, static_cast<int64_t>(value));
1122
1123 #define VALIDATE_INT(value, cmp) \
1124 if (!(value cmp)) { \
1125 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
1126 __FUNCTION__, static_cast<int64_t>(value)); \
1127 return EINVAL; \
1128 }
1129
1130 #define WARN_INT(value, cmp) \
1131 if (!(value cmp)) { \
1132 ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
1133 __FUNCTION__, value); \
1134 }
1135
APerformanceHint_createSession(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos)1136 APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
1137 const int32_t* threadIds, size_t size,
1138 int64_t initialTargetWorkDurationNanos) {
1139 VALIDATE_PTR(manager)
1140 VALIDATE_PTR(threadIds)
1141 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
1142 }
1143
APerformanceHint_createSessionUsingConfig(APerformanceHintManager * manager,ASessionCreationConfig * sessionCreationConfig,APerformanceHintSession ** sessionOut)1144 int APerformanceHint_createSessionUsingConfig(APerformanceHintManager* manager,
1145 ASessionCreationConfig* sessionCreationConfig,
1146 APerformanceHintSession** sessionOut) {
1147 VALIDATE_PTR(manager);
1148 VALIDATE_PTR(sessionCreationConfig);
1149 VALIDATE_PTR(sessionOut);
1150 *sessionOut = nullptr;
1151
1152 return manager->createSessionUsingConfig(sessionCreationConfig, sessionOut);
1153 }
1154
APerformanceHint_createSessionUsingConfigInternal(APerformanceHintManager * manager,ASessionCreationConfig * sessionCreationConfig,APerformanceHintSession ** sessionOut,SessionTag tag)1155 int APerformanceHint_createSessionUsingConfigInternal(APerformanceHintManager* manager,
1156 ASessionCreationConfig* sessionCreationConfig,
1157 APerformanceHintSession** sessionOut,
1158 SessionTag tag) {
1159 VALIDATE_PTR(manager);
1160 VALIDATE_PTR(sessionCreationConfig);
1161 VALIDATE_PTR(sessionOut);
1162 *sessionOut = nullptr;
1163
1164 return manager->createSessionUsingConfig(sessionCreationConfig, sessionOut,
1165 static_cast<hal::SessionTag>(tag));
1166 }
1167
APerformanceHint_createSessionInternal(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos,SessionTag tag)1168 APerformanceHintSession* APerformanceHint_createSessionInternal(
1169 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
1170 int64_t initialTargetWorkDurationNanos, SessionTag tag) {
1171 VALIDATE_PTR(manager)
1172 VALIDATE_PTR(threadIds)
1173 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
1174 static_cast<hal::SessionTag>(tag));
1175 }
1176
APerformanceHint_createSessionFromJava(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos)1177 APerformanceHintSession* APerformanceHint_createSessionFromJava(
1178 APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
1179 int64_t initialTargetWorkDurationNanos) {
1180 VALIDATE_PTR(manager)
1181 VALIDATE_PTR(threadIds)
1182 return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
1183 hal::SessionTag::APP, true);
1184 }
1185
APerformanceHint_borrowSessionFromJava(JNIEnv * env,jobject sessionObj)1186 APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env, jobject sessionObj) {
1187 VALIDATE_PTR(env)
1188 VALIDATE_PTR(sessionObj)
1189 return APerformanceHintManager::getInstance()->getSessionFromJava(env, sessionObj);
1190 }
1191
APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager * manager)1192 int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
1193 VALIDATE_PTR(manager)
1194 return manager->getPreferredRateNanos();
1195 }
1196
APerformanceHint_getMaxGraphicsPipelineThreadsCount(APerformanceHintManager * manager)1197 int APerformanceHint_getMaxGraphicsPipelineThreadsCount(APerformanceHintManager* manager) {
1198 VALIDATE_PTR(manager);
1199 return manager->getMaxGraphicsPipelineThreadsCount();
1200 }
1201
APerformanceHint_updateTargetWorkDuration(APerformanceHintSession * session,int64_t targetDurationNanos)1202 int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
1203 int64_t targetDurationNanos) {
1204 VALIDATE_PTR(session)
1205 VALIDATE_INT(targetDurationNanos, >= 0)
1206 return session->updateTargetWorkDuration(targetDurationNanos);
1207 }
1208
APerformanceHint_reportActualWorkDuration(APerformanceHintSession * session,int64_t actualDurationNanos)1209 int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
1210 int64_t actualDurationNanos) {
1211 VALIDATE_PTR(session)
1212 VALIDATE_INT(actualDurationNanos, > 0)
1213 return session->reportActualWorkDuration(actualDurationNanos);
1214 }
1215
APerformanceHint_closeSession(APerformanceHintSession * session)1216 void APerformanceHint_closeSession(APerformanceHintSession* session) {
1217 VALIDATE_PTR(session)
1218 if (session->isJava()) {
1219 LOG_ALWAYS_FATAL("%s: Java-owned PerformanceHintSession cannot be closed in native",
1220 __FUNCTION__);
1221 return;
1222 }
1223 delete session;
1224 }
1225
APerformanceHint_closeSessionFromJava(APerformanceHintSession * session)1226 void APerformanceHint_closeSessionFromJava(APerformanceHintSession* session) {
1227 VALIDATE_PTR(session)
1228 delete session;
1229 }
1230
APerformanceHint_sendHint(APerformanceHintSession * session,SessionHint hint)1231 int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
1232 VALIDATE_PTR(session)
1233 std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)};
1234 int64_t now = ::android::uptimeNanos();
1235 return session->sendHints(hints, now, "HWUI hint");
1236 }
1237
APerformanceHint_setThreads(APerformanceHintSession * session,const pid_t * threadIds,size_t size)1238 int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
1239 size_t size) {
1240 VALIDATE_PTR(session)
1241 VALIDATE_PTR(threadIds)
1242 return session->setThreads(threadIds, size);
1243 }
1244
APerformanceHint_getThreadIds(APerformanceHintSession * session,int32_t * const threadIds,size_t * const size)1245 int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
1246 size_t* const size) {
1247 VALIDATE_PTR(session)
1248 return session->getThreadIds(threadIds, size);
1249 }
1250
APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession * session,bool enabled)1251 int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
1252 VALIDATE_PTR(session)
1253 return session->setPreferPowerEfficiency(enabled);
1254 }
1255
APerformanceHint_reportActualWorkDuration2(APerformanceHintSession * session,AWorkDuration * workDurationPtr)1256 int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
1257 AWorkDuration* workDurationPtr) {
1258 VALIDATE_PTR(session)
1259 VALIDATE_PTR(workDurationPtr)
1260 VALIDATE_INT(workDurationPtr->durationNanos, > 0)
1261 VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
1262 VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
1263 VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
1264 VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
1265 return session->reportActualWorkDuration(workDurationPtr);
1266 }
1267
APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession * session,bool cpu,bool gpu,const char * debugName)1268 int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu,
1269 const char* debugName) {
1270 VALIDATE_PTR(session)
1271 VALIDATE_PTR(debugName)
1272 return session->notifyWorkloadIncrease(cpu, gpu, debugName);
1273 }
1274
APerformanceHint_notifyWorkloadReset(APerformanceHintSession * session,bool cpu,bool gpu,const char * debugName)1275 int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu,
1276 const char* debugName) {
1277 VALIDATE_PTR(session)
1278 VALIDATE_PTR(debugName)
1279 return session->notifyWorkloadReset(cpu, gpu, debugName);
1280 }
1281
APerformanceHint_notifyWorkloadSpike(APerformanceHintSession * session,bool cpu,bool gpu,const char * debugName)1282 int APerformanceHint_notifyWorkloadSpike(APerformanceHintSession* session, bool cpu, bool gpu,
1283 const char* debugName) {
1284 VALIDATE_PTR(session)
1285 VALIDATE_PTR(debugName)
1286 return session->notifyWorkloadSpike(cpu, gpu, debugName);
1287 }
1288
APerformanceHint_setNativeSurfaces(APerformanceHintSession * session,ANativeWindow ** nativeWindows,size_t nativeWindowsSize,ASurfaceControl ** surfaceControls,size_t surfaceControlsSize)1289 int APerformanceHint_setNativeSurfaces(APerformanceHintSession* session,
1290 ANativeWindow** nativeWindows, size_t nativeWindowsSize,
1291 ASurfaceControl** surfaceControls,
1292 size_t surfaceControlsSize) {
1293 VALIDATE_PTR(session)
1294 return session->setNativeSurfaces(nativeWindows, nativeWindowsSize, surfaceControls,
1295 surfaceControlsSize);
1296 }
1297
APerformanceHint_isFeatureSupported(APerformanceHintFeature feature)1298 bool APerformanceHint_isFeatureSupported(APerformanceHintFeature feature) {
1299 APerformanceHintManager* manager = APerformanceHintManager::getInstance();
1300 if (manager == nullptr) {
1301 // Clearly whatever it is isn't supported in this case
1302 return false;
1303 }
1304 return manager->isFeatureSupported(feature);
1305 }
1306
AWorkDuration_create()1307 AWorkDuration* AWorkDuration_create() {
1308 return new AWorkDuration();
1309 }
1310
AWorkDuration_release(AWorkDuration * aWorkDuration)1311 void AWorkDuration_release(AWorkDuration* aWorkDuration) {
1312 VALIDATE_PTR(aWorkDuration)
1313 delete aWorkDuration;
1314 }
1315
AWorkDuration_setActualTotalDurationNanos(AWorkDuration * aWorkDuration,int64_t actualTotalDurationNanos)1316 void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
1317 int64_t actualTotalDurationNanos) {
1318 VALIDATE_PTR(aWorkDuration)
1319 WARN_INT(actualTotalDurationNanos, > 0)
1320 aWorkDuration->durationNanos = actualTotalDurationNanos;
1321 }
1322
AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration * aWorkDuration,int64_t workPeriodStartTimestampNanos)1323 void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
1324 int64_t workPeriodStartTimestampNanos) {
1325 VALIDATE_PTR(aWorkDuration)
1326 WARN_INT(workPeriodStartTimestampNanos, > 0)
1327 aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
1328 }
1329
AWorkDuration_setActualCpuDurationNanos(AWorkDuration * aWorkDuration,int64_t actualCpuDurationNanos)1330 void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
1331 int64_t actualCpuDurationNanos) {
1332 VALIDATE_PTR(aWorkDuration)
1333 WARN_INT(actualCpuDurationNanos, >= 0)
1334 aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
1335 }
1336
AWorkDuration_setActualGpuDurationNanos(AWorkDuration * aWorkDuration,int64_t actualGpuDurationNanos)1337 void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
1338 int64_t actualGpuDurationNanos) {
1339 VALIDATE_PTR(aWorkDuration)
1340 WARN_INT(actualGpuDurationNanos, >= 0)
1341 aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
1342 }
1343
APerformanceHint_setIHintManagerForTesting(void * iManager)1344 void APerformanceHint_setIHintManagerForTesting(void* iManager) {
1345 if (iManager == nullptr) {
1346 gHintManagerForTesting = nullptr;
1347 }
1348 gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
1349 }
1350
APerformanceHint_setUseFMQForTesting(bool enabled)1351 void APerformanceHint_setUseFMQForTesting(bool enabled) {
1352 gForceFMQEnabled = enabled;
1353 }
1354
ASessionCreationConfig_create()1355 ASessionCreationConfig* ASessionCreationConfig_create() {
1356 return new ASessionCreationConfig();
1357 }
1358
ASessionCreationConfig_release(ASessionCreationConfig * config)1359 void ASessionCreationConfig_release(ASessionCreationConfig* config) {
1360 VALIDATE_PTR(config)
1361 delete config;
1362 }
1363
ASessionCreationConfig_setTids(ASessionCreationConfig * config,const pid_t * tids,size_t size)1364 void ASessionCreationConfig_setTids(ASessionCreationConfig* config, const pid_t* tids,
1365 size_t size) {
1366 VALIDATE_PTR(config)
1367 VALIDATE_PTR(tids)
1368 HARD_VALIDATE_INT(size, > 0)
1369
1370 config->tids = std::vector<int32_t>(tids, tids + size);
1371 }
1372
ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig * config,int64_t targetWorkDurationNanos)1373 void ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig* config,
1374 int64_t targetWorkDurationNanos) {
1375 VALIDATE_PTR(config)
1376 config->targetWorkDurationNanos = targetWorkDurationNanos;
1377 }
1378
ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig * config,bool enabled)1379 void ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig* config, bool enabled) {
1380 VALIDATE_PTR(config)
1381 config->setMode(hal::SessionMode::POWER_EFFICIENCY, enabled);
1382 }
1383
ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig * config,bool enabled)1384 void ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, bool enabled) {
1385 VALIDATE_PTR(config)
1386 config->setMode(hal::SessionMode::GRAPHICS_PIPELINE, enabled);
1387 }
1388
APerformanceHint_getRateLimiterPropertiesForTesting(int32_t * maxLoadHintsPerInterval,int64_t * loadHintInterval)1389 void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
1390 int64_t* loadHintInterval) {
1391 *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval;
1392 *loadHintInterval = kLoadHintInterval;
1393 }
1394
APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior)1395 void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
1396 kForceNewHintBehavior = newBehavior;
1397 }
1398
ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig * config,ANativeWindow ** nativeWindows,size_t nativeWindowsSize,ASurfaceControl ** surfaceControls,size_t surfaceControlsSize)1399 void ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config,
1400 ANativeWindow** nativeWindows,
1401 size_t nativeWindowsSize,
1402 ASurfaceControl** surfaceControls,
1403 size_t surfaceControlsSize) {
1404 VALIDATE_PTR(config)
1405 APerformanceHintManager::layersFromNativeSurfaces<wp<IBinder>>(nativeWindows, nativeWindowsSize,
1406 surfaceControls,
1407 surfaceControlsSize,
1408 config->layers);
1409 }
1410
ASessionCreationConfig_setUseAutoTiming(ASessionCreationConfig * _Nonnull config,bool cpu,bool gpu)1411 void ASessionCreationConfig_setUseAutoTiming(ASessionCreationConfig* _Nonnull config, bool cpu,
1412 bool gpu) {
1413 VALIDATE_PTR(config)
1414 config->setMode(hal::SessionMode::AUTO_CPU, cpu);
1415 config->setMode(hal::SessionMode::AUTO_GPU, gpu);
1416 }
1417