Skip to content

Commit

Permalink
Merge pull request #19705 from hrydgard/debugger-core-timing
Browse files Browse the repository at this point in the history
ImDebugger: Add a window to inspect upcoming CoreTiming events
  • Loading branch information
hrydgard authored Dec 7, 2024
2 parents 3ca3a79 + b3346df commit b3227e5
Show file tree
Hide file tree
Showing 13 changed files with 134 additions and 27 deletions.
1 change: 1 addition & 0 deletions Common/Common.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@
<ClInclude Include="Data\Collections\CharQueue.h" />
<ClInclude Include="Data\Collections\FixedSizeQueue.h" />
<ClInclude Include="Data\Collections\Hashmaps.h" />
<ClInclude Include="Data\Collections\LinkedList.h" />
<ClInclude Include="Data\Collections\Slice.h" />
<ClInclude Include="Data\Collections\ThreadSafeList.h" />
<ClInclude Include="Data\Collections\TinySet.h" />
Expand Down
3 changes: 3 additions & 0 deletions Common/Common.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,9 @@
<ClInclude Include="Data\Collections\CharQueue.h">
<Filter>Data\Collections</Filter>
</ClInclude>
<ClInclude Include="Data\Collections\LinkedList.h">
<Filter>Data\Collections</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ABI.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions Common/Data/Collections/LinkedList.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

template <class T>
struct LinkedListItem : public T {
LinkedListItem<T> *next;
};
7 changes: 1 addition & 6 deletions Common/Serialize/Serializer.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,12 @@
#include "Common/CommonTypes.h"
#include "Common/Log.h"
#include "Common/File/Path.h"
#include "Common/Data/Collections/LinkedList.h"

namespace File {
class IOFile;
};

template <class T>
struct LinkedListItem : public T
{
LinkedListItem<T> *next;
};

class PointerWrap;

class PointerWrapSection
Expand Down
24 changes: 9 additions & 15 deletions Core/CoreTiming.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,14 @@ int CPU_HZ = 222000000;
#define INITIAL_SLICE_LENGTH 20000
#define MAX_SLICE_LENGTH 100000000

namespace CoreTiming
{

struct EventType {
TimedCallback callback;
const char *name;
};
namespace CoreTiming {

static std::vector<EventType> event_types;
// Only used during restore.
static std::set<int> usedEventTypes;
static std::set<int> restoredEventTypes;
static int nextEventTypeRestoreId = -1;

struct BaseEvent {
s64 time;
u64 userdata;
int type;
};

typedef LinkedListItem<BaseEvent> Event;

Event *first;
Event *eventPool = 0;

Expand Down Expand Up @@ -120,6 +106,14 @@ u64 GetGlobalTimeUs() {
return lastGlobalTimeUs + usSinceLast;
}

const Event *GetFirstEvent() {
return first;
}

const std::vector<EventType> &GetEventTypes() {
return event_types;
}

Event* GetNewEvent()
{
if(!eventPool)
Expand Down
28 changes: 23 additions & 5 deletions Core/CoreTiming.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
#pragma once

#include <string>
#include <vector>
#include "Common/CommonTypes.h"
#include "Common/Data/Collections/LinkedList.h"

// This is a system to schedule events into the emulated machine's future. Time is measured
// in main CPU clock cycles.
Expand Down Expand Up @@ -70,21 +72,33 @@ inline s64 cyclesToUs(s64 cycles) {
return (cycles * 1000000) / CPU_HZ;
}

namespace CoreTiming
{
void Init();
void Shutdown();

namespace CoreTiming {
typedef void (*MHzChangeCallback)();
typedef void (*TimedCallback)(u64 userdata, int cyclesLate);

struct EventType {
TimedCallback callback;
const char *name;
};

struct BaseEvent {
s64 time;
u64 userdata;
int type;
};
typedef LinkedListItem<BaseEvent> Event;

void Init();
void Shutdown();

u64 GetTicks();
u64 GetIdleTicks();
u64 GetGlobalTimeUs();
u64 GetGlobalTimeUsScaled();

// Returns the event_type identifier.
int RegisterEvent(const char *name, TimedCallback callback);

// For save states.
void RestoreRegisterEvent(int &event_type, const char *name, TimedCallback callback);
void UnregisterAllEvents();
Expand All @@ -94,6 +108,8 @@ namespace CoreTiming
void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata=0);
s64 UnscheduleEvent(int event_type, u64 userdata);

const std::vector<EventType> &GetEventTypes();
const Event *GetFirstEvent();
void RemoveEvent(int event_type);
bool IsScheduled(int event_type);
void Advance();
Expand All @@ -116,6 +132,8 @@ namespace CoreTiming

void SetClockFrequencyHz(int cpuHz);
int GetClockFrequencyHz();

// TODO: Add accessors?
extern int slicelength;

}; // end of namespace
15 changes: 15 additions & 0 deletions Core/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -779,3 +779,18 @@ bool CreateSysDirectories() {
}
return true;
}

const char *CoreStateToString(CoreState state) {
switch (state) {
case CORE_RUNNING_CPU: return "RUNNING_CPU";
case CORE_NEXTFRAME: return "NEXTFRAME";
case CORE_STEPPING_CPU: return "STEPPING_CPU";
case CORE_POWERUP: return "POWERUP";
case CORE_POWERDOWN: return "POWERDOWN";
case CORE_BOOT_ERROR: return "BOOT_ERROR";
case CORE_RUNTIME_ERROR: return "RUNTIME_ERROR";
case CORE_STEPPING_GE: return "STEPPING_GE";
case CORE_RUNNING_GE: return "RUNNING_GE";
default: return "N/A";
}
}
2 changes: 2 additions & 0 deletions Core/System.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ enum CoreState {
CORE_RUNNING_GE,
};

const char *CoreStateToString(CoreState state);

extern bool coreCollectDebugStats;

extern volatile CoreState coreState;
Expand Down
21 changes: 21 additions & 0 deletions GPU/Debugger/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@ static uint32_t g_skipPcOnce = 0;
static std::vector<std::pair<int, int>> restrictPrimRanges;
static std::string restrictPrimRule;

const char *BreakNextToString(BreakNext next) {
switch (next) {
case BreakNext::NONE: return "NONE,";
case BreakNext::OP: return "OP";
case BreakNext::DRAW: return "DRAW";
case BreakNext::TEX: return "TEX";
case BreakNext::NONTEX: return "NONTEX";
case BreakNext::FRAME: return "FRAME";
case BreakNext::VSYNC: return "VSYNC";
case BreakNext::PRIM: return "PRIM";
case BreakNext::CURVE: return "CURVE";
case BreakNext::COUNT: return "COUNT";
default: return "N/A";
}
}

static void Init() {
if (!inited) {
GPUBreakpoints::Init([](bool flag) {
Expand All @@ -69,6 +85,10 @@ bool IsActive() {
return active;
}

BreakNext GetBreakNext() {
return breakNext;
}

void SetBreakNext(BreakNext next) {
SetActive(true);
breakNext = next;
Expand Down Expand Up @@ -166,6 +186,7 @@ NotifyResult NotifyCommand(u32 pc) {
}

g_skipPcOnce = pc;
breakNext = BreakNext::NONE;
return NotifyResult::Break; // new. caller will call GPUStepping::EnterStepping().
}

Expand Down
2 changes: 2 additions & 0 deletions GPU/Debugger/Debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ bool IsActive();

void SetBreakNext(BreakNext next);
void SetBreakCount(int c, bool relative = false);
BreakNext GetBreakNext();
const char *BreakNextToString(BreakNext next);

enum class NotifyResult {
Execute,
Expand Down
37 changes: 36 additions & 1 deletion UI/ImDebugger/ImDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include "Core/HLE/sceAudiocodec.h"
#include "Core/HLE/sceMp3.h"
#include "Core/HLE/AtracCtx.h"

#include "Core/CoreTiming.h"
// Threads window
#include "Core/HLE/sceKernelThread.h"

Expand All @@ -41,7 +41,36 @@

extern bool g_TakeScreenshot;

void DrawSchedulerView(ImConfig &cfg) {
ImGui::SetNextWindowSize(ImVec2(420, 300), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Event Scheduler", &cfg.schedulerOpen)) {
ImGui::End();
return;
}
s64 ticks = CoreTiming::GetTicks();
if (ImGui::BeginChild("event_list", ImVec2(300.0f, 0.0))) {
const CoreTiming::Event *event = CoreTiming::GetFirstEvent();
while (event) {
ImGui::Text("%s (%lld)", CoreTiming::GetEventTypes()[event->type].name, event->time - ticks);
event = event->next;
}
ImGui::EndChild();
}
ImGui::SameLine();
if (ImGui::BeginChild("general")) {
ImGui::Text("CoreState: %s", CoreStateToString(coreState));
ImGui::Text("downcount: %d", currentMIPS->downcount);
ImGui::Text("slicelength: %d", CoreTiming::slicelength);
ImGui::Text("Ticks: %lld", ticks);
ImGui::Text("Clock (MHz): %0.1f", (float)CoreTiming::GetClockFrequencyHz() / 1000000.0f);
ImGui::Text("Global time (us): %lld", CoreTiming::GetGlobalTimeUs());
ImGui::EndChild();
}
ImGui::End();
}

void DrawRegisterView(MIPSDebugInterface *mipsDebug, bool *open) {
ImGui::SetNextWindowSize(ImVec2(320, 600), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Registers", open)) {
ImGui::End();
return;
Expand Down Expand Up @@ -814,6 +843,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::MenuItem("Registers", nullptr, &cfg_.regsOpen);
ImGui::MenuItem("Callstacks", nullptr, &cfg_.callstackOpen);
ImGui::MenuItem("Breakpoints", nullptr, &cfg_.breakpointsOpen);
ImGui::MenuItem("Scheduler", nullptr, &cfg_.schedulerOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("HLE")) {
Expand Down Expand Up @@ -932,6 +962,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
if (cfg_.geStateOpen) {
DrawGeStateWindow(cfg_, gpuDebug);
}

if (cfg_.schedulerOpen) {
DrawSchedulerView(cfg_);
}
}

void ImDisasmWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, CoreState coreState) {
Expand Down Expand Up @@ -1155,6 +1189,7 @@ void ImConfig::SyncConfig(IniFile *ini, bool save) {
sync.Sync("debugStatsOpen", &debugStatsOpen, false);
sync.Sync("geDebuggerOpen", &geDebuggerOpen, false);
sync.Sync("geStateOpen", &geStateOpen, false);
sync.Sync("schedulerOpen", &schedulerOpen, false);

sync.SetSection(ini->GetOrCreateSection("Settings"));
sync.Sync("displayLatched", &displayLatched, false);
Expand Down
1 change: 1 addition & 0 deletions UI/ImDebugger/ImDebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ struct ImConfig {
bool debugStatsOpen;
bool geDebuggerOpen;
bool geStateOpen;
bool schedulerOpen;

// HLE explorer settings
// bool filterByUsed = true;
Expand Down
14 changes: 14 additions & 0 deletions UI/ImDebugger/ImGe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, GPUDebugInterface *gpuDebug) {
// TODO: This doesn't work correctly.
// GPUDebug::SetBreakNext(GPUDebug::BreakNext::FRAME);
//}

bool disableStepButtons = GPUDebug::GetBreakNext() != GPUDebug::BreakNext::NONE;

if (disableStepButtons) {
ImGui::BeginDisabled();
}
ImGui::SameLine();
if (ImGui::Button("Tex")) {
GPUDebug::SetBreakNext(GPUDebug::BreakNext::TEX);
Expand All @@ -276,6 +282,9 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, GPUDebugInterface *gpuDebug) {
if (ImGui::Button("Single step")) {
GPUDebug::SetBreakNext(GPUDebug::BreakNext::OP);
}
if (disableStepButtons) {
ImGui::EndDisabled();
}

// Line break
if (ImGui::Button("Goto PC")) {
Expand All @@ -290,6 +299,11 @@ void ImGeDebuggerWindow::Draw(ImConfig &cfg, GPUDebugInterface *gpuDebug) {
ImGui::EndPopup();
}

// Display any pending step event.
if (GPUDebug::GetBreakNext() != GPUDebug::BreakNext::NONE) {
ImGui::Text("Step pending (waiting for CPU): %s", GPUDebug::BreakNextToString(GPUDebug::GetBreakNext()));
}

// Let's display the current CLUT.

// First, let's list any active display lists in the left column.
Expand Down

0 comments on commit b3227e5

Please sign in to comment.