Merge pull request #19252 from hrydgard/jitir-profiling-prep

Preparations for adding a performance profiler for the IR Interpreter
This commit is contained in:
Henrik Rydgård
2024-06-05 13:02:28 +02:00
committed by GitHub
16 changed files with 552 additions and 440 deletions
+2
View File
@@ -1554,6 +1554,8 @@ list(APPEND NativeAppSource
UI/CwCheatScreen.cpp
UI/InstallZipScreen.h
UI/InstallZipScreen.cpp
UI/JitCompareScreen.h
UI/JitCompareScreen.cpp
UI/MemStickScreen.h
UI/MemStickScreen.cpp
UI/ProfilerDraw.h
+1 -1
View File
@@ -234,7 +234,7 @@ void LogManager::Log(LogLevel level, LogType type, const char *file, int line, c
file = fileshort + 1;
}
GetTimeFormatted(message.timestamp);
GetCurrentTimeFormatted(message.timestamp);
if (hleCurrentThreadName) {
snprintf(message.header, sizeof(message.header), "%-12.12s %c[%s]: %s:%d",
+14 -7
View File
@@ -33,7 +33,9 @@ public:
Destroy();
}
if (factory == nullptr) return;
if (!factory) {
return;
}
HRESULT hr = factory->CreateTextFormat(
fname.c_str(),
@@ -45,15 +47,20 @@ public:
L"",
&textFmt
);
if (FAILED(hr)) {
ERROR_LOG(G3D, "Failed creating font %s", fname.c_str());
}
}
void Destroy() {
textFmt->Release();
if (textFmt) {
textFmt->Release();
}
textFmt = nullptr;
}
IDWriteFactory4* factory = nullptr;
IDWriteFontCollection1* fontCollection = nullptr;
IDWriteTextFormat* textFmt = nullptr;
IDWriteFactory4 *factory = nullptr;
IDWriteFontCollection1 *fontCollection = nullptr;
IDWriteTextFormat *textFmt = nullptr;
std::wstring fname;
int height;
DWRITE_FONT_WEIGHT weight;
@@ -61,8 +68,8 @@ public:
};
struct TextDrawerContext {
ID2D1Bitmap1* bitmap;
ID2D1Bitmap1* mirror_bmp;
ID2D1Bitmap1 *bitmap;
ID2D1Bitmap1 *mirror_bmp;
};
TextDrawerUWP::TextDrawerUWP(Draw::DrawContext *draw) : TextDrawer(draw), ctx_(nullptr) {
+74 -6
View File
@@ -4,6 +4,7 @@
#include <cstdint>
#include "Common/TimeUtil.h"
#include "Common/Log.h"
#ifdef HAVE_LIBNX
#include <switch.h>
@@ -31,8 +32,8 @@
// TODO: https://github.com/floooh/sokol/blob/9a6237fcdf213e6da48e4f9201f144bcb2dcb46f/sokol_time.h#L229-L248
static const double micros = 1000000.0;
static const double nanos = 1000000000.0;
constexpr double micros = 1000000.0;
constexpr double nanos = 1000000000.0;
#if PPSSPP_PLATFORM(WINDOWS)
@@ -40,12 +41,16 @@ static LARGE_INTEGER frequency;
static double frequencyMult;
static LARGE_INTEGER startTime;
double time_now_d() {
static inline void InitTime() {
if (frequency.QuadPart == 0) {
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&startTime);
frequencyMult = 1.0 / static_cast<double>(frequency.QuadPart);
}
}
double time_now_d() {
InitTime();
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
double elapsed = static_cast<double>(time.QuadPart - startTime.QuadPart);
@@ -86,6 +91,22 @@ void yield() {
YieldProcessor();
}
TimeSpan::TimeSpan() {
_dbg_assert_(frequencyMult != 0.0);
QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&nativeStart_));
}
double TimeSpan::ElapsedSeconds() const {
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
double elapsed = static_cast<double>(time.QuadPart - nativeStart_);
return elapsed * frequencyMult;
}
int64_t TimeSpan::ElapsedNanos() const {
return (int64_t)(ElapsedSeconds() * 1000000000.0);
}
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS)
// The only intended use is to match the timings in VK_GOOGLE_display_timing
@@ -128,10 +149,34 @@ void yield() {
#endif
}
TimeSpan::TimeSpan() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
nativeStart_ = ts.tv_sec;
nsecs_ = ts.tv_nsec;
}
int64_t TimeSpan::ElapsedNanos() const {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
int64_t secs = ts.tv_sec - nativeStart_;
int64_t nsecs = ts.tv_nsec - nsecs_;
if (nsecs < 0) {
secs--;
nsecs += 1000000000;
}
return secs * 1000000000ULL + nsecs;
}
double TimeSpan::ElapsedSeconds() const {
return (double)ElapsedNanos() * (1.0 / nanos);
}
#else
static time_t start;
double time_now_d() {
static time_t start;
struct timeval tv;
gettimeofday(&tv, nullptr);
if (start == 0) {
@@ -141,7 +186,6 @@ double time_now_d() {
}
uint64_t time_now_raw() {
static time_t start;
struct timeval tv;
gettimeofday(&tv, nullptr);
if (start == 0) {
@@ -164,6 +208,30 @@ double time_now_unix_utc() {
return time_now_raw();
}
TimeSpan::TimeSpan() {
struct timeval tv;
gettimeofday(&tv, nullptr);
nativeStart_ = tv.tv_sec;
nsecs_ = tv.tv_usec;
}
int64_t TimeSpan::ElapsedNanos() const {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
int64_t secs = ts.tv_sec - nativeStart_;
int64_t usecs = ts.tv_nsec - nsecs_;
if (usecs < 0) {
secs--;
usecs += 1000000;
}
return secs * 1000000000 + usecs * 1000;
}
double TimeSpan::ElapsedSeconds() const {
return (double)ElapsedNanos() * (1.0 / 1000000000);
}
#endif
void sleep_ms(int ms) {
@@ -180,7 +248,7 @@ void sleep_ms(int ms) {
// Return the current time formatted as Minutes:Seconds:Milliseconds
// in the form 00:00:000.
void GetTimeFormatted(char formattedTime[13]) {
void GetCurrentTimeFormatted(char formattedTime[13]) {
time_t sysTime;
time(&sysTime);
+15 -3
View File
@@ -1,5 +1,4 @@
#pragma once
#include <cstdint>
// Seconds.
@@ -22,7 +21,7 @@ void sleep_ms(int ms);
// Yield. Signals that this thread is busy-waiting but wants to allow other hyperthreads to run.
void yield();
void GetTimeFormatted(char formattedTime[13]);
void GetCurrentTimeFormatted(char formattedTime[13]);
// Rust-style Instant for clear and easy timing.
class Instant {
@@ -30,10 +29,23 @@ public:
static Instant Now() {
return Instant(time_now_d());
}
double Elapsed() const {
double ElapsedSeconds() const {
return time_now_d() - instantTime_;
}
private:
explicit Instant(double initTime) : instantTime_(initTime) {}
double instantTime_;
};
// Most accurate timer possible - no extra double conversions. Only for spans.
class TimeSpan {
public:
TimeSpan();
double ElapsedSeconds() const;
int64_t ElapsedNanos() const;
private:
uint64_t nativeStart_;
#ifndef _WIN32
int64_t nsecs_;
#endif
};
+2 -2
View File
@@ -23,14 +23,14 @@ public:
if (at3pCtx_) {
codecOpen_ = true;
} else {
ERROR_LOG(ME, "Failed to open atrac3+ context! (channels=%d blockAlign=%d ed=%d)", channels, blockAlign, extraDataSize);
ERROR_LOG(ME, "Failed to open atrac3+ context! (channels=%d blockAlign=%d ed=%d)", channels, (int)blockAlign, (int)extraDataSize);
}
} else if (audioType_ == PSP_CODEC_AT3) {
at3Ctx_ = atrac3_alloc(channels, &blockAlign_, extraData, (int)extraDataSize);
if (at3Ctx_) {
codecOpen_ = true;
} else {
ERROR_LOG(ME, "Failed to open atrac3 context! !channels=%d blockAlign=%d ed=%d)", channels, blockAlign, extraDataSize);
ERROR_LOG(ME, "Failed to open atrac3 context! !channels=%d blockAlign=%d ed=%d)", channels, (int)blockAlign, (int)extraDataSize);
}
}
for (int i = 0; i < 2; i++) {
+1 -361
View File
@@ -69,6 +69,7 @@
#include "UI/MainScreen.h"
#include "UI/ControlMappingScreen.h"
#include "UI/GameSettingsScreen.h"
#include "UI/JitCompareScreen.h"
#ifdef _WIN32
// Want to avoid including the full header here as it includes d3dx.h
@@ -920,367 +921,6 @@ void SystemInfoScreen::CreateInternalsTab(UI::ViewGroup *internals) {
#endif
}
void AddressPromptScreen::CreatePopupContents(UI::ViewGroup *parent) {
using namespace UI;
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
addrView_ = new TextView(dev->T("Enter address"), ALIGN_HCENTER, false);
parent->Add(addrView_);
ViewGroup *grid = new GridLayout(GridLayoutSettings(60, 40));
parent->Add(grid);
for (int i = 0; i < 16; ++i) {
char temp[16];
snprintf(temp, 16, " %X ", i);
buttons_[i] = new Button(temp);
grid->Add(buttons_[i])->OnClick.Handle(this, &AddressPromptScreen::OnDigitButton);
}
parent->Add(new Button(dev->T("Backspace")))->OnClick.Handle(this, &AddressPromptScreen::OnBackspace);
}
void AddressPromptScreen::OnCompleted(DialogResult result) {
if (result == DR_OK) {
UI::EventParams e{};
e.v = root_;
e.a = addr_;
OnChoice.Trigger(e);
}
}
UI::EventReturn AddressPromptScreen::OnDigitButton(UI::EventParams &e) {
for (int i = 0; i < 16; ++i) {
if (buttons_[i] == e.v) {
AddDigit(i);
}
}
return UI::EVENT_DONE;
}
UI::EventReturn AddressPromptScreen::OnBackspace(UI::EventParams &e) {
BackspaceDigit();
return UI::EVENT_DONE;
}
void AddressPromptScreen::AddDigit(int n) {
if ((addr_ & 0xF0000000) == 0) {
addr_ = addr_ * 16 + n;
}
UpdatePreviewDigits();
}
void AddressPromptScreen::BackspaceDigit() {
addr_ /= 16;
UpdatePreviewDigits();
}
void AddressPromptScreen::UpdatePreviewDigits() {
if (addr_ != 0) {
char temp[32];
snprintf(temp, 32, "%8X", addr_);
addrView_->SetText(temp);
} else {
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
addrView_->SetText(dev->T("Enter address"));
}
}
bool AddressPromptScreen::key(const KeyInput &key) {
if (key.flags & KEY_DOWN) {
if (key.keyCode >= NKCODE_0 && key.keyCode <= NKCODE_9) {
AddDigit(key.keyCode - NKCODE_0);
} else if (key.keyCode >= NKCODE_A && key.keyCode <= NKCODE_F) {
AddDigit(10 + key.keyCode - NKCODE_A);
// NKCODE_DEL is backspace.
} else if (key.keyCode == NKCODE_DEL) {
BackspaceDigit();
} else if (key.keyCode == NKCODE_ENTER) {
TriggerFinish(DR_OK);
} else {
return UIDialogScreen::key(key);
}
} else {
return UIDialogScreen::key(key);
}
return true;
}
// Three panes: Block chooser, MIPS view, ARM/x86 view
void JitCompareScreen::CreateViews() {
auto di = GetI18NCategory(I18NCat::DIALOG);
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
using namespace UI;
root_ = new LinearLayout(ORIENT_HORIZONTAL);
ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
ScrollView *midColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.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 = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.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("Prev")))->OnClick.Handle(this, &JitCompareScreen::OnPrevBlock);
leftColumn->Add(new Choice(dev->T("Next")))->OnClick.Handle(this, &JitCompareScreen::OnNextBlock);
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);
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);
blockName_ = leftColumn->Add(new TextView(dev->T("No block")));
blockAddr_ = leftColumn->Add(new TextEdit("", dev->T("Block address"), "", new LayoutParams(FILL_PARENT, WRAP_CONTENT)));
blockAddr_->OnTextChange.Handle(this, &JitCompareScreen::OnAddressChange);
blockStats_ = leftColumn->Add(new TextView(""));
EventParams ignore{};
OnCurrentBlock(ignore);
}
void JitCompareScreen::UpdateDisasm() {
leftDisasm_->Clear();
rightDisasm_->Clear();
using namespace UI;
if (!MIPSComp::jit) {
return;
}
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
if (!blockCacheDebug->IsValidBlock(currentBlock_)) {
return;
}
char temp[256];
snprintf(temp, sizeof(temp), "%i/%i", currentBlock_, blockCacheDebug->GetNumBlocks());
blockName_->SetText(temp);
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;
}
JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(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);
}
} else {
for (const auto &line : debugInfo.irDisasm) {
rightDisasm_->Add(new TextView(line))->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);
}
UI::EventReturn JitCompareScreen::OnAddressChange(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;
u32 addr;
if (blockAddr_->GetText().size() > 8)
return UI::EVENT_DONE;
if (1 == sscanf(blockAddr_->GetText().c_str(), "%08x", &addr)) {
if (Memory::IsValidAddress(addr)) {
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(addr);
UpdateDisasm();
}
}
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnShowStats(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;
BlockCacheStats bcStats;
blockCache->ComputeStats(bcStats);
NOTICE_LOG(JIT, "Num blocks: %i", bcStats.numBlocks);
NOTICE_LOG(JIT, "Average Bloat: %0.2f%%", 100 * bcStats.avgBloat);
NOTICE_LOG(JIT, "Min Bloat: %0.2f%% (%08x)", 100 * bcStats.minBloat, bcStats.minBloatBlock);
NOTICE_LOG(JIT, "Max Bloat: %0.2f%% (%08x)", 100 * bcStats.maxBloat, bcStats.maxBloatBlock);
int ctr = 0, sz = (int)bcStats.bloatMap.size();
for (auto iter : bcStats.bloatMap) {
if (ctr < 10 || ctr > sz - 10) {
NOTICE_LOG(JIT, "%08x: %f", iter.second, iter.first);
} else if (ctr == 10) {
NOTICE_LOG(JIT, "...");
}
ctr++;
}
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) {
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
auto addressPrompt = new AddressPromptScreen(dev->T("Block address"));
addressPrompt->OnChoice.Handle(this, &JitCompareScreen::OnBlockAddress);
screenManager()->push(addressPrompt);
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) {
return UI::EVENT_DONE;
}
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
if (!blockCache)
return UI::EVENT_DONE;
if (Memory::IsValidAddress(e.a)) {
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a);
} else {
currentBlock_ = -1;
}
UpdateDisasm();
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) {
return;
}
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
if (!blockCache)
return;
int numBlocks = blockCache->GetNumBlocks();
if (numBlocks > 0) {
bool anyWanted = false;
int tries = 0;
while (!anyWanted && tries < numBlocks) {
currentBlock_ = rand() % numBlocks;
if (blockCache->IsValidBlock(currentBlock_)) {
JitBlockDebugInfo b = blockCache->GetBlockDebugInfo(currentBlock_);
u32 mipsBytes = (u32)b.origDisasm.size() * 4;
for (u32 addr = b.originalAddress; addr < b.originalAddress + mipsBytes; addr += 4) {
MIPSOpcode opcode = Memory::Read_Instruction(addr);
if (MIPSGetInfo(opcode) & flag) {
char temp[256];
MIPSDisAsm(opcode, addr, temp, sizeof(temp));
// INFO_LOG(HLE, "Stopping at random instruction: %08x %s", addr, temp);
anyWanted = true;
break;
}
}
}
tries++;
}
if (!anyWanted)
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;
}
int ShaderListScreen::ListShaders(DebugShaderType shaderType, UI::LinearLayout *view) {
using namespace UI;
std::vector<std::string> shaderIds_ = gpu->DebugGetShaderIDs(shaderType);
-59
View File
@@ -117,34 +117,6 @@ protected:
void CreateInternalsTab(UI::ViewGroup *internals);
};
class AddressPromptScreen : public PopupScreen {
public:
AddressPromptScreen(std::string_view title) : PopupScreen(title, "OK", "Cancel"), addrView_(NULL), addr_(0) {
memset(buttons_, 0, sizeof(buttons_));
}
const char *tag() const override { return "AddressPrompt"; }
bool key(const KeyInput &key) override;
UI::Event OnChoice;
protected:
void CreatePopupContents(UI::ViewGroup *parent) override;
void OnCompleted(DialogResult result) override;
UI::EventReturn OnDigitButton(UI::EventParams &e);
UI::EventReturn OnBackspace(UI::EventParams &e);
private:
void AddDigit(int n);
void BackspaceDigit();
void UpdatePreviewDigits();
UI::TextView *addrView_;
UI::Button *buttons_[16];
unsigned int addr_;
};
class GPIGPOScreen : public PopupScreen {
public:
GPIGPOScreen(std::string_view title) : PopupScreen(title, "OK") {}
@@ -154,37 +126,6 @@ protected:
void CreatePopupContents(UI::ViewGroup *parent) override;
};
class JitCompareScreen : public UIDialogScreenWithBackground {
public:
void CreateViews() override;
const char *tag() const override { return "JitCompare"; }
private:
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);
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);
int currentBlock_ = -1;
UI::TextView *blockName_;
UI::TextEdit *blockAddr_;
UI::TextView *blockStats_;
UI::LinearLayout *leftDisasm_;
UI::LinearLayout *rightDisasm_;
};
class ShaderListScreen : public UIDialogScreenWithBackground {
public:
void CreateViews() override;
+369
View File
@@ -0,0 +1,369 @@
#include "UI/JitCompareScreen.h"
#include "Core/MemMap.h"
#include "Core/MIPS/MIPSTables.h"
#include "Core/MIPS/JitCommon/JitBlockCache.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "Core/MIPS/JitCommon/JitState.h"
// Three panes: Block chooser, MIPS view, ARM/x86 view
void JitCompareScreen::CreateViews() {
auto di = GetI18NCategory(I18NCat::DIALOG);
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
using namespace UI;
root_ = new LinearLayout(ORIENT_HORIZONTAL);
ScrollView *leftColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(1.0f)));
LinearLayout *leftColumn = leftColumnScroll->Add(new LinearLayout(ORIENT_VERTICAL));
ScrollView *midColumnScroll = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.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 = root_->Add(new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(2.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("Prev")))->OnClick.Handle(this, &JitCompareScreen::OnPrevBlock);
leftColumn->Add(new Choice(dev->T("Next")))->OnClick.Handle(this, &JitCompareScreen::OnNextBlock);
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);
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);
blockName_ = leftColumn->Add(new TextView(dev->T("No block")));
blockAddr_ = leftColumn->Add(new TextEdit("", dev->T("Block address"), "", new LayoutParams(FILL_PARENT, WRAP_CONTENT)));
blockAddr_->OnTextChange.Handle(this, &JitCompareScreen::OnAddressChange);
blockStats_ = leftColumn->Add(new TextView(""));
EventParams ignore{};
OnCurrentBlock(ignore);
}
void JitCompareScreen::UpdateDisasm() {
leftDisasm_->Clear();
rightDisasm_->Clear();
using namespace UI;
if (!MIPSComp::jit) {
return;
}
JitBlockCacheDebugInterface *blockCacheDebug = MIPSComp::jit->GetBlockCacheDebugInterface();
if (!blockCacheDebug->IsValidBlock(currentBlock_)) {
return;
}
char temp[256];
snprintf(temp, sizeof(temp), "%i/%i", currentBlock_, blockCacheDebug->GetNumBlocks());
blockName_->SetText(temp);
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;
}
JitBlockDebugInfo debugInfo = blockCacheDebug->GetBlockDebugInfo(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);
}
} else {
for (const auto &line : debugInfo.irDisasm) {
rightDisasm_->Add(new TextView(line))->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);
}
UI::EventReturn JitCompareScreen::OnAddressChange(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;
u32 addr;
if (blockAddr_->GetText().size() > 8)
return UI::EVENT_DONE;
if (1 == sscanf(blockAddr_->GetText().c_str(), "%08x", &addr)) {
if (Memory::IsValidAddress(addr)) {
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(addr);
UpdateDisasm();
}
}
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnShowStats(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;
BlockCacheStats bcStats;
blockCache->ComputeStats(bcStats);
NOTICE_LOG(JIT, "Num blocks: %i", bcStats.numBlocks);
NOTICE_LOG(JIT, "Average Bloat: %0.2f%%", 100 * bcStats.avgBloat);
NOTICE_LOG(JIT, "Min Bloat: %0.2f%% (%08x)", 100 * bcStats.minBloat, bcStats.minBloatBlock);
NOTICE_LOG(JIT, "Max Bloat: %0.2f%% (%08x)", 100 * bcStats.maxBloat, bcStats.maxBloatBlock);
int ctr = 0, sz = (int)bcStats.bloatMap.size();
for (auto iter : bcStats.bloatMap) {
if (ctr < 10 || ctr > sz - 10) {
NOTICE_LOG(JIT, "%08x: %f", iter.second, iter.first);
} else if (ctr == 10) {
NOTICE_LOG(JIT, "...");
}
ctr++;
}
return UI::EVENT_DONE;
}
UI::EventReturn JitCompareScreen::OnSelectBlock(UI::EventParams &e) {
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
auto addressPrompt = new AddressPromptScreen(dev->T("Block address"));
addressPrompt->OnChoice.Handle(this, &JitCompareScreen::OnBlockAddress);
screenManager()->push(addressPrompt);
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) {
return UI::EVENT_DONE;
}
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
if (!blockCache)
return UI::EVENT_DONE;
if (Memory::IsValidAddress(e.a)) {
currentBlock_ = blockCache->GetBlockNumberFromStartAddress(e.a);
} else {
currentBlock_ = -1;
}
UpdateDisasm();
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) {
return;
}
JitBlockCacheDebugInterface *blockCache = MIPSComp::jit->GetBlockCacheDebugInterface();
if (!blockCache)
return;
int numBlocks = blockCache->GetNumBlocks();
if (numBlocks > 0) {
bool anyWanted = false;
int tries = 0;
while (!anyWanted && tries < numBlocks) {
currentBlock_ = rand() % numBlocks;
if (blockCache->IsValidBlock(currentBlock_)) {
JitBlockDebugInfo b = blockCache->GetBlockDebugInfo(currentBlock_);
u32 mipsBytes = (u32)b.origDisasm.size() * 4;
for (u32 addr = b.originalAddress; addr < b.originalAddress + mipsBytes; addr += 4) {
MIPSOpcode opcode = Memory::Read_Instruction(addr);
if (MIPSGetInfo(opcode) & flag) {
char temp[256];
MIPSDisAsm(opcode, addr, temp, sizeof(temp));
// INFO_LOG(HLE, "Stopping at random instruction: %08x %s", addr, temp);
anyWanted = true;
break;
}
}
}
tries++;
}
if (!anyWanted)
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;
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
addrView_ = new TextView(dev->T("Enter address"), ALIGN_HCENTER, false);
parent->Add(addrView_);
ViewGroup *grid = new GridLayout(GridLayoutSettings(60, 40));
parent->Add(grid);
for (int i = 0; i < 16; ++i) {
char temp[16];
snprintf(temp, 16, " %X ", i);
buttons_[i] = new Button(temp);
grid->Add(buttons_[i])->OnClick.Handle(this, &AddressPromptScreen::OnDigitButton);
}
parent->Add(new Button(dev->T("Backspace")))->OnClick.Handle(this, &AddressPromptScreen::OnBackspace);
}
void AddressPromptScreen::OnCompleted(DialogResult result) {
if (result == DR_OK) {
UI::EventParams e{};
e.v = root_;
e.a = addr_;
OnChoice.Trigger(e);
}
}
UI::EventReturn AddressPromptScreen::OnDigitButton(UI::EventParams &e) {
for (int i = 0; i < 16; ++i) {
if (buttons_[i] == e.v) {
AddDigit(i);
}
}
return UI::EVENT_DONE;
}
UI::EventReturn AddressPromptScreen::OnBackspace(UI::EventParams &e) {
BackspaceDigit();
return UI::EVENT_DONE;
}
void AddressPromptScreen::AddDigit(int n) {
if ((addr_ & 0xF0000000) == 0) {
addr_ = addr_ * 16 + n;
}
UpdatePreviewDigits();
}
void AddressPromptScreen::BackspaceDigit() {
addr_ /= 16;
UpdatePreviewDigits();
}
void AddressPromptScreen::UpdatePreviewDigits() {
if (addr_ != 0) {
char temp[32];
snprintf(temp, 32, "%8X", addr_);
addrView_->SetText(temp);
} else {
auto dev = GetI18NCategory(I18NCat::DEVELOPER);
addrView_->SetText(dev->T("Enter address"));
}
}
bool AddressPromptScreen::key(const KeyInput &key) {
if (key.flags & KEY_DOWN) {
if (key.keyCode >= NKCODE_0 && key.keyCode <= NKCODE_9) {
AddDigit(key.keyCode - NKCODE_0);
} else if (key.keyCode >= NKCODE_A && key.keyCode <= NKCODE_F) {
AddDigit(10 + key.keyCode - NKCODE_A);
// NKCODE_DEL is backspace.
} else if (key.keyCode == NKCODE_DEL) {
BackspaceDigit();
} else if (key.keyCode == NKCODE_ENTER) {
TriggerFinish(DR_OK);
} else {
return UIDialogScreen::key(key);
}
} else {
return UIDialogScreen::key(key);
}
return true;
}
+60
View File
@@ -0,0 +1,60 @@
#pragma once
#include "Common/UI/UIScreen.h"
#include "UI/MiscScreens.h"
class JitCompareScreen : public UIDialogScreenWithBackground {
public:
void CreateViews() override;
const char *tag() const override { return "JitCompare"; }
private:
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);
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);
int currentBlock_ = -1;
UI::TextView *blockName_;
UI::TextEdit *blockAddr_;
UI::TextView *blockStats_;
UI::LinearLayout *leftDisasm_;
UI::LinearLayout *rightDisasm_;
};
class AddressPromptScreen : public PopupScreen {
public:
AddressPromptScreen(std::string_view title) : PopupScreen(title, "OK", "Cancel") {}
const char *tag() const override { return "AddressPrompt"; }
bool key(const KeyInput &key) override;
UI::Event OnChoice;
protected:
void CreatePopupContents(UI::ViewGroup *parent) override;
void OnCompleted(DialogResult result) override;
UI::EventReturn OnDigitButton(UI::EventParams &e);
UI::EventReturn OnBackspace(UI::EventParams &e);
private:
void AddDigit(int n);
void BackspaceDigit();
void UpdatePreviewDigits();
UI::TextView *addrView_ = nullptr;
UI::Button *buttons_[16]{};
unsigned int addr_ = 0;
};
+2
View File
@@ -51,6 +51,7 @@
<ClCompile Include="GameScreen.cpp" />
<ClCompile Include="GameSettingsScreen.cpp" />
<ClCompile Include="GPUDriverTestScreen.cpp" />
<ClCompile Include="JitCompareScreen.cpp" />
<ClCompile Include="JoystickHistoryView.cpp" />
<ClCompile Include="MainScreen.cpp" />
<ClCompile Include="MemStickScreen.cpp" />
@@ -90,6 +91,7 @@
<ClInclude Include="GameSettingsScreen.h" />
<ClInclude Include="CwCheatScreen.h" />
<ClInclude Include="GPUDriverTestScreen.h" />
<ClInclude Include="JitCompareScreen.h" />
<ClInclude Include="JoystickHistoryView.h" />
<ClInclude Include="MainScreen.h" />
<ClInclude Include="MemStickScreen.h" />
+6
View File
@@ -95,6 +95,9 @@
<ClCompile Include="DriverManagerScreen.cpp">
<Filter>Screens</Filter>
</ClCompile>
<ClCompile Include="JitCompareScreen.cpp">
<Filter>Screens</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="GameInfoCache.h" />
@@ -190,6 +193,9 @@
<ClInclude Include="DriverManagerScreen.h">
<Filter>Screens</Filter>
</ClInclude>
<ClInclude Include="JitCompareScreen.h">
<Filter>Screens</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Screens">
+2
View File
@@ -127,6 +127,7 @@
<ClInclude Include="..\..\UI\GameSettingsScreen.h" />
<ClInclude Include="..\..\UI\GPUDriverTestScreen.h" />
<ClInclude Include="..\..\UI\InstallZipScreen.h" />
<ClInclude Include="..\..\UI\JitCompareScreen.h" />
<ClInclude Include="..\..\UI\JoystickHistoryView.h" />
<ClInclude Include="..\..\UI\TabbedDialogScreen.h" />
<ClInclude Include="..\..\UI\RetroAchievementScreens.h" />
@@ -166,6 +167,7 @@
<ClCompile Include="..\..\UI\GameSettingsScreen.cpp" />
<ClCompile Include="..\..\UI\GPUDriverTestScreen.cpp" />
<ClCompile Include="..\..\UI\InstallZipScreen.cpp" />
<ClCompile Include="..\..\UI\JitCompareScreen.cpp" />
<ClCompile Include="..\..\UI\JoystickHistoryView.cpp" />
<ClCompile Include="..\..\UI\TabbedDialogScreen.cpp" />
<ClCompile Include="..\..\UI\RetroAchievementScreens.cpp" />
+2
View File
@@ -38,6 +38,7 @@
<ClCompile Include="..\..\UI\RetroAchievementScreens.cpp" />
<ClCompile Include="..\..\UI\DebugOverlay.cpp" />
<ClCompile Include="..\..\UI\DriverManagerScreen.cpp" />
<ClCompile Include="..\..\UI\JitCompareScreen.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@@ -77,5 +78,6 @@
<ClInclude Include="..\..\UI\RetroAchievementScreens.h" />
<ClInclude Include="..\..\UI\DebugOverlay.h" />
<ClInclude Include="..\..\UI\DriverManagerScreen.h" />
<ClInclude Include="..\..\UI\JitCompareScreen.h" />
</ItemGroup>
</Project>
+1
View File
@@ -855,6 +855,7 @@ LOCAL_SRC_FILES := \
$(SRC)/UI/TouchControlVisibilityScreen.cpp \
$(SRC)/UI/CwCheatScreen.cpp \
$(SRC)/UI/InstallZipScreen.cpp \
$(SRC)/UI/JitCompareScreen.cpp \
$(SRC)/UI/OnScreenDisplay.cpp \
$(SRC)/UI/ProfilerDraw.cpp \
$(SRC)/UI/NativeApp.cpp \
+1 -1
View File
@@ -119,7 +119,7 @@ bool TestMultithreadedScheduling() {
threads.clear();
printf("Stress test elapsed: %0.2f", start.Elapsed());
printf("Stress test elapsed: %0.2f", start.ElapsedSeconds());
return true;
}