diff --git a/fml/cpu_affinity.cc b/fml/cpu_affinity.cc index c4e89613b252a..ae759e24c4218 100644 --- a/fml/cpu_affinity.cc +++ b/fml/cpu_affinity.cc @@ -3,13 +3,34 @@ // found in the LICENSE file. #include "flutter/fml/cpu_affinity.h" +#include "flutter/fml/build_config.h" #include #include #include +#ifdef FML_OS_ANDROID +#include "flutter/fml/platform/android/cpu_affinity.h" +#endif // FML_OS_ANDROID + namespace fml { +std::optional EfficiencyCoreCount() { +#ifdef FML_OS_ANDROID + return AndroidEfficiencyCoreCount(); +#else + return std::nullopt; +#endif +} + +bool RequestAffinity(CpuAffinity affinity) { +#ifdef FML_OS_ANDROID + return AndroidRequestAffinity(affinity); +#else + return true; +#endif +} + CPUSpeedTracker::CPUSpeedTracker(std::vector data) : cpu_speeds_(std::move(data)) { std::optional max_speed = std::nullopt; @@ -61,7 +82,6 @@ const std::vector& CPUSpeedTracker::GetIndices( // required because files under /proc do not always return a valid size // when using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed. std::optional ReadIntFromFile(const std::string& path) { - // size_t data_length = 0u; std::ifstream file; file.open(path.c_str()); diff --git a/fml/cpu_affinity.h b/fml/cpu_affinity.h index 3ea45a4fa3d3b..31b58940a61a1 100644 --- a/fml/cpu_affinity.h +++ b/fml/cpu_affinity.h @@ -27,6 +27,24 @@ enum class CpuAffinity { kNotPerformance, }; +/// @brief Request count of efficiency cores. +/// +/// Efficiency cores are defined as those with the lowest reported +/// cpu_max_freq. If the CPU speed could not be determined, or if all +/// cores have the same reported speed then this returns std::nullopt. +/// That is, the result will never be 0. +std::optional EfficiencyCoreCount(); + +/// @brief Request the given affinity for the current thread. +/// +/// Returns true if successfull, or if it was a no-op. This function is +/// only supported on Android devices. +/// +/// Affinity requests are based on documented CPU speed. This speed data +/// is parsed from cpuinfo_max_freq files, see also: +/// https://www.kernel.org/doc/Documentation/cpu-freq/user-guide.txt +bool RequestAffinity(CpuAffinity affinity); + struct CpuIndexAndSpeed { // The index of the given CPU. size_t index; diff --git a/fml/cpu_affinity_unittests.cc b/fml/cpu_affinity_unittests.cc index eb2f010bc66d6..8a5c90687ed24 100644 --- a/fml/cpu_affinity_unittests.cc +++ b/fml/cpu_affinity_unittests.cc @@ -12,6 +12,11 @@ namespace fml { namespace testing { +TEST(CpuAffinity, NonAndroidPlatformDefaults) { + ASSERT_FALSE(fml::EfficiencyCoreCount().has_value()); + ASSERT_TRUE(fml::RequestAffinity(fml::CpuAffinity::kEfficiency)); +} + TEST(CpuAffinity, NormalSlowMedFastCores) { auto speeds = {CpuIndexAndSpeed{.index = 0, .speed = 1}, CpuIndexAndSpeed{.index = 1, .speed = 2}, diff --git a/fml/platform/android/cpu_affinity.cc b/fml/platform/android/cpu_affinity.cc index 737f8204b9b6e..f7477e97de3b0 100644 --- a/fml/platform/android/cpu_affinity.cc +++ b/fml/platform/android/cpu_affinity.cc @@ -11,6 +11,7 @@ #include #include #include +#include "flutter/fml/logging.h" namespace fml { @@ -36,15 +37,27 @@ void InitCPUInfo(size_t cpu_count) { gCPUTracker = new CPUSpeedTracker(cpu_speeds); } -bool RequestAffinity(CpuAffinity affinity) { +bool SetUpCPUTracker() { // Populate CPU Info if uninitialized. auto count = std::thread::hardware_concurrency(); std::call_once(gCPUTrackerFlag, [count]() { InitCPUInfo(count); }); - if (gCPUTracker == nullptr) { + if (gCPUTracker == nullptr || !gCPUTracker->IsValid()) { + return false; + } + return true; +} + +std::optional AndroidEfficiencyCoreCount() { + if (!SetUpCPUTracker()) { return true; } + auto result = gCPUTracker->GetIndices(CpuAffinity::kEfficiency).size(); + FML_DCHECK(result > 0); + return result; +} - if (!gCPUTracker->IsValid()) { +bool AndroidRequestAffinity(CpuAffinity affinity) { + if (!SetUpCPUTracker()) { return true; } diff --git a/fml/platform/android/cpu_affinity.h b/fml/platform/android/cpu_affinity.h index 03c59ad5e9126..4ce1e7964aef9 100644 --- a/fml/platform/android/cpu_affinity.h +++ b/fml/platform/android/cpu_affinity.h @@ -8,14 +8,10 @@ namespace fml { -/// @brief Request the given affinity for the current thread. -/// -/// Returns true if successfull, or if it was a no-op. This function is -/// only supported on Android devices. -/// -/// Affinity requests are based on documented CPU speed. This speed data -/// is parsed from cpuinfo_max_freq files, see also: -/// https://www.kernel.org/doc/Documentation/cpu-freq/user-guide.txt -bool RequestAffinity(CpuAffinity affinity); +/// @brief Android specific implementation of EfficiencyCoreCount. +std::optional AndroidEfficiencyCoreCount(); + +/// @brief Android specific implementation of RequestAffinity. +bool AndroidRequestAffinity(CpuAffinity affinity); } // namespace fml diff --git a/impeller/renderer/backend/vulkan/context_vk.cc b/impeller/renderer/backend/vulkan/context_vk.cc index 5453f060f7a44..0a7b0db2bfabd 100644 --- a/impeller/renderer/backend/vulkan/context_vk.cc +++ b/impeller/renderer/backend/vulkan/context_vk.cc @@ -16,6 +16,7 @@ #include #include +#include "flutter/fml/cpu_affinity.h" #include "flutter/fml/trace_event.h" #include "impeller/base/validation.h" #include "impeller/renderer/backend/vulkan/allocator_vk.h" @@ -130,13 +131,16 @@ void ContextVK::Setup(Settings settings) { raster_message_loop_ = fml::ConcurrentMessageLoop::Create( std::min(4u, std::thread::hardware_concurrency())); -#ifdef FML_OS_ANDROID raster_message_loop_->PostTaskToAllWorkers([]() { + // Currently we only use the worker task pool for small parts of a frame + // workload, if this changes this setting may need to be adjusted. + fml::RequestAffinity(fml::CpuAffinity::kNotPerformance); +#ifdef FML_OS_ANDROID if (::setpriority(PRIO_PROCESS, gettid(), -5) != 0) { FML_LOG(ERROR) << "Failed to set Workers task runner priority"; } - }); #endif // FML_OS_ANDROID + }); auto& dispatcher = VULKAN_HPP_DEFAULT_DISPATCHER; dispatcher.init(settings.proc_address_callback); diff --git a/impeller/renderer/backend/vulkan/fence_waiter_vk.cc b/impeller/renderer/backend/vulkan/fence_waiter_vk.cc index 4a16c7a79a716..ef906f869af2c 100644 --- a/impeller/renderer/backend/vulkan/fence_waiter_vk.cc +++ b/impeller/renderer/backend/vulkan/fence_waiter_vk.cc @@ -8,6 +8,7 @@ #include #include +#include "flutter/fml/cpu_affinity.h" #include "flutter/fml/thread.h" #include "flutter/fml/trace_event.h" #include "impeller/base/validation.h" @@ -86,8 +87,8 @@ static std::vector GetFencesForWaitSet(const WaitSet& set) { void FenceWaiterVK::Main() { fml::Thread::SetCurrentThreadName( fml::Thread::ThreadConfig{"io.flutter.impeller.fence_waiter"}); - - using namespace std::literals::chrono_literals; + // Since this thread mostly waits on fences, it doesn't need to be fast. + fml::RequestAffinity(fml::CpuAffinity::kEfficiency); while (true) { // We'll read the terminate_ flag within the lock below. diff --git a/impeller/renderer/backend/vulkan/resource_manager_vk.cc b/impeller/renderer/backend/vulkan/resource_manager_vk.cc index f981321c7115e..b719737337f8e 100644 --- a/impeller/renderer/backend/vulkan/resource_manager_vk.cc +++ b/impeller/renderer/backend/vulkan/resource_manager_vk.cc @@ -4,6 +4,7 @@ #include "impeller/renderer/backend/vulkan/resource_manager_vk.h" +#include "flutter/fml/cpu_affinity.h" #include "flutter/fml/thread.h" #include "flutter/fml/trace_event.h" #include "fml/logging.h" @@ -39,6 +40,9 @@ void ResourceManagerVK::Start() { fml::Thread::SetCurrentThreadName( fml::Thread::ThreadConfig{"io.flutter.impeller.resource_manager"}); + // While this code calls destructors it doesn't need to be particularly fast + // with them, as long as it doesn't interrupt raster thread. + fml::RequestAffinity(fml::CpuAffinity::kEfficiency); bool should_exit = false; while (!should_exit) { diff --git a/runtime/dart_vm.cc b/runtime/dart_vm.cc index 48715c5cc2eec..152a4cd6665ce 100644 --- a/runtime/dart_vm.cc +++ b/runtime/dart_vm.cc @@ -11,6 +11,7 @@ #include "flutter/common/settings.h" #include "flutter/fml/compiler_specific.h" +#include "flutter/fml/cpu_affinity.h" #include "flutter/fml/logging.h" #include "flutter/fml/mapping.h" #include "flutter/fml/size.h" @@ -285,7 +286,9 @@ size_t DartVM::GetVMLaunchCount() { DartVM::DartVM(const std::shared_ptr& vm_data, std::shared_ptr isolate_name_server) : settings_(vm_data->GetSettings()), - concurrent_message_loop_(fml::ConcurrentMessageLoop::Create()), + concurrent_message_loop_(fml::ConcurrentMessageLoop::Create( + fml::EfficiencyCoreCount().value_or( + std::thread::hardware_concurrency()))), skia_concurrent_executor_( [runner = concurrent_message_loop_->GetTaskRunner()]( const fml::closure& work) { runner->PostTask(work); }), diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index 39aef72727d9d..4ae3c82203bee 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -16,11 +16,11 @@ #include #include +#include "flutter/fml/cpu_affinity.h" #include "flutter/fml/logging.h" #include "flutter/fml/make_copyable.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/native_library.h" -#include "flutter/fml/platform/android/cpu_affinity.h" #include "flutter/fml/platform/android/jni_util.h" #include "flutter/lib/ui/painting/image_generator_registry.h" #include "flutter/shell/common/rasterizer.h"