Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UI/ImDebugger/ImJitViewer.cpp
3925 views
1
#include "ppsspp_config.h"
2
3
#include "UI/ImDebugger/ImJitViewer.h"
4
#include "UI/ImDebugger/ImDebugger.h"
5
#include "Core/Config.h"
6
7
#include "Core/MIPS/JitCommon/JitBlockCache.h"
8
#include "Core/MIPS/JitCommon/JitCommon.h"
9
#include "Core/MIPS/JitCommon/JitState.h"
10
#include "Core/MIPS/IR/IRJit.h"
11
12
void ImJitViewerWindow::GoToBlockAtAddr(u32 addr) {
13
for (auto &block : blockList_) {
14
if (addr >= block.addr && addr < block.addr + (u32)block.sizeInBytes) {
15
curBlockNum_ = block.blockNum;
16
break;
17
}
18
}
19
}
20
21
void ImJitViewerWindow::Draw(ImConfig &cfg, ImControl &control) {
22
ImGui::SetNextWindowSize(ImVec2(500, 400), ImGuiCond_FirstUseEver);
23
if (!ImGui::Begin("JitViewer", &cfg.jitViewerOpen)) {
24
ImGui::End();
25
return;
26
}
27
28
const CPUCore core = (CPUCore)g_Config.iCpuCore;
29
30
if (core == CPUCore::INTERPRETER) {
31
ImGui::TextUnformatted("JIT Viewer is only available with JIT or IR-based CPU cores.");
32
ImGui::End();
33
return;
34
}
35
36
// Options menu
37
if (ImGui::BeginPopup("Options")) {
38
// ImGui::Checkbox("Auto-scroll", &AutoScroll);
39
ImGui::EndPopup();
40
}
41
42
#if PPSSPP_ARCH(AMD64)
43
const char *TARGET = "X86-64";
44
#elif PPSSPP_ARCH(X86)
45
const char *TARGET = "X86";
46
#elif PPSSPP_ARCH(ARM64)
47
48
const char *TARGET = "ARM64";
49
#elif PPSSPP_ARCH(ARM)
50
const char *TARGET = "ARM32";
51
#else
52
const char *TARGET = "TARGET";
53
#endif
54
55
// Three or four columns: One table for blocks that can be sorted in various ways,
56
// then the remaining are either MIPS/IR/TARGET or MIPS/TARGET or MIPS/IR depending on the JIT type.
57
int numColumns = 3;
58
if (core == CPUCore::JIT_IR) {
59
numColumns = 4;
60
}
61
62
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
63
64
if (core_ != (int)core) {
65
// Core changed, need to refresh.
66
refresh_ = true;
67
core_ = (int)core;
68
}
69
70
if (sortSpecs_ && sortSpecs_->SpecsDirty) {
71
refresh_ = true;
72
sortSpecs_->SpecsDirty = false;
73
}
74
75
// If the CPU moved, and we're not currently running, update the cached blocklist.
76
const CoreState coreStateCached = coreState;
77
if (coreStateCached == CORE_STEPPING_CPU || coreStateCached == CORE_NEXTFRAME || refresh_) {
78
const int cpuStepCount = Core_GetSteppingCounter();
79
if (lastCpuStepCount_ != cpuStepCount || refresh_) {
80
refresh_ = false;
81
lastCpuStepCount_ = cpuStepCount;
82
blockList_.clear();
83
curBlockNum_ = -1;
84
const int blockCount = blockCacheDebug->GetNumBlocks();
85
blockList_.reserve(blockCount);
86
INFO_LOG(Log::Debugger, "Updating JIT block list... %d blocks", blockCacheDebug->GetNumBlocks());
87
for (int i = 0; i < blockCount; i++) {
88
if (!blockCacheDebug->IsValidBlock(i)) {
89
continue;
90
}
91
JitBlockMeta meta = blockCacheDebug->GetBlockMeta(i);
92
if (!meta.valid) {
93
continue;
94
}
95
CachedBlock cb;
96
cb.addr = meta.addr;
97
cb.sizeInBytes = meta.sizeInBytes;
98
cb.blockNum = i;
99
#ifdef IR_PROFILING
100
JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(i);
101
cb.profileStats = stats;
102
#endif
103
blockList_.push_back(cb);
104
}
105
106
std::sort(blockList_.begin(), blockList_.end(), [this](const CachedBlock &a, const CachedBlock &b) {
107
if (!sortSpecs_ || sortSpecs_->SpecsCount <= 0) {
108
return a.addr < b.addr;
109
}
110
const ImGuiTableColumnSortSpecs *spec = &sortSpecs_->Specs[0];
111
int delta = 0;
112
switch (spec->ColumnUserID) {
113
case 0: delta = (int)a.blockNum - (int)b.blockNum; break;
114
case 1: delta = (int)a.addr - (int)b.addr; break;
115
case 2: delta = a.sizeInBytes - b.sizeInBytes; break;
116
#ifdef IR_PROFILING
117
case 3: delta = a.profileStats.executions - b.profileStats.executions; break;
118
case 4: delta = a.profileStats.totalNanos - b.profileStats.totalNanos; break;
119
#endif
120
}
121
if (delta == 0) {
122
return a.addr < b.addr;
123
}
124
if (spec->SortDirection == ImGuiSortDirection_Ascending) {
125
return delta < 0;
126
} else {
127
return delta > 0;
128
}
129
});
130
}
131
} else {
132
ImGui::Text("Pause to update block list");
133
}
134
135
if (ImGui::BeginTable("columns", numColumns, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersH | ImGuiTableFlags_Resizable)) {
136
ImGui::TableSetupColumn("Blocks");
137
ImGui::TableSetupColumn("MIPS");
138
if (core == CPUCore::JIT_IR || core == CPUCore::IR_INTERPRETER) {
139
ImGui::TableSetupColumn("IR");
140
}
141
if (core == CPUCore::JIT_IR || core == CPUCore::JIT) {
142
ImGui::TableSetupColumn(TARGET);
143
}
144
145
ImGui::TableHeadersRow();
146
147
ImGui::TableNextRow();
148
ImGui::TableNextColumn();
149
150
// For separate scrolling.
151
ImGui::BeginChild("LeftPane", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar);
152
#ifdef IR_PROFILING
153
const int numColumns = (core == CPUCore::IR_INTERPRETER) ? 5 : 3;
154
#else
155
const int numColumns = 3;
156
#endif
157
if (ImGui::BeginTable("blocks", numColumns, ImGuiTableFlags_Sortable | ImGuiTableFlags_Resizable)) {
158
ImGui::TableSetupColumn("Num", 0, 0, 0);
159
ImGui::TableSetupColumn("Addr", 0, 0, 1);
160
ImGui::TableSetupColumn("Size", 0, 0, 2);
161
#ifdef IR_PROFILING
162
if (numColumns == 5) {
163
ImGui::TableSetupColumn("Exec", 0, 0, 3);
164
ImGui::TableSetupColumn("Ns", 0, 0, 4);
165
}
166
#endif
167
ImGui::TableHeadersRow();
168
sortSpecs_ = ImGui::TableGetSortSpecs();
169
170
ImGuiListClipper clipper;
171
clipper.Begin((int)blockList_.size());
172
173
while (clipper.Step()) {
174
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
175
const auto &block = blockList_[i];
176
177
ImGui::TableNextRow();
178
ImGui::TableNextColumn();
179
180
char label[32];
181
snprintf(label, sizeof(label), "%d", block.blockNum);
182
183
if (ImGui::Selectable(label, block.blockNum == curBlockNum_, ImGuiSelectableFlags_SpanAllColumns)) {
184
curBlockNum_ = block.blockNum;
185
if (curBlockNum_ >= 0 && curBlockNum_ < blockCacheDebug->GetNumBlocks()) {
186
debugInfo_ = blockCacheDebug->GetBlockDebugInfo(curBlockNum_);
187
}
188
}
189
190
ImGui::TableNextColumn();
191
ImGui::Text("%08x", block.addr);
192
193
ImGui::TableNextColumn();
194
ImGui::Text("%d", block.sizeInBytes);
195
196
#ifdef IR_PROFILING
197
if (numColumns == 5) {
198
ImGui::TableNextColumn();
199
ImGui::Text("%d", block.profileStats.executions);
200
201
ImGui::TableNextColumn();
202
ImGui::Text("%0.3f ms", (double)block.profileStats.totalNanos * 0.000001);
203
}
204
#endif
205
}
206
}
207
208
clipper.End();
209
ImGui::EndTable();
210
211
}
212
213
ImGui::EndChild();
214
215
ImGui::TableNextColumn();
216
217
ImGui::BeginChild("MIPSPane", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar);
218
219
for (const auto &line : debugInfo_.origDisasm) {
220
ImGui::TextUnformatted(line.c_str());
221
}
222
ImGui::EndChild();
223
224
if (core == CPUCore::JIT_IR || core == CPUCore::IR_INTERPRETER) {
225
ImGui::TableNextColumn();
226
227
ImGui::BeginChild("IRPane", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar);
228
// TODO : When we have both target and IR, need a third column.
229
for (const auto &line : debugInfo_.irDisasm) {
230
ImGui::TextUnformatted(line.c_str());
231
}
232
ImGui::EndChild();
233
}
234
235
if (core == CPUCore::JIT_IR || core == CPUCore::JIT) {
236
ImGui::TableNextColumn();
237
238
ImGui::BeginChild("TargetPane", ImVec2(0, 0), true, ImGuiWindowFlags_HorizontalScrollbar);
239
for (const auto &line : debugInfo_.targetDisasm) {
240
ImGui::TextUnformatted(line.c_str());
241
}
242
ImGui::EndChild();
243
}
244
245
ImGui::EndTable();
246
}
247
248
ImGui::End();
249
}
250
251