diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index f22f33a63c..461f84edf3 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1742,9 +1742,11 @@ void thread_base::initialize(bool(*wait_cb)(const void*)) g_tls_log_prefix = [] { - return thread_ctrl::g_tls_this_thread->m_name.get(); + return thread_ctrl::get_name_cached(); }; + std::string name = thread_ctrl::get_name_cached(); + #ifdef _MSC_VER struct THREADNAME_INFO { @@ -1755,11 +1757,11 @@ void thread_base::initialize(bool(*wait_cb)(const void*)) }; // Set thread name for VS debugger - if (IsDebuggerPresent()) + if (IsDebuggerPresent()) [&]() NEVER_INLINE { THREADNAME_INFO info; info.dwType = 0x1000; - info.szName = m_name.get().c_str(); + info.szName = name.c_str(); info.dwThreadID = -1; info.dwFlags = 0; @@ -1770,17 +1772,19 @@ void thread_base::initialize(bool(*wait_cb)(const void*)) __except (EXCEPTION_EXECUTE_HANDLER) { } - } + }(); #endif #if defined(__APPLE__) - pthread_setname_np(m_name.get().substr(0, 15).c_str()); + name.resize(std::min(15, name.size())); + pthread_setname_np(name.c_str()); #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) - pthread_set_name_np(pthread_self(), m_name.get().c_str()); + pthread_set_name_np(pthread_self(), name.c_str()); #elif defined(__NetBSD__) - pthread_setname_np(pthread_self(), "%s", const_cast(m_name.get().c_str())); + pthread_setname_np(pthread_self(), "%s", name.data()); #elif !defined(_WIN32) - pthread_setname_np(pthread_self(), m_name.get().substr(0, 15).c_str()); + name.resize(std::min(15, name.size())); + pthread_setname_np(pthread_self(), name.c_str()); #endif #ifdef __linux__ @@ -1842,7 +1846,7 @@ bool thread_base::finalize(int) noexcept g_tls_log_prefix = [] { - return thread_ctrl::g_tls_this_thread->m_name.get(); + return thread_ctrl::get_name_cached(); }; sig_log.notice("Thread time: %fs (%fGc); Faults: %u [rsx:%u, spu:%u]; [soft:%u hard:%u]; Switches:[vol:%u unvol:%u]", @@ -1934,8 +1938,27 @@ void thread_ctrl::_wait_for(u64 usec, bool alert /* true */) } } +std::string thread_ctrl::get_name_cached() +{ + auto _this = thread_ctrl::g_tls_this_thread; + + if (!_this) + { + return {}; + } + + static thread_local stx::shared_cptr name_cache; + + if (!_this->m_tname.is_equal(name_cache)) [[unlikely]] + { + name_cache = _this->m_tname.load(); + } + + return *name_cache; +} + thread_base::thread_base(std::string_view name) - : m_name(name) + : m_tname(stx::shared_cptr::make(name)) { } diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 67ade70ef1..05d6995026 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -2,6 +2,7 @@ #include "types.h" #include "util/atomic.hpp" +#include "util/shared_cptr.hpp" #include #include @@ -128,7 +129,7 @@ class thread_base atomic_t m_state_notifier{nullptr}; // Thread name - lf_value m_name; + stx::atomic_cptr m_tname; // atomic_t m_cycles = 0; @@ -186,31 +187,34 @@ class thread_ctrl final friend class thread_base; + // Optimized get_name() for logging + static std::string get_name_cached(); + public: // Get current thread name - static std::string_view get_name() + static std::string get_name() { - return g_tls_this_thread->m_name.get(); + return *g_tls_this_thread->m_tname.load(); } // Get thread name template - static std::string_view get_name(const named_thread& thread) + static std::string get_name(const named_thread& thread) { - return static_cast(thread).m_name.get(); + return *static_cast(thread).m_tname.load(); } // Set current thread name (not recommended) static void set_name(std::string_view name) { - g_tls_this_thread->m_name.assign(name); + g_tls_this_thread->m_tname.store(stx::shared_cptr::make(name)); } // Set thread name (not recommended) template static void set_name(named_thread& thread, std::string_view name) { - static_cast(thread).m_name.assign(name); + static_cast(thread).m_tname.store(stx::shared_cptr::make(name)); } template diff --git a/Utilities/lockless.h b/Utilities/lockless.h index 8745408dd0..3936cdda85 100644 --- a/Utilities/lockless.h +++ b/Utilities/lockless.h @@ -488,79 +488,3 @@ public: return {}; } }; - -// Assignable lock-free thread-safe value of any type (memory-inefficient) -template -class lf_value final -{ - atomic_t m_head; - - T m_data; - -public: - template - explicit constexpr lf_value(Args&&... args) - : m_head(this) - , m_data(std::forward(args)...) - { - } - - ~lf_value() - { - // All values are kept in the queue until the end - for (lf_value* ptr = m_head.load(); ptr != this;) - { - delete std::exchange(ptr, std::exchange(ptr->m_head.raw(), ptr)); - } - } - - // Get current head, allows to inspect old values - [[nodiscard]] const lf_value* head() const - { - return m_head.load(); - } - - // Inspect the initial (oldest) value - [[nodiscard]] const T& first() const - { - return m_data; - } - - [[nodiscard]] const T& get() const - { - return m_head.load()->m_data; - } - - [[nodiscard]] operator const T&() const - { - return m_head.load()->m_data; - } - - // Construct new value in-place - template - const T& assign(Args&&... args) - { - lf_value* val = new lf_value(std::forward(args)...); - lf_value* old = m_head.load(); - - do - { - val->m_head = old; - } - while (!m_head.compare_exchange(old, val)); - - return val->m_data; - } - - // Copy-assign new value - const T& operator =(const T& value) - { - return assign(value); - } - - // Move-assign new value - const T& operator =(T&& value) - { - return assign(std::move(value)); - } -}; diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 43d72b32e1..00cd7ca740 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -512,7 +512,7 @@ void cpu_thread::notify() } else { - fmt::throw_exception("Invalid cpu_thread type"); + fmt::throw_exception("Invalid cpu_thread type" HERE); } } @@ -529,7 +529,24 @@ void cpu_thread::abort() } else { - fmt::throw_exception("Invalid cpu_thread type"); + fmt::throw_exception("Invalid cpu_thread type" HERE); + } +} + +std::string cpu_thread::get_name() const +{ + // Downcast to correct type + if (id_type() == 1) + { + return thread_ctrl::get_name(*static_cast*>(this)); + } + else if (id_type() == 2) + { + return thread_ctrl::get_name(*static_cast*>(this)); + } + else + { + fmt::throw_exception("Invalid cpu_thread type" HERE); } } diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index dfe7735f3f..2a891db006 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -74,7 +74,7 @@ public: } // Check thread type - u32 id_type() + u32 id_type() const { return id >> 24; } @@ -88,8 +88,8 @@ public: // Thread stats for external observation static atomic_t g_threads_created, g_threads_deleted; - // Get thread name - virtual std::string get_name() const = 0; + // Get thread name (as assigned to named_thread) + std::string get_name() const; // Get CPU state dump virtual std::string dump() const; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index e895872d7c..df10d5af22 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -430,11 +430,6 @@ void ppu_thread::on_cleanup(named_thread* _this) idm::remove>(_this->id); } -std::string ppu_thread::get_name() const -{ - return fmt::format("PPU[0x%x] Thread (%s)", id, ppu_name.get()); -} - std::string ppu_thread::dump() const { std::string ret = cpu_thread::dump(); @@ -718,7 +713,7 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3 , stack_addr(param.stack_addr) , joiner(-!!detached) , start_time(get_guest_system_time()) - , ppu_name(name) + , ppu_tname(stx::shared_cptr::make(name)) { gpr[1] = stack_addr + stack_size - 0x70; @@ -830,7 +825,15 @@ void ppu_thread::fast_call(u32 addr, u32 rtoc) g_tls_log_prefix = [] { const auto _this = static_cast(get_current_cpu_thread()); - return fmt::format("%s [0x%08x]", thread_ctrl::get_name(), _this->cia); + + static thread_local stx::shared_cptr name_cache; + + if (!_this->ppu_tname.is_equal(name_cache)) [[unlikely]] + { + name_cache = _this->ppu_tname.load(); + } + + return fmt::format("PPU[0x%x] Thread (%s) [0x%08x]", _this->id, *name_cache.get(), _this->cia); }; auto at_ret = [&]() diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 6f1d55cf3d..e076e433d8 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -46,7 +46,6 @@ public: static void on_cleanup(named_thread*); - virtual std::string get_name() const override; virtual std::string dump() const override; virtual void cpu_task() override final; virtual void cpu_sleep() override; @@ -186,7 +185,8 @@ public: const char* current_function{}; // Current function name for diagnosis, optimized for speed. const char* last_function{}; // Sticky copy of current_function, is not cleared on function return - lf_value ppu_name; // Thread name + // Thread name + stx::atomic_cptr ppu_tname; be_t* get_stack_arg(s32 i, u64 align = alignof(u64)); void exec_task(); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 54105aea6f..fdeb7d9c87 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1008,11 +1008,6 @@ spu_imm_table_t::spu_imm_table_t() } } -std::string spu_thread::get_name() const -{ - return fmt::format("%sSPU[0x%07x] Thread (%s)", offset >= RAW_SPU_BASE_ADDR ? "Raw" : "", lv2_id, spu_name.get()); -} - std::string spu_thread::dump() const { std::string ret = cpu_thread::dump(); @@ -1163,7 +1158,15 @@ void spu_thread::cpu_task() g_tls_log_prefix = [] { const auto cpu = static_cast(get_current_cpu_thread()); - return fmt::format("%s [0x%05x]", thread_ctrl::get_name(), cpu->pc); + + static thread_local stx::shared_cptr name_cache; + + if (!cpu->spu_tname.is_equal(name_cache)) [[unlikely]] + { + name_cache = cpu->spu_tname.load(); + } + + return fmt::format("%sSPU[0x%07x] Thread (%s) [0x%05x]", cpu->offset >= RAW_SPU_BASE_ADDR ? "Raw" : "", cpu->lv2_id, *name_cache.get(), cpu->pc); }; if (jit) @@ -1237,7 +1240,7 @@ spu_thread::spu_thread(vm::addr_t ls, lv2_spu_group* group, u32 index, std::stri , offset(ls) , group(group) , lv2_id(lv2_id) - , spu_name(name) + , spu_tname(stx::shared_cptr::make(name)) { if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit) { diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 2384dc9214..b302dc71a6 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -498,7 +498,6 @@ public: class spu_thread : public cpu_thread { public: - virtual std::string get_name() const override; virtual std::string dump() const override; virtual void cpu_task() override final; virtual void cpu_mem() override; @@ -588,7 +587,7 @@ public: u32 npc; // SPU Next Program Counter register }; - atomic_t status_npc; + atomic_t status_npc; std::array int_ctrl; // SPU Class 0, 1, 2 Interrupt Management @@ -602,7 +601,8 @@ private: public: const u32 lv2_id; // The actual id that is used by syscalls - lf_value spu_name; // Thread name + // Thread name + stx::atomic_cptr spu_tname; std::unique_ptr jit; // Recompiler instance diff --git a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index ae50cb8f97..d6ef445525 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -385,7 +385,7 @@ error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id) thread_ctrl::notify(*thread); // Dirty hack for sound: confirm the creation of _mxr000 event queue - if (thread->ppu_name.get() == "_cellsurMixerMain"sv) + if (*thread->ppu_tname.load() == "_cellsurMixerMain"sv) { lv2_obj::sleep(ppu); @@ -432,9 +432,12 @@ error_code sys_ppu_thread_rename(u32 thread_id, vm::cptr name) constexpr u32 max_size = 27; // max size including null terminator const auto pname = name.get_ptr(); + // Make valid name + auto _name = stx::shared_cptr::make(pname, std::find(pname, pname + max_size, '\0')); + // thread_ctrl name is not changed (TODO) - const std::string res = thread->ppu_name.assign(pname, std::find(pname, pname + max_size, '\0')); - sys_ppu_thread.warning(u8"sys_ppu_thread_rename(): Thread renamed to ā€œ%sā€", res); + sys_ppu_thread.warning(u8"sys_ppu_thread_rename(): Thread renamed to ā€œ%sā€", *_name); + thread->ppu_tname.store(std::move(_name)); return CELL_OK; } diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index 0e884e6a63..b19027bdf4 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -271,7 +271,7 @@ void kernel_explorer::Update() idm::select>([&](u32 id, ppu_thread& ppu) { lv2_types.back().count++; - l_addTreeChild(lv2_types.back().node, qstr(fmt::format("PPU Thread: ID = 0x%08x '%s'", id, ppu.ppu_name.get()))); + l_addTreeChild(lv2_types.back().node, qstr(fmt::format("PPU Thread: ID = 0x%08x '%s'", id, *ppu.ppu_tname.load()))); }); lv2_types.emplace_back(l_addTreeChild(root, "SPU Threads")); @@ -279,7 +279,7 @@ void kernel_explorer::Update() idm::select>([&](u32 /*id*/, spu_thread& spu) { lv2_types.back().count++; - l_addTreeChild(lv2_types.back().node, qstr(fmt::format("SPU Thread: ID = 0x%08x '%s'", spu.lv2_id, spu.spu_name.get()))); + l_addTreeChild(lv2_types.back().node, qstr(fmt::format("SPU Thread: ID = 0x%08x '%s'", spu.lv2_id, *spu.spu_tname.load()))); }); lv2_types.emplace_back(l_addTreeChild(root, "SPU Thread Groups"));