Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UI/JitCompareScreen.cpp
5670 views
1
#include <algorithm>
2
3
#include "UI/JitCompareScreen.h"
4
#include "Common/Data/Text/I18n.h"
5
#include "Common/UI/ViewGroup.h"
6
#include "Common/Render/DrawBuffer.h"
7
#include "Core/MemMap.h"
8
#include "Core/MIPS/MIPSTables.h"
9
#include "Core/MIPS/JitCommon/JitBlockCache.h"
10
#include "Core/MIPS/JitCommon/JitCommon.h"
11
#include "Core/MIPS/JitCommon/JitState.h"
12
#include "UI/PopupScreens.h"
13
14
JitCompareScreen::JitCompareScreen() : UITabbedBaseDialogScreen(Path()) {
15
if (!MIPSComp::jit) {
16
return;
17
}
18
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
19
// The only defaults that make sense.
20
if (blockCacheDebug->SupportsProfiling()) {
21
listSort_ = ListSort::TIME_SPENT;
22
} else {
23
listSort_ = ListSort::BLOCK_LENGTH_DESC;
24
}
25
FillBlockList();
26
}
27
28
// Three panes: Block chooser, MIPS view, ARM/x86 view
29
void JitCompareScreen::CreateTabs() {
30
auto di = GetI18NCategory(I18NCat::DIALOG);
31
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
32
33
using namespace UI;
34
35
AddTab("Block List", dev->T("Block List"), [=](LinearLayout *tabContent) {
36
// Should match the ListSort enum
37
static ContextMenuItem sortMenu[] = {
38
{ "Block number", "I_ARROW_UP" },
39
{ "Block length", "I_ARROW_DOWN" },
40
{ "Block length", "I_ARROW_UP" },
41
{ "Time spent", "I_ARROW_DOWN" },
42
{ "Executions", "I_ARROW_DOWN" },
43
};
44
int sortCount = ARRAY_SIZE(sortMenu);
45
if (MIPSComp::jit) {
46
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
47
if (!blockCacheDebug->SupportsProfiling()) {
48
sortCount -= 2;
49
}
50
}
51
52
LinearLayout *listTopBar = tabContent->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
53
Choice *sortButton = new Choice(dev->T("Sort..."), new LinearLayoutParams());
54
listTopBar->Add(sortButton)->OnClick.Add([this, sortButton, sortCount](UI::EventParams &e) {
55
PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(sortMenu, sortCount, I18NCat::DEVELOPER, sortButton);
56
screenManager()->push(contextMenu);
57
contextMenu->OnChoice.Add([=](EventParams &e) -> void {
58
if (e.a < (int)ListSort::MAX) {
59
listSort_ = (ListSort)e.a;
60
UpdateDisasm();
61
}
62
});
63
});
64
// leftColumn->Add(new Choice(dev->T("By Address")))->OnClick.Handle(this, &JitCompareScreen::OnSelectBlock);
65
listTopBar->Add(new Choice(dev->T("All"), new LinearLayoutParams()))->OnClick.Add([=](UI::EventParams &e) {
66
listType_ = ListType::ALL_BLOCKS;
67
UpdateDisasm();
68
});
69
listTopBar->Add(new Choice(dev->T("FPU"), new LinearLayoutParams()))->OnClick.Add([=](UI::EventParams &e) {
70
listType_ = ListType::FPU_BLOCKS;
71
UpdateDisasm();
72
});
73
listTopBar->Add(new Choice(dev->T("VFPU"), new LinearLayoutParams()))->OnClick.Add([=](UI::EventParams &e) {
74
listType_ = ListType::VFPU_BLOCKS;
75
UpdateDisasm();
76
});
77
78
blockListContainer_ = tabContent->Add(new LinearLayout(ORIENT_VERTICAL));
79
});
80
81
AddTab("Comparison", dev->T("Jit Compare"), [=](LinearLayout *tabContent) {
82
LinearLayout *blockTopBar = tabContent->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
83
blockTopBar->Add(new Button("", ImageID("I_ARROW_LEFT")))->OnClick.Add([=](UI::EventParams &e) {
84
if (currentBlock_ >= 1)
85
currentBlock_--;
86
UpdateDisasm();
87
});
88
blockTopBar->Add(new Button("", ImageID("I_ARROW_RIGHT")))->OnClick.Add([=](UI::EventParams &e) {
89
if (currentBlock_ < (int)blockList_.size() - 1)
90
currentBlock_++;
91
if (currentBlock_ == -1 && !blockList_.empty()) {
92
currentBlock_ = 0;
93
}
94
UpdateDisasm();
95
});
96
blockTopBar->Add(new Button(dev->T("Random")))->OnClick.Add([=](UI::EventParams &e) {
97
if (blockList_.empty()) {
98
return;
99
}
100
currentBlock_ = rand() % blockList_.size();
101
UpdateDisasm();
102
});
103
104
blockAddr_ = blockTopBar->Add(new TextEdit("", dev->T("Block address"), ""));
105
blockAddr_->OnEnter.Handle(this, &JitCompareScreen::OnAddressChange);
106
blockName_ = blockTopBar->Add(new TextView(dev->T("No block")));
107
blockStats_ = blockTopBar->Add(new TextView(""));
108
109
tabContent->Add(new Button("test"));
110
111
LinearLayout *columns = tabContent->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f)));
112
113
ScrollView *midColumnScroll = columns->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
114
LinearLayout *midColumn = midColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
115
midColumn->SetTag("JitCompareLeftDisasm");
116
leftDisasm_ = midColumn->Add(new LinearLayout(ORIENT_VERTICAL));
117
leftDisasm_->SetSpacing(0.0f);
118
119
ScrollView *rightColumnScroll = columns->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
120
rightColumnScroll->SetTag("JitCompareRightDisasm");
121
LinearLayout *rightColumn = rightColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
122
rightDisasm_ = rightColumn->Add(new LinearLayout(ORIENT_VERTICAL));
123
rightDisasm_->SetSpacing(0.0f);
124
}, TabFlags::NonScrollable);
125
126
AddTab("Stats", dev->T("Stats"), [=](LinearLayout *tabContent) {
127
globalStats_ = tabContent->Add(new TextView("N/A"));
128
});
129
130
EnsureTabs(); // don't create them lazily, due to the interdependences
131
UpdateDisasm();
132
}
133
134
void JitCompareScreen::FillBlockList() {
135
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
136
blockList_.clear();
137
int64_t sumTotalNanos = 0;
138
int64_t sumExecutions = 0;
139
bool profiling = blockCacheDebug->SupportsProfiling();
140
for (int i = 0; i < blockCacheDebug->GetNumBlocks(); i++) {
141
if (!blockCacheDebug->IsValidBlock(i)) {
142
continue;
143
}
144
145
switch (listType_) {
146
case ListType::ALL_BLOCKS:
147
blockList_.push_back(i);
148
break;
149
case ListType::FPU_BLOCKS:
150
case ListType::VFPU_BLOCKS:
151
{
152
const uint64_t flags = listType_ == ListType::FPU_BLOCKS ? IS_FPU : IS_VFPU;
153
// const uint64_t antiFlags = IS_SYSCALL;
154
const uint64_t antiFlags = 0;
155
JitBlockMeta meta = blockCacheDebug->GetBlockMeta(i);
156
if (meta.valid) {
157
for (u32 addr = meta.addr; addr < meta.addr + meta.sizeInBytes; addr += 4) {
158
MIPSOpcode opcode = Memory::Read_Instruction(addr);
159
MIPSInfo info = MIPSGetInfo(opcode);
160
if ((info & flags) && !(info & antiFlags)) {
161
blockList_.push_back(i);
162
break;
163
}
164
}
165
}
166
break;
167
}
168
default:
169
break;
170
}
171
172
if (profiling) {
173
JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(i);
174
sumTotalNanos += stats.totalNanos;
175
sumExecutions += stats.executions;
176
}
177
}
178
179
sumTotalNanos_ = sumTotalNanos;
180
sumExecutions_ = sumExecutions;
181
182
if (listSort_ == ListSort::BLOCK_NUM) {
183
// Already sorted, effectively.
184
return;
185
}
186
187
std::sort(blockList_.begin(), blockList_.end(), [=](const int &a_index, const int &b_index) {
188
// First, check metadata sorts.
189
switch (listSort_) {
190
case ListSort::BLOCK_LENGTH_DESC:
191
{
192
JitBlockMeta a_meta = blockCacheDebug->GetBlockMeta(a_index);
193
JitBlockMeta b_meta = blockCacheDebug->GetBlockMeta(b_index);
194
return a_meta.sizeInBytes > b_meta.sizeInBytes; // reverse for descending
195
}
196
case ListSort::BLOCK_LENGTH_ASC:
197
{
198
JitBlockMeta a_meta = blockCacheDebug->GetBlockMeta(a_index);
199
JitBlockMeta b_meta = blockCacheDebug->GetBlockMeta(b_index);
200
return a_meta.sizeInBytes < b_meta.sizeInBytes;
201
}
202
default:
203
break;
204
}
205
JitBlockProfileStats a_stats = blockCacheDebug->GetBlockProfileStats(a_index);
206
JitBlockProfileStats b_stats = blockCacheDebug->GetBlockProfileStats(b_index);
207
switch (listSort_) {
208
case ListSort::EXECUTIONS:
209
return a_stats.executions > b_stats.executions;
210
case ListSort::TIME_SPENT:
211
return a_stats.totalNanos > b_stats.totalNanos;
212
default:
213
return false;
214
}
215
});
216
217
if (currentBlock_ < 0 && !blockList_.empty()) {
218
currentBlock_ = 0;
219
}
220
}
221
222
void JitCompareScreen::UpdateDisasm() {
223
leftDisasm_->Clear();
224
rightDisasm_->Clear();
225
226
using namespace UI;
227
228
if (!MIPSComp::jit) {
229
return;
230
}
231
232
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
233
234
FillBlockList();
235
236
if (currentBlock_ >= 0 && currentBlock_ < blockList_.size()) { // Update disassembly
237
char temp[256];
238
snprintf(temp, sizeof(temp), "%d/%d", currentBlock_, (int)blockList_.size());
239
blockName_->SetText(temp);
240
241
int blockNum = blockList_[currentBlock_];
242
243
if (!blockCacheDebug->IsValidBlock(blockNum)) {
244
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
245
leftDisasm_->Add(new TextView(dev->T("No block")));
246
rightDisasm_->Add(new TextView(dev->T("No block")));
247
blockStats_->SetText("(no stats)");
248
return;
249
}
250
251
JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(blockNum);
252
snprintf(temp, sizeof(temp), "%08x", debugInfo.originalAddress);
253
blockAddr_->SetText(temp);
254
255
// Alright. First generate the MIPS disassembly.
256
257
// TODO: Need a way to communicate branch continuing.
258
for (const auto &line : debugInfo.origDisasm) {
259
leftDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);
260
}
261
262
// TODO : When we have both target and IR, need a third column.
263
if (debugInfo.targetDisasm.size()) {
264
for (const auto &line : debugInfo.targetDisasm) {
265
rightDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);
266
}
267
} else {
268
for (const auto &line : debugInfo.irDisasm) {
269
rightDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);
270
}
271
}
272
273
int numMips = leftDisasm_->GetNumSubviews();
274
int numHost = rightDisasm_->GetNumSubviews();
275
double bloat = 100.0 * numHost / numMips;
276
if (blockCacheDebug->SupportsProfiling()) {
277
JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(blockNum);
278
int execs = (int)stats.executions;
279
double us = (double)stats.totalNanos / 1000000.0;
280
double percentage = 100.0 * (double)stats.totalNanos / (double)sumTotalNanos_;
281
snprintf(temp, sizeof(temp), "%d runs, %0.2f ms, %0.2f%%, bloat: %0.1f%%", execs, us, percentage, bloat);
282
} else {
283
snprintf(temp, sizeof(temp), "bloat: %0.1f%%", bloat);
284
}
285
blockStats_->SetText(temp);
286
}
287
{ // Update block list
288
blockListContainer_->Clear();
289
bool profiling = blockCacheDebug->SupportsProfiling();
290
for (int i = 0; i < std::min(200, (int)blockList_.size()); i++) {
291
int blockNum = blockList_[i];
292
JitBlockMeta meta = blockCacheDebug->GetBlockMeta(blockNum);
293
char temp[512], small[512];
294
if (profiling) {
295
JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(blockNum);
296
int execs = (int)stats.executions;
297
double us = (double)stats.totalNanos / 1000000.0;
298
double percentage = 100.0 * (double)stats.totalNanos / (double)sumTotalNanos_;
299
snprintf(temp, sizeof(temp), "%08x: %d instrs (%d runs, %0.2f ms, %0.2f%%)", meta.addr, meta.sizeInBytes / 4, execs, us, percentage);
300
} else {
301
snprintf(temp, sizeof(temp), "%08x: %d instrs", meta.addr, meta.sizeInBytes / 4);
302
}
303
snprintf(small, sizeof(small), "Small text");
304
Choice *blockChoice = blockListContainer_->Add(new Choice(temp, small));
305
blockChoice->OnClick.Handle(this, &JitCompareScreen::OnBlockClick);
306
}
307
}
308
309
// Update stats
310
{
311
BlockCacheStats bcStats{};
312
blockCacheDebug->ComputeStats(bcStats);
313
314
char stats[1024];
315
snprintf(stats, sizeof(stats),
316
"Num blocks: %d\n"
317
"Average Bloat: %0.2f%%\n"
318
"Min Bloat: %0.2f%% (%08x)\n"
319
"Max Bloat: %0.2f%% (%08x)\n",
320
blockCacheDebug->GetNumBlocks(),
321
100.0 * bcStats.avgBloat,
322
100.0 * bcStats.minBloat, bcStats.minBloatBlock,
323
100.0 * bcStats.maxBloat, bcStats.maxBloatBlock);
324
325
globalStats_->SetText(stats);
326
}
327
}
328
329
void JitCompareScreen::OnBlockClick(UI::EventParams &e) {
330
int blockIndex = blockListContainer_->IndexOfSubview(e.v);
331
if (blockIndex >= 0) {
332
currentBlock_ = blockIndex;
333
SetCurrentTab(1);
334
UpdateDisasm();
335
}
336
}
337
338
void JitCompareScreen::OnAddressChange(UI::EventParams &e) {
339
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
340
if (!MIPSComp::jit) {
341
return;
342
}
343
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
344
if (!blockCache)
345
return;
346
u32 addr;
347
if (blockAddr_->GetText().size() > 8)
348
return;
349
if (1 == sscanf(blockAddr_->GetText().c_str(), "%08x", &addr)) {
350
if (Memory::IsValidAddress(addr)) {
351
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(addr);
352
UpdateDisasm();
353
}
354
}
355
}
356
357
void JitCompareScreen::OnSelectBlock(UI::EventParams &e) {
358
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
359
360
auto addressPrompt = new AddressPromptScreen(dev->T("Block address"));
361
addressPrompt->OnChoice.Handle(this, &JitCompareScreen::OnBlockAddress);
362
screenManager()->push(addressPrompt);
363
}
364
365
void JitCompareScreen::OnBlockAddress(UI::EventParams &e) {
366
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
367
if (!MIPSComp::jit) {
368
return;
369
}
370
371
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
372
if (!blockCache)
373
return;
374
375
if (Memory::IsValidAddress(e.a)) {
376
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a);
377
} else {
378
currentBlock_ = -1;
379
}
380
UpdateDisasm();
381
}
382
383
/*
384
void JitCompareScreen::OnRandomBlock(int flag) {
385
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
386
if (!MIPSComp::jit) {
387
return;
388
}
389
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
390
if (!blockCache)
391
return;
392
393
int numBlocks = blockCache->GetNumBlocks();
394
if (numBlocks > 0) {
395
bool anyWanted = false;
396
int tries = 0;
397
while (!anyWanted && tries < numBlocks) {
398
currentBlock_ = rand() % numBlocks;
399
if (blockCache->IsValidBlock(currentBlock_)) {
400
JitBlockDebugInfo b = blockCache->GetBlockDebugInfo(currentBlock_);
401
u32 mipsBytes = (u32)b.origDisasm.size() * 4;
402
for (u32 addr = b.originalAddress; addr < b.originalAddress + mipsBytes; addr += 4) {
403
MIPSOpcode opcode = Memory::Read_Instruction(addr);
404
if (MIPSGetInfo(opcode) & flag) {
405
char temp[256];
406
MIPSDisAsm(opcode, addr, temp, sizeof(temp));
407
// INFO_LOG(Log::HLE, "Stopping at random instruction: %08x %s", addr, temp);
408
anyWanted = true;
409
break;
410
}
411
}
412
}
413
tries++;
414
}
415
416
if (!anyWanted)
417
currentBlock_ = -1;
418
}
419
UpdateDisasm();
420
}*/
421
422
void AddressPromptScreen::CreatePopupContents(UI::ViewGroup *parent) {
423
using namespace UI;
424
425
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
426
427
addrView_ = new TextView(dev->T("Enter address"), ALIGN_HCENTER, false);
428
parent->Add(addrView_);
429
430
ViewGroup *grid = new GridLayout(GridLayoutSettings(60, 40));
431
parent->Add(grid);
432
433
for (int i = 0; i < 16; ++i) {
434
char temp[16];
435
snprintf(temp, 16, " %X ", i);
436
buttons_[i] = new Button(temp);
437
grid->Add(buttons_[i])->OnClick.Handle(this, &AddressPromptScreen::OnDigitButton);
438
}
439
440
parent->Add(new Button(dev->T("Backspace")))->OnClick.Handle(this, &AddressPromptScreen::OnBackspace);
441
}
442
443
void AddressPromptScreen::OnCompleted(DialogResult result) {
444
if (result == DR_OK) {
445
UI::EventParams e{};
446
e.v = root_;
447
e.a = addr_;
448
OnChoice.Trigger(e);
449
}
450
}
451
452
void AddressPromptScreen::OnDigitButton(UI::EventParams &e) {
453
for (int i = 0; i < 16; ++i) {
454
if (buttons_[i] == e.v) {
455
AddDigit(i);
456
}
457
}
458
}
459
460
void AddressPromptScreen::OnBackspace(UI::EventParams &e) {
461
BackspaceDigit();
462
}
463
464
void AddressPromptScreen::AddDigit(int n) {
465
if ((addr_ & 0xF0000000) == 0) {
466
addr_ = addr_ * 16 + n;
467
}
468
UpdatePreviewDigits();
469
}
470
471
void AddressPromptScreen::BackspaceDigit() {
472
addr_ /= 16;
473
UpdatePreviewDigits();
474
}
475
476
void AddressPromptScreen::UpdatePreviewDigits() {
477
if (addr_ != 0) {
478
char temp[32];
479
snprintf(temp, 32, "%8X", addr_);
480
addrView_->SetText(temp);
481
} else {
482
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
483
addrView_->SetText(dev->T("Enter address"));
484
}
485
}
486
487
bool AddressPromptScreen::key(const KeyInput &key) {
488
if (key.flags & KeyInputFlags::DOWN) {
489
if (key.keyCode >= NKCODE_0 && key.keyCode <= NKCODE_9) {
490
AddDigit(key.keyCode - NKCODE_0);
491
} else if (key.keyCode >= NKCODE_A && key.keyCode <= NKCODE_F) {
492
AddDigit(10 + key.keyCode - NKCODE_A);
493
// NKCODE_DEL is backspace.
494
} else if (key.keyCode == NKCODE_DEL) {
495
BackspaceDigit();
496
} else if (key.keyCode == NKCODE_ENTER) {
497
TriggerFinish(DR_OK);
498
} else {
499
return UIDialogScreen::key(key);
500
}
501
} else {
502
return UIDialogScreen::key(key);
503
}
504
return true;
505
}
506
507