diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 62edef9faa..f566edad12 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2709,9 +2709,18 @@ u64 thread_ctrl::get_affinity_mask(thread_class group) break; case 16: // 1700, 1800, 2700, TR 1900X family - ppu_mask = 0b1111111100000000; - spu_mask = ppu_mask; - rsx_mask = 0b0000000000111100; + if (g_cfg.core.thread_scheduler == thread_scheduler_mode::alt) + { + ppu_mask = 0b0010000010000000; + spu_mask = 0b0000101010101010; + rsx_mask = 0b1000000000000000; + } + else + { + ppu_mask = 0b1111111100000000; + spu_mask = ppu_mask; + rsx_mask = 0b0000000000111100; + } break; case 12: // 1600, 2600 family, Assign threads 3-12 @@ -2739,16 +2748,36 @@ u64 thread_ctrl::get_affinity_mask(thread_class group) spu_mask = 0b000000111111000000000000; rsx_mask = 0b000000000000111111000000; break; - default: - if (thread_count >= 16) + case 16: + // 5800X + if (g_cfg.core.thread_scheduler == thread_scheduler_mode::alt) + { + ppu_mask = 0b0000000011110000; + spu_mask = 0b1111111100000000; + rsx_mask = 0b0000000000001111; + } + else { // Verified by more than one windows user on 16-thread CPU ppu_mask = spu_mask = rsx_mask = (0b10101010101010101010101010101010 & all_cores_mask); } + case 12: + // 5600X + if (g_cfg.core.thread_scheduler == thread_scheduler_mode::alt) + { + ppu_mask = 0b000000001100; + spu_mask = 0b111111110000; + rsx_mask = 0b000000000011; + } else { ppu_mask = spu_mask = rsx_mask = all_cores_mask; } + default: + if (thread_count > 24) + { + ppu_mask = spu_mask = rsx_mask = (0b10101010101010101010101010101010 & all_cores_mask); + } break; } break; @@ -2774,23 +2803,8 @@ u64 thread_ctrl::get_affinity_mask(thread_class group) } case native_core_arrangement::intel_ht: { - /* This has been disabled as it seems to degrade performance instead of improving it. - if (thread_count <= 4) - { - //i3 or worse - switch (group) - { - case thread_class::rsx: - case thread_class::ppu: - return (0b0101 & all_cores_mask); - case thread_class::spu: - return (0b1010 & all_cores_mask); - case thread_class::general: - return all_cores_mask; - } - } - */ - + if (thread_count >= 12 && g_cfg.core.thread_scheduler == thread_scheduler_mode::alt) + return (0b10101010101010101010101010101010 & all_cores_mask); // Potentially improves performance by mimicking HT off return all_cores_mask; } } diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 0e35523535..f0ecf35331 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -405,7 +405,7 @@ void cpu_thread::operator()() { g_tls_this_thread = this; - if (g_cfg.core.thread_scheduler_enabled) + if (g_cfg.core.thread_scheduler != thread_scheduler_mode::os) { thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(id_type() == 1 ? thread_class::ppu : thread_class::spu)); } diff --git a/rpcs3/Emu/RSX/RSXOffload.cpp b/rpcs3/Emu/RSX/RSXOffload.cpp index 7b1318fdcf..0db638343e 100644 --- a/rpcs3/Emu/RSX/RSXOffload.cpp +++ b/rpcs3/Emu/RSX/RSXOffload.cpp @@ -29,7 +29,7 @@ namespace rsx m_thread_id = std::this_thread::get_id(); - if (g_cfg.core.thread_scheduler_enabled) + if (g_cfg.core.thread_scheduler != thread_scheduler_mode::os) { thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(thread_class::rsx)); } diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 4ccbf480e8..079d5ee858 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -639,7 +639,7 @@ namespace rsx // Raise priority above other threads thread_ctrl::scoped_priority high_prio(+1); - if (g_cfg.core.thread_scheduler_enabled) + if (g_cfg.core.thread_scheduler != thread_scheduler_mode::os) { thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(thread_class::rsx)); } diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index 9def08a713..b507ab7295 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -17,13 +17,6 @@ struct cfg_root : cfg::node bool has_rtm() const; public: - static constexpr bool thread_scheduler_enabled_def = -#ifdef _WIN32 - true; -#else - false; -#endif - node_core(cfg::node* _this) : cfg::node(_this, "Core") {} cfg::_enum ppu_decoder{ this, "PPU Decoder", ppu_decoder_type::llvm }; @@ -33,7 +26,7 @@ struct cfg_root : cfg::node cfg::string llvm_cpu{ this, "Use LLVM CPU" }; cfg::_int<0, INT32_MAX> llvm_threads{ this, "Max LLVM Compile Threads", 0 }; cfg::_bool ppu_llvm_greedy_mode{ this, "PPU LLVM Greedy Mode", false, false }; - cfg::_bool thread_scheduler_enabled{ this, "Enable thread scheduler", thread_scheduler_enabled_def }; + cfg::_enum thread_scheduler{this, "Thread Scheduler Mode", thread_scheduler_mode::os}; cfg::_bool set_daz_and_ftz{ this, "Set DAZ and FTZ", false }; cfg::_enum spu_decoder{ this, "SPU Decoder", spu_decoder_type::llvm }; cfg::_bool lower_spu_priority{ this, "Lower SPU thread priority" }; diff --git a/rpcs3/Emu/system_config_types.cpp b/rpcs3/Emu/system_config_types.cpp index 360aa0bdbb..5e7b07e716 100644 --- a/rpcs3/Emu/system_config_types.cpp +++ b/rpcs3/Emu/system_config_types.cpp @@ -436,3 +436,19 @@ void fmt_class_string::format(std::string& out, u64 arg) return unknown; }); } + +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](thread_scheduler_mode value) + { + switch (value) + { + case thread_scheduler_mode::old: return "RPCS3 Scheduler"; + case thread_scheduler_mode::alt: return "RPCS3 Alternative Scheduler"; + case thread_scheduler_mode::os: return "Operating System"; + } + + return unknown; + }); +} diff --git a/rpcs3/Emu/system_config_types.h b/rpcs3/Emu/system_config_types.h index 57c924e35c..52c8e16934 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -201,3 +201,10 @@ enum class vk_gpu_scheduler_mode host, device }; + +enum class thread_scheduler_mode +{ + os, + old, + alt +}; diff --git a/rpcs3/rpcs3qt/emu_settings.cpp b/rpcs3/rpcs3qt/emu_settings.cpp index 252bac4a2b..737948813e 100644 --- a/rpcs3/rpcs3qt/emu_settings.cpp +++ b/rpcs3/rpcs3qt/emu_settings.cpp @@ -831,6 +831,14 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_ case spu_block_size_type::giga: return tr("Giga", "SPU block size"); } break; + case emu_settings_type::ThreadSchedulerMode: + switch (static_cast(index)) + { + case thread_scheduler_mode::old: return tr("RPCS3 Scheduler", "Thread Scheduler Mode"); + case thread_scheduler_mode::alt: return tr("RPCS3 Alternative Scheduler", "Thread Scheduler Mode"); + case thread_scheduler_mode::os: return tr("Operating System", "Thread Scheduler Mode"); + } + break; case emu_settings_type::EnableTSX: switch (static_cast(index)) { diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index 9bee452ebf..d5f6acdba8 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -11,7 +11,7 @@ enum class emu_settings_type PPUDecoder, SPUDecoder, HookStaticFuncs, - EnableThreadScheduler, + ThreadSchedulerMode, LowerSPUThreadPrio, SPULoopDetection, PreferredSPUThreads, @@ -162,7 +162,7 @@ static const QMap settings_location = { emu_settings_type::PPUDecoder, { "Core", "PPU Decoder"}}, { emu_settings_type::SPUDecoder, { "Core", "SPU Decoder"}}, { emu_settings_type::HookStaticFuncs, { "Core", "Hook static functions"}}, - { emu_settings_type::EnableThreadScheduler, { "Core", "Enable thread scheduler"}}, + { emu_settings_type::ThreadSchedulerMode, { "Core", "Thread Scheduler Mode"}}, { emu_settings_type::LowerSPUThreadPrio, { "Core", "Lower SPU thread priority"}}, { emu_settings_type::SPULoopDetection, { "Core", "SPU loop detection"}}, { emu_settings_type::PreferredSPUThreads, { "Core", "Preferred SPU Threads"}}, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 446f393cf4..8aa049e56f 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -193,9 +193,6 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->spuCache, emu_settings_type::SPUCache); SubscribeTooltip(ui->spuCache, tooltips.settings.spu_cache); - m_emu_settings->EnhanceCheckBox(ui->enableScheduler, emu_settings_type::EnableThreadScheduler); - SubscribeTooltip(ui->enableScheduler, tooltips.settings.enable_thread_scheduler); - m_emu_settings->EnhanceCheckBox(ui->lowerSPUThrPrio, emu_settings_type::LowerSPUThreadPrio); SubscribeTooltip(ui->lowerSPUThrPrio, tooltips.settings.lower_spu_thread_priority); @@ -210,6 +207,14 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceComboBox(ui->spuBlockSize, emu_settings_type::SPUBlockSize); SubscribeTooltip(ui->gb_spuBlockSize, tooltips.settings.spu_block_size); + m_emu_settings->EnhanceComboBox(ui->threadsched, emu_settings_type::ThreadSchedulerMode); + SubscribeTooltip(ui->gb_threadsched, tooltips.settings.enable_thread_scheduler); + if (u32 min_thread_count = 12; utils::get_thread_count() < min_thread_count) + { + ui->gb_threadsched->setDisabled(true); + ui->gb_threadsched->setToolTip(tr("This feature is disabled for CPUs with less than %0 threads").arg(min_thread_count)); + } + m_emu_settings->EnhanceComboBox(ui->preferredSPUThreads, emu_settings_type::PreferredSPUThreads, true); SubscribeTooltip(ui->gb_spu_threads, tooltips.settings.preferred_spu_threads); ui->preferredSPUThreads->setItemText(ui->preferredSPUThreads->findData(0), tr("Auto", "Preferred SPU threads")); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 64de9bd45f..f87235b1df 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -143,13 +143,6 @@ Additional Settings - - - - Enable thread scheduler - - - @@ -200,7 +193,7 @@ - + @@ -255,6 +248,24 @@ + + + + + 0 + 0 + + + + Thread Scheduler + + + + + + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 9220f1f90e..8f4369bb5a 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -64,7 +64,7 @@ public: const QString spu_llvm = tr("Recompiles and caches the game's SPU code using the LLVM Recompiler before running which adds extra start-up time.\nThis is the fastest option with very good compatibility.\nIf you experience issues, use the ASMJIT Recompiler."); const QString accurate_xfloat = tr("Adds extra accuracy to SPU float vectors processing.\nFixes bugs in various games at the cost of performance.\nThis setting is only applied when SPU Decoder is set to Fast or LLVM."); const QString spu_cache = tr("Caches compiled SPU modules on disc.\nShould normally stay enabled.\nDisable this if the cache becomes too large.\nDisabling it does not remove the existing cache."); - const QString enable_thread_scheduler = tr("Allows RPCS3 to manually schedule physical cores to run specific tasks on, instead of letting the OS handle it.\nVery useful on Windows, especially for AMD Ryzen systems where it can give huge performance gains.\nNote: This function is only implemented for AMD Ryzen CPUs."); + const QString enable_thread_scheduler = tr("Control how RPCS3 utilizes the threads of your system, only useful for 6C/12T CPUs or higher up.\nEach option heavily depends on the game and on your CPU, it's recommended to try each option to find out which performs the best."); const QString lower_spu_thread_priority = tr("Runs SPU threads with lower priority than PPU threads.\nUsually faster on an i3 or i5, possibly slower or no difference on an i7 or Ryzen."); const QString spu_loop_detection = tr("Try to detect loop conditions in SPU kernels and use them as scheduling hints.\nImproves performance and reduces CPU usage.\nMay cause severe audio stuttering in rare cases."); const QString enable_tsx = tr("Enable usage of TSX instructions.\nNeeds to be forced on some Haswell or Broadwell CPUs.\nForcing this on older Hardware can lead to system instability, use it with caution.");