Initial tracy profiler support

This commit is contained in:
Mr-Wiseguy 2025-08-10 02:08:20 -04:00
parent d34934aa7e
commit c75f35be57
10 changed files with 276 additions and 4 deletions

View file

@ -5,6 +5,8 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS OFF)
set(LIBRECOMP_TRACY_PATH "" CACHE STRING "Include path for Tracy library, if used.")
# Define the library
add_library(librecomp STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/ai.cpp"
@ -52,6 +54,11 @@ target_compile_options(librecomp PRIVATE
-Wno-unused-parameter
)
if(NOT LIBRECOMP_TRACY_PATH STREQUAL "")
target_compile_definitions(librecomp PRIVATE "TRACY_ENABLED")
target_include_directories(librecomp PRIVATE ${ULTRAMODERN_TRACY_PATH})
endif()
if (WIN32)
add_compile_definitions(NOMINMAX)
endif()

View file

@ -3,6 +3,7 @@
#include <string>
#include <ultramodern/ultra64.h>
#include <ultramodern/ultramodern.hpp>
#include <ultramodern/ultramodern_tracy.hpp>
#define VI_NTSC_CLOCK 48681812
@ -13,9 +14,13 @@ extern "C" void osAiSetFrequency_recomp(uint8_t* rdram, recomp_context* ctx) {
//freq = VI_NTSC_CLOCK / dacRate;
ctx->r2 = freq;
ultramodern::set_audio_frequency(freq);
std::string tracy_message = "Set AI Freq: " + std::to_string(freq);
TracyMessage(tracy_message.c_str(), tracy_message.size() + 1);
}
extern "C" void osAiSetNextBuffer_recomp(uint8_t* rdram, recomp_context* ctx) {
ZoneScoped;
ultramodern::queue_audio_buffer(rdram, ctx->r4, ctx->r5);
ctx->r2 = 0;
}

View file

@ -10,6 +10,7 @@
#include "librecomp/files.hpp"
#include <ultramodern/ultra64.h>
#include <ultramodern/ultramodern.hpp>
#include <ultramodern/ultramodern_tracy.hpp>
static std::vector<uint8_t> rom;
@ -310,6 +311,7 @@ void do_dma(RDRAM_ARG PTR(OSMesgQueue) mq, gpr rdram_address, uint32_t physical_
}
extern "C" void osPiStartDma_recomp(RDRAM_ARG recomp_context* ctx) {
ZoneScoped;
uint32_t mb = ctx->r4;
uint32_t pri = ctx->r5;
uint32_t direction = ctx->r6;
@ -327,6 +329,7 @@ extern "C" void osPiStartDma_recomp(RDRAM_ARG recomp_context* ctx) {
}
extern "C" void osEPiStartDma_recomp(RDRAM_ARG recomp_context* ctx) {
ZoneScoped;
OSPiHandle* handle = TO_PTR(OSPiHandle, ctx->r4);
OSIoMesg* mb = TO_PTR(OSIoMesg, ctx->r5);
uint32_t direction = ctx->r6;
@ -344,6 +347,7 @@ extern "C" void osEPiStartDma_recomp(RDRAM_ARG recomp_context* ctx) {
}
extern "C" void osEPiReadIo_recomp(RDRAM_ARG recomp_context * ctx) {
ZoneScoped;
OSPiHandle* handle = TO_PTR(OSPiHandle, ctx->r4);
uint32_t devAddr = handle->baseAddress | ctx->r5;
gpr dramAddr = ctx->r6;

View file

@ -1,6 +1,7 @@
#include <cstdio>
#include <fstream>
#include <ultramodern/ultramodern.hpp>
#include <ultramodern/ultramodern_tracy.hpp>
#include "recomp.h"
extern "C" void osSpTaskLoad_recomp(uint8_t* rdram, recomp_context* ctx) {
@ -10,6 +11,7 @@ extern "C" void osSpTaskLoad_recomp(uint8_t* rdram, recomp_context* ctx) {
bool dump_frame = false;
extern "C" void osSpTaskStartGo_recomp(uint8_t* rdram, recomp_context* ctx) {
ZoneScoped;
//printf("[sp] osSpTaskStartGo(0x%08X)\n", (uint32_t)ctx->r4);
OSTask* task = TO_PTR(OSTask, ctx->r4);
if (task->t.type == M_GFXTASK) {

View file

@ -5,6 +5,8 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_EXTENSIONS OFF)
set(ULTRAMODERN_TRACY_PATH "" CACHE STRING "Include path for Tracy library, if used.")
add_library(ultramodern STATIC
"${CMAKE_CURRENT_SOURCE_DIR}/src/audio.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/error_handling.cpp"
@ -35,6 +37,11 @@ target_compile_options(ultramodern PRIVATE
-Wno-unused-parameter
)
if(NOT ULTRAMODERN_TRACY_PATH STREQUAL "")
target_compile_definitions(ultramodern PRIVATE "TRACY_ENABLED")
target_include_directories(ultramodern PRIVATE ${ULTRAMODERN_TRACY_PATH})
endif()
if (WIN32)
add_compile_definitions(NOMINMAX)
endif()

View file

@ -0,0 +1,218 @@
#ifndef __ULTRAMODERN_TRACY_H__
#define __ULTRAMODERN_TRACY_H__
#ifdef TRACY_ENABLED
# define TRACY_ENABLE
# include <tracy/Tracy.hpp>
# include <tracy/TracyC.h>
namespace tracy {
void SetThreadName( const char* name );
void SetThreadNameWithHint( const char* name, int32_t groupHint );
const char* GetThreadName( uint32_t id );
const char* GetEnvVar( const char* name );
}
#define TracySetThreadName(name) tracy::SetThreadName(name)
#define TracySetThreadNameWithHint(name, groupHint) tracy::SetThreadNameWithHint(name, groupHint)
#else
// C++ API
# define TracyNoop
# define ZoneNamed(x,y)
# define ZoneNamedN(x,y,z)
# define ZoneNamedC(x,y,z)
# define ZoneNamedNC(x,y,z,w)
# define ZoneTransient(x,y)
# define ZoneTransientN(x,y,z)
# define ZoneScoped
# define ZoneScopedN(x)
# define ZoneScopedC(x)
# define ZoneScopedNC(x,y)
# define ZoneText(x,y)
# define ZoneTextV(x,y,z)
# define ZoneTextF(x,...)
# define ZoneTextVF(x,y,...)
# define ZoneName(x,y)
# define ZoneNameV(x,y,z)
# define ZoneNameF(x,...)
# define ZoneNameVF(x,y,...)
# define ZoneColor(x)
# define ZoneColorV(x,y)
# define ZoneValue(x)
# define ZoneValueV(x,y)
# define ZoneIsActive false
# define ZoneIsActiveV(x) false
# define FrameMark
# define FrameMarkNamed(x)
# define FrameMarkStart(x)
# define FrameMarkEnd(x)
# define FrameImage(x,y,z,w,a)
# define TracyLockable( type, varname ) type varname
# define TracyLockableN( type, varname, desc ) type varname
# define TracySharedLockable( type, varname ) type varname
# define TracySharedLockableN( type, varname, desc ) type varname
# define LockableBase( type ) type
# define SharedLockableBase( type ) type
# define LockMark(x) (void)x
# define LockableName(x,y,z)
# define TracyPlot(x,y)
# define TracyPlotConfig(x,y,z,w,a)
# define TracyMessage(x,y)
# define TracyMessageL(x)
# define TracyMessageC(x,y,z)
# define TracyMessageLC(x,y)
# define TracyAppInfo(x,y)
# define TracyAlloc(x,y)
# define TracyFree(x)
# define TracySecureAlloc(x,y)
# define TracySecureFree(x)
# define TracyAllocN(x,y,z)
# define TracyFreeN(x,y)
# define TracySecureAllocN(x,y,z)
# define TracySecureFreeN(x,y)
# define ZoneNamedS(x,y,z)
# define ZoneNamedNS(x,y,z,w)
# define ZoneNamedCS(x,y,z,w)
# define ZoneNamedNCS(x,y,z,w,a)
# define ZoneTransientS(x,y,z)
# define ZoneTransientNS(x,y,z,w)
# define ZoneScopedS(x)
# define ZoneScopedNS(x,y)
# define ZoneScopedCS(x,y)
# define ZoneScopedNCS(x,y,z)
# define TracyAllocS(x,y,z)
# define TracyFreeS(x,y)
# define TracySecureAllocS(x,y,z)
# define TracySecureFreeS(x,y)
# define TracyAllocNS(x,y,z,w)
# define TracyFreeNS(x,y,z)
# define TracySecureAllocNS(x,y,z,w)
# define TracySecureFreeNS(x,y,z)
# define TracyMessageS(x,y,z)
# define TracyMessageLS(x,y)
# define TracyMessageCS(x,y,z,w)
# define TracyMessageLCS(x,y,z)
# define TracySourceCallbackRegister(x,y)
# define TracyParameterRegister(x,y)
# define TracyParameterSetup(x,y,z,w)
# define TracyIsConnected false
# define TracyIsStarted false
# define TracySetProgramName(x)
# define TracyFiberEnter(x)
# define TracyFiberEnterHint(x,y)
# define TracyFiberLeave
// C API
typedef const void* TracyCZoneCtx;
typedef const void* TracyCLockCtx;
# define TracyCZone(c,x)
# define TracyCZoneN(c,x,y)
# define TracyCZoneC(c,x,y)
# define TracyCZoneNC(c,x,y,z)
# define TracyCZoneEnd(c)
# define TracyCZoneText(c,x,y)
# define TracyCZoneName(c,x,y)
# define TracyCZoneColor(c,x)
# define TracyCZoneValue(c,x)
# define TracyCAlloc(x,y)
# define TracyCFree(x)
# define TracyCMemoryDiscard(x)
# define TracyCSecureAlloc(x,y)
# define TracyCSecureFree(x)
# define TracyCSecureMemoryDiscard(x)
# define TracyCAllocN(x,y,z)
# define TracyCFreeN(x,y)
# define TracyCSecureAllocN(x,y,z)
# define TracyCSecureFreeN(x,y)
# define TracyCFrameMark
# define TracyCFrameMarkNamed(x)
# define TracyCFrameMarkStart(x)
# define TracyCFrameMarkEnd(x)
# define TracyCFrameImage(x,y,z,w,a)
# define TracyCPlot(x,y)
# define TracyCPlotF(x,y)
# define TracyCPlotI(x,y)
# define TracyCPlotConfig(x,y,z,w,a)
# define TracyCMessage(x,y)
# define TracyCMessageL(x)
# define TracyCMessageC(x,y,z)
# define TracyCMessageLC(x,y)
# define TracyCAppInfo(x,y)
# define TracyCZoneS(x,y,z)
# define TracyCZoneNS(x,y,z,w)
# define TracyCZoneCS(x,y,z,w)
# define TracyCZoneNCS(x,y,z,w,a)
# define TracyCAllocS(x,y,z)
# define TracyCFreeS(x,y)
# define TracyCMemoryDiscardS(x,y)
# define TracyCSecureAllocS(x,y,z)
# define TracyCSecureFreeS(x,y)
# define TracyCSecureMemoryDiscardS(x,y)
# define TracyCAllocNS(x,y,z,w)
# define TracyCFreeNS(x,y,z)
# define TracyCSecureAllocNS(x,y,z,w)
# define TracyCSecureFreeNS(x,y,z)
# define TracyCMessageS(x,y,z)
# define TracyCMessageLS(x,y)
# define TracyCMessageCS(x,y,z,w)
# define TracyCMessageLCS(x,y,z)
# define TracyCLockCtx(l)
# define TracyCLockAnnounce(l)
# define TracyCLockTerminate(l)
# define TracyCLockBeforeLock(l)
# define TracyCLockAfterLock(l)
# define TracyCLockAfterUnlock(l)
# define TracyCLockAfterTryLock(l,x)
# define TracyCLockMark(l)
# define TracyCLockCustomName(l,x,y)
# define TracyCIsConnected 0
# define TracyCIsStarted 0
# define TracyCFiberEnter(fiber)
# define TracyCFiberLeave
// Other tracy functions
#define TracySetThreadName(name)
#define TracySetThreadNameWithHint(name, groupHint)
#endif
#endif

View file

@ -13,6 +13,7 @@
#include "ultramodern/ultra64.h"
#include "ultramodern/ultramodern.hpp"
#include "ultramodern/ultramodern_tracy.hpp"
#include "ultramodern/rsp.hpp"
#include "ultramodern/renderer_context.hpp"
@ -231,6 +232,7 @@ void vi_thread_func() {
ViState* cur_state = events_context.vi.get_cur_state();
if (remaining_retraces == 0) {
if (cur_state->mq != NULLPTR) {
TracyMessageL("VI Event");
if (osSendMesg(PASS_RDRAM cur_state->mq, cur_state->msg, OS_MESG_NOBLOCK) == -1) {
//printf("Game skipped a VI frame!\n");
}
@ -238,6 +240,7 @@ void vi_thread_func() {
remaining_retraces = cur_state->retrace_count;
}
if (events_context.ai.mq != NULLPTR) {
TracyMessageL("AI Event");
if (osSendMesg(PASS_RDRAM events_context.ai.mq, events_context.ai.msg, OS_MESG_NOBLOCK) == -1) {
//printf("Game skipped a AI frame!\n");
}
@ -367,7 +370,10 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
ultramodern::measure_input_latency();
[[maybe_unused]] auto renderer_start = std::chrono::high_resolution_clock::now();
renderer_context->send_dl(&task_action->task);
{
ZoneScopedN("Displaylist");
renderer_context->send_dl(&task_action->task);
}
[[maybe_unused]] auto renderer_end = std::chrono::high_resolution_clock::now();
dp_complete();
// printf("Renderer ProcessDList time: %d us\n", static_cast<u32>(std::chrono::duration_cast<std::chrono::microseconds>(renderer_end - renderer_start).count()));
@ -444,6 +450,7 @@ void set_dummy_vi(bool odd) {
}
extern "C" void osViSwapBuffer(RDRAM_ARG PTR(void) frameBufPtr) {
ZoneScoped;
std::lock_guard lock{ events_context.message_mutex };
events_context.vi.get_next_state()->framebuffer = frameBufPtr;
}

View file

@ -3,6 +3,7 @@
#include "ultramodern/input.hpp"
#include "ultramodern/ultra64.h"
#include "ultramodern/ultramodern.hpp"
#include "ultramodern/ultramodern_tracy.hpp"
static ultramodern::input::callbacks_t input_callbacks {};
@ -104,6 +105,7 @@ extern "C" s32 osContStartQuery(RDRAM_ARG PTR(OSMesgQueue) mq) {
}
extern "C" s32 osContStartReadData(RDRAM_ARG PTR(OSMesgQueue) mq) {
ZoneScoped;
if (input_callbacks.poll_input != nullptr) {
input_callbacks.poll_input();
}
@ -128,6 +130,7 @@ extern "C" void osContGetQuery(RDRAM_ARG PTR(OSContStatus) data_) {
}
extern "C" void osContGetReadData(OSContPad *data) {
ZoneScoped;
for (int controller = 0; controller < max_controllers; controller++) {
uint16_t buttons = 0;
float x = 0.0f;
@ -168,6 +171,7 @@ s32 osMotorStart(RDRAM_ARG PTR(OSPfs) pfs) {
}
s32 __osMotorAccess(RDRAM_ARG PTR(OSPfs) pfs_, s32 flag) {
ZoneScoped;
OSPfs *pfs = TO_PTR(OSPfs, pfs_);
if (input_callbacks.set_rumble != nullptr) {

View file

@ -2,6 +2,7 @@
#include <cstring>
#include "ultramodern/rsp.hpp"
#include "ultramodern/ultramodern_tracy.hpp"
static ultramodern::rsp::callbacks_t rsp_callbacks {};
@ -16,6 +17,7 @@ void ultramodern::rsp::init() {
}
bool ultramodern::rsp::run_task(RDRAM_ARG const OSTask* task) {
ZoneScoped;
assert(rsp_callbacks.run_task != nullptr);
return rsp_callbacks.run_task(PASS_RDRAM task);

View file

@ -5,6 +5,7 @@
#include "ultramodern/ultra64.h"
#include "ultramodern/ultramodern.hpp"
#include "ultramodern/ultramodern_tracy.hpp"
#include "blockingconcurrentqueue.h"
#include "ultramodern/threads.hpp"
@ -146,8 +147,14 @@ void ultramodern::set_native_thread_name(const std::string& name) {
void ultramodern::set_native_thread_priority(ThreadPriority pri) {}
#endif
void wait_for_resumed(RDRAM_ARG UltraThreadContext* thread_context) {
void wait_for_resumed(RDRAM_ARG UltraThreadContext* thread_context, bool first_start = false) {
if (!first_start) {
// TracyMessageL("Pause");
}
thread_context->running.wait();
if (!first_start) {
// TracyMessageL("Resume");
}
// If this thread's context was replaced by another thread or deleted, destroy it again from its own context.
// This will trigger thread cleanup instead.
if (TO_PTR(OSThread, ultramodern::this_thread())->context != thread_context) {
@ -189,9 +196,15 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry
is_game_thread = true;
// Set the thread name
ultramodern::set_native_thread_name(ultramodern::threads::get_game_thread_name(self));
std::string thread_name = ultramodern::threads::get_game_thread_name(self);
// Copy the thread name into the fixed address buffer (for profiling).
ultramodern::set_native_thread_name(thread_name);
ultramodern::set_native_thread_priority(ultramodern::ThreadPriority::High);
// Set the thread name in tracy and the thread group to 0x1064 to indicate a game thread.
TracySetThreadNameWithHint(thread_name.c_str(), 0x1064);
// Signal the initialized semaphore to indicate that this thread can be started.
thread_context->initialized.signal();
@ -199,10 +212,13 @@ static void _thread_func(RDRAM_ARG PTR(OSThread) self_, PTR(thread_func_t) entry
// Wait until the thread is marked as running.
try {
wait_for_resumed(PASS_RDRAM thread_context);
ZoneScopedN("Wait for Start");
wait_for_resumed(PASS_RDRAM thread_context, true);
} catch (ultramodern::thread_terminated& terminated) {
}
TracyMessageL("Start");
// Make sure the thread wasn't replaced or destroyed before it was started.
if (self->context == thread_context) {
debug_printf("[Thread] Thread started: %d\n", self->id);