diff --git a/CMakeLists.txt b/CMakeLists.txt index db1ee1534e..f62b8f3560 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index cc3c6bf884..f7b59b8447 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -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", diff --git a/Common/Render/Text/draw_text_uwp.cpp b/Common/Render/Text/draw_text_uwp.cpp index b1139569b7..b61541da91 100644 --- a/Common/Render/Text/draw_text_uwp.cpp +++ b/Common/Render/Text/draw_text_uwp.cpp @@ -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) { diff --git a/Common/TimeUtil.cpp b/Common/TimeUtil.cpp index b24a1da4e3..fdb6817723 100644 --- a/Common/TimeUtil.cpp +++ b/Common/TimeUtil.cpp @@ -4,6 +4,7 @@ #include #include "Common/TimeUtil.h" +#include "Common/Log.h" #ifdef HAVE_LIBNX #include @@ -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(frequency.QuadPart); } +} + +double time_now_d() { + InitTime(); LARGE_INTEGER time; QueryPerformanceCounter(&time); double elapsed = static_cast(time.QuadPart - startTime.QuadPart); @@ -86,6 +91,22 @@ void yield() { YieldProcessor(); } +TimeSpan::TimeSpan() { + _dbg_assert_(frequencyMult != 0.0); + QueryPerformanceCounter(reinterpret_cast(&nativeStart_)); +} + +double TimeSpan::ElapsedSeconds() const { + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + double elapsed = static_cast(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); diff --git a/Common/TimeUtil.h b/Common/TimeUtil.h index 779ba07d21..578886f3f7 100644 --- a/Common/TimeUtil.h +++ b/Common/TimeUtil.h @@ -1,5 +1,4 @@ #pragma once - #include // 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 +}; diff --git a/Core/HW/Atrac3Standalone.cpp b/Core/HW/Atrac3Standalone.cpp index 2e4ad22086..a585db1791 100644 --- a/Core/HW/Atrac3Standalone.cpp +++ b/Core/HW/Atrac3Standalone.cpp @@ -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++) { diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index a9f34766aa..afd9ad7508 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -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(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 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 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 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 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 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 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 shaderIds_ = gpu->DebugGetShaderIDs(shaderType); diff --git a/UI/DevScreens.h b/UI/DevScreens.h index ada7c5e129..ef9965ba4d 100644 --- a/UI/DevScreens.h +++ b/UI/DevScreens.h @@ -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; diff --git a/UI/JitCompareScreen.cpp b/UI/JitCompareScreen.cpp new file mode 100644 index 0000000000..53f45a316e --- /dev/null +++ b/UI/JitCompareScreen.cpp @@ -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(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 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 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 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 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 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 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; +} diff --git a/UI/JitCompareScreen.h b/UI/JitCompareScreen.h new file mode 100644 index 0000000000..027f3e7bb6 --- /dev/null +++ b/UI/JitCompareScreen.h @@ -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; +}; diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index 74aefd02e6..e1fcc93938 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -51,6 +51,7 @@ + @@ -90,6 +91,7 @@ + diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 24c3cc6cf0..ba5da5148c 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -95,6 +95,9 @@ Screens + + Screens + @@ -190,6 +193,9 @@ Screens + + Screens + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index f3b4c5a085..40838af5ed 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -127,6 +127,7 @@ + @@ -166,6 +167,7 @@ + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index 18fe8834c3..b7bb978d11 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -38,6 +38,7 @@ + @@ -77,5 +78,6 @@ + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index c49ac79c4e..150161553f 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -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 \ diff --git a/unittest/TestThreadManager.cpp b/unittest/TestThreadManager.cpp index 10a8b581b7..ff15044ffb 100644 --- a/unittest/TestThreadManager.cpp +++ b/unittest/TestThreadManager.cpp @@ -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; }