CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/UI/JitCompareScreen.cpp
Views: 1401
#include <algorithm>12#include "UI/JitCompareScreen.h"34#include "Core/MemMap.h"5#include "Core/MIPS/MIPSTables.h"6#include "Core/MIPS/JitCommon/JitBlockCache.h"7#include "Core/MIPS/JitCommon/JitCommon.h"8#include "Core/MIPS/JitCommon/JitState.h"910JitCompareScreen::JitCompareScreen() : UIDialogScreenWithBackground() {11JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();12// The only defaults that make sense.13if (blockCacheDebug->SupportsProfiling()) {14listSort_ = ListSort::TIME_SPENT;15} else {16listSort_ = ListSort::BLOCK_LENGTH_DESC;17}18FillBlockList();19}2021void JitCompareScreen::Flip() {22using namespace UI;23// If we add more, let's convert to a for loop.24switch (viewMode_) {25case ViewMode::DISASM:26comparisonView_->SetVisibility(V_VISIBLE);27blockListView_->SetVisibility(V_GONE);28statsView_->SetVisibility(V_GONE);29break;30case ViewMode::BLOCK_LIST:31comparisonView_->SetVisibility(V_GONE);32blockListView_->SetVisibility(V_VISIBLE);33statsView_->SetVisibility(V_GONE);34break;35case ViewMode::STATS:36comparisonView_->SetVisibility(V_GONE);37blockListView_->SetVisibility(V_GONE);38statsView_->SetVisibility(V_VISIBLE);39break;40}41}4243// Three panes: Block chooser, MIPS view, ARM/x86 view44void JitCompareScreen::CreateViews() {45auto di = GetI18NCategory(I18NCat::DIALOG);46auto dev = GetI18NCategory(I18NCat::DEVELOPER);4748using namespace UI;4950root_ = new LinearLayout(ORIENT_HORIZONTAL);5152ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(200, FILL_PARENT)));53LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));5455comparisonView_ = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));56comparisonView_->SetVisibility(V_VISIBLE);57LinearLayout *blockTopBar = comparisonView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));58blockTopBar->Add(new Button("", ImageID("I_ARROW_UP")))->OnClick.Add([this](UI::EventParams &e) {59viewMode_ = ViewMode::BLOCK_LIST;60Flip();61return UI::EVENT_DONE;62});63blockTopBar->Add(new Button("", ImageID("I_ARROW_LEFT")))->OnClick.Add([=](UI::EventParams &e) {64if (currentBlock_ >= 1)65currentBlock_--;66UpdateDisasm();67return UI::EVENT_DONE;68});69blockTopBar->Add(new Button("", ImageID("I_ARROW_RIGHT")))->OnClick.Add([=](UI::EventParams &e) {70if (currentBlock_ < blockList_.size() - 1)71currentBlock_++;72UpdateDisasm();73return UI::EVENT_DONE;74});75blockTopBar->Add(new Button(dev->T("Random")))->OnClick.Add([=](UI::EventParams &e) {76if (blockList_.empty()) {77return UI::EVENT_DONE;78}79currentBlock_ = rand() % blockList_.size();80UpdateDisasm();81return UI::EVENT_DONE;82});8384blockAddr_ = blockTopBar->Add(new TextEdit("", dev->T("Block address"), ""));85blockAddr_->OnEnter.Handle(this, &JitCompareScreen::OnAddressChange);86blockName_ = blockTopBar->Add(new TextView(dev->T("No block")));87blockStats_ = blockTopBar->Add(new TextView(""));8889LinearLayout *columns = comparisonView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f)));9091ScrollView *midColumnScroll = columns->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));92LinearLayout *midColumn = midColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));93midColumn->SetTag("JitCompareLeftDisasm");94leftDisasm_ = midColumn->Add(new LinearLayout(ORIENT_VERTICAL));95leftDisasm_->SetSpacing(0.0f);9697ScrollView *rightColumnScroll = columns->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));98rightColumnScroll->SetTag("JitCompareRightDisasm");99LinearLayout *rightColumn = rightColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));100rightDisasm_ = rightColumn->Add(new LinearLayout(ORIENT_VERTICAL));101rightDisasm_->SetSpacing(0.0f);102103blockListView_ = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));104blockListView_->SetVisibility(V_GONE);105106// Should match the ListSort enum107static ContextMenuItem sortMenu[] = {108{ "Block number", "I_ARROW_UP" },109{ "Block length", "I_ARROW_DOWN" },110{ "Block length", "I_ARROW_UP" },111{ "Time spent", "I_ARROW_DOWN" },112{ "Executions", "I_ARROW_DOWN" },113};114int sortCount = ARRAY_SIZE(sortMenu);115if (MIPSComp::jit) {116JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();117if (!blockCacheDebug->SupportsProfiling()) {118sortCount -= 2;119}120}121122LinearLayout *listTopBar = blockListView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));123Button *sortButton = new Button(dev->T("Sort..."));124listTopBar->Add(sortButton)->OnClick.Add([this, sortButton, sortCount](UI::EventParams &e) {125PopupContextMenuScreen *contextMenu = new UI::PopupContextMenuScreen(sortMenu, sortCount, I18NCat::DEVELOPER, sortButton);126screenManager()->push(contextMenu);127contextMenu->OnChoice.Add([=](EventParams &e) -> UI::EventReturn {128if (e.a < (int)ListSort::MAX) {129listSort_ = (ListSort)e.a;130UpdateDisasm();131}132return UI::EVENT_DONE;133});134return UI::EVENT_DONE;135});136137ScrollView *blockScroll = blockListView_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));138blockListContainer_ = blockScroll->Add(new LinearLayout(ORIENT_VERTICAL));139140statsView_ = root_->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));141statsView_->SetVisibility(V_GONE);142143LinearLayout *statsTopBar = statsView_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));144ScrollView *statsScroll = statsView_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));145statsContainer_ = statsScroll->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT)));146147// leftColumn->Add(new Choice(dev->T("By Address")))->OnClick.Handle(this, &JitCompareScreen::OnSelectBlock);148leftColumn->Add(new Choice(dev->T("All")))->OnClick.Add([=](UI::EventParams &e) {149listType_ = ListType::ALL_BLOCKS;150viewMode_ = ViewMode::BLOCK_LIST;151UpdateDisasm();152return UI::EVENT_DONE;153});154leftColumn->Add(new Choice(dev->T("FPU")))->OnClick.Add([=](UI::EventParams &e) {155listType_ = ListType::FPU_BLOCKS;156viewMode_ = ViewMode::BLOCK_LIST;157UpdateDisasm();158return UI::EVENT_DONE;159});160leftColumn->Add(new Choice(dev->T("VFPU")))->OnClick.Add([=](UI::EventParams &e) {161listType_ = ListType::VFPU_BLOCKS;162viewMode_ = ViewMode::BLOCK_LIST;163UpdateDisasm();164return UI::EVENT_DONE;165});166167leftColumn->Add(new Choice(dev->T("Stats")))->OnClick.Handle(this, &JitCompareScreen::OnShowStats);168leftColumn->Add(new Choice(di->T("Back")))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);169UpdateDisasm();170}171172void JitCompareScreen::FillBlockList() {173JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();174blockList_.clear();175int64_t sumTotalNanos = 0;176int64_t sumExecutions = 0;177bool profiling = blockCacheDebug->SupportsProfiling();178for (int i = 0; i < blockCacheDebug->GetNumBlocks(); i++) {179if (!blockCacheDebug->IsValidBlock(i)) {180continue;181}182183switch (listType_) {184case ListType::ALL_BLOCKS:185blockList_.push_back(i);186break;187case ListType::FPU_BLOCKS:188case ListType::VFPU_BLOCKS:189{190const uint64_t flags = listType_ == ListType::FPU_BLOCKS ? IS_FPU : IS_VFPU;191// const uint64_t antiFlags = IS_SYSCALL;192const uint64_t antiFlags = 0;193JitBlockMeta meta = blockCacheDebug->GetBlockMeta(i);194if (meta.valid) {195for (u32 addr = meta.addr; addr < meta.addr + meta.sizeInBytes; addr += 4) {196MIPSOpcode opcode = Memory::Read_Instruction(addr);197MIPSInfo info = MIPSGetInfo(opcode);198if ((info & flags) && !(info & antiFlags)) {199blockList_.push_back(i);200break;201}202}203}204}205default:206break;207}208209if (profiling) {210JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(i);211sumTotalNanos += stats.totalNanos;212sumExecutions += stats.executions;213}214}215216sumTotalNanos_ = sumTotalNanos;217sumExecutions_ = sumExecutions;218219if (listSort_ == ListSort::BLOCK_NUM) {220// Already sorted, effectively.221return;222}223224std::sort(blockList_.begin(), blockList_.end(), [=](const int &a_index, const int &b_index) {225// First, check metadata sorts.226switch (listSort_) {227case ListSort::BLOCK_LENGTH_DESC:228{229JitBlockMeta a_meta = blockCacheDebug->GetBlockMeta(a_index);230JitBlockMeta b_meta = blockCacheDebug->GetBlockMeta(b_index);231return a_meta.sizeInBytes > b_meta.sizeInBytes; // reverse for descending232}233case ListSort::BLOCK_LENGTH_ASC:234{235JitBlockMeta a_meta = blockCacheDebug->GetBlockMeta(a_index);236JitBlockMeta b_meta = blockCacheDebug->GetBlockMeta(b_index);237return a_meta.sizeInBytes < b_meta.sizeInBytes;238}239default:240break;241}242JitBlockProfileStats a_stats = blockCacheDebug->GetBlockProfileStats(a_index);243JitBlockProfileStats b_stats = blockCacheDebug->GetBlockProfileStats(b_index);244switch (listSort_) {245case ListSort::EXECUTIONS:246return a_stats.executions > b_stats.executions;247case ListSort::TIME_SPENT:248return a_stats.totalNanos > b_stats.totalNanos;249default:250return false;251}252});253}254255void JitCompareScreen::UpdateDisasm() {256leftDisasm_->Clear();257rightDisasm_->Clear();258259using namespace UI;260261if (!MIPSComp::jit) {262return;263}264265JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();266if (viewMode_ == ViewMode::DISASM && (currentBlock_ < 0 || currentBlock_ >= (int)blockList_.size())) {267viewMode_ = ViewMode::BLOCK_LIST;268}269270FillBlockList();271Flip();272273if (viewMode_ == ViewMode::DISASM) {274char temp[256];275snprintf(temp, sizeof(temp), "%d/%d", currentBlock_, (int)blockList_.size());276blockName_->SetText(temp);277278int blockNum = blockList_[currentBlock_];279280if (!blockCacheDebug->IsValidBlock(blockNum)) {281auto dev = GetI18NCategory(I18NCat::DEVELOPER);282leftDisasm_->Add(new TextView(dev->T("No block")));283rightDisasm_->Add(new TextView(dev->T("No block")));284blockStats_->SetText("");285return;286}287288JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(blockNum);289snprintf(temp, sizeof(temp), "%08x", debugInfo.originalAddress);290blockAddr_->SetText(temp);291292// Alright. First generate the MIPS disassembly.293294// TODO: Need a way to communicate branch continuing.295for (const auto &line : debugInfo.origDisasm) {296leftDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);297}298299// TODO : When we have both target and IR, need a third column.300if (debugInfo.targetDisasm.size()) {301for (const auto &line : debugInfo.targetDisasm) {302rightDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);303}304} else {305for (const auto &line : debugInfo.irDisasm) {306rightDisasm_->Add(new TextView(line, FLAG_DYNAMIC_ASCII, false))->SetFocusable(true);307}308}309310int numMips = leftDisasm_->GetNumSubviews();311int numHost = rightDisasm_->GetNumSubviews();312double bloat = 100.0 * numHost / numMips;313if (blockCacheDebug->SupportsProfiling()) {314JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(blockNum);315int execs = (int)stats.executions;316double us = (double)stats.totalNanos / 1000000.0;317double percentage = 100.0 * (double)stats.totalNanos / (double)sumTotalNanos_;318snprintf(temp, sizeof(temp), "%d runs, %0.2f ms, %0.2f%%, bloat: %0.1f%%", execs, us, percentage, bloat);319} else {320snprintf(temp, sizeof(temp), "bloat: %0.1f%%", bloat);321}322blockStats_->SetText(temp);323} else if (viewMode_ == ViewMode::BLOCK_LIST) {324blockListContainer_->Clear();325bool profiling = blockCacheDebug->SupportsProfiling();326for (int i = 0; i < std::min(100, (int)blockList_.size()); i++) {327int blockNum = blockList_[i];328JitBlockMeta meta = blockCacheDebug->GetBlockMeta(blockNum);329char temp[512], small[512];330if (profiling) {331JitBlockProfileStats stats = blockCacheDebug->GetBlockProfileStats(blockNum);332int execs = (int)stats.executions;333double us = (double)stats.totalNanos / 1000000.0;334double percentage = 100.0 * (double)stats.totalNanos / (double)sumTotalNanos_;335snprintf(temp, sizeof(temp), "%08x: %d instrs (%d runs, %0.2f ms, %0.2f%%)", meta.addr, meta.sizeInBytes / 4, execs, us, percentage);336} else {337snprintf(temp, sizeof(temp), "%08x: %d instrs", meta.addr, meta.sizeInBytes / 4);338}339snprintf(small, sizeof(small), "Small text");340Choice *blockChoice = blockListContainer_->Add(new Choice(temp, small));341blockChoice->OnClick.Handle(this, &JitCompareScreen::OnBlockClick);342}343} else { // viewMode_ == ViewMode::STATS344statsContainer_->Clear();345346BlockCacheStats bcStats;347blockCacheDebug->ComputeStats(bcStats);348349char stats[1024];350snprintf(stats, sizeof(stats),351"Num blocks: %d\n"352"Average Bloat: %0.2f%%\n"353"Min Bloat: %0.2f%% (%08x)\n"354"Max Bloat: %0.2f%% (%08x)\n",355blockCacheDebug->GetNumBlocks(),356100.0 * bcStats.avgBloat,357100.0 * bcStats.minBloat, bcStats.minBloatBlock,358100.0 * bcStats.maxBloat, bcStats.maxBloatBlock);359360statsContainer_->Add(new TextView(stats));361}362}363364UI::EventReturn JitCompareScreen::OnBlockClick(UI::EventParams &e) {365int blockIndex = blockListContainer_->IndexOfSubview(e.v);366if (blockIndex >= 0) {367viewMode_ = ViewMode::DISASM;368currentBlock_ = blockIndex;369UpdateDisasm();370}371return UI::EVENT_DONE;372}373374UI::EventReturn JitCompareScreen::OnAddressChange(UI::EventParams &e) {375std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);376if (!MIPSComp::jit) {377return UI::EVENT_DONE;378}379JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();380if (!blockCache)381return UI::EVENT_DONE;382u32 addr;383if (blockAddr_->GetText().size() > 8)384return UI::EVENT_DONE;385if (1 == sscanf(blockAddr_->GetText().c_str(), "%08x", &addr)) {386if (Memory::IsValidAddress(addr)) {387currentBlock_ = blockCache->GetBlockNumberFromStartAddress(addr);388UpdateDisasm();389}390}391return UI::EVENT_DONE;392}393394UI::EventReturn JitCompareScreen::OnShowStats(UI::EventParams &e) {395std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);396if (!MIPSComp::jit) {397return UI::EVENT_DONE;398}399400viewMode_ = ViewMode::STATS;401UpdateDisasm();402return UI::EVENT_DONE;403}404405406UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) {407auto dev = GetI18NCategory(I18NCat::DEVELOPER);408409auto addressPrompt = new AddressPromptScreen(dev->T("Block address"));410addressPrompt->OnChoice.Handle(this, &JitCompareScreen::OnBlockAddress);411screenManager()->push(addressPrompt);412return UI::EVENT_DONE;413}414415UI::EventReturn JitCompareScreen::OnBlockAddress(UI::EventParams &e) {416std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);417if (!MIPSComp::jit) {418return UI::EVENT_DONE;419}420421JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();422if (!blockCache)423return UI::EVENT_DONE;424425if (Memory::IsValidAddress(e.a)) {426currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a);427} else {428currentBlock_ = -1;429}430UpdateDisasm();431return UI::EVENT_DONE;432}433434/*435void JitCompareScreen::OnRandomBlock(int flag) {436std::lock_guard<std::recursive_mutex> guard(MIPSComp::jitLock);437if (!MIPSComp::jit) {438return;439}440JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();441if (!blockCache)442return;443444int numBlocks = blockCache->GetNumBlocks();445if (numBlocks > 0) {446bool anyWanted = false;447int tries = 0;448while (!anyWanted && tries < numBlocks) {449currentBlock_ = rand() % numBlocks;450if (blockCache->IsValidBlock(currentBlock_)) {451JitBlockDebugInfo b = blockCache->GetBlockDebugInfo(currentBlock_);452u32 mipsBytes = (u32)b.origDisasm.size() * 4;453for (u32 addr = b.originalAddress; addr < b.originalAddress + mipsBytes; addr += 4) {454MIPSOpcode opcode = Memory::Read_Instruction(addr);455if (MIPSGetInfo(opcode) & flag) {456char temp[256];457MIPSDisAsm(opcode, addr, temp, sizeof(temp));458// INFO_LOG(Log::HLE, "Stopping at random instruction: %08x %s", addr, temp);459anyWanted = true;460break;461}462}463}464tries++;465}466467if (!anyWanted)468currentBlock_ = -1;469}470UpdateDisasm();471}*/472473void AddressPromptScreen::CreatePopupContents(UI::ViewGroup *parent) {474using namespace UI;475476auto dev = GetI18NCategory(I18NCat::DEVELOPER);477478addrView_ = new TextView(dev->T("Enter address"), ALIGN_HCENTER, false);479parent->Add(addrView_);480481ViewGroup *grid = new GridLayout(GridLayoutSettings(60, 40));482parent->Add(grid);483484for (int i = 0; i < 16; ++i) {485char temp[16];486snprintf(temp, 16, " %X ", i);487buttons_[i] = new Button(temp);488grid->Add(buttons_[i])->OnClick.Handle(this, &AddressPromptScreen::OnDigitButton);489}490491parent->Add(new Button(dev->T("Backspace")))->OnClick.Handle(this, &AddressPromptScreen::OnBackspace);492}493494void AddressPromptScreen::OnCompleted(DialogResult result) {495if (result == DR_OK) {496UI::EventParams e{};497e.v = root_;498e.a = addr_;499OnChoice.Trigger(e);500}501}502503UI::EventReturn AddressPromptScreen::OnDigitButton(UI::EventParams &e) {504for (int i = 0; i < 16; ++i) {505if (buttons_[i] == e.v) {506AddDigit(i);507}508}509return UI::EVENT_DONE;510}511512UI::EventReturn AddressPromptScreen::OnBackspace(UI::EventParams &e) {513BackspaceDigit();514return UI::EVENT_DONE;515}516517void AddressPromptScreen::AddDigit(int n) {518if ((addr_ & 0xF0000000) == 0) {519addr_ = addr_ * 16 + n;520}521UpdatePreviewDigits();522}523524void AddressPromptScreen::BackspaceDigit() {525addr_ /= 16;526UpdatePreviewDigits();527}528529void AddressPromptScreen::UpdatePreviewDigits() {530if (addr_ != 0) {531char temp[32];532snprintf(temp, 32, "%8X", addr_);533addrView_->SetText(temp);534} else {535auto dev = GetI18NCategory(I18NCat::DEVELOPER);536addrView_->SetText(dev->T("Enter address"));537}538}539540bool AddressPromptScreen::key(const KeyInput &key) {541if (key.flags & KEY_DOWN) {542if (key.keyCode >= NKCODE_0 && key.keyCode <= NKCODE_9) {543AddDigit(key.keyCode - NKCODE_0);544} else if (key.keyCode >= NKCODE_A && key.keyCode <= NKCODE_F) {545AddDigit(10 + key.keyCode - NKCODE_A);546// NKCODE_DEL is backspace.547} else if (key.keyCode == NKCODE_DEL) {548BackspaceDigit();549} else if (key.keyCode == NKCODE_ENTER) {550TriggerFinish(DR_OK);551} else {552return UIDialogScreen::key(key);553}554} else {555return UIDialogScreen::key(key);556}557return true;558}559560561