From df7b4666569a53edd2558d0ad1a76b7398aabf49 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 23 Apr 2017 23:09:27 +0300 Subject: [PATCH] spu: Speed hacks - Do not starve PPU threads optionally hint to the OS scheduler to give less attention to SPUs ui: Add speed 'hacks' as configurable options --- Utilities/Thread.cpp | 1 + Utilities/Thread.h | 3 +++ rpcs3/Emu/CPU/CPUThread.cpp | 36 ++++++++++++++++++++++++++++++++++++ rpcs3/Emu/CPU/CPUThread.h | 4 ++++ rpcs3/Emu/Cell/SPUThread.cpp | 31 ++++++++++++++++++++++++++++++- rpcs3/Emu/Cell/SPUThread.h | 1 + rpcs3/Gui/SettingsDialog.cpp | 8 +++++++- 7 files changed, 82 insertions(+), 2 deletions(-) diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index c226922efe..d66ab76182 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1750,6 +1750,7 @@ void named_thread::start_thread(const std::shared_ptr& _this) try { LOG_TRACE(GENERAL, "Thread started"); + on_spawn(); on_task(); LOG_TRACE(GENERAL, "Thread ended"); } diff --git a/Utilities/Thread.h b/Utilities/Thread.h index ab29162f36..3844a99052 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -258,6 +258,9 @@ protected: // Thread finalization (called after on_task) virtual void on_exit() {} + // Called once upon thread spawn within the thread's own context + virtual void on_spawn() {} + public: // ID initialization virtual void on_init(const std::shared_ptr& _this) diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index bbde4b87be..cea46639cb 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -4,6 +4,11 @@ #include "CPUThread.h" #include "Emu/IdManager.h" #include "Utilities/GDBDebugServer.h" +#include "Utilities/Config.h" + +#ifdef _WIN32 +#include +#endif DECLARE(cpu_thread::g_threads_created){0}; DECLARE(cpu_thread::g_threads_deleted){0}; @@ -178,3 +183,34 @@ std::string cpu_thread::dump() const { return fmt::format("Type: %s\n" "State: %s\n", typeid(*this).name(), state.load()); } + +void cpu_thread::set_native_priority(int priority) +{ +#ifdef _WIN32 + HANDLE _this_thread = GetCurrentThread(); + INT native_priority = THREAD_PRIORITY_NORMAL; + + switch (priority) + { + default: + case 0: + break; + case 1: + native_priority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case -1: + native_priority = THREAD_PRIORITY_BELOW_NORMAL; + break; + } + + SetThreadPriority(_this_thread, native_priority); +#endif // _WIN32 +} + +void cpu_thread::set_ideal_processor_core(int core) +{ +#ifdef _WIN32 + HANDLE _this_thread = GetCurrentThread(); + SetThreadIdealProcessor(_this_thread, core); +#endif +} \ No newline at end of file diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index fa69f2d421..fed3cf0f9f 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -65,6 +65,10 @@ public: // Callback for cpu_flag::suspend virtual void cpu_sleep() {} + + //native scheduler tweaks + void set_native_priority(int priority); + void set_ideal_processor_core(int core); }; inline cpu_thread* get_current_cpu_thread() noexcept diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 004fb4ef25..dc7eac55e9 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -20,6 +20,8 @@ #include #include +#include +#include #ifdef _MSC_VER bool operator ==(const u128& lhs, const u128& rhs) @@ -49,10 +51,14 @@ cfg::map_entry g_cfg_spu_decoder(cfg::root.core, "SPU Decoder" }); cfg::bool_entry g_cfg_spu_debug(cfg::root.core, "SPU Debug"); +cfg::bool_entry g_cfg_core_bind_spu_cores(cfg::root.core, "Bind SPU threads to secondary cores"); +cfg::bool_entry g_cfg_core_lower_spu_priority(cfg::root.core, "Lower SPU thread priority"); const spu_decoder s_spu_interpreter_precise; const spu_decoder s_spu_interpreter_fast; +std::atomic g_num_spu_threads = { 0ull }; + void spu_int_ctrl_t::set(u64 ints) { // leave only enabled interrupts @@ -134,6 +140,29 @@ spu_imm_table_t::spu_imm_table_t() } } +void SPUThread::on_spawn() +{ + if (g_cfg_core_bind_spu_cores) + { + //Get next secondary core number + auto core_count = std::thread::hardware_concurrency(); + if (core_count > 0 && core_count <= 16) + { + auto half_count = core_count / 2; + auto assigned_secondary_core = ((g_num_spu_threads % half_count) * 2) + 1; + + set_ideal_processor_core(assigned_secondary_core); + } + } + + if (g_cfg_core_lower_spu_priority) + { + set_native_priority(-1); + } + + g_num_spu_threads++; +} + void SPUThread::on_init(const std::shared_ptr& _this) { if (!offset) @@ -208,7 +237,7 @@ extern thread_local std::string(*g_tls_log_prefix)(); void SPUThread::cpu_task() { std::fesetround(FE_TOWARDZERO); - + if (g_cfg_spu_decoder.get() == spu_decoder_type::asmjit) { if (!spu_db) spu_db = fxm::get_always(); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index b3a53f3c3f..d20c5d1240 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -504,6 +504,7 @@ public: class SPUThread : public cpu_thread { public: + virtual void on_spawn() override; virtual void on_init(const std::shared_ptr&) override; virtual std::string get_name() const override; virtual std::string dump() const override; diff --git a/rpcs3/Gui/SettingsDialog.cpp b/rpcs3/Gui/SettingsDialog.cpp index 519b105977..21db9d6eb5 100644 --- a/rpcs3/Gui/SettingsDialog.cpp +++ b/rpcs3/Gui/SettingsDialog.cpp @@ -226,7 +226,7 @@ SettingsDialog::SettingsDialog(wxWindow* parent, const std::string& path) std::vector> pads; - static const u32 width = 458; + static const u32 width = 512; static const u32 height = 400; // Settings panels @@ -310,6 +310,8 @@ SettingsDialog::SettingsDialog(wxWindow* parent, const std::string& path) wxComboBox* cbox_sys_lang = new wxComboBox(p_system, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY); wxCheckBox* chbox_core_hook_stfunc = new wxCheckBox(p_core, wxID_ANY, "Hook static functions"); + wxCheckBox* chbox_core_bind_spu_threads = new wxCheckBox(p_core, wxID_ANY, "Bind SPU threads to secondary cores"); + wxCheckBox* chbox_core_lower_spu_priority = new wxCheckBox(p_core, wxID_ANY, "Lower SPU thread priority"); wxCheckBox* chbox_vfs_enable_host_root = new wxCheckBox(p_system, wxID_ANY, "Enable /host_root/"); wxCheckBox* chbox_gs_log_prog = new wxCheckBox(p_graphics, wxID_ANY, "Log Shader Programs"); wxCheckBox* chbox_gs_dump_depth = new wxCheckBox(p_graphics, wxID_ANY, "Write Depth Buffer"); @@ -391,6 +393,8 @@ SettingsDialog::SettingsDialog(wxWindow* parent, const std::string& path) EnableModuleList(rbox_lib_loader->GetSelection()); pads.emplace_back(std::make_unique(cfg_location{ "Core", "Hook static functions" }, chbox_core_hook_stfunc)); + pads.emplace_back(std::make_unique(cfg_location{ "Core", "Bind SPU threads to secondary cores" }, chbox_core_bind_spu_threads)); + pads.emplace_back(std::make_unique(cfg_location{ "Core", "Lower SPU thread priority" }, chbox_core_lower_spu_priority)); pads.emplace_back(std::make_unique(cfg_location{ "VFS", "Enable /host_root/" }, chbox_vfs_enable_host_root)); pads.emplace_back(std::make_unique(cfg_location{ "Video", "Renderer" }, cbox_gs_render)); @@ -482,6 +486,8 @@ SettingsDialog::SettingsDialog(wxWindow* parent, const std::string& path) s_subpanel_core1->Add(rbox_ppu_decoder, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core1->Add(rbox_spu_decoder, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core1->Add(chbox_core_hook_stfunc, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_core1->Add(chbox_core_bind_spu_threads, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_core1->Add(chbox_core_lower_spu_priority, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core2->Add(rbox_lib_loader, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core2->Add(s_round_core_lle, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_core->Add(s_subpanel_core1);