From 6ad58c881339bf9300eeb17fbb535d4c8dcf37ac Mon Sep 17 00:00:00 2001 From: DH Date: Wed, 19 Mar 2025 05:03:15 +0300 Subject: [PATCH] android: add affinity support with config add aarch64 get_cpu_name teach cfg::try_to_enum_value and cfg::try_to_enum_list ignore gaps --- rpcs3/Utilities/Config.cpp | 19 ++++++- rpcs3/Utilities/Thread.cpp | 51 +++++++++++++++++-- .../CPU/Backends/AArch64/AArch64Common.cpp | 10 ++++ .../Emu/CPU/Backends/AArch64/AArch64Common.h | 1 + rpcs3/rpcs3/Emu/system_config.h | 17 +++++++ rpcs3/rpcs3/util/cpu_stats.cpp | 4 +- 6 files changed, 94 insertions(+), 8 deletions(-) diff --git a/rpcs3/Utilities/Config.cpp b/rpcs3/Utilities/Config.cpp index a017034da..e955263c8 100644 --- a/rpcs3/Utilities/Config.cpp +++ b/rpcs3/Utilities/Config.cpp @@ -226,6 +226,7 @@ bool try_to_string(std::string* out, const f64& value) bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string::format) func, std::string_view value) { u64 max = umax; + std::size_t gap = 0; for (u64 i = 0;; i++) { @@ -242,9 +243,15 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string::format) f fmt_class_string::format(hex, i); if (var == hex) { - break; + if (++gap > 100) + { + break; + } + + continue; } + gap = 0; max = i; } @@ -281,6 +288,7 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string::format) f std::vector cfg::try_to_enum_list(decltype(&fmt_class_string::format) func) { std::vector result; + std::size_t gap = 0; for (u64 i = 0;; i++) { @@ -291,9 +299,16 @@ std::vector cfg::try_to_enum_list(decltype(&fmt_class_string:: fmt_class_string::format(hex, i); if (var == hex) { - break; + if (++gap > 100) + { + break; + } + + continue; } + gap = 0; + result.emplace_back(std::move(var)); } diff --git a/rpcs3/Utilities/Thread.cpp b/rpcs3/Utilities/Thread.cpp index 6ab63de93..53b3347cb 100644 --- a/rpcs3/Utilities/Thread.cpp +++ b/rpcs3/Utilities/Thread.cpp @@ -111,6 +111,22 @@ extern thread_local std::string(*g_tls_log_prefix)(); enum cpu_threads_emulation_info_dump_t : u32 {}; +template<> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](thread_class value) + { + switch (value) + { + case thread_class::general: return "General"; + case thread_class::ppu: return "PPU"; + case thread_class::spu: return "SPU"; + case thread_class::rsx: return "RSX"; + } + return unknown; + }); +} + std::string dump_useful_thread_info() { std::string result; @@ -2926,6 +2942,28 @@ void thread_ctrl::detect_cpu_layout() u64 thread_ctrl::get_affinity_mask(thread_class group) { +#ifdef ANDROID + u64 mask = 0; + thread_class affinities[] = { + g_cfg.core.affinity.cpu0.get(), + g_cfg.core.affinity.cpu1.get(), + g_cfg.core.affinity.cpu2.get(), + g_cfg.core.affinity.cpu3.get(), + g_cfg.core.affinity.cpu4.get(), + g_cfg.core.affinity.cpu5.get(), + g_cfg.core.affinity.cpu6.get(), + g_cfg.core.affinity.cpu7.get() + }; + + for (std::size_t i = 0; i < std::size(affinities); ++i) { + if (affinities[i] == group || affinities[i] == thread_class::general) { + mask |= 1ull < i; + } + } + + return mask; +#endif + detect_cpu_layout(); if (const auto thread_count = utils::get_thread_count()) @@ -3205,7 +3243,7 @@ void thread_ctrl::set_thread_affinity_mask(u64 mask) thread_affinity_policy_data_t policy = { static_cast(std::countr_zero(mask)) }; thread_port_t mach_thread = pthread_mach_thread_np(pthread_self()); thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, reinterpret_cast(&policy), !mask ? 0 : 1); -#elif !defined(ANDROID) && (defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__)) +#elif (defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__)) if (!mask) { // Reset affinity mask @@ -3232,8 +3270,11 @@ void thread_ctrl::set_thread_affinity_mask(u64 mask) break; } } - +#ifdef ANDROID + if (int err = sched_setaffinity(::gettid(), sizeof(cpu_set_t), &cs)) +#else if (int err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs)) +#endif { sig_log.error("Failed to set thread affinity 0x%x: error %d.", mask, err); } @@ -3257,11 +3298,15 @@ u64 thread_ctrl::get_thread_affinity_mask() sig_log.error("Failed to get thread affinity mask."); return 0; -#elif !defined(ANDROID) && (defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__)) +#elif (defined(__linux__) || defined(__DragonFly__) || defined(__FreeBSD__)) cpu_set_t cs; CPU_ZERO(&cs); +#ifdef ANDROID + if (int err = sched_getaffinity(::gettid(), sizeof(cpu_set_t), &cs)) +#else if (int err = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t), &cs)) +#endif { sig_log.error("Failed to get thread affinity mask: error %d.", err); return 0; diff --git a/rpcs3/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp b/rpcs3/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp index 2685020d1..132ac8611 100644 --- a/rpcs3/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp +++ b/rpcs3/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.cpp @@ -246,6 +246,16 @@ namespace aarch64 #endif } + const char *get_cpu_name(int cpu) + { + const auto midr = read_MIDR_EL1(cpu); + const auto implementer_id = (midr >> 24) & 0xff; + const auto part_id = (midr >> 4) & 0xfff; + + const auto part_info = find_cpu_part(implementer_id, part_id); + return part_info ? part_info->name : nullptr; + } + std::string get_cpu_name() { std::map core_layout; diff --git a/rpcs3/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.h b/rpcs3/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.h index dff06dfb8..de373909d 100644 --- a/rpcs3/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.h +++ b/rpcs3/rpcs3/Emu/CPU/Backends/AArch64/AArch64Common.h @@ -37,6 +37,7 @@ namespace aarch64 "xzr", ".", "sp" }; + const char *get_cpu_name(int cpu); std::string get_cpu_name(); std::string get_cpu_brand(); } diff --git a/rpcs3/rpcs3/Emu/system_config.h b/rpcs3/rpcs3/Emu/system_config.h index a3863d987..126bb5dc4 100644 --- a/rpcs3/rpcs3/Emu/system_config.h +++ b/rpcs3/rpcs3/Emu/system_config.h @@ -1,5 +1,6 @@ #pragma once +#include "Utilities/Thread.h" #include "system_config_types.h" #include "Utilities/Config.h" @@ -46,6 +47,22 @@ struct cfg_root : cfg::node cfg::_bool accurate_cache_line_stores{ this, "Accurate Cache Line Stores", false }; cfg::_bool rsx_accurate_res_access{this, "Accurate RSX reservation access", false, true}; +#ifdef ANDROID + struct node_affinity : cfg::node + { + public: + node_affinity(cfg::node* _this) : cfg::node(_this, "Affinity") {} + cfg::_enum cpu0{this, "CPU0", thread_class::general, true}; + cfg::_enum cpu1{this, "CPU1", thread_class::general, true}; + cfg::_enum cpu2{this, "CPU2", thread_class::general, true}; + cfg::_enum cpu3{this, "CPU3", thread_class::general, true}; + cfg::_enum cpu4{this, "CPU4", thread_class::general, true}; + cfg::_enum cpu5{this, "CPU5", thread_class::general, true}; + cfg::_enum cpu6{this, "CPU6", thread_class::general, true}; + cfg::_enum cpu7{this, "CPU7", thread_class::general, true}; + } affinity { this }; +#endif + struct fifo_setting : public cfg::_enum { using _enum = cfg::_enum; diff --git a/rpcs3/rpcs3/util/cpu_stats.cpp b/rpcs3/rpcs3/util/cpu_stats.cpp index 42c5304be..5a3c65f83 100644 --- a/rpcs3/rpcs3/util/cpu_stats.cpp +++ b/rpcs3/rpcs3/util/cpu_stats.cpp @@ -197,8 +197,7 @@ namespace utils } } -#elif __linux__ -#ifndef ANDROID +#elif __linux__ && !defined(ANDROID) m_previous_idle_times_per_cpu.resize(utils::get_thread_count(), 0.0); m_previous_total_times_per_cpu.resize(utils::get_thread_count(), 0.0); @@ -289,7 +288,6 @@ namespace utils { perf_log.error("Failed to open /proc/stat (%s)", strerror(errno)); } -#endif #else total_usage = get_usage(); #endif