Rework the JitCompare window to hold a list of blocks, and allow some filtering and browsing

This commit is contained in:
Henrik Rydgård committed 2024-06-05 18:16:33 +02:00
1 parent c538ce8bf0
commit 3bb74ea9ad
9 files changed
+258 -123

No files matched your search

+1 -1
View File
@@ -462,7 +462,7 @@ public:
Visibility GetVisibility() const { return visibility_; }
const std::string &Tag() const { return tag_; }
void SetTag(const std::string &str) { tag_ = str; }
void SetTag(std::string_view str) { tag_ = str; }
// Fake RTTI
virtual bool IsViewGroup() const { return false; }
+10
View File
@@ -67,6 +67,16 @@ bool ViewGroup::ContainsSubview(const View *view) const {
return false;
}
int ViewGroup::IndexOfSubview(const View *view) const {
int index = 0;
for (const View *subview : views_) {
if (subview == view)
return index;
index++;
}
return -1;
}
void ViewGroup::Clear() {
for (View *view : views_) {
delete view;
+1
View File
@@ -65,6 +65,7 @@ public:
bool CanBeFocused() const override { return false; }
bool IsViewGroup() const override { return true; }
bool ContainsSubview(const View *view) const override;
int IndexOfSubview(const View *view) const;
virtual void SetBG(const Drawable &bg) { bg_ = bg; }
+8
View File
@@ -155,6 +155,14 @@ public:
void RestoreSavedEmuHackOps(const std::vector<u32> &saved);
JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override;
JitBlockMeta GetBlockMeta(int blockNum) const override {
JitBlockMeta meta{};
if (IsValidBlock(blockNum)) {
meta.valid = true;
blocks_[blockNum].GetRange(meta.addr, meta.sizeInBytes);
}
return meta;
}
void ComputeStats(BlockCacheStats &bcStats) const override;
int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override;
+4
View File
@@ -718,6 +718,10 @@ bool IRNativeBlockCacheDebugInterface::IsValidBlock(int blockNum) const {
return irBlocks_.IsValidBlock(blockNum);
}
JitBlockMeta IRNativeBlockCacheDebugInterface::GetBlockMeta(int blockNum) const {
return irBlocks_.GetBlockMeta(blockNum);
}
int IRNativeBlockCacheDebugInterface::GetNumBlocks() const {
return irBlocks_.GetNumBlocks();
}
+1
View File
@@ -165,6 +165,7 @@ public:
int GetNumBlocks() const override;
int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const override;
JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const override;
JitBlockMeta GetBlockMeta(int blockNum) const override;
void ComputeStats(BlockCacheStats &bcStats) const override;
bool IsValidBlock(int blockNum) const override;
+17 -1
View File
@@ -103,6 +103,12 @@ struct JitBlockDebugInfo {
std::vector<std::string> targetDisasm;
};
struct JitBlockMeta {
bool valid;
uint32_t addr;
uint32_t sizeInBytes;
};
struct JitBlockProfileStats {
int64_t executions;
int64_t totalNanos;
@@ -113,6 +119,7 @@ public:
virtual int GetNumBlocks() const = 0;
virtual int GetBlockNumberFromStartAddress(u32 em_address, bool realBlocksOnly = true) const = 0;
virtual JitBlockDebugInfo GetBlockDebugInfo(int blockNum) const = 0; // Expensive
virtual JitBlockMeta GetBlockMeta(int blockNum) const = 0;
virtual JitBlockProfileStats GetBlockProfileStats(int blockNum) const { // Cheap
return JitBlockProfileStats{};
}
@@ -174,7 +181,16 @@ public:
void RestoreSavedEmuHackOps(const std::vector<u32> &saved);
int GetNumBlocks() const override { return num_blocks_; }
bool IsValidBlock(int blockNum) const override { return blockNum < num_blocks_ && !blocks_[blockNum].invalid; }
bool IsValidBlock(int blockNum) const override { return blockNum >= 0 && blockNum < num_blocks_ && !blocks_[blockNum].invalid; }
JitBlockMeta GetBlockMeta(int blockNum) const override {
JitBlockMeta meta{};
if (IsValidBlock(blockNum)) {
meta.valid = true;
meta.addr = blocks_[blockNum].originalAddress;
meta.sizeInBytes = blocks_[blockNum].originalSize;
}
return meta;
}
static int GetBlockExitSize();
+190 -112
View File
@@ -1,3 +1,5 @@
#include <algorithm>
#include "UI/JitCompareScreen.h"
#include "Core/MemMap.h"
@@ -6,6 +8,24 @@
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/MIPS/JitCommon/JitState.h"
JitCompareScreen::JitCompareScreen() : UIDialogScreenWithBackground() {
FillBlockList();
}
void JitCompareScreen::Flip() {
using namespace UI;
switch (viewMode_) {
case ViewMode::DISASM:
comparisonView_->SetVisibility(V_VISIBLE);
blockListView_->SetVisibility(V_GONE);
break;
case ViewMode::BLOCK_LIST:
comparisonView_->SetVisibility(V_GONE);
blockListView_->SetVisibility(V_VISIBLE);
break;
}
}
// Three panes: Block chooser, MIPS view, ARM/x86 view
void JitCompareScreen::CreateViews() {
auto di = GetI18NCategory(I18NCat::DIALOG);
@@ -18,39 +38,130 @@ void JitCompareScreen::CreateViews() {
ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(200, FILL_PARENT)));
LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
LinearLayout *mainView = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
LinearLayout *topBar = mainView->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
topBar->Add(new Button(dev->T("Prev")))->OnClick.Handle(this, &JitCompareScreen::OnPrevBlock);
topBar->Add(new Button(dev->T("Next")))->OnClick.Handle(this, &JitCompareScreen::OnNextBlock);
blockAddr_ = topBar->Add(new TextEdit("", dev->T("Block address"), ""));
comparisonView_ = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
LinearLayout *blockTopBar = comparisonView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));
blockTopBar->Add(new Button(dev->T("Back to list")))->OnClick.Add([this](UI::EventParams &e) {
viewMode_ = ViewMode::BLOCK_LIST;
Flip();
return UI::EVENT_DONE;
});
blockTopBar->Add(new Button(dev->T("Prev")))->OnClick.Add([=](UI::EventParams &e) {
currentBlock_--;
UpdateDisasm();
return UI::EVENT_DONE;
});
blockTopBar->Add(new Button(dev->T("Next")))->OnClick.Add([=](UI::EventParams &e) {
currentBlock_++;
UpdateDisasm();
return UI::EVENT_DONE;
});
blockTopBar->Add(new Button(dev->T("Random")))->OnClick.Add([=](UI::EventParams &e) {
if (blockList_.empty()) {
return UI::EVENT_DONE;
}
currentBlock_ = rand() % blockList_.size();
UpdateDisasm();
return UI::EVENT_DONE;
});
blockAddr_ = blockTopBar->Add(new TextEdit("", dev->T("Block address"), ""));
blockAddr_->OnEnter.Handle(this, &JitCompareScreen::OnAddressChange);
blockName_ = topBar->Add(new TextView(dev->T("No block")));
blockStats_ = topBar->Add(new TextView(""));
blockName_ = blockTopBar->Add(new TextView(dev->T("No block")));
blockStats_ = blockTopBar->Add(new TextView(""));
LinearLayout *comparisonView = mainView->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f)));
LinearLayout *columns = comparisonView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f)));
ScrollView *midColumnScroll = comparisonView->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
ScrollView *midColumnScroll = columns->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
LinearLayout *midColumn = midColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
midColumn->SetTag("JitCompareLeftDisasm");
leftDisasm_ = midColumn->Add(new LinearLayout(ORIENT_VERTICAL));
leftDisasm_->SetSpacing(0.0f);
ScrollView *rightColumnScroll = comparisonView->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
ScrollView *rightColumnScroll = columns->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
rightColumnScroll->SetTag("JitCompareRightDisasm");
LinearLayout *rightColumn = rightColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
rightDisasm_ = rightColumn->Add(new LinearLayout(ORIENT_VERTICAL));
rightDisasm_->SetSpacing(0.0f);
leftColumn->Add(new Choice(dev->T("Current")))->OnClick.Handle(this, &JitCompareScreen::OnCurrentBlock);
leftColumn->Add(new Choice(dev->T("By Address")))->OnClick.Handle(this, &JitCompareScreen::OnSelectBlock);
leftColumn->Add(new Choice(dev->T("Random")))->OnClick.Handle(this, &JitCompareScreen::OnRandomBlock);
leftColumn->Add(new Choice(dev->T("FPU")))->OnClick.Handle(this, &JitCompareScreen::OnRandomFPUBlock);
leftColumn->Add(new Choice(dev->T("VFPU")))->OnClick.Handle(this, &JitCompareScreen::OnRandomVFPUBlock);
blockListView_ = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
blockListView_->SetVisibility(V_GONE);
blockListContainer_ = blockListView_->Add(new LinearLayout(ORIENT_VERTICAL));
// leftColumn->Add(new Choice(dev->T("By Address")))->OnClick.Handle(this, &JitCompareScreen::OnSelectBlock);
leftColumn->Add(new Choice(dev->T("All")))->OnClick.Add([=](UI::EventParams &e) {
listType_ = ListType::ALL_BLOCKS;
viewMode_ = ViewMode::BLOCK_LIST;
UpdateDisasm();
return UI::EVENT_DONE;
});
leftColumn->Add(new Choice(dev->T("FPU")))->OnClick.Add([=](UI::EventParams &e) {
listType_ = ListType::FPU_BLOCKS;
viewMode_ = ViewMode::BLOCK_LIST;
UpdateDisasm();
return UI::EVENT_DONE;
});
leftColumn->Add(new Choice(dev->T("VFPU")))->OnClick.Add([=](UI::EventParams &e) {
listType_ = ListType::VFPU_BLOCKS;
viewMode_ = ViewMode::BLOCK_LIST;
UpdateDisasm();
return UI::EVENT_DONE;
});
leftColumn->Add(new Choice(dev->T("Stats")))->OnClick.Handle(this, &JitCompareScreen::OnShowStats);
leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
UpdateDisasm();
}
EventParams ignore{};
OnCurrentBlock(ignore);
void JitCompareScreen::FillBlockList() {
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
blockList_.clear();
for (int i = 0; i < blockCacheDebug->GetNumBlocks(); i++) {
if (!blockCacheDebug->IsValidBlock(i)) {
continue;
}
switch (listType_) {
case ListType::ALL_BLOCKS:
blockList_.push_back(i);
break;
case ListType::FPU_BLOCKS:
case ListType::VFPU_BLOCKS:
{
const int flags = listType_ == ListType::FPU_BLOCKS ? IS_FPU : IS_VFPU;
JitBlockMeta meta = blockCacheDebug->GetBlockMeta(i);
if (meta.valid) {
for (u32 addr = meta.addr; addr < meta.addr + meta.sizeInBytes; addr += 4) {
MIPSOpcode opcode = Memory::Read_Instruction(addr);
if (MIPSGetInfo(opcode) & flags) {
blockList_.push_back(i);
break;
}
}
}
}
default:
break;
}
}
if (listSort_ == ListSort::BLOCK_NUM) {
// Already sorted, effectively.
return;
}
if (listSort_ != ListSort::BLOCK_LENGTH_DESC) {
return;
}
std::sort(blockList_.begin(), blockList_.end(), [=](const int &a_index, const int &b_index) {
JitBlockMeta a_meta = blockCacheDebug->GetBlockMeta(a_index);
JitBlockMeta b_meta = blockCacheDebug->GetBlockMeta(b_index);
switch (listSort_) {
case ListSort::BLOCK_LENGTH_DESC:
return a_meta.sizeInBytes > b_meta.sizeInBytes; // reverse for descending
default:
return false;
}
});
}
void JitCompareScreen::UpdateDisasm() {
@@ -64,50 +175,76 @@ void JitCompareScreen::UpdateDisasm() {
}
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
if (!blockCacheDebug->IsValidBlock(currentBlock_)) {
return;
if (viewMode_ == ViewMode::DISASM && (currentBlock_ < 0 || currentBlock_ >= (int)blockList_.size())) {
viewMode_ = ViewMode::BLOCK_LIST;
}
char temp[256];
snprintf(temp, sizeof(temp), "%d/%d", currentBlock_, blockCacheDebug->GetNumBlocks());
blockName_->SetText(temp);
FillBlockList();
Flip();
if (currentBlock_ < 0 || !blockCacheDebug || currentBlock_ >= blockCacheDebug->GetNumBlocks()) {
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
leftDisasm_->Add(new TextView(dev->T("No block")));
rightDisasm_->Add(new TextView(dev->T("No block")));
blockStats_->SetText("");
return;
}
if (viewMode_ == ViewMode::DISASM) {
char temp[256];
snprintf(temp, sizeof(temp), "%d/%d", currentBlock_, (int)blockList_.size());
blockName_->SetText(temp);
JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(currentBlock_);
int blockNum = blockList_[currentBlock_];
snprintf(temp, sizeof(temp), "%08x", debugInfo.originalAddress);
blockAddr_->SetText(temp);
// Alright. First generate the MIPS disassembly.
// TODO: Need a way to communicate branch continuing.
for (const auto &line : debugInfo.origDisasm) {
leftDisasm_->Add(new TextView(line))->SetFocusable(true);
}
// TODO : When we have both target and IR, need a third column.
if (debugInfo.targetDisasm.size()) {
for (const auto &line : debugInfo.targetDisasm) {
rightDisasm_->Add(new TextView(line))->SetFocusable(true);
if (!blockCacheDebug->IsValidBlock(blockNum)) {
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
leftDisasm_->Add(new TextView(dev->T("No block")));
rightDisasm_->Add(new TextView(dev->T("No block")));
blockStats_->SetText("");
return;
}
JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(blockNum);
snprintf(temp, sizeof(temp), "%08x", debugInfo.originalAddress);
blockAddr_->SetText(temp);
// Alright. First generate the MIPS disassembly.
// TODO: Need a way to communicate branch continuing.
for (const auto &line : debugInfo.origDisasm) {
leftDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);
}
// TODO : When we have both target and IR, need a third column.
if (debugInfo.targetDisasm.size()) {
for (const auto &line : debugInfo.targetDisasm) {
rightDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);
}
} else {
for (const auto &line : debugInfo.irDisasm) {
rightDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);
}
}
int numMips = leftDisasm_->GetNumSubviews();
int numHost = rightDisasm_->GetNumSubviews();
snprintf(temp, sizeof(temp), "%d to %d : %d%%", numMips, numHost, 100 * numHost / numMips);
blockStats_->SetText(temp);
} else {
for (const auto &line : debugInfo.irDisasm) {
rightDisasm_->Add(new TextView(line))->SetFocusable(true);
blockListContainer_->Clear();
for (int i = 0; i < std::min(100, (int)blockList_.size()); i++) {
JitBlockMeta meta = blockCacheDebug->GetBlockMeta(blockList_[i]);
char temp[512], small[512];
snprintf(temp, sizeof(temp), "%08x: %d instrs", meta.addr, meta.sizeInBytes / 4);
snprintf(small, sizeof(small), "Small text");
Choice *blockChoice = blockListContainer_->Add(new Choice(temp, small));
blockChoice->OnClick.Handle(this, &JitCompareScreen::OnBlockClick);
}
}
}
int numMips = leftDisasm_->GetNumSubviews();
int numHost = rightDisasm_->GetNumSubviews();
snprintf(temp, sizeof(temp), "%d to %d : %d%%", numMips, numHost, 100 * numHost / numMips);
blockStats_->SetText(temp);
UI::EventReturn JitCompareScreen::OnBlockClick(UI::EventParams &e) {
int blockIndex = blockListContainer_->IndexOfSubview(e.v);
if (blockIndex >= 0) {
viewMode_ = ViewMode::DISASM;
currentBlock_ = blockIndex;
UpdateDisasm();
}
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnAddressChange(UI::EventParams &e) {
@@ -169,18 +306,6 @@ UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) {
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnPrevBlock(UI::EventParams &e) {
currentBlock_--;
UpdateDisasm();
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnNextBlock(UI::EventParams &e) {
currentBlock_++;
UpdateDisasm();
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) {
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
if (!MIPSComp::jit) {
@@ -200,40 +325,7 @@ UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) {
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnRandomBlock(UI::EventParams &e) {
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
if (!MIPSComp::jit) {
return UI::EVENT_DONE;
}
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
if (!blockCache)
return UI::EVENT_DONE;
int numBlocks = blockCache->GetNumBlocks();
if (numBlocks > 0) {
int tries = 100;
while (tries-- > 0) {
currentBlock_ = rand() % numBlocks;
if (blockCache->IsValidBlock(currentBlock_)) {
break;
}
}
}
UpdateDisasm();
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnRandomVFPUBlock(UI::EventParams &e) {
OnRandomBlock(IS_VFPU);
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnRandomFPUBlock(UI::EventParams &e) {
OnRandomBlock(IS_FPU);
return UI::EVENT_DONE;
}
/*
void JitCompareScreen::OnRandomBlock(int flag) {
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
if (!MIPSComp::jit) {
@@ -270,21 +362,7 @@ void JitCompareScreen::OnRandomBlock(int flag) {
currentBlock_ = -1;
}
UpdateDisasm();
}
UI::EventReturn JitCompareScreen::OnCurrentBlock(UI::EventParams &e) {
std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);
if (!MIPSComp::jit) {
return UI::EVENT_DONE;
}
JitBlockCache *blockCache = MIPSComp::jit->GetBlockCache();
if (!blockCache)
return UI::EVENT_DONE;
currentBlock_ = blockCache->GetBlockNumberFromAddress(currentMIPS->pc);
UpdateDisasm();
return UI::EVENT_DONE;
}
}*/
void AddressPromptScreen::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
+26 -9
View File
@@ -4,31 +4,48 @@
class JitCompareScreen : public UIDialogScreenWithBackground {
public:
JitCompareScreen();
void CreateViews() override;
const char *tag() const override { return "JitCompare"; }
private:
void Flip();
void UpdateDisasm();
UI::EventReturn OnRandomBlock(UI::EventParams &e);
UI::EventReturn OnRandomFPUBlock(UI::EventParams &e);
UI::EventReturn OnRandomVFPUBlock(UI::EventParams &e);
void OnRandomBlock(int flag);
UI::EventReturn OnCurrentBlock(UI::EventParams &e);
// Uses the current ListType
void FillBlockList();
UI::LinearLayout *comparisonView_;
UI::ScrollView *blockListView_;
UI::LinearLayout *blockListContainer_;
UI::EventReturn OnSelectBlock(UI::EventParams &e);
UI::EventReturn OnPrevBlock(UI::EventParams &e);
UI::EventReturn OnNextBlock(UI::EventParams &e);
UI::EventReturn OnBlockAddress(UI::EventParams &e);
UI::EventReturn OnAddressChange(UI::EventParams &e);
UI::EventReturn OnShowStats(UI::EventParams &e);
UI::EventReturn OnBlockClick(UI::EventParams &e);
// To switch, change the below things and call RecreateViews();
enum ViewMode {
enum class ViewMode {
BLOCK_LIST,
DISASM,
};
ViewMode viewMode_ = DISASM;
enum class ListType {
ALL_BLOCKS,
FPU_BLOCKS,
VFPU_BLOCKS,
};
enum class ListSort {
BLOCK_NUM,
BLOCK_LENGTH_DESC,
TIME_SPENT,
EXECUTIONS,
};
ViewMode viewMode_ = ViewMode::BLOCK_LIST;
ListType listType_ = ListType::ALL_BLOCKS;
ListSort listSort_ = ListSort::BLOCK_LENGTH_DESC;
int currentBlock_ = -1; // For DISASM mode
std::vector<int> blockList_; // for BLOCK_LIST mode