From c51b9fed0fe2ecf33689c8ef04a24d11b57350a6 Mon Sep 17 00:00:00 2001 From: CamilleLaVey Date: Wed, 29 Jul 2026 00:27:04 -0400 Subject: [PATCH] [TEST] Rework Android CPU affinity/ threading 2 --- src/common/thread.cpp | 42 +++++++++++++++++++ src/common/thread.h | 6 +++ src/common/thread_worker.h | 11 +++-- .../renderer_vulkan/vk_pipeline_cache.cpp | 5 ++- .../texture_cache/texture_cache_base.h | 3 +- src/video_core/textures/workers.cpp | 5 ++- 6 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 6298e34f8e..2b920d3c42 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp @@ -1,5 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -111,6 +112,35 @@ const cpu_set_t& PerformanceCoreMask() { static const cpu_set_t mask = ComputePerformanceCoreMask(); return mask; } + +cpu_set_t ComputeEfficiencyCoreMask() { + cpu_set_t mask; + CPU_ZERO(&mask); + + const cpu_set_t& performance = PerformanceCoreMask(); + if (CPU_COUNT(&performance) == 0) { + return mask; + } + + cpu_set_t allowed; + CPU_ZERO(&allowed); + if (sched_getaffinity(gettid(), sizeof(allowed), &allowed) != 0) { + return mask; + } + + const int total = static_cast(std::thread::hardware_concurrency()); + for (int cpu = 0; cpu < total; ++cpu) { + if (CPU_ISSET(cpu, &allowed) && !CPU_ISSET(cpu, &performance)) { + CPU_SET(cpu, &mask); + } + } + return mask; +} + +const cpu_set_t& EfficiencyCoreMask() { + static const cpu_set_t mask = ComputeEfficiencyCoreMask(); + return mask; +} } // Anonymous namespace #endif @@ -234,6 +264,18 @@ void SetCurrentThreadToPerformanceCores() { #endif } +void SetCurrentThreadToEfficiencyCores() { +#if defined(__ANDROID__) + const cpu_set_t& mask = EfficiencyCoreMask(); + if (CPU_COUNT(&mask) == 0) { + return; + } + if (sched_setaffinity(gettid(), sizeof(mask), &mask) != 0) { + LOG_DEBUG(Common, "Could not restrict thread to efficiency cores: {}", GetLastErrorMsg()); + } +#endif +} + #ifdef ARCHITECTURE_x86_64 // On Linux and UNIX systems, a futex would nominally be used to cover the costs // the idea is that it's intuitivelly cheaper to use a direct instruction as opposed to a full futex call diff --git a/src/common/thread.h b/src/common/thread.h index 80088fbb20..9e853511c3 100644 --- a/src/common/thread.h +++ b/src/common/thread.h @@ -99,8 +99,14 @@ enum class ThreadPriority : u32 { Critical = 4, }; +enum class ThreadPlacement : u32 { + Default = 0, + Background = 1, +}; + void SetCurrentThreadPriority(ThreadPriority new_priority); void SetCurrentThreadName(const char* name); void SetCurrentThreadToPerformanceCores(); +void SetCurrentThreadToEfficiencyCores(); } // namespace Common diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h index 6ec9d6a2bd..3f440fcdba 100644 --- a/src/common/thread_worker.h +++ b/src/common/thread_worker.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project @@ -37,10 +37,15 @@ class StatefulThreadWorker { using StateMaker = std::conditional_t, DummyCallable>; public: - explicit StatefulThreadWorker(size_t num_workers, std::string name, StateMaker func = {}) + explicit StatefulThreadWorker(size_t num_workers, std::string name, StateMaker func = {}, + ThreadPlacement placement = ThreadPlacement::Default) : workers_queued{num_workers}, thread_name{std::move(name)} { - const auto lambda = [this, func](std::stop_token stop_token) { + const auto lambda = [this, func, placement](std::stop_token stop_token) { Common::SetCurrentThreadName(thread_name.c_str()); + if (placement == ThreadPlacement::Background) { + Common::SetCurrentThreadPriority(ThreadPriority::Low); + Common::SetCurrentThreadToEfficiencyCores(); + } { [[maybe_unused]] std::conditional_t state{func()}; while (!stop_token.stop_requested()) { diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index b46b02cd27..04368eb3f8 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp @@ -349,8 +349,9 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, use_asynchronous_shaders{Settings::values.use_asynchronous_shaders.GetValue()}, use_vulkan_pipeline_cache{Settings::values.use_vulkan_driver_pipeline_cache.GetValue()}, workers(device.HasBrokenParallelShaderCompiling() ? 1ULL : GetTotalPipelineWorkers(), - "VkPipelineBuilder"), - serialization_thread(1, "VkPipelineSerialization") { + "VkPipelineBuilder", {}, Common::ThreadPlacement::Background), + serialization_thread(1, "VkPipelineSerialization", {}, + Common::ThreadPlacement::Background) { const auto& float_control{device.FloatControlProperties()}; const VkDriverId driver_id{device.GetDriverID()}; const VkShaderStageFlags subgroup_stages{device.GetSubgroupSupportedStages()}; diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index d079ad1f7b..136ddc868d 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -529,7 +529,8 @@ private: u64 frame_tick = 0; u64 last_sampler_gc_frame = (std::numeric_limits::max)(); - Common::ThreadWorker texture_decode_worker{1, "TextureDecoder"}; + Common::ThreadWorker texture_decode_worker{1, "TextureDecoder", {}, + Common::ThreadPlacement::Background}; std::vector> async_decodes; std::deque unswizzle_queue; diff --git a/src/video_core/textures/workers.cpp b/src/video_core/textures/workers.cpp index 780e0c4da9..058cc0ab6f 100644 --- a/src/video_core/textures/workers.cpp +++ b/src/video_core/textures/workers.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project @@ -10,7 +10,8 @@ namespace Tegra::Texture { Common::ThreadWorker& GetThreadWorkers() { static Common::ThreadWorker workers{(std::max)(std::thread::hardware_concurrency(), 2U) / 2, - "ImageTranscode"}; + "ImageTranscode", {}, + Common::ThreadPlacement::Background}; return workers; }