Skip to content

Commit

Permalink
Debugging: Add minimalist PPC profiler
Browse files Browse the repository at this point in the history
  • Loading branch information
Exzap committed Jun 25, 2023
1 parent 45072fc commit 9499870
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 39 deletions.
14 changes: 14 additions & 0 deletions src/Cafe/OS/RPL/rpl_symbol_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,20 @@ RPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address)
return rplSymbolStorage.map_symbolByAddress[address];
}

RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address)
{
// highly inefficient but doesn't matter for now
std::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);
for(uint32 i=0; i<4096; i++)
{
RPLStoredSymbol* symbol = rplSymbolStorage.map_symbolByAddress[address];
if(symbol)
return symbol;
address -= 4;
}
return nullptr;
}

void rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol)
{
std::unique_lock<std::mutex> lck(rplSymbolStorage.m_symbolStorageMutex);
Expand Down
1 change: 1 addition & 0 deletions src/Cafe/OS/RPL/rpl_symbol_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ RPLStoredSymbol* rplSymbolStorage_store(const char* libName, const char* symbolN
void rplSymbolStorage_remove(RPLStoredSymbol* storedSymbol);
void rplSymbolStorage_removeRange(MPTR address, sint32 length);
RPLStoredSymbol* rplSymbolStorage_getByAddress(MPTR address);
RPLStoredSymbol* rplSymbolStorage_getByClosestAddress(MPTR address);
void rplSymbolStorage_createJumpProxySymbol(MPTR jumpAddress, MPTR destAddress);

std::unordered_map<uint32, RPLStoredSymbol*>& rplSymbolStorage_lockSymbolMap();
Expand Down
10 changes: 7 additions & 3 deletions src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,17 +812,21 @@ namespace coreinit
return suspendCounter > 0;
}

bool OSIsThreadRunningNoLock(OSThread_t* thread)
{
cemu_assert_debug(__OSHasSchedulerLock());
return thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING;
}

bool OSIsThreadRunning(OSThread_t* thread)
{
bool isRunning = false;
__OSLockScheduler();
if (thread->state == OSThread_t::THREAD_STATE::STATE_RUNNING)
isRunning = true;
isRunning = OSIsThreadRunningNoLock(thread);
__OSUnlockScheduler();
return isRunning;
}


void OSCancelThread(OSThread_t* thread)
{
__OSLockScheduler();
Expand Down
3 changes: 3 additions & 0 deletions src/Cafe/OS/libs/coreinit/coreinit_Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ namespace coreinit

bool OSIsThreadTerminated(OSThread_t* thread);
bool OSIsThreadSuspended(OSThread_t* thread);
bool OSIsThreadRunningNoLock(OSThread_t* thread);
bool OSIsThreadRunning(OSThread_t* thread);

// OSThreadQueue
Expand Down Expand Up @@ -603,6 +604,8 @@ namespace coreinit
void __OSAddReadyThreadToRunQueue(OSThread_t* thread);
bool __OSCoreShouldSwitchToThread(OSThread_t* currentThread, OSThread_t* newThread);
void __OSQueueThreadDeallocation(OSThread_t* thread);

bool __OSIsThreadActive(OSThread_t* thread);
}

#pragma pack()
Expand Down
118 changes: 118 additions & 0 deletions src/gui/components/wxProgressDialogManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#pragma once

#include <wx/event.h>
#include <wx/progdlg.h>
#include <wx/thread.h>
#include "util/helpers/Semaphore.h"

wxDEFINE_EVENT(wxEVT_CREATE_PROGRESS_DIALOG, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_DESTROY_PROGRESS_DIALOG, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_UPDATE_PROGRESS_DIALOG, wxThreadEvent);

// wrapper for wxGenericProgressDialog which can be used from any thread
class wxProgressDialogManager : public wxEvtHandler
{
public:
wxProgressDialogManager(wxWindow* parent) : m_parent(parent), m_dialog(nullptr)
{
Bind(wxEVT_CREATE_PROGRESS_DIALOG, &wxProgressDialogManager::OnCreateProgressDialog, this);
Bind(wxEVT_DESTROY_PROGRESS_DIALOG, &wxProgressDialogManager::OnDestroyProgressDialog, this);
Bind(wxEVT_UPDATE_PROGRESS_DIALOG, &wxProgressDialogManager::OnUpdateProgressDialog, this);
}

~wxProgressDialogManager()
{
if (m_dialog)
Destroy();
}

void Create(const wxString& title, const wxString& message, int maximum, int style = wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_REMAINING_TIME)
{
m_instanceSemaphore.increment();
m_isCancelled = false;
m_isSkipped = false;
wxThreadEvent event(wxEVT_CREATE_PROGRESS_DIALOG);
event.SetString(title);
event.SetInt(maximum);
event.SetExtraLong(style);
wxQueueEvent(this, event.Clone());
}

void Destroy()
{
wxThreadEvent event(wxEVT_DESTROY_PROGRESS_DIALOG);
wxQueueEvent(this, event.Clone());
m_instanceSemaphore.waitUntilZero(); // wait until destruction is complete
}

// this also updates the cancel and skip state
void Update(int value, const wxString& newmsg = wxEmptyString)
{
wxThreadEvent event(wxEVT_UPDATE_PROGRESS_DIALOG);
event.SetInt(value);
event.SetString(newmsg);
wxQueueEvent(this, event.Clone());
}

bool IsCancelled() const
{
return m_isCancelled;
}

bool IsSkipped() const
{
return m_isSkipped;
}

bool IsCancelledOrSkipped() const
{
return m_isCancelled || m_isSkipped;
}

private:
void OnCreateProgressDialog(wxThreadEvent& event)
{
if (m_dialog)
{
m_dialog->Destroy();
m_instanceSemaphore.waitUntilZero();
}
m_maximum = event.GetInt();
m_dialog = new wxGenericProgressDialog(event.GetString(), "Please wait...", m_maximum, m_parent, event.GetExtraLong());
}

void OnDestroyProgressDialog(wxThreadEvent& event)
{
if (m_dialog)
{
m_dialog->Destroy();
m_dialog = nullptr;
m_instanceSemaphore.decrement();
}
}

void OnUpdateProgressDialog(wxThreadEvent& event)
{
if (m_dialog)
{
// make sure that progress is never >= maximum
// because wxGenericProgressDialog seems to become crashy on destruction otherwise
int progress = event.GetInt();
if(progress >= m_maximum)
progress = m_maximum - 1;
bool wasSkipped = false;
bool r = m_dialog->Update(progress, event.GetString(), &wasSkipped);
if(!r)
m_isCancelled = true;
if(wasSkipped)
m_isSkipped = true;
}
}

wxWindow* m_parent;
wxGenericProgressDialog* m_dialog;
bool m_isCancelled{false};
bool m_isSkipped{false};
int m_maximum{0};
CounterSemaphore m_instanceSemaphore; // used to synchronize destruction of the dialog
};

0 comments on commit 9499870

Please sign in to comment.