/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "Hal.h" #include "HalLog.h" #include "HalTypes.h" #include "AndroidBuild.h" #include #include #include #include typedef struct APerformanceHintManager APerformanceHintManager; typedef struct APerformanceHintSession APerformanceHintSession; namespace mozilla { namespace hal_impl { class __attribute__(( availability(android, introduced = 33))) AndroidPerformanceHintSession final : public hal::PerformanceHintSession { // Creates a PerformanceHintSession wrapping the provided NDK // APerformanceHintSession instance. This assumes ownership of aSession, // therefore the caller must not close the session itself. explicit AndroidPerformanceHintSession(APerformanceHintSession* aSession) : mSession(aSession) {} public: AndroidPerformanceHintSession(AndroidPerformanceHintSession& aOther) = delete; AndroidPerformanceHintSession(AndroidPerformanceHintSession&& aOther) { mSession = aOther.mSession; aOther.mSession = nullptr; } static UniquePtr Create( APerformanceHintManager* manager, const nsTArray& threads, int64_t initialTargetWorkDurationNanos) { if (APerformanceHintSession* session = APerformanceHint_createSession( manager, threads.Elements(), threads.Length(), initialTargetWorkDurationNanos)) { return WrapUnique(new AndroidPerformanceHintSession(session)); } else { return nullptr; } } ~AndroidPerformanceHintSession() { if (mSession) { APerformanceHint_closeSession(mSession); } } void UpdateTargetWorkDuration(TimeDuration aDuration) override { APerformanceHint_updateTargetWorkDuration( mSession, aDuration.ToMicroseconds() * 1000); } void ReportActualWorkDuration(TimeDuration aDuration) override { APerformanceHint_reportActualWorkDuration( mSession, aDuration.ToMicroseconds() * 1000); } private: APerformanceHintSession* mSession; }; static APerformanceHintManager* InitManager() { if (__builtin_available(android 33, *)) { // At the time of writing we are only aware of PerformanceHintManager being // implemented on Tensor devices (Pixel 6 and 7 families). On most devices // createSession() will simply return null. However, on some devices // createSession() does return a session but scheduling does not appear to // be affected in any way. Rather than pretending to the caller that // PerformanceHintManager is available on such devices, return null allowing // them to use another means of achieving the performance they require. const auto socManufacturer = java::sdk::Build::SOC_MANUFACTURER()->ToString(); if (!socManufacturer.EqualsASCII("Google")) { return nullptr; } return APerformanceHint_getManager(); } else { return nullptr; } } UniquePtr CreatePerformanceHintSession( const nsTArray& aThreads, mozilla::TimeDuration aTargetWorkDuration) { // C++ guarantees local static variable initialization is thread safe static APerformanceHintManager* manager = InitManager(); if (!manager) { return nullptr; } nsTArray tids(aThreads.Length()); std::transform(aThreads.cbegin(), aThreads.cend(), MakeBackInserter(tids), [](pthread_t handle) { return pthread_gettid_np(handle); }); if (__builtin_available(android 33, *)) { return AndroidPerformanceHintSession::Create( manager, tids, aTargetWorkDuration.ToMicroseconds() * 1000); } else { return nullptr; } } } // namespace hal_impl } // namespace mozilla