From ff5dea821b4605ad09f4050c7903aa18639f4fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 8 Oct 2025 12:59:33 -0600 Subject: [PATCH] New jit viewer is starting to work a bit. --- Core/MIPS/IR/IRJit.cpp | 3 + UI/ImDebugger/ImDebugger.cpp | 1 + UI/ImDebugger/ImJitViewer.cpp | 158 +++++++++++++++---- UI/ImDebugger/ImJitViewer.h | 21 +++ UWP/UI_UWP/UI_UWP.vcxproj | 2 + UWP/UI_UWP/UI_UWP.vcxproj.filters | 249 +++++++++++++++++++++++------- android/jni/Android.mk | 1 + 7 files changed, 346 insertions(+), 89 deletions(-) diff --git a/Core/MIPS/IR/IRJit.cpp b/Core/MIPS/IR/IRJit.cpp index 633b3282f8..a11b882630 100644 --- a/Core/MIPS/IR/IRJit.cpp +++ b/Core/MIPS/IR/IRJit.cpp @@ -461,6 +461,9 @@ JitBlockDebugInfo IRBlockCache::GetBlockDebugInfo(int blockNum) const { uint32_t start, size; ir.GetRange(&start, &size); debugInfo.originalAddress = start; // TODO + if (!Memory::IsValid4AlignedAddress(start)) { + return debugInfo; + } debugInfo.origDisasm.reserve(((start + size) - start) / 4); for (u32 addr = start; addr < start + size; addr += 4) { diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index e5e8c859fb..ebe6c93a2a 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -2850,6 +2850,7 @@ void ImConfig::SyncConfig(IniFile *ini, bool save) { sync.Sync("watchOpen", &watchOpen, false); sync.Sync("paramSFOOpen", ¶mSFOOpen, false); sync.Sync("atracToolOpen", &atracToolOpen, false); + sync.Sync("jitViewerOpen", &jitViewerOpen, false); for (int i = 0; i < 4; i++) { char name[64]; snprintf(name, sizeof(name), "memory%dOpen", i + 1); diff --git a/UI/ImDebugger/ImJitViewer.cpp b/UI/ImDebugger/ImJitViewer.cpp index 656b46c026..ceb3f984a9 100644 --- a/UI/ImDebugger/ImJitViewer.cpp +++ b/UI/ImDebugger/ImJitViewer.cpp @@ -8,6 +8,15 @@ #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/MIPS/JitCommon/JitState.h" +void ImJitViewerWindow::GoToBlockAtAddr(u32 addr) { + for (auto &block : blockList_) { + if (addr >= block.addr && addr < block.addr + (u32)block.sizeInBytes) { + curBlockNum_ = block.blockNum; + break; + } + } +} + void ImJitViewerWindow::Draw(ImConfig &cfg, ImControl &control) { ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver); if (!ImGui::Begin("JitViewer", &cfg.jitViewerOpen)) { @@ -29,17 +38,17 @@ void ImJitViewerWindow::Draw(ImConfig &cfg, ImControl &control) { ImGui::EndPopup(); } -#if PPSSPP_ARCH(X64) +#if PPSSPP_ARCH(AMD64) const char *TARGET = "X86-64"; #elif PPSSPP_ARCH(X86) const char *TARGET = "X86"; #elif PPSSPP_ARCH(ARM64) const char *TARGET = "ARM64"; -#elif PPSSPP_ARCH(ARM32) +#elif PPSSPP_ARCH(ARM) const char *TARGET = "ARM32"; #else - cosnt char *TARGET = "TARGET"; + const char *TARGET = "TARGET"; #endif // Three or four columns: One table for blocks that can be sorted in various ways, @@ -49,7 +58,75 @@ void ImJitViewerWindow::Draw(ImConfig &cfg, ImControl &control) { numColumns = 4; } - if (ImGui::BeginTable("columns", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH | ImGuiTableFlags_Resizable)) { + JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface(); + + if (core_ != (int)core) { + // Core changed, need to refresh. + refresh_ = true; + core_ = (int)core; + } + + if (sortSpecs_ && sortSpecs_->SpecsDirty) { + refresh_ = true; + sortSpecs_->SpecsDirty = false; + } + + // If the CPU moved, and we're not currently running, update the cached blocklist. + const CoreState coreStateCached = coreState; + if (coreStateCached == CORE_STEPPING_CPU || coreStateCached == CORE_NEXTFRAME || refresh_) { + const int cpuStepCount = Core_GetSteppingCounter(); + if (lastCpuStepCount_ != cpuStepCount || refresh_) { + refresh_ = false; + lastCpuStepCount_ = cpuStepCount; + blockList_.clear(); + curBlockNum_ = -1; + const int blockCount = blockCacheDebug->GetNumBlocks(); + blockList_.reserve(blockCount); + INFO_LOG(Log::Debugger, "Updating JIT block list... %d blocks", blockCacheDebug->GetNumBlocks()); + for (int i = 0; i < blockCount; i++) { + if (!blockCacheDebug->IsValidBlock(i)) { + continue; + } + JitBlockMeta meta = blockCacheDebug->GetBlockMeta(i); + if (!meta.valid) { + continue; + } + CachedBlock cb; + cb.addr = meta.addr; + cb.sizeInBytes = meta.sizeInBytes; + cb.blockNum = i; + blockList_.push_back(cb); + } + + std::sort(blockList_.begin(), blockList_.end(), [this](const CachedBlock &a, const CachedBlock &b) { + if (!sortSpecs_ || sortSpecs_->SpecsCount <= 0) { + return a.addr < b.addr; + } + const ImGuiTableColumnSortSpecs *spec = &sortSpecs_->Specs[0]; + int delta = 0; + if (spec->ColumnUserID == 0) { + delta = (int)a.blockNum - (int)b.blockNum; + } else + if (spec->ColumnUserID == 1) { + delta = (int)a.addr - (int)b.addr; + } else if (spec->ColumnUserID == 2) { + delta = a.sizeInBytes - b.sizeInBytes; + } + if (delta == 0) { + return a.addr < b.addr; + } + if (spec->SortDirection == ImGuiSortDirection_Ascending) { + return delta < 0; + } else { + return delta > 0; + } + }); + } + } else { + ImGui::Text("Pause to update block list"); + } + + if (ImGui::BeginTable("columns", numColumns, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH | ImGuiTableFlags_Resizable)) { ImGui::TableSetupColumn("Blocks"); ImGui::TableSetupColumn("MIPS"); if (core == CPUCore::JIT_IR || core == CPUCore::IR_INTERPRETER) { @@ -64,45 +141,68 @@ void ImJitViewerWindow::Draw(ImConfig &cfg, ImControl &control) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::Text("Blocklist"); - JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface(); - int64_t sumTotalNanos = 0; - int64_t sumExecutions = 0; - bool profiling = blockCacheDebug->SupportsProfiling(); - for (int i = 0; i < blockCacheDebug->GetNumBlocks(); i++) { - if (!blockCacheDebug->IsValidBlock(i)) { - continue; + // For separate scrolling. + ImGui::BeginChild("LeftPane", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar); + + if (ImGui::BeginTable("blocks", 3, ImGuiTableFlags_Sortable | ImGuiTableFlags_Resizable)) { + ImGui::TableSetupColumn("Num", 0, 0, 0); + ImGui::TableSetupColumn("Addr", 0, 0, 1); + ImGui::TableSetupColumn("Size", 0, 0, 2); + ImGui::TableHeadersRow(); + + sortSpecs_ = ImGui::TableGetSortSpecs(); + + for (int i = 0; i < (int)blockList_.size(); i++) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + char label[32]; + snprintf(label, sizeof(label), "%d", blockList_[i].blockNum); + if (ImGui::Selectable(label, blockList_[i].blockNum == curBlockNum_, ImGuiSelectableFlags_SpanAllColumns)) { + curBlockNum_ = blockList_[i].blockNum; + if (curBlockNum_ >= 0 && curBlockNum_ < blockCacheDebug->GetNumBlocks()) { + debugInfo_ = blockCacheDebug->GetBlockDebugInfo(curBlockNum_); + } + } + ImGui::TableNextColumn(); + ImGui::Text("%08x", blockList_[i].addr); + ImGui::TableNextColumn(); + ImGui::Text("%d", blockList_[i].sizeInBytes); } - JitBlockMeta meta = blockCacheDebug->GetBlockMeta(i); - ImGui::Text("%08x %d", meta.addr, meta.sizeInBytes); + ImGui::EndTable(); } + ImGui::EndChild(); + ImGui::TableNextColumn(); - ImGui::Text("MIPS"); + ImGui::BeginChild("MIPSPane", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar); + + for (const auto &line : debugInfo_.origDisasm) { + ImGui::TextUnformatted(line.c_str()); + } + ImGui::EndChild(); if (core == CPUCore::JIT_IR || core == CPUCore::IR_INTERPRETER) { - ImGui::TableNextColumn(); - ImGui::Text("IR"); + ImGui::BeginChild("IRPane", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar); + // TODO : When we have both target and IR, need a third column. + for (const auto &line : debugInfo_.irDisasm) { + ImGui::TextUnformatted(line.c_str()); + } + ImGui::EndChild(); } + if (core == CPUCore::JIT_IR || core == CPUCore::JIT) { ImGui::TableNextColumn(); - ImGui::Text("Target asm"); + + ImGui::BeginChild("TargetPane", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar); + for (const auto &line : debugInfo_.targetDisasm) { + ImGui::TextUnformatted(line.c_str()); + } + ImGui::EndChild(); } - /* - if (ImGui::BeginTable("blocks", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH | ImGuiTableFlags_ScrollY)) { - - - for (auto &block : blocks) { - char label[64]; - snprintf(label, sizeof(label), "0x%08X", block.startAddress); - if (ImGui::Selectable(label, false, ImGuiSelectableFlags_SpanAllColumns)) { - ", 3) - */ - ImGui::EndTable(); } diff --git a/UI/ImDebugger/ImJitViewer.h b/UI/ImDebugger/ImJitViewer.h index e08ef3919e..87a379c21a 100644 --- a/UI/ImDebugger/ImJitViewer.h +++ b/UI/ImDebugger/ImJitViewer.h @@ -5,6 +5,7 @@ #include "ext/imgui/imgui.h" #include "Core/Debugger/DebugInterface.h" +#include "Core/MIPS/JitCommon/JitBlockCache.h" struct ImConfig; struct ImControl; @@ -15,4 +16,24 @@ public: const char *Title() const { return "JIT Viewer"; } + + void GoToBlockAtAddr(u32 addr); + +private: + struct CachedBlock { + u32 addr; + int sizeInBytes; + int blockNum; + }; + std::vector blockList_; + int curBlockNum_ = -1; + + int lastCpuStepCount_ = -1; + int blockSortColumn_ = 0; + + bool refresh_ = false; + int core_ = -1; + + ImGuiTableSortSpecs *sortSpecs_ = nullptr; + JitBlockDebugInfo debugInfo_; }; diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index ca7fdc827a..4d14b3fa83 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -107,6 +107,7 @@ + @@ -157,6 +158,7 @@ + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index 423e806d2c..f064528ae2 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -3,43 +3,15 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - ImDebugger @@ -58,50 +30,113 @@ ImDebugger - - + + ImDebugger + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + - - - - - - - - - - - - - - - - - - - - - - - - - - - - ImDebugger @@ -120,13 +155,107 @@ ImDebugger - - + + ImDebugger + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + + + Screens + {4013cb89-6145-451c-9cb1-d63d01f66bd5} + + {38b8413d-438d-4197-9db8-7bd123fc7431} + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index c828ef1469..c74c4c410b 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -895,6 +895,7 @@ LOCAL_SRC_FILES := \ $(SRC)/UI/ImDebugger/ImConsole.cpp \ $(SRC)/UI/ImDebugger/ImDisasmView.cpp \ $(SRC)/UI/ImDebugger/ImMemView.cpp \ + $(SRC)/UI/ImDebugger/ImJitViewer.cpp \ $(SRC)/UI/ImDebugger/ImStructViewer.cpp \ $(SRC)/UI/AudioCommon.cpp \ $(SRC)/UI/BackgroundAudio.cpp \