• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SessionHint.h>
20 #include <aidl/android/hardware/power/SessionMode.h>
21 #include <aidl/android/hardware/power/SessionTag.h>
22 #include <aidl/android/hardware/power/WorkDuration.h>
23 #include <aidl/android/os/IHintManager.h>
24 #include <aidl/android/os/IHintSession.h>
25 #include <android-base/stringprintf.h>
26 #include <android/binder_manager.h>
27 #include <android/binder_status.h>
28 #include <android/performance_hint.h>
29 #include <android/trace.h>
30 #include <inttypes.h>
31 #include <performance_hint_private.h>
32 #include <utils/SystemClock.h>
33 
34 #include <chrono>
35 #include <set>
36 #include <utility>
37 #include <vector>
38 
39 using namespace android;
40 using namespace aidl::android::os;
41 
42 using namespace std::chrono_literals;
43 
44 // Namespace for AIDL types coming from the PowerHAL
45 namespace hal = aidl::android::hardware::power;
46 
47 using android::base::StringPrintf;
48 
49 struct APerformanceHintSession;
50 
51 constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
52 struct AWorkDuration : public hal::WorkDuration {};
53 
54 // Shared lock for the whole PerformanceHintManager and sessions
55 static std::mutex sHintMutex = std::mutex{};
56 
57 struct APerformanceHintManager {
58 public:
59     static APerformanceHintManager* getInstance();
60     APerformanceHintManager(std::shared_ptr<IHintManager> service, int64_t preferredRateNanos);
61     APerformanceHintManager() = delete;
62     ~APerformanceHintManager() = default;
63 
64     APerformanceHintSession* createSession(const int32_t* threadIds, size_t size,
65                                            int64_t initialTargetWorkDurationNanos,
66                                            hal::SessionTag tag = hal::SessionTag::APP);
67     int64_t getPreferredRateNanos() const;
68 
69 private:
70     // Necessary to create an empty binder object
tokenStubOnCreateAPerformanceHintManager71     static void* tokenStubOnCreate(void*) {
72         return nullptr;
73     }
tokenStubOnDestroyAPerformanceHintManager74     static void tokenStubOnDestroy(void*) {}
tokenStubOnTransactAPerformanceHintManager75     static binder_status_t tokenStubOnTransact(AIBinder*, transaction_code_t, const AParcel*,
76                                                AParcel*) {
77         return STATUS_OK;
78     }
79 
80     static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
81 
82     std::shared_ptr<IHintManager> mHintManager;
83     ndk::SpAIBinder mToken;
84     const int64_t mPreferredRateNanos;
85 };
86 
87 struct APerformanceHintSession {
88 public:
89     APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
90                             std::shared_ptr<IHintSession> session, int64_t preferredRateNanos,
91                             int64_t targetDurationNanos,
92                             std::optional<hal::SessionConfig> sessionConfig);
93     APerformanceHintSession() = delete;
94     ~APerformanceHintSession();
95 
96     int updateTargetWorkDuration(int64_t targetDurationNanos);
97     int reportActualWorkDuration(int64_t actualDurationNanos);
98     int sendHint(SessionHint hint);
99     int setThreads(const int32_t* threadIds, size_t size);
100     int getThreadIds(int32_t* const threadIds, size_t* size);
101     int setPreferPowerEfficiency(bool enabled);
102     int reportActualWorkDuration(AWorkDuration* workDuration);
103 
104 private:
105     friend struct APerformanceHintManager;
106 
107     int reportActualWorkDurationInternal(AWorkDuration* workDuration);
108 
109     std::shared_ptr<IHintManager> mHintManager;
110     std::shared_ptr<IHintSession> mHintSession;
111     // HAL preferred update rate
112     const int64_t mPreferredRateNanos;
113     // Target duration for choosing update rate
114     int64_t mTargetDurationNanos;
115     // First target hit timestamp
116     int64_t mFirstTargetMetTimestamp;
117     // Last target hit timestamp
118     int64_t mLastTargetMetTimestamp;
119     // Last hint reported from sendHint indexed by hint value
120     std::vector<int64_t> mLastHintSentTimestamp;
121     // Cached samples
122     std::vector<hal::WorkDuration> mActualWorkDurations;
123     std::string mSessionName;
124     static int64_t sIDCounter;
125     // The most recent set of thread IDs
126     std::vector<int32_t> mLastThreadIDs;
127     std::optional<hal::SessionConfig> mSessionConfig;
128     // Tracing helpers
129     void traceThreads(std::vector<int32_t>& tids);
130     void tracePowerEfficient(bool powerEfficient);
131     void traceActualDuration(int64_t actualDuration);
132     void traceBatchSize(size_t batchSize);
133     void traceTargetDuration(int64_t targetDuration);
134 };
135 
136 static std::shared_ptr<IHintManager>* gIHintManagerForTesting = nullptr;
137 static APerformanceHintManager* gHintManagerForTesting = nullptr;
138 // Start above the int32 range so we don't collide with config sessions
139 int64_t APerformanceHintSession::sIDCounter = INT32_MAX;
140 
141 // ===================================== APerformanceHintManager implementation
APerformanceHintManager(std::shared_ptr<IHintManager> manager,int64_t preferredRateNanos)142 APerformanceHintManager::APerformanceHintManager(std::shared_ptr<IHintManager> manager,
143                                                  int64_t preferredRateNanos)
144       : mHintManager(std::move(manager)), mPreferredRateNanos(preferredRateNanos) {
145     static AIBinder_Class* tokenBinderClass =
146             AIBinder_Class_define("phm_token", tokenStubOnCreate, tokenStubOnDestroy,
147                                   tokenStubOnTransact);
148     mToken = ndk::SpAIBinder(AIBinder_new(tokenBinderClass, nullptr));
149 }
150 
getInstance()151 APerformanceHintManager* APerformanceHintManager::getInstance() {
152     if (gHintManagerForTesting) return gHintManagerForTesting;
153     if (gIHintManagerForTesting) {
154         APerformanceHintManager* manager = create(*gIHintManagerForTesting);
155         gIHintManagerForTesting = nullptr;
156         return manager;
157     }
158     static APerformanceHintManager* instance = create(nullptr);
159     return instance;
160 }
161 
create(std::shared_ptr<IHintManager> manager)162 APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintManager> manager) {
163     if (!manager) {
164         manager = IHintManager::fromBinder(
165                 ndk::SpAIBinder(AServiceManager_waitForService("performance_hint")));
166     }
167     if (manager == nullptr) {
168         ALOGE("%s: PerformanceHint service is not ready ", __FUNCTION__);
169         return nullptr;
170     }
171     int64_t preferredRateNanos = -1L;
172     ndk::ScopedAStatus ret = manager->getHintSessionPreferredRate(&preferredRateNanos);
173     if (!ret.isOk()) {
174         ALOGE("%s: PerformanceHint cannot get preferred rate. %s", __FUNCTION__, ret.getMessage());
175         return nullptr;
176     }
177     if (preferredRateNanos <= 0) {
178         preferredRateNanos = -1L;
179     }
180     return new APerformanceHintManager(std::move(manager), preferredRateNanos);
181 }
182 
createSession(const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos,hal::SessionTag tag)183 APerformanceHintSession* APerformanceHintManager::createSession(
184         const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos,
185         hal::SessionTag tag) {
186     std::vector<int32_t> tids(threadIds, threadIds + size);
187     std::shared_ptr<IHintSession> session;
188     ndk::ScopedAStatus ret;
189     std::optional<hal::SessionConfig> sessionConfig;
190     ret = mHintManager->createHintSessionWithConfig(mToken, tids, initialTargetWorkDurationNanos,
191                                                     tag, &sessionConfig, &session);
192 
193     if (!ret.isOk() || !session) {
194         return nullptr;
195     }
196     auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
197                                            initialTargetWorkDurationNanos, sessionConfig);
198     std::scoped_lock lock(sHintMutex);
199     out->traceThreads(tids);
200     out->traceTargetDuration(initialTargetWorkDurationNanos);
201     out->tracePowerEfficient(false);
202     return out;
203 }
204 
getPreferredRateNanos() const205 int64_t APerformanceHintManager::getPreferredRateNanos() const {
206     return mPreferredRateNanos;
207 }
208 
209 // ===================================== APerformanceHintSession implementation
210 
APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,std::shared_ptr<IHintSession> session,int64_t preferredRateNanos,int64_t targetDurationNanos,std::optional<hal::SessionConfig> sessionConfig)211 APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager,
212                                                  std::shared_ptr<IHintSession> session,
213                                                  int64_t preferredRateNanos,
214                                                  int64_t targetDurationNanos,
215                                                  std::optional<hal::SessionConfig> sessionConfig)
216       : mHintManager(hintManager),
217         mHintSession(std::move(session)),
218         mPreferredRateNanos(preferredRateNanos),
219         mTargetDurationNanos(targetDurationNanos),
220         mFirstTargetMetTimestamp(0),
221         mLastTargetMetTimestamp(0),
222         mSessionConfig(sessionConfig) {
223     if (sessionConfig->id > INT32_MAX) {
224         ALOGE("Session ID too large, must fit 32-bit integer");
225     }
226     std::scoped_lock lock(sHintMutex);
227     constexpr int numEnums =
228             ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin();
229     mLastHintSentTimestamp = std::vector<int64_t>(numEnums, 0);
230     int64_t traceId = sessionConfig.has_value() ? sessionConfig->id : ++sIDCounter;
231     mSessionName = android::base::StringPrintf("ADPF Session %" PRId64, traceId);
232 }
233 
~APerformanceHintSession()234 APerformanceHintSession::~APerformanceHintSession() {
235     ndk::ScopedAStatus ret = mHintSession->close();
236     if (!ret.isOk()) {
237         ALOGE("%s: HintSession close failed: %s", __FUNCTION__, ret.getMessage());
238     }
239 }
240 
updateTargetWorkDuration(int64_t targetDurationNanos)241 int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
242     if (targetDurationNanos <= 0) {
243         ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
244         return EINVAL;
245     }
246     ndk::ScopedAStatus ret = mHintSession->updateTargetWorkDuration(targetDurationNanos);
247     if (!ret.isOk()) {
248         ALOGE("%s: HintSession updateTargetWorkDuration failed: %s", __FUNCTION__,
249               ret.getMessage());
250         return EPIPE;
251     }
252     std::scoped_lock lock(sHintMutex);
253     mTargetDurationNanos = targetDurationNanos;
254     /**
255      * Most of the workload is target_duration dependent, so now clear the cached samples
256      * as they are most likely obsolete.
257      */
258     mActualWorkDurations.clear();
259     traceBatchSize(0);
260     traceTargetDuration(targetDurationNanos);
261     mFirstTargetMetTimestamp = 0;
262     mLastTargetMetTimestamp = 0;
263     return 0;
264 }
265 
reportActualWorkDuration(int64_t actualDurationNanos)266 int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNanos) {
267     hal::WorkDuration workDuration{.durationNanos = actualDurationNanos,
268                                    .workPeriodStartTimestampNanos = 0,
269                                    .cpuDurationNanos = actualDurationNanos,
270                                    .gpuDurationNanos = 0};
271 
272     return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
273 }
274 
sendHint(SessionHint hint)275 int APerformanceHintSession::sendHint(SessionHint hint) {
276     std::scoped_lock lock(sHintMutex);
277     if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
278         ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
279         return EINVAL;
280     }
281     int64_t now = uptimeNanos();
282 
283     // Limit sendHint to a pre-detemined rate for safety
284     if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
285         return 0;
286     }
287 
288     ndk::ScopedAStatus ret = mHintSession->sendHint(hint);
289 
290     if (!ret.isOk()) {
291         ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage());
292         return EPIPE;
293     }
294     mLastHintSentTimestamp[hint] = now;
295     return 0;
296 }
297 
setThreads(const int32_t * threadIds,size_t size)298 int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
299     if (size == 0) {
300         ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__);
301         return EINVAL;
302     }
303     std::vector<int32_t> tids(threadIds, threadIds + size);
304     ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
305     if (!ret.isOk()) {
306         ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
307         if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
308             return EINVAL;
309         } else if (ret.getExceptionCode() == EX_SECURITY) {
310             return EPERM;
311         }
312         return EPIPE;
313     }
314 
315     std::scoped_lock lock(sHintMutex);
316     traceThreads(tids);
317 
318     return 0;
319 }
320 
getThreadIds(int32_t * const threadIds,size_t * size)321 int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
322     std::vector<int32_t> tids;
323     ndk::ScopedAStatus ret = mHintManager->getHintSessionThreadIds(mHintSession, &tids);
324     if (!ret.isOk()) {
325         ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
326         return EPIPE;
327     }
328 
329     // When threadIds is nullptr, this is the first call to determine the size
330     // of the thread ids list.
331     if (threadIds == nullptr) {
332         *size = tids.size();
333         return 0;
334     }
335 
336     // Second call to return the actual list of thread ids.
337     *size = tids.size();
338     for (size_t i = 0; i < *size; ++i) {
339         threadIds[i] = tids[i];
340     }
341     return 0;
342 }
343 
setPreferPowerEfficiency(bool enabled)344 int APerformanceHintSession::setPreferPowerEfficiency(bool enabled) {
345     ndk::ScopedAStatus ret =
346             mHintSession->setMode(static_cast<int32_t>(hal::SessionMode::POWER_EFFICIENCY),
347                                   enabled);
348 
349     if (!ret.isOk()) {
350         ALOGE("%s: HintSession setPreferPowerEfficiency failed: %s", __FUNCTION__,
351               ret.getMessage());
352         return EPIPE;
353     }
354     std::scoped_lock lock(sHintMutex);
355     tracePowerEfficient(enabled);
356     return OK;
357 }
358 
reportActualWorkDuration(AWorkDuration * workDuration)359 int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuration) {
360     return reportActualWorkDurationInternal(workDuration);
361 }
362 
reportActualWorkDurationInternal(AWorkDuration * workDuration)363 int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
364     int64_t actualTotalDurationNanos = workDuration->durationNanos;
365     int64_t now = uptimeNanos();
366     workDuration->timeStampNanos = now;
367     std::scoped_lock lock(sHintMutex);
368     traceActualDuration(workDuration->durationNanos);
369     mActualWorkDurations.push_back(std::move(*workDuration));
370 
371     if (actualTotalDurationNanos >= mTargetDurationNanos) {
372         // Reset timestamps if we are equal or over the target.
373         mFirstTargetMetTimestamp = 0;
374     } else {
375         // Set mFirstTargetMetTimestamp for first time meeting target.
376         if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
377             (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
378             mFirstTargetMetTimestamp = now;
379         }
380         /**
381          * Rate limit the change if the update is over mPreferredRateNanos since first
382          * meeting target and less than mPreferredRateNanos since last meeting target.
383          */
384         if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
385             now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
386             traceBatchSize(mActualWorkDurations.size());
387             return 0;
388         }
389         mLastTargetMetTimestamp = now;
390     }
391 
392     ndk::ScopedAStatus ret = mHintSession->reportActualWorkDuration2(mActualWorkDurations);
393     if (!ret.isOk()) {
394         ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
395               ret.getMessage());
396         mFirstTargetMetTimestamp = 0;
397         mLastTargetMetTimestamp = 0;
398         traceBatchSize(mActualWorkDurations.size());
399         return ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
400     }
401     mActualWorkDurations.clear();
402     traceBatchSize(0);
403 
404     return 0;
405 }
406 // ===================================== Tracing helpers
407 
traceThreads(std::vector<int32_t> & tids)408 void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
409     std::set<int32_t> tidSet{tids.begin(), tids.end()};
410 
411     // Disable old TID tracing
412     for (int32_t tid : mLastThreadIDs) {
413         if (!tidSet.count(tid)) {
414             std::string traceName =
415                     android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
416             ATrace_setCounter(traceName.c_str(), 0);
417         }
418     }
419 
420     // Add new TID tracing
421     for (int32_t tid : tids) {
422         std::string traceName =
423                 android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
424         ATrace_setCounter(traceName.c_str(), 1);
425     }
426 
427     mLastThreadIDs = std::move(tids);
428 }
429 
tracePowerEfficient(bool powerEfficient)430 void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
431     ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
432 }
433 
traceActualDuration(int64_t actualDuration)434 void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
435     ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
436 }
437 
traceBatchSize(size_t batchSize)438 void APerformanceHintSession::traceBatchSize(size_t batchSize) {
439     std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
440     ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
441 }
442 
traceTargetDuration(int64_t targetDuration)443 void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
444     ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
445 }
446 
447 // ===================================== C API
APerformanceHint_getManager()448 APerformanceHintManager* APerformanceHint_getManager() {
449     return APerformanceHintManager::getInstance();
450 }
451 
452 #define VALIDATE_PTR(ptr) \
453     LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
454 
455 #define VALIDATE_INT(value, cmp)                                                             \
456     if (!(value cmp)) {                                                                      \
457         ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
458               __FUNCTION__, value);                                                          \
459         return EINVAL;                                                                       \
460     }
461 
462 #define WARN_INT(value, cmp)                                                                 \
463     if (!(value cmp)) {                                                                      \
464         ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
465               __FUNCTION__, value);                                                          \
466     }
467 
APerformanceHint_createSession(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos)468 APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager* manager,
469                                                         const int32_t* threadIds, size_t size,
470                                                         int64_t initialTargetWorkDurationNanos) {
471     VALIDATE_PTR(manager)
472     VALIDATE_PTR(threadIds)
473     return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
474 }
475 
APerformanceHint_createSessionInternal(APerformanceHintManager * manager,const int32_t * threadIds,size_t size,int64_t initialTargetWorkDurationNanos,SessionTag tag)476 APerformanceHintSession* APerformanceHint_createSessionInternal(
477         APerformanceHintManager* manager, const int32_t* threadIds, size_t size,
478         int64_t initialTargetWorkDurationNanos, SessionTag tag) {
479     VALIDATE_PTR(manager)
480     VALIDATE_PTR(threadIds)
481     return manager->createSession(threadIds, size, initialTargetWorkDurationNanos,
482                                   static_cast<hal::SessionTag>(tag));
483 }
484 
APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager * manager)485 int64_t APerformanceHint_getPreferredUpdateRateNanos(APerformanceHintManager* manager) {
486     VALIDATE_PTR(manager)
487     return manager->getPreferredRateNanos();
488 }
489 
APerformanceHint_updateTargetWorkDuration(APerformanceHintSession * session,int64_t targetDurationNanos)490 int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
491                                               int64_t targetDurationNanos) {
492     VALIDATE_PTR(session)
493     return session->updateTargetWorkDuration(targetDurationNanos);
494 }
495 
APerformanceHint_reportActualWorkDuration(APerformanceHintSession * session,int64_t actualDurationNanos)496 int APerformanceHint_reportActualWorkDuration(APerformanceHintSession* session,
497                                               int64_t actualDurationNanos) {
498     VALIDATE_PTR(session)
499     VALIDATE_INT(actualDurationNanos, > 0)
500     return session->reportActualWorkDuration(actualDurationNanos);
501 }
502 
APerformanceHint_closeSession(APerformanceHintSession * session)503 void APerformanceHint_closeSession(APerformanceHintSession* session) {
504     VALIDATE_PTR(session)
505     delete session;
506 }
507 
APerformanceHint_sendHint(APerformanceHintSession * session,SessionHint hint)508 int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) {
509     VALIDATE_PTR(session)
510     return session->sendHint(hint);
511 }
512 
APerformanceHint_setThreads(APerformanceHintSession * session,const pid_t * threadIds,size_t size)513 int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds,
514                                 size_t size) {
515     VALIDATE_PTR(session)
516     VALIDATE_PTR(threadIds)
517     return session->setThreads(threadIds, size);
518 }
519 
APerformanceHint_getThreadIds(APerformanceHintSession * session,int32_t * const threadIds,size_t * const size)520 int APerformanceHint_getThreadIds(APerformanceHintSession* session, int32_t* const threadIds,
521                                   size_t* const size) {
522     VALIDATE_PTR(session)
523     return session->getThreadIds(threadIds, size);
524 }
525 
APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession * session,bool enabled)526 int APerformanceHint_setPreferPowerEfficiency(APerformanceHintSession* session, bool enabled) {
527     VALIDATE_PTR(session)
528     return session->setPreferPowerEfficiency(enabled);
529 }
530 
APerformanceHint_reportActualWorkDuration2(APerformanceHintSession * session,AWorkDuration * workDurationPtr)531 int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session,
532                                                AWorkDuration* workDurationPtr) {
533     VALIDATE_PTR(session)
534     VALIDATE_PTR(workDurationPtr)
535     VALIDATE_INT(workDurationPtr->durationNanos, > 0)
536     VALIDATE_INT(workDurationPtr->workPeriodStartTimestampNanos, > 0)
537     VALIDATE_INT(workDurationPtr->cpuDurationNanos, >= 0)
538     VALIDATE_INT(workDurationPtr->gpuDurationNanos, >= 0)
539     VALIDATE_INT(workDurationPtr->gpuDurationNanos + workDurationPtr->cpuDurationNanos, > 0)
540     return session->reportActualWorkDuration(workDurationPtr);
541 }
542 
AWorkDuration_create()543 AWorkDuration* AWorkDuration_create() {
544     return new AWorkDuration();
545 }
546 
AWorkDuration_release(AWorkDuration * aWorkDuration)547 void AWorkDuration_release(AWorkDuration* aWorkDuration) {
548     VALIDATE_PTR(aWorkDuration)
549     delete aWorkDuration;
550 }
551 
AWorkDuration_setActualTotalDurationNanos(AWorkDuration * aWorkDuration,int64_t actualTotalDurationNanos)552 void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* aWorkDuration,
553                                                int64_t actualTotalDurationNanos) {
554     VALIDATE_PTR(aWorkDuration)
555     WARN_INT(actualTotalDurationNanos, > 0)
556     aWorkDuration->durationNanos = actualTotalDurationNanos;
557 }
558 
AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration * aWorkDuration,int64_t workPeriodStartTimestampNanos)559 void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* aWorkDuration,
560                                                     int64_t workPeriodStartTimestampNanos) {
561     VALIDATE_PTR(aWorkDuration)
562     WARN_INT(workPeriodStartTimestampNanos, > 0)
563     aWorkDuration->workPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
564 }
565 
AWorkDuration_setActualCpuDurationNanos(AWorkDuration * aWorkDuration,int64_t actualCpuDurationNanos)566 void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* aWorkDuration,
567                                              int64_t actualCpuDurationNanos) {
568     VALIDATE_PTR(aWorkDuration)
569     WARN_INT(actualCpuDurationNanos, >= 0)
570     aWorkDuration->cpuDurationNanos = actualCpuDurationNanos;
571 }
572 
AWorkDuration_setActualGpuDurationNanos(AWorkDuration * aWorkDuration,int64_t actualGpuDurationNanos)573 void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* aWorkDuration,
574                                              int64_t actualGpuDurationNanos) {
575     VALIDATE_PTR(aWorkDuration)
576     WARN_INT(actualGpuDurationNanos, >= 0)
577     aWorkDuration->gpuDurationNanos = actualGpuDurationNanos;
578 }
579 
APerformanceHint_setIHintManagerForTesting(void * iManager)580 void APerformanceHint_setIHintManagerForTesting(void* iManager) {
581     delete gHintManagerForTesting;
582     gHintManagerForTesting = nullptr;
583     gIHintManagerForTesting = static_cast<std::shared_ptr<IHintManager>*>(iManager);
584 }
585