1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
11 #include "AndroidBuild.h"
16 #include <sys/types.h>
18 typedef struct APerformanceHintManager APerformanceHintManager
;
19 typedef struct APerformanceHintSession APerformanceHintSession
;
24 #define LOAD_FN(api, lib, name) \
26 api->m##name = reinterpret_cast<Fn##name>(dlsym(handle, #name)); \
27 if (!api->m##name) { \
28 HAL_ERR("Failed to load %s", #name); \
33 class PerformanceHintManagerApi final
{
35 static PerformanceHintManagerApi
* Get() {
36 // C++ guarantees local static variable initialization is thread safe
37 static UniquePtr
<PerformanceHintManagerApi
> api
= Create();
41 APerformanceHintManager
* APerformanceHint_getManager() const {
42 return mAPerformanceHint_getManager();
45 APerformanceHintSession
* APerformanceHint_createSession(
46 APerformanceHintManager
* manager
, const int32_t* threadIds
, size_t size
,
47 int64_t initialTargetWorkDurationNanos
) const {
48 return mAPerformanceHint_createSession(manager
, threadIds
, size
,
49 initialTargetWorkDurationNanos
);
52 int APerformanceHint_updateTargetWorkDuration(
53 APerformanceHintSession
* session
, int64_t targetDurationNanos
) const {
54 return mAPerformanceHint_updateTargetWorkDuration(session
,
58 int APerformanceHint_reportActualWorkDuration(
59 APerformanceHintSession
* session
, int64_t actualDurationNanos
) const {
60 return mAPerformanceHint_reportActualWorkDuration(session
,
64 void APerformanceHint_closeSession(APerformanceHintSession
* session
) const {
65 mAPerformanceHint_closeSession(session
);
69 PerformanceHintManagerApi() = default;
71 static UniquePtr
<PerformanceHintManagerApi
> Create() {
72 if (mozilla::jni::GetAPIVersion() < __ANDROID_API_T__
) {
76 void* const handle
= dlopen("libandroid.so", RTLD_LAZY
| RTLD_LOCAL
);
78 HAL_ERR("Failed to open libandroid.so");
82 auto api
= WrapUnique(new PerformanceHintManagerApi());
83 LOAD_FN(api
, handle
, APerformanceHint_getManager
);
84 LOAD_FN(api
, handle
, APerformanceHint_createSession
);
85 LOAD_FN(api
, handle
, APerformanceHint_updateTargetWorkDuration
);
86 LOAD_FN(api
, handle
, APerformanceHint_reportActualWorkDuration
);
87 LOAD_FN(api
, handle
, APerformanceHint_closeSession
);
92 using FnAPerformanceHint_getManager
= APerformanceHintManager
* (*)();
93 using FnAPerformanceHint_createSession
=
94 APerformanceHintSession
* (*)(APerformanceHintManager
* manager
,
95 const int32_t* threadIds
, size_t size
,
96 int64_t initialTargetWorkDurationNanos
);
97 using FnAPerformanceHint_updateTargetWorkDuration
=
98 int (*)(APerformanceHintSession
* session
, int64_t targetDurationNanos
);
99 using FnAPerformanceHint_reportActualWorkDuration
=
100 int (*)(APerformanceHintSession
* session
, int64_t actualDurationNanos
);
101 using FnAPerformanceHint_closeSession
=
102 void (*)(APerformanceHintSession
* session
);
104 FnAPerformanceHint_getManager mAPerformanceHint_getManager
= nullptr;
105 FnAPerformanceHint_createSession mAPerformanceHint_createSession
= nullptr;
106 FnAPerformanceHint_updateTargetWorkDuration
107 mAPerformanceHint_updateTargetWorkDuration
= nullptr;
108 FnAPerformanceHint_reportActualWorkDuration
109 mAPerformanceHint_reportActualWorkDuration
= nullptr;
110 FnAPerformanceHint_closeSession mAPerformanceHint_closeSession
= nullptr;
113 class AndroidPerformanceHintSession final
: public hal::PerformanceHintSession
{
115 // Creates a PerformanceHintSession wrapping the provided NDK
116 // APerformanceHintSession instance. This assumes ownership of aSession,
117 // therefore the caller must not close the session itself.
118 explicit AndroidPerformanceHintSession(APerformanceHintSession
* aSession
)
119 : mSession(aSession
) {}
121 AndroidPerformanceHintSession(AndroidPerformanceHintSession
& aOther
) = delete;
122 AndroidPerformanceHintSession(AndroidPerformanceHintSession
&& aOther
) {
123 mSession
= aOther
.mSession
;
124 aOther
.mSession
= nullptr;
127 ~AndroidPerformanceHintSession() {
129 PerformanceHintManagerApi::Get()->APerformanceHint_closeSession(mSession
);
133 void UpdateTargetWorkDuration(TimeDuration aDuration
) override
{
134 PerformanceHintManagerApi::Get()->APerformanceHint_updateTargetWorkDuration(
135 mSession
, aDuration
.ToMicroseconds() * 1000);
138 void ReportActualWorkDuration(TimeDuration aDuration
) override
{
139 PerformanceHintManagerApi::Get()->APerformanceHint_reportActualWorkDuration(
140 mSession
, aDuration
.ToMicroseconds() * 1000);
144 APerformanceHintSession
* mSession
;
147 static APerformanceHintManager
* InitManager() {
148 const auto* api
= PerformanceHintManagerApi::Get();
153 // At the time of writing we are only aware of PerformanceHintManager being
154 // implemented on Tensor devices (Pixel 6 and 7 families). On most devices
155 // createSession() will simply return null. However, on some devices
156 // createSession() does return a session but scheduling does not appear to be
157 // affected in any way. Rather than pretending to the caller that
158 // PerformanceHintManager is available on such devices, return null allowing
159 // them to use another means of achieving the performance they require.
160 const auto socManufacturer
= java::sdk::Build::SOC_MANUFACTURER()->ToString();
161 if (!socManufacturer
.EqualsASCII("Google")) {
165 return api
->APerformanceHint_getManager();
168 UniquePtr
<hal::PerformanceHintSession
> CreatePerformanceHintSession(
169 const nsTArray
<PlatformThreadHandle
>& aThreads
,
170 mozilla::TimeDuration aTargetWorkDuration
) {
171 // C++ guarantees local static variable initialization is thread safe
172 static APerformanceHintManager
* manager
= InitManager();
178 const auto* api
= PerformanceHintManagerApi::Get();
180 nsTArray
<pid_t
> tids(aThreads
.Length());
181 std::transform(aThreads
.cbegin(), aThreads
.cend(), MakeBackInserter(tids
),
182 [](pthread_t handle
) { return pthread_gettid_np(handle
); });
184 APerformanceHintSession
* session
= api
->APerformanceHint_createSession(
185 manager
, tids
.Elements(), tids
.Length(),
186 aTargetWorkDuration
.ToMicroseconds() * 1000);
191 return MakeUnique
<AndroidPerformanceHintSession
>(session
);
194 } // namespace hal_impl
195 } // namespace mozilla