diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 3df51b6936..fdb493b7a8 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -1527,6 +1527,14 @@ void ppu_thread::cpu_on_stop() current_function = {}; } + + // TODO: More conditions + if (Emu.IsStopped() && g_cfg.core.spu_debug) + { + std::string ret; + dump_all(ret); + ppu_log.notice("thread context: %s", ret); + } } void ppu_thread::exec_task() diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index cd13230384..a826a27724 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1263,6 +1263,31 @@ std::string spu_thread::dump_misc() const return ret; } +void spu_thread::cpu_on_stop() +{ + if (current_func) + { + if (start_time) + { + ppu_log.warning("'%s' aborted (%fs)", current_func, (get_guest_system_time() - start_time) / 1000000.); + } + else + { + ppu_log.warning("'%s' aborted", current_func); + } + + current_func = {}; + } + + // TODO: More conditions + if (Emu.IsStopped() && g_cfg.core.spu_debug) + { + std::string ret; + dump_all(ret); + spu_log.notice("thread context: %s", ret); + } +} + void spu_thread::cpu_init() { std::memset(gpr.data(), 0, gpr.size() * sizeof(gpr[0])); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index b0dcbaa9a5..e478415baa 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -682,6 +682,7 @@ public: virtual std::vector> dump_callstack_list() const override; virtual std::string dump_misc() const override; virtual void cpu_task() override final; + virtual void cpu_on_stop() override; virtual void cpu_return() override; virtual void cpu_work() override; virtual ~spu_thread() override; @@ -965,6 +966,9 @@ public: ~spu_function_logger() { - spu.start_time = 0; + if (!spu.is_stopped()) + { + spu.start_time = 0; + } } }; diff --git a/rpcs3/rpcs3qt/kernel_explorer.cpp b/rpcs3/rpcs3qt/kernel_explorer.cpp index e5baf78b70..3e7b25e811 100644 --- a/rpcs3/rpcs3qt/kernel_explorer.cpp +++ b/rpcs3/rpcs3qt/kernel_explorer.cpp @@ -601,20 +601,34 @@ void kernel_explorer::update() std::optional> lock_idm_lv2(std::in_place, id_manager::g_mutex, lv2_obj::g_mutex); + // Postponed as much as possible for time accuracy + const u64 current_time = get_guest_system_time(); + + auto get_wait_time_str = [&](u64 start_time) -> std::string + { + if (!start_time) + { + return {}; + } + + const f64 wait_time = (current_time - start_time) / 1000000.; + return fmt::format(" (%.1fs)", wait_time); + }; + idm::select>([&](u32 id, ppu_thread& ppu) { const auto func = ppu.last_function; const ppu_thread_status status = lv2_obj::ppu_state(&ppu, false, false); - add_leaf(find_node(root, additional_nodes::ppu_threads), qstr(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, Status: %s, State: %s, %s func: “%s”", id, *ppu.ppu_tname.load(), +ppu.prio, ppu.joiner.load(), status, ppu.state.load() - , ppu.ack_suspend ? "After" : (ppu.current_function ? "In" : "Last"), func ? func : ""))); + add_leaf(find_node(root, additional_nodes::ppu_threads), qstr(fmt::format(u8"PPU 0x%07x: “%s”, PRIO: %d, Joiner: %s, Status: %s, State: %s, %s func: “%s”%s", id, *ppu.ppu_tname.load(), +ppu.prio, ppu.joiner.load(), status, ppu.state.load() + , ppu.ack_suspend ? "After" : (ppu.current_function ? "In" : "Last"), func ? func : "", get_wait_time_str(ppu.start_time)))); }, idm::unlocked); lock_idm_lv2.reset(); idm::select>([&](u32 /*id*/, spu_thread& spu) { - QTreeWidgetItem* spu_thread_tree = add_solid_node(find_node(root, additional_nodes::spu_threads), qstr(fmt::format(u8"SPU 0x%07x: “%s”, State: %s, Type: %s", spu.lv2_id, *spu.spu_tname.load(), spu.state.load(), spu.get_type()))); + QTreeWidgetItem* spu_thread_tree = add_solid_node(find_node(root, additional_nodes::spu_threads), qstr(fmt::format(u8"SPU 0x%07x: “%s”, State: %s, Type: %s%s", spu.lv2_id, *spu.spu_tname.load(), spu.state.load(), spu.get_type(), get_wait_time_str(spu.start_time)))); if (spu.get_type() == spu_type::threaded) {