Update tracy to 0.12.0

This commit is contained in:
2025-06-02 19:59:55 +03:00
parent 7c5628d47e
commit 6c63c2f650
18 changed files with 832 additions and 467 deletions

View File

@@ -282,7 +282,12 @@ extern "C"
t_SymFromInlineContext _SymFromInlineContext = 0;
t_SymGetLineFromInlineContext _SymGetLineFromInlineContext = 0;
TRACY_API ___tracy_t_RtlWalkFrameChain ___tracy_RtlWalkFrameChain = 0;
typedef unsigned long (__stdcall *___tracy_t_RtlWalkFrameChain)( void**, unsigned long, unsigned long );
___tracy_t_RtlWalkFrameChain ___tracy_RtlWalkFrameChainPtr = nullptr;
TRACY_API unsigned long ___tracy_RtlWalkFrameChain( void** callers, unsigned long count, unsigned long flags)
{
return ___tracy_RtlWalkFrameChainPtr(callers, count, flags);
}
}
struct ModuleCache
@@ -307,7 +312,7 @@ size_t s_krnlCacheCnt;
void InitCallstackCritical()
{
___tracy_RtlWalkFrameChain = (___tracy_t_RtlWalkFrameChain)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "RtlWalkFrameChain" );
___tracy_RtlWalkFrameChainPtr = (___tracy_t_RtlWalkFrameChain)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "RtlWalkFrameChain" );
}
void DbgHelpInit()

View File

@@ -7,7 +7,8 @@
namespace tracy
{
static tracy_force_inline void* Callstack( int /*depth*/ ) { return nullptr; }
static constexpr bool has_callstack() { return false; }
static tracy_force_inline void* Callstack( int32_t /*depth*/ ) { return nullptr; }
}
#else
@@ -36,6 +37,8 @@ static tracy_force_inline void* Callstack( int /*depth*/ ) { return nullptr; }
namespace tracy
{
static constexpr bool has_callstack() { return true; }
struct CallstackSymbolData
{
const char* file;
@@ -77,11 +80,10 @@ debuginfod_client* GetDebuginfodClient();
extern "C"
{
typedef unsigned long (__stdcall *___tracy_t_RtlWalkFrameChain)( void**, unsigned long, unsigned long );
TRACY_API extern ___tracy_t_RtlWalkFrameChain ___tracy_RtlWalkFrameChain;
TRACY_API unsigned long ___tracy_RtlWalkFrameChain( void**, unsigned long, unsigned long );
}
static tracy_force_inline void* Callstack( int depth )
static tracy_force_inline void* Callstack( int32_t depth )
{
assert( depth >= 1 && depth < 63 );
auto trace = (uintptr_t*)tracy_malloc( ( 1 + depth ) * sizeof( uintptr_t ) );
@@ -110,7 +112,7 @@ static _Unwind_Reason_Code tracy_unwind_callback( struct _Unwind_Context* ctx, v
return _URC_NO_REASON;
}
static tracy_force_inline void* Callstack( int depth )
static tracy_force_inline void* Callstack( int32_t depth )
{
assert( depth >= 1 && depth < 63 );
@@ -125,7 +127,7 @@ static tracy_force_inline void* Callstack( int depth )
#elif TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6
static tracy_force_inline void* Callstack( int depth )
static tracy_force_inline void* Callstack( int32_t depth )
{
assert( depth >= 1 );

View File

@@ -78,6 +78,9 @@
#include "TracyArmCpuTable.hpp"
#include "TracySysTrace.hpp"
#if defined TRACY_MANUAL_LIFETIME && !defined(TRACY_DELAYED_INIT)
# error "TRACY_MANUAL_LIFETIME requires enabled TRACY_DELAYED_INIT"
#endif
#ifdef TRACY_PORT
# ifndef TRACY_DATA_PORT
@@ -104,9 +107,12 @@
# include <lmcons.h>
extern "C" typedef LONG (WINAPI *t_RtlGetVersion)( PRTL_OSVERSIONINFOW );
extern "C" typedef BOOL (WINAPI *t_GetLogicalProcessorInformationEx)( LOGICAL_PROCESSOR_RELATIONSHIP, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD );
extern "C" typedef char* (WINAPI *t_WineGetVersion)();
extern "C" typedef char* (WINAPI *t_WineGetBuildId)();
#else
# include <unistd.h>
# include <limits.h>
# include <fcntl.h>
#endif
#if defined __linux__
# include <sys/sysinfo.h>
@@ -528,7 +534,16 @@ static const char* GetHostInfo()
# ifdef __MINGW32__
ptr += sprintf( ptr, "OS: Windows %i.%i.%i (MingW)\n", (int)ver.dwMajorVersion, (int)ver.dwMinorVersion, (int)ver.dwBuildNumber );
# else
ptr += sprintf( ptr, "OS: Windows %lu.%lu.%lu\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber );
auto WineGetVersion = (t_WineGetVersion)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "wine_get_version" );
auto WineGetBuildId = (t_WineGetBuildId)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "wine_get_build_id" );
if( WineGetVersion && WineGetBuildId )
{
ptr += sprintf( ptr, "OS: Windows %lu.%lu.%lu (Wine %s [%s])\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, WineGetVersion(), WineGetBuildId() );
}
else
{
ptr += sprintf( ptr, "OS: Windows %lu.%lu.%lu\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber );
}
# endif
}
#elif defined __linux__
@@ -1388,6 +1403,8 @@ TRACY_API LuaZoneState& GetLuaZoneState() { return s_luaZoneState; }
TRACY_API bool ProfilerAvailable() { return s_instance != nullptr; }
TRACY_API bool ProfilerAllocatorAvailable() { return !RpThreadShutdown; }
constexpr static size_t SafeSendBufferSize = 65536;
Profiler::Profiler()
: m_timeBegin( 0 )
, m_mainThread( detail::GetThreadHandleImpl() )
@@ -1461,6 +1478,21 @@ Profiler::Profiler()
m_userPort = atoi( userPort );
}
m_safeSendBuffer = (char*)tracy_malloc( SafeSendBufferSize );
#ifndef _WIN32
pipe(m_pipe);
# if defined __APPLE__ || defined BSD
// FreeBSD/XNU don't have F_SETPIPE_SZ, so use the default
m_pipeBufSize = 16384;
# else
m_pipeBufSize = (int)(ptrdiff_t)SafeSendBufferSize;
while( fcntl( m_pipe[0], F_SETPIPE_SZ, m_pipeBufSize ) < 0 && errno == EPERM ) m_pipeBufSize /= 2; // too big; reduce
m_pipeBufSize = fcntl( m_pipe[0], F_GETPIPE_SZ );
# endif
fcntl( m_pipe[1], F_SETFL, O_NONBLOCK );
#endif
#if !defined(TRACY_DELAYED_INIT) || !defined(TRACY_MANUAL_LIFETIME)
SpawnWorkerThreads();
#endif
@@ -1486,7 +1518,9 @@ void Profiler::InstallCrashHandler()
#endif
#if defined _WIN32 && !defined TRACY_UWP && !defined TRACY_NO_CRASH_HANDLER
m_exceptionHandler = AddVectoredExceptionHandler( 1, CrashFilter );
// We cannot use Vectored Exception handling because it catches application-wide frame-based SEH blocks. We only
// want to catch unhandled exceptions.
m_prevHandler = SetUnhandledExceptionFilter( CrashFilter );
#endif
#ifndef TRACY_NO_CRASH_HANDLER
@@ -1497,20 +1531,29 @@ void Profiler::InstallCrashHandler()
void Profiler::RemoveCrashHandler()
{
#if defined _WIN32 && !defined TRACY_UWP
if( m_crashHandlerInstalled ) RemoveVectoredExceptionHandler( m_exceptionHandler );
#if defined _WIN32 && !defined TRACY_UWP && !defined TRACY_NO_CRASH_HANDLER
if( m_crashHandlerInstalled )
{
auto prev = SetUnhandledExceptionFilter( (LPTOP_LEVEL_EXCEPTION_FILTER)m_prevHandler );
if( prev != CrashFilter ) SetUnhandledExceptionFilter( prev ); // A different exception filter was installed over ours => put it back
}
#endif
#if defined __linux__ && !defined TRACY_NO_CRASH_HANDLER
if( m_crashHandlerInstalled )
{
sigaction( TRACY_CRASH_SIGNAL, &m_prevSignal.pwr, nullptr );
sigaction( SIGILL, &m_prevSignal.ill, nullptr );
sigaction( SIGFPE, &m_prevSignal.fpe, nullptr );
sigaction( SIGSEGV, &m_prevSignal.segv, nullptr );
sigaction( SIGPIPE, &m_prevSignal.pipe, nullptr );
sigaction( SIGBUS, &m_prevSignal.bus, nullptr );
sigaction( SIGABRT, &m_prevSignal.abrt, nullptr );
auto restore = []( int signum, struct sigaction* prev ) {
struct sigaction old;
sigaction( signum, prev, &old );
if( old.sa_sigaction != CrashHandler ) sigaction( signum, &old, nullptr ); // A different signal handler was installed over ours => put it back
};
restore( TRACY_CRASH_SIGNAL, &m_prevSignal.pwr );
restore( SIGILL, &m_prevSignal.ill );
restore( SIGFPE, &m_prevSignal.fpe );
restore( SIGSEGV, &m_prevSignal.segv );
restore( SIGPIPE, &m_prevSignal.pipe );
restore( SIGBUS, &m_prevSignal.bus );
restore( SIGABRT, &m_prevSignal.abrt );
}
#endif
m_crashHandlerInstalled = false;
@@ -1599,6 +1642,12 @@ Profiler::~Profiler()
tracy_free( m_kcore );
#endif
#ifndef _WIN32
close( m_pipe[0] );
close( m_pipe[1] );
#endif
tracy_free( m_safeSendBuffer );
tracy_free( m_lz4Buf );
tracy_free( m_buffer );
LZ4_freeStream( (LZ4_stream_t*)m_stream );
@@ -2826,6 +2875,15 @@ Profiler::DequeueStatus Profiler::DequeueSerial()
MemWrite( &item->memFree.time, dt );
break;
}
case QueueType::MemDiscard:
case QueueType::MemDiscardCallstack:
{
int64_t t = MemRead<int64_t>( &item->memDiscard.time );
int64_t dt = t - refSerial;
refSerial = t;
MemWrite( &item->memDiscard.time, dt );
break;
}
case QueueType::GpuZoneBeginSerial:
case QueueType::GpuZoneBeginCallstackSerial:
{
@@ -3062,6 +3120,62 @@ bool Profiler::CommitData()
return ret;
}
char* Profiler::SafeCopyProlog( const char* data, size_t size )
{
bool success = true;
char* buf = m_safeSendBuffer;
#ifndef NDEBUG
assert( !m_inUse.exchange(true) );
#endif
if( size > SafeSendBufferSize ) buf = (char*)tracy_malloc( size );
#ifdef _WIN32
__try
{
memcpy( buf, data, size );
}
__except( 1 /*EXCEPTION_EXECUTE_HANDLER*/ )
{
success = false;
}
#else
// Send through the pipe to ensure safe reads
for( size_t offset = 0; offset != size; /*in loop*/ )
{
size_t sendsize = size - offset;
ssize_t result1, result2;
while( ( result1 = write( m_pipe[1], data + offset, sendsize ) ) < 0 && errno == EINTR ) { /* retry */ }
if( result1 < 0 )
{
success = false;
break;
}
while( ( result2 = read( m_pipe[0], buf + offset, result1 ) ) < 0 && errno == EINTR ) { /* retry */ }
if( result2 != result1 )
{
success = false;
break;
}
offset += result1;
}
#endif
if( success ) return buf;
SafeCopyEpilog( buf );
return nullptr;
}
void Profiler::SafeCopyEpilog( char* buf )
{
if( buf != m_safeSendBuffer ) tracy_free( buf );
#ifndef NDEBUG
m_inUse.store( false );
#endif
}
bool Profiler::SendData( const char* data, size_t len )
{
const lz4sz_t lz4sz = LZ4_compress_fast_continue( (LZ4_stream_t*)m_stream, data, m_lz4Buf + sizeof( lz4sz_t ), (int)len, LZ4Size, 1 );
@@ -3750,17 +3864,48 @@ void Profiler::ReportTopology()
# endif
if( !_GetLogicalProcessorInformationEx ) return;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* packageInfo = nullptr;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* dieInfo = nullptr;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* coreInfo = nullptr;
DWORD psz = 0;
_GetLogicalProcessorInformationEx( RelationProcessorPackage, nullptr, &psz );
auto packageInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)tracy_malloc( psz );
auto res = _GetLogicalProcessorInformationEx( RelationProcessorPackage, packageInfo, &psz );
assert( res );
if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
packageInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)tracy_malloc( psz );
auto res = _GetLogicalProcessorInformationEx( RelationProcessorPackage, packageInfo, &psz );
assert( res );
}
else
{
psz = 0;
}
DWORD dsz = 0;
_GetLogicalProcessorInformationEx( RelationProcessorDie, nullptr, &dsz );
if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
dieInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)tracy_malloc( dsz );
auto res = _GetLogicalProcessorInformationEx( RelationProcessorDie, dieInfo, &dsz );
assert( res );
}
else
{
dsz = 0;
}
DWORD csz = 0;
_GetLogicalProcessorInformationEx( RelationProcessorCore, nullptr, &csz );
auto coreInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)tracy_malloc( csz );
res = _GetLogicalProcessorInformationEx( RelationProcessorCore, coreInfo, &csz );
assert( res );
if( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
{
coreInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)tracy_malloc( csz );
auto res = _GetLogicalProcessorInformationEx( RelationProcessorCore, coreInfo, &csz );
assert( res );
}
else
{
csz = 0;
}
SYSTEM_INFO sysinfo;
GetSystemInfo( &sysinfo );
@@ -3788,6 +3933,24 @@ void Profiler::ReportTopology()
idx++;
}
idx = 0;
ptr = dieInfo;
while( (char*)ptr < ((char*)dieInfo) + dsz )
{
assert( ptr->Relationship == RelationProcessorDie );
// FIXME account for GroupCount
auto mask = ptr->Processor.GroupMask[0].Mask;
int core = 0;
while( mask != 0 )
{
if( mask & 1 ) cpuData[core].die = idx;
core++;
mask >>= 1;
}
ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((char*)ptr) + ptr->Size);
idx++;
}
idx = 0;
ptr = coreInfo;
while( (char*)ptr < ((char*)coreInfo) + csz )
@@ -3848,12 +4011,26 @@ void Profiler::ReportTopology()
fclose( f );
cpuData[i].package = uint32_t( atoi( buf ) );
cpuData[i].thread = i;
sprintf( path, "%s%i/topology/core_id", basePath, i );
f = fopen( path, "rb" );
read = fread( buf, 1, 1024, f );
buf[read] = '\0';
fclose( f );
cpuData[i].core = uint32_t( atoi( buf ) );
if( f )
{
read = fread( buf, 1, 1024, f );
buf[read] = '\0';
fclose( f );
cpuData[i].core = uint32_t( atoi( buf ) );
}
sprintf( path, "%s%i/topology/die_id", basePath, i );
f = fopen( path, "rb" );
if( f )
{
read = fread( buf, 1, 1024, f );
buf[read] = '\0';
fclose( f );
cpuData[i].die = uint32_t( atoi( buf ) );
}
}
for( int i=0; i<numcpus; i++ )
@@ -3986,58 +4163,58 @@ void Profiler::ConfigurePlot( const char* name, PlotFormatType type, bool step,
TracyLfqCommit;
}
void Profiler::Message( const char* txt, size_t size, int callstack )
void Profiler::Message( const char* txt, size_t size, int32_t callstack_depth )
{
assert( size < (std::numeric_limits<uint16_t>::max)() );
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
if( callstack != 0 )
if( callstack_depth != 0 && has_callstack() )
{
tracy::GetProfiler().SendCallstack( callstack );
tracy::GetProfiler().SendCallstack( callstack_depth );
}
auto ptr = (char*)tracy_malloc( size );
memcpy( ptr, txt, size );
TracyQueuePrepare( callstack == 0 ? QueueType::Message : QueueType::MessageCallstack );
TracyQueuePrepare( callstack_depth == 0 ? QueueType::Message : QueueType::MessageCallstack );
MemWrite( &item->messageFat.time, GetTime() );
MemWrite( &item->messageFat.text, (uint64_t)ptr );
MemWrite( &item->messageFat.size, (uint16_t)size );
TracyQueueCommit( messageFatThread );
}
void Profiler::Message( const char* txt, int callstack )
void Profiler::Message( const char* txt, int32_t callstack_depth )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
if( callstack != 0 )
if( callstack_depth != 0 && has_callstack() )
{
tracy::GetProfiler().SendCallstack( callstack );
tracy::GetProfiler().SendCallstack( callstack_depth );
}
TracyQueuePrepare( callstack == 0 ? QueueType::MessageLiteral : QueueType::MessageLiteralCallstack );
TracyQueuePrepare( callstack_depth == 0 ? QueueType::MessageLiteral : QueueType::MessageLiteralCallstack );
MemWrite( &item->messageLiteral.time, GetTime() );
MemWrite( &item->messageLiteral.text, (uint64_t)txt );
TracyQueueCommit( messageLiteralThread );
}
void Profiler::MessageColor( const char* txt, size_t size, uint32_t color, int callstack )
void Profiler::MessageColor( const char* txt, size_t size, uint32_t color, int32_t callstack_depth )
{
assert( size < (std::numeric_limits<uint16_t>::max)() );
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
if( callstack != 0 )
if( callstack_depth != 0 && has_callstack() )
{
tracy::GetProfiler().SendCallstack( callstack );
tracy::GetProfiler().SendCallstack( callstack_depth );
}
auto ptr = (char*)tracy_malloc( size );
memcpy( ptr, txt, size );
TracyQueuePrepare( callstack == 0 ? QueueType::MessageColor : QueueType::MessageColorCallstack );
TracyQueuePrepare( callstack_depth == 0 ? QueueType::MessageColor : QueueType::MessageColorCallstack );
MemWrite( &item->messageColorFat.time, GetTime() );
MemWrite( &item->messageColorFat.text, (uint64_t)ptr );
MemWrite( &item->messageColorFat.b, uint8_t( ( color ) & 0xFF ) );
@@ -4047,17 +4224,17 @@ void Profiler::MessageColor( const char* txt, size_t size, uint32_t color, int c
TracyQueueCommit( messageColorFatThread );
}
void Profiler::MessageColor( const char* txt, uint32_t color, int callstack )
void Profiler::MessageColor( const char* txt, uint32_t color, int32_t callstack_depth )
{
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
if( callstack != 0 )
if( callstack_depth != 0 && has_callstack() )
{
tracy::GetProfiler().SendCallstack( callstack );
tracy::GetProfiler().SendCallstack( callstack_depth );
}
TracyQueuePrepare( callstack == 0 ? QueueType::MessageLiteralColor : QueueType::MessageLiteralColorCallstack );
TracyQueuePrepare( callstack_depth == 0 ? QueueType::MessageLiteralColor : QueueType::MessageLiteralColorCallstack );
MemWrite( &item->messageColorLiteral.time, GetTime() );
MemWrite( &item->messageColorLiteral.text, (uint64_t)txt );
MemWrite( &item->messageColorLiteral.b, uint8_t( ( color ) & 0xFF ) );
@@ -4112,23 +4289,25 @@ void Profiler::MemFree( const void* ptr, bool secure )
void Profiler::MemAllocCallstack( const void* ptr, size_t size, int depth, bool secure )
{
if( secure && !ProfilerAvailable() ) return;
#ifdef TRACY_HAS_CALLSTACK
auto& profiler = GetProfiler();
if( depth > 0 && has_callstack() )
{
auto& profiler = GetProfiler();
# ifdef TRACY_ON_DEMAND
if( !profiler.IsConnected() ) return;
if( !profiler.IsConnected() ) return;
# endif
const auto thread = GetThreadHandle();
const auto thread = GetThreadHandle();
auto callstack = Callstack( depth );
auto callstack = Callstack( depth );
profiler.m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemAlloc( QueueType::MemAllocCallstack, thread, ptr, size );
profiler.m_serialLock.unlock();
#else
static_cast<void>(depth); // unused
MemAlloc( ptr, size, secure );
#endif
profiler.m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemAlloc( QueueType::MemAllocCallstack, thread, ptr, size );
profiler.m_serialLock.unlock();
}
else
{
MemAlloc( ptr, size, secure );
}
}
void Profiler::MemFreeCallstack( const void* ptr, int depth, bool secure )
@@ -4139,23 +4318,25 @@ void Profiler::MemFreeCallstack( const void* ptr, int depth, bool secure )
MemFree( ptr, secure );
return;
}
#ifdef TRACY_HAS_CALLSTACK
auto& profiler = GetProfiler();
if( depth > 0 && has_callstack() )
{
auto& profiler = GetProfiler();
# ifdef TRACY_ON_DEMAND
if( !profiler.IsConnected() ) return;
if( !profiler.IsConnected() ) return;
# endif
const auto thread = GetThreadHandle();
const auto thread = GetThreadHandle();
auto callstack = Callstack( depth );
auto callstack = Callstack( depth );
profiler.m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemFree( QueueType::MemFreeCallstack, thread, ptr );
profiler.m_serialLock.unlock();
#else
static_cast<void>(depth); // unused
MemFree( ptr, secure );
#endif
profiler.m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemFree( QueueType::MemFreeCallstack, thread, ptr );
profiler.m_serialLock.unlock();
}
else
{
MemFree( ptr, secure );
}
}
void Profiler::MemAllocNamed( const void* ptr, size_t size, bool secure, const char* name )
@@ -4189,59 +4370,98 @@ void Profiler::MemFreeNamed( const void* ptr, bool secure, const char* name )
void Profiler::MemAllocCallstackNamed( const void* ptr, size_t size, int depth, bool secure, const char* name )
{
if( secure && !ProfilerAvailable() ) return;
#ifdef TRACY_HAS_CALLSTACK
auto& profiler = GetProfiler();
if( depth > 0 && has_callstack() )
{
auto& profiler = GetProfiler();
# ifdef TRACY_ON_DEMAND
if( !profiler.IsConnected() ) return;
if( !profiler.IsConnected() ) return;
# endif
const auto thread = GetThreadHandle();
const auto thread = GetThreadHandle();
auto callstack = Callstack( depth );
auto callstack = Callstack( depth );
profiler.m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemName( name );
SendMemAlloc( QueueType::MemAllocCallstackNamed, thread, ptr, size );
profiler.m_serialLock.unlock();
#else
static_cast<void>(depth); // unused
MemAllocNamed( ptr, size, secure, name );
#endif
profiler.m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemName( name );
SendMemAlloc( QueueType::MemAllocCallstackNamed, thread, ptr, size );
profiler.m_serialLock.unlock();
}
else
{
MemAllocNamed( ptr, size, secure, name );
}
}
void Profiler::MemFreeCallstackNamed( const void* ptr, int depth, bool secure, const char* name )
{
if( secure && !ProfilerAvailable() ) return;
#ifdef TRACY_HAS_CALLSTACK
auto& profiler = GetProfiler();
if( depth > 0 && has_callstack() )
{
auto& profiler = GetProfiler();
# ifdef TRACY_ON_DEMAND
if( !profiler.IsConnected() ) return;
if( !profiler.IsConnected() ) return;
# endif
const auto thread = GetThreadHandle();
auto callstack = Callstack( depth );
profiler.m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemName( name );
SendMemFree( QueueType::MemFreeCallstackNamed, thread, ptr );
profiler.m_serialLock.unlock();
}
else
{
MemFreeNamed( ptr, secure, name );
}
}
void Profiler::MemDiscard( const char* name, bool secure )
{
if( secure && !ProfilerAvailable() ) return;
#ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
#endif
const auto thread = GetThreadHandle();
auto callstack = Callstack( depth );
GetProfiler().m_serialLock.lock();
SendMemDiscard( QueueType::MemDiscard, thread, name );
GetProfiler().m_serialLock.unlock();
}
profiler.m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemName( name );
SendMemFree( QueueType::MemFreeCallstackNamed, thread, ptr );
profiler.m_serialLock.unlock();
#else
static_cast<void>(depth); // unused
MemFreeNamed( ptr, secure, name );
#endif
void Profiler::MemDiscardCallstack( const char* name, bool secure, int32_t depth )
{
if( secure && !ProfilerAvailable() ) return;
if( depth > 0 && has_callstack() )
{
# ifdef TRACY_ON_DEMAND
if( !GetProfiler().IsConnected() ) return;
# endif
const auto thread = GetThreadHandle();
auto callstack = Callstack( depth );
GetProfiler().m_serialLock.lock();
SendCallstackSerial( callstack );
SendMemDiscard( QueueType::MemDiscard, thread, name );
GetProfiler().m_serialLock.unlock();
}
else
{
MemDiscard( name, secure );
}
}
void Profiler::SendCallstack( int depth )
{
#ifdef TRACY_HAS_CALLSTACK
auto ptr = Callstack( depth );
TracyQueuePrepare( QueueType::Callstack );
MemWrite( &item->callstackFat.ptr, (uint64_t)ptr );
TracyQueueCommit( callstackFatThread );
#else
static_cast<void>(depth); // unused
#endif
if( depth > 0 && has_callstack() )
{
auto ptr = Callstack( depth );
TracyQueuePrepare( QueueType::Callstack );
MemWrite( &item->callstackFat.ptr, (uint64_t)ptr );
TracyQueueCommit( callstackFatThread );
}
}
void Profiler::ParameterRegister( ParameterCallback cb, void* data )
@@ -4266,7 +4486,7 @@ void Profiler::ParameterSetup( uint32_t idx, const char* name, bool isBool, int3
TracyLfqCommit;
}
void Profiler::SendCallstack( int depth, const char* skipBefore )
void Profiler::SendCallstack( int32_t depth, const char* skipBefore )
{
#ifdef TRACY_HAS_CALLSTACK
auto ptr = Callstack( depth );
@@ -4341,13 +4561,12 @@ void Profiler::HandleSymbolCodeQuery( uint64_t symbol, uint32_t size )
}
else
{
if( !EnsureReadable( symbol ) )
{
AckSymbolCodeNotAvailable();
return;
}
auto&& lambda = [ this, symbol ]( const char* buf, size_t size ) {
SendLongString( symbol, buf, size, QueueType::SymbolCode );
};
SendLongString( symbol, (const char*)symbol, size, QueueType::SymbolCode );
// 'symbol' may have come from a module that has since unloaded, perform a safe copy before sending
if( !WithSafeCopy( (const char*)symbol, size, lambda ) ) AckSymbolCodeNotAvailable();
}
}
@@ -4471,7 +4690,7 @@ int64_t Profiler::GetTimeQpc()
extern "C" {
#endif
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin( const struct ___tracy_source_location_data* srcloc, int active )
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin( const struct ___tracy_source_location_data* srcloc, int32_t active )
{
___tracy_c_zone_context ctx;
#ifdef TRACY_ON_DEMAND
@@ -4499,7 +4718,7 @@ TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin( const struct ___tracy_source_l
return ctx;
}
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_callstack( const struct ___tracy_source_location_data* srcloc, int depth, int active )
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_callstack( const struct ___tracy_source_location_data* srcloc, int32_t depth, int32_t active )
{
___tracy_c_zone_context ctx;
#ifdef TRACY_ON_DEMAND
@@ -4518,17 +4737,21 @@ TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_callstack( const struct ___trac
TracyQueueCommitC( zoneValidationThread );
}
#endif
tracy::GetProfiler().SendCallstack( depth );
auto zoneQueue = tracy::QueueType::ZoneBegin;
if( depth > 0 && tracy::has_callstack() )
{
TracyQueuePrepareC( tracy::QueueType::ZoneBeginCallstack );
tracy::MemWrite( &item->zoneBegin.time, tracy::Profiler::GetTime() );
tracy::MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );
TracyQueueCommitC( zoneBeginThread );
tracy::GetProfiler().SendCallstack( depth );
zoneQueue = tracy::QueueType::ZoneBeginCallstack;
}
TracyQueuePrepareC( zoneQueue );
tracy::MemWrite( &item->zoneBegin.time, tracy::Profiler::GetTime() );
tracy::MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );
TracyQueueCommitC( zoneBeginThread );
return ctx;
}
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc( uint64_t srcloc, int active )
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc( uint64_t srcloc, int32_t active )
{
___tracy_c_zone_context ctx;
#ifdef TRACY_ON_DEMAND
@@ -4560,7 +4783,7 @@ TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc( uint64_t srcloc, int act
return ctx;
}
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc_callstack( uint64_t srcloc, int depth, int active )
TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc_callstack( uint64_t srcloc, int32_t depth, int32_t active )
{
___tracy_c_zone_context ctx;
#ifdef TRACY_ON_DEMAND
@@ -4583,13 +4806,17 @@ TRACY_API TracyCZoneCtx ___tracy_emit_zone_begin_alloc_callstack( uint64_t srclo
TracyQueueCommitC( zoneValidationThread );
}
#endif
tracy::GetProfiler().SendCallstack( depth );
auto zoneQueue = tracy::QueueType::ZoneBeginAllocSrcLoc;
if( depth > 0 && tracy::has_callstack() )
{
TracyQueuePrepareC( tracy::QueueType::ZoneBeginAllocSrcLocCallstack );
tracy::MemWrite( &item->zoneBegin.time, tracy::Profiler::GetTime() );
tracy::MemWrite( &item->zoneBegin.srcloc, srcloc );
TracyQueueCommitC( zoneBeginThread );
tracy::GetProfiler().SendCallstack( depth );
zoneQueue = tracy::QueueType::ZoneBeginAllocSrcLocCallstack;
}
TracyQueuePrepareC( zoneQueue );
tracy::MemWrite( &item->zoneBegin.time, tracy::Profiler::GetTime() );
tracy::MemWrite( &item->zoneBegin.srcloc, srcloc );
TracyQueueCommitC( zoneBeginThread );
return ctx;
}
@@ -4687,26 +4914,78 @@ TRACY_API void ___tracy_emit_zone_value( TracyCZoneCtx ctx, uint64_t value )
}
}
TRACY_API void ___tracy_emit_memory_alloc( const void* ptr, size_t size, int secure ) { tracy::Profiler::MemAlloc( ptr, size, secure != 0 ); }
TRACY_API void ___tracy_emit_memory_alloc_callstack( const void* ptr, size_t size, int depth, int secure ) { tracy::Profiler::MemAllocCallstack( ptr, size, depth, secure != 0 ); }
TRACY_API void ___tracy_emit_memory_free( const void* ptr, int secure ) { tracy::Profiler::MemFree( ptr, secure != 0 ); }
TRACY_API void ___tracy_emit_memory_free_callstack( const void* ptr, int depth, int secure ) { tracy::Profiler::MemFreeCallstack( ptr, depth, secure != 0 ); }
TRACY_API void ___tracy_emit_memory_alloc_named( const void* ptr, size_t size, int secure, const char* name ) { tracy::Profiler::MemAllocNamed( ptr, size, secure != 0, name ); }
TRACY_API void ___tracy_emit_memory_alloc_callstack_named( const void* ptr, size_t size, int depth, int secure, const char* name ) { tracy::Profiler::MemAllocCallstackNamed( ptr, size, depth, secure != 0, name ); }
TRACY_API void ___tracy_emit_memory_free_named( const void* ptr, int secure, const char* name ) { tracy::Profiler::MemFreeNamed( ptr, secure != 0, name ); }
TRACY_API void ___tracy_emit_memory_free_callstack_named( const void* ptr, int depth, int secure, const char* name ) { tracy::Profiler::MemFreeCallstackNamed( ptr, depth, secure != 0, name ); }
TRACY_API void ___tracy_emit_memory_alloc( const void* ptr, size_t size, int32_t secure ) { tracy::Profiler::MemAlloc( ptr, size, secure != 0 ); }
TRACY_API void ___tracy_emit_memory_alloc_callstack( const void* ptr, size_t size, int32_t depth, int32_t secure )
{
if( depth > 0 && tracy::has_callstack() )
{
tracy::Profiler::MemAllocCallstack( ptr, size, depth, secure != 0 );
}
else
{
tracy::Profiler::MemAlloc( ptr, size, secure != 0 );
}
}
TRACY_API void ___tracy_emit_memory_free( const void* ptr, int32_t secure ) { tracy::Profiler::MemFree( ptr, secure != 0 ); }
TRACY_API void ___tracy_emit_memory_free_callstack( const void* ptr, int32_t depth, int32_t secure )
{
if( depth > 0 && tracy::has_callstack() )
{
tracy::Profiler::MemFreeCallstack( ptr, depth, secure != 0 );
}
else
{
tracy::Profiler::MemFree( ptr, secure != 0 );
}
}
TRACY_API void ___tracy_emit_memory_discard( const char* name, int32_t secure ) { tracy::Profiler::MemDiscard( name, secure != 0 ); }
TRACY_API void ___tracy_emit_memory_discard_callstack( const char* name, int32_t secure, int32_t depth )
{
if( depth > 0 && tracy::has_callstack() )
{
tracy::Profiler::MemDiscardCallstack( name, secure != 0, depth );
}
else
{
tracy::Profiler::MemDiscard( name, secure != 0 );
}
}
TRACY_API void ___tracy_emit_memory_alloc_named( const void* ptr, size_t size, int32_t secure, const char* name ) { tracy::Profiler::MemAllocNamed( ptr, size, secure != 0, name ); }
TRACY_API void ___tracy_emit_memory_alloc_callstack_named( const void* ptr, size_t size, int32_t depth, int32_t secure, const char* name )
{
if( depth > 0 && tracy::has_callstack() )
{
tracy::Profiler::MemAllocCallstackNamed( ptr, size, depth, secure != 0, name );
}
else
{
tracy::Profiler::MemAllocNamed( ptr, size, secure != 0, name );
}
}
TRACY_API void ___tracy_emit_memory_free_named( const void* ptr, int32_t secure, const char* name ) { tracy::Profiler::MemFreeNamed( ptr, secure != 0, name ); }
TRACY_API void ___tracy_emit_memory_free_callstack_named( const void* ptr, int32_t depth, int32_t secure, const char* name )
{
if( depth > 0 && tracy::has_callstack() )
{
tracy::Profiler::MemFreeCallstackNamed( ptr, depth, secure != 0, name );
}
else
{
tracy::Profiler::MemFreeNamed( ptr, secure != 0, name );
}
}
TRACY_API void ___tracy_emit_frame_mark( const char* name ) { tracy::Profiler::SendFrameMark( name ); }
TRACY_API void ___tracy_emit_frame_mark_start( const char* name ) { tracy::Profiler::SendFrameMark( name, tracy::QueueType::FrameMarkMsgStart ); }
TRACY_API void ___tracy_emit_frame_mark_end( const char* name ) { tracy::Profiler::SendFrameMark( name, tracy::QueueType::FrameMarkMsgEnd ); }
TRACY_API void ___tracy_emit_frame_image( const void* image, uint16_t w, uint16_t h, uint8_t offset, int flip ) { tracy::Profiler::SendFrameImage( image, w, h, offset, flip ); }
TRACY_API void ___tracy_emit_frame_image( const void* image, uint16_t w, uint16_t h, uint8_t offset, int32_t flip ) { tracy::Profiler::SendFrameImage( image, w, h, offset, flip != 0 ); }
TRACY_API void ___tracy_emit_plot( const char* name, double val ) { tracy::Profiler::PlotData( name, val ); }
TRACY_API void ___tracy_emit_plot_float( const char* name, float val ) { tracy::Profiler::PlotData( name, val ); }
TRACY_API void ___tracy_emit_plot_int( const char* name, int64_t val ) { tracy::Profiler::PlotData( name, val ); }
TRACY_API void ___tracy_emit_plot_config( const char* name, int type, int step, int fill, uint32_t color ) { tracy::Profiler::ConfigurePlot( name, tracy::PlotFormatType(type), step, fill, color ); }
TRACY_API void ___tracy_emit_message( const char* txt, size_t size, int callstack ) { tracy::Profiler::Message( txt, size, callstack ); }
TRACY_API void ___tracy_emit_messageL( const char* txt, int callstack ) { tracy::Profiler::Message( txt, callstack ); }
TRACY_API void ___tracy_emit_messageC( const char* txt, size_t size, uint32_t color, int callstack ) { tracy::Profiler::MessageColor( txt, size, color, callstack ); }
TRACY_API void ___tracy_emit_messageLC( const char* txt, uint32_t color, int callstack ) { tracy::Profiler::MessageColor( txt, color, callstack ); }
TRACY_API void ___tracy_emit_plot_config( const char* name, int32_t type, int32_t step, int32_t fill, uint32_t color ) { tracy::Profiler::ConfigurePlot( name, tracy::PlotFormatType(type), step != 0, fill != 0, color ); }
TRACY_API void ___tracy_emit_message( const char* txt, size_t size, int32_t callstack_depth ) { tracy::Profiler::Message( txt, size, callstack_depth ); }
TRACY_API void ___tracy_emit_messageL( const char* txt, int32_t callstack_depth ) { tracy::Profiler::Message( txt, callstack_depth ); }
TRACY_API void ___tracy_emit_messageC( const char* txt, size_t size, uint32_t color, int32_t callstack_depth ) { tracy::Profiler::MessageColor( txt, size, color, callstack_depth ); }
TRACY_API void ___tracy_emit_messageLC( const char* txt, uint32_t color, int32_t callstack_depth ) { tracy::Profiler::MessageColor( txt, color, callstack_depth ); }
TRACY_API void ___tracy_emit_message_appinfo( const char* txt, size_t size ) { tracy::Profiler::MessageAppInfo( txt, size ); }
TRACY_API uint64_t ___tracy_alloc_srcloc( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, uint32_t color ) {
@@ -5004,7 +5283,7 @@ TRACY_API void ___tracy_terminate_lockable_ctx( struct __tracy_lockable_context_
tracy::tracy_free((void*)lockdata);
}
TRACY_API int ___tracy_before_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )
TRACY_API int32_t ___tracy_before_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )
{
#ifdef TRACY_ON_DEMAND
bool queue = false;
@@ -5016,7 +5295,7 @@ TRACY_API int ___tracy_before_lock_lockable_ctx( struct __tracy_lockable_context
if( active != connected ) lockdata->m_active.store( connected, std::memory_order_relaxed );
if( connected ) queue = true;
}
if( !queue ) return false;
if( !queue ) return static_cast<int32_t>(false);
#endif
auto item = tracy::Profiler::QueueSerial();
@@ -5025,7 +5304,7 @@ TRACY_API int ___tracy_before_lock_lockable_ctx( struct __tracy_lockable_context
tracy::MemWrite( &item->lockWait.id, lockdata->m_id );
tracy::MemWrite( &item->lockWait.time, tracy::Profiler::GetTime() );
tracy::Profiler::QueueSerialFinish();
return true;
return static_cast<int32_t>(true);
}
TRACY_API void ___tracy_after_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata )
@@ -5057,7 +5336,7 @@ TRACY_API void ___tracy_after_unlock_lockable_ctx( struct __tracy_lockable_conte
tracy::Profiler::QueueSerialFinish();
}
TRACY_API void ___tracy_after_try_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata, int acquired )
TRACY_API void ___tracy_after_try_lock_lockable_ctx( struct __tracy_lockable_context_data* lockdata, int32_t acquired )
{
#ifdef TRACY_ON_DEMAND
if( !acquired ) return;
@@ -5122,9 +5401,9 @@ TRACY_API void ___tracy_custom_name_lockable_ctx( struct __tracy_lockable_contex
tracy::Profiler::QueueSerialFinish();
}
TRACY_API int ___tracy_connected( void )
TRACY_API int32_t ___tracy_connected( void )
{
return tracy::GetProfiler().IsConnected();
return static_cast<int32_t>( tracy::GetProfiler().IsConnected() );
}
#ifdef TRACY_FIBERS
@@ -5132,7 +5411,7 @@ TRACY_API void ___tracy_fiber_enter( const char* fiber ){ tracy::Profiler::Enter
TRACY_API void ___tracy_fiber_leave( void ){ tracy::Profiler::LeaveFiber(); }
#endif
# ifdef TRACY_MANUAL_LIFETIME
# if defined TRACY_MANUAL_LIFETIME && defined TRACY_DELAYED_INIT
TRACY_API void ___tracy_startup_profiler( void )
{
tracy::StartupProfiler();
@@ -5143,9 +5422,9 @@ TRACY_API void ___tracy_shutdown_profiler( void )
tracy::ShutdownProfiler();
}
TRACY_API int ___tracy_profiler_started( void )
TRACY_API int32_t ___tracy_profiler_started( void )
{
return tracy::s_isProfilerStarted.load( std::memory_order_seq_cst );
return static_cast<int32_t>( tracy::s_isProfilerStarted.load( std::memory_order_seq_cst ) );
}
# endif

View File

@@ -97,11 +97,11 @@ struct LuaZoneState
#define TracyLfqPrepare( _type ) \
moodycamel::ConcurrentQueueDefaultTraits::index_t __magic; \
auto __token = GetToken(); \
tracy::moodycamel::ConcurrentQueueDefaultTraits::index_t __magic; \
auto __token = tracy::GetToken(); \
auto& __tail = __token->get_tail_index(); \
auto item = __token->enqueue_begin( __magic ); \
MemWrite( &item->hdr.type, _type );
tracy::MemWrite( &item->hdr.type, _type );
#define TracyLfqCommit \
__tail.store( __magic + 1, std::memory_order_release );
@@ -119,11 +119,11 @@ struct LuaZoneState
#ifdef TRACY_FIBERS
# define TracyQueuePrepare( _type ) \
auto item = Profiler::QueueSerial(); \
MemWrite( &item->hdr.type, _type );
auto item = tracy::Profiler::QueueSerial(); \
tracy::MemWrite( &item->hdr.type, _type );
# define TracyQueueCommit( _name ) \
MemWrite( &item->_name.thread, GetThreadHandle() ); \
Profiler::QueueSerialFinish();
tracy::MemWrite( &item->_name.thread, tracy::GetThreadHandle() ); \
tracy::Profiler::QueueSerialFinish();
# define TracyQueuePrepareC( _type ) \
auto item = tracy::Profiler::QueueSerial(); \
tracy::MemWrite( &item->hdr.type, _type );
@@ -283,6 +283,8 @@ public:
static void MemFreeNamed( const void* ptr, bool secure, const char* name );
static void MemAllocCallstackNamed( const void* ptr, size_t size, int depth, bool secure, const char* name );
static void MemFreeCallstackNamed( const void* ptr, int depth, bool secure, const char* name );
static void MemDiscard( const char* name, bool secure );
static void MemDiscardCallstack( const char* name, bool secure, int32_t depth );
static void SendCallstack( int depth );
static void ParameterRegister( ParameterCallback cb, void* data );
static void ParameterSetup( uint32_t idx, const char* name, bool isBool, int32_t val );
@@ -312,7 +314,7 @@ public:
}
#endif
void SendCallstack( int depth, const char* skipBefore );
void SendCallstack( int32_t depth, const char* skipBefore );
static void CutCallstack( void* callstack, const char* skipBefore );
static bool ShouldExit();
@@ -420,7 +422,7 @@ private:
void InstallCrashHandler();
void RemoveCrashHandler();
void ClearQueues( tracy::moodycamel::ConsumerToken& token );
void ClearSerial();
DequeueStatus Dequeue( tracy::moodycamel::ConsumerToken& token );
@@ -453,6 +455,21 @@ private:
m_bufferOffset += int( len );
}
char* SafeCopyProlog( const char* p, size_t size );
void SafeCopyEpilog( char* buf );
template<class Callable> // must be void( const char* buf, size_t size )
bool WithSafeCopy( const char* p, size_t size, Callable&& callable )
{
if( char* buf = SafeCopyProlog( p, size ) )
{
callable( buf, size );
SafeCopyEpilog( buf );
return true;
}
return false;
}
bool SendData( const char* data, size_t len );
void SendLongString( uint64_t ptr, const char* str, size_t len, QueueType type );
void SendSourceLocation( uint64_t ptr );
@@ -482,14 +499,13 @@ private:
static tracy_force_inline void SendCallstackSerial( void* ptr )
{
#ifdef TRACY_HAS_CALLSTACK
auto item = GetProfiler().m_serialQueue.prepare_next();
MemWrite( &item->hdr.type, QueueType::CallstackSerial );
MemWrite( &item->callstackFat.ptr, (uint64_t)ptr );
GetProfiler().m_serialQueue.commit_next();
#else
static_cast<void>(ptr); // unused
#endif
if( has_callstack() )
{
auto item = GetProfiler().m_serialQueue.prepare_next();
MemWrite( &item->hdr.type, QueueType::CallstackSerial );
MemWrite( &item->callstackFat.ptr, (uint64_t)ptr );
GetProfiler().m_serialQueue.commit_next();
}
}
static tracy_force_inline void SendMemAlloc( QueueType type, const uint32_t thread, const void* ptr, size_t size )
@@ -527,6 +543,18 @@ private:
GetProfiler().m_serialQueue.commit_next();
}
static tracy_force_inline void SendMemDiscard( QueueType type, const uint32_t thread, const char* name )
{
assert( type == QueueType::MemDiscard || type == QueueType::MemDiscardCallstack );
auto item = GetProfiler().m_serialQueue.prepare_next();
MemWrite( &item->hdr.type, type );
MemWrite( &item->memDiscard.time, GetTime() );
MemWrite( &item->memDiscard.thread, thread );
MemWrite( &item->memDiscard.name, (uint64_t)name );
GetProfiler().m_serialQueue.commit_next();
}
static tracy_force_inline void SendMemName( const char* name )
{
assert( name );
@@ -610,9 +638,19 @@ private:
char* m_queryData;
char* m_queryDataPtr;
#if defined _WIN32
void* m_exceptionHandler;
#ifndef NDEBUG
// m_safeSendBuffer and m_pipe should only be used by the Tracy Profiler thread; this ensures that in debug builds.
std::atomic_bool m_inUse{ false };
#endif
char* m_safeSendBuffer;
#if defined _WIN32
void* m_prevHandler;
#else
int m_pipe[2];
int m_pipeBufSize;
#endif
#ifdef __linux__
struct {
struct sigaction pwr, ill, fpe, segv, pipe, bus, abrt;

View File

@@ -10,6 +10,8 @@
#include "../common/TracyAlign.hpp"
#include "../common/TracyAlloc.hpp"
#include "../client/TracyLock.hpp"
#include "TracyProfiler.hpp"
#include "TracyCallstack.hpp"
namespace tracy
{
@@ -35,7 +37,7 @@ void ScopedZone::End()
TracyQueueCommit( zoneEndThread );
}
ScopedZone::ScopedZone( const SourceLocationData* srcloc, bool is_active )
ScopedZone::ScopedZone( const SourceLocationData* srcloc, int32_t depth, bool is_active )
#ifdef TRACY_ON_DEMAND
: m_active( is_active && GetProfiler().IsConnected() )
#else
@@ -46,13 +48,19 @@ ScopedZone::ScopedZone( const SourceLocationData* srcloc, bool is_active )
#ifdef TRACY_ON_DEMAND
m_connectionId = GetProfiler().ConnectionId();
#endif
TracyQueuePrepare( QueueType::ZoneBegin );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );
TracyQueueCommit( zoneBeginThread );
}
auto zoneQueue = QueueType::ZoneBegin;
if( depth > 0 && has_callstack() )
{
GetProfiler().SendCallstack( depth );
zoneQueue = QueueType::ZoneBeginCallstack;
}
TracyQueuePrepare( zoneQueue );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );
TracyQueueCommit( zoneBeginThread );
}
ScopedZone::ScopedZone( const SourceLocationData* srcloc, int depth, bool is_active )
ScopedZone::ScopedZone( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, uint32_t color, int32_t depth, bool is_active )
#ifdef TRACY_ON_DEMAND
: m_active( is_active && GetProfiler().IsConnected() )
#else
@@ -63,55 +71,21 @@ ScopedZone::ScopedZone( const SourceLocationData* srcloc, int depth, bool is_act
#ifdef TRACY_ON_DEMAND
m_connectionId = GetProfiler().ConnectionId();
#endif
GetProfiler().SendCallstack( depth );
auto zoneQueue = QueueType::ZoneBeginAllocSrcLoc;
if( depth > 0 && has_callstack() )
{
GetProfiler().SendCallstack( depth );
zoneQueue = QueueType::ZoneBeginAllocSrcLocCallstack;
}
TracyQueuePrepare( zoneQueue );
const auto srcloc =
Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz, color );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, srcloc );
TracyQueueCommit( zoneBeginThread );
}
TracyQueuePrepare( QueueType::ZoneBeginCallstack );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );
TracyQueueCommit( zoneBeginThread );
}
ScopedZone::ScopedZone( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, uint32_t color, bool is_active )
#ifdef TRACY_ON_DEMAND
: m_active( is_active && GetProfiler().IsConnected() )
#else
: m_active( is_active )
#endif
{
if( !m_active ) return;
#ifdef TRACY_ON_DEMAND
m_connectionId = GetProfiler().ConnectionId();
#endif
TracyQueuePrepare( QueueType::ZoneBeginAllocSrcLoc );
const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz, color );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, srcloc );
TracyQueueCommit( zoneBeginThread );
}
ScopedZone::ScopedZone( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, bool is_active ) : ScopedZone( line, source, sourceSz, function, functionSz, name, nameSz, static_cast<uint32_t>(0), is_active ) {}
ScopedZone::ScopedZone( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, uint32_t color, int depth, bool is_active )
#ifdef TRACY_ON_DEMAND
: m_active( is_active && GetProfiler().IsConnected() )
#else
: m_active( is_active )
#endif
{
if( !m_active ) return;
#ifdef TRACY_ON_DEMAND
m_connectionId = GetProfiler().ConnectionId();
#endif
GetProfiler().SendCallstack( depth );
TracyQueuePrepare( QueueType::ZoneBeginAllocSrcLocCallstack );
const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz, color );
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
MemWrite( &item->zoneBegin.srcloc, srcloc );
TracyQueueCommit( zoneBeginThread );
}
ScopedZone::ScopedZone( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, int depth, bool is_active ) : ScopedZone( line, source, sourceSz, function, functionSz, name, nameSz, 0, depth, is_active ) {}
ScopedZone::ScopedZone( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const char* name, size_t nameSz, int32_t depth, bool is_active ) : ScopedZone( line, source, sourceSz, function, functionSz, name, nameSz, 0, depth, is_active ) {}
ScopedZone::~ScopedZone()
{

View File

@@ -85,7 +85,7 @@ void SysPower::ScanDirectory( const char* path, int parent )
FILE* f = fopen( tmp, "r" );
if( f )
{
fscanf( f, "%" PRIu64, &maxRange );
(void)fscanf( f, "%" PRIu64, &maxRange );
fclose( f );
}
}

View File

@@ -173,8 +173,11 @@ void WINAPI EventRecordCallback( PEVENT_RECORD record )
MemWrite( &item->contextSwitch.oldThread, cswitch->oldThreadId );
MemWrite( &item->contextSwitch.newThread, cswitch->newThreadId );
MemWrite( &item->contextSwitch.cpu, record->BufferContext.ProcessorNumber );
MemWrite( &item->contextSwitch.reason, cswitch->oldThreadWaitReason );
MemWrite( &item->contextSwitch.state, cswitch->oldThreadState );
MemWrite( &item->contextSwitch.oldThreadWaitReason, cswitch->oldThreadWaitReason );
MemWrite( &item->contextSwitch.oldThreadState, cswitch->oldThreadState );
MemWrite( &item->contextSwitch.newThreadPriority, cswitch->newThreadPriority );
MemWrite( &item->contextSwitch.oldThreadPriority, cswitch->oldThreadPriority );
MemWrite( &item->contextSwitch.previousCState, cswitch->previousCState );
TracyLfqCommit;
}
else if( hdr.EventDescriptor.Opcode == 50 )
@@ -183,7 +186,10 @@ void WINAPI EventRecordCallback( PEVENT_RECORD record )
TracyLfqPrepare( QueueType::ThreadWakeup );
MemWrite( &item->threadWakeup.time, hdr.TimeStamp.QuadPart );
MemWrite( &item->threadWakeup.cpu, record->BufferContext.ProcessorNumber );
MemWrite( &item->threadWakeup.thread, rt->threadId );
MemWrite( &item->threadWakeup.adjustReason, rt->adjustReason );
MemWrite( &item->threadWakeup.adjustIncrement, rt->adjustIncrement );
TracyLfqCommit;
}
else if( hdr.EventDescriptor.Opcode == 1 || hdr.EventDescriptor.Opcode == 3 )
@@ -498,11 +504,11 @@ void SysTraceGetExternalName( uint64_t thread, const char*& threadName, const ch
if( _GetThreadDescription )
{
PWSTR tmp;
_GetThreadDescription( hnd, &tmp );
char buf[256];
if( tmp )
if ( SUCCEEDED( _GetThreadDescription( hnd, &tmp ) ) )
{
char buf[256];
auto ret = wcstombs( buf, tmp, 256 );
LocalFree(tmp);
if( ret != 0 )
{
threadName = CopyString( buf, ret );
@@ -678,7 +684,7 @@ enum TraceEventId
EventBranchMiss,
EventVsync,
EventContextSwitch,
EventWakeup,
EventWaking,
};
static void ProbePreciseIp( perf_event_attr& pe, unsigned long long config0, unsigned long long config1, pid_t pid )
@@ -767,16 +773,16 @@ bool SysTraceStart( int64_t& samplingPeriod )
TracyDebug( "perf_event_paranoid: %i\n", paranoidLevel );
#endif
int switchId = -1, wakeupId = -1, vsyncId = -1;
int switchId = -1, wakingId = -1, vsyncId = -1;
const auto switchIdStr = ReadFile( "/sys/kernel/debug/tracing/events/sched/sched_switch/id" );
if( switchIdStr ) switchId = atoi( switchIdStr );
const auto wakeupIdStr = ReadFile( "/sys/kernel/debug/tracing/events/sched/sched_wakeup/id" );
if( wakeupIdStr ) wakeupId = atoi( wakeupIdStr );
const auto wakingIdStr = ReadFile( "/sys/kernel/debug/tracing/events/sched/sched_waking/id" );
if( wakingIdStr ) wakingId = atoi( wakingIdStr );
const auto vsyncIdStr = ReadFile( "/sys/kernel/debug/tracing/events/drm/drm_vblank_event/id" );
if( vsyncIdStr ) vsyncId = atoi( vsyncIdStr );
TracyDebug( "sched_switch id: %i\n", switchId );
TracyDebug( "sched_wakeup id: %i\n", wakeupId );
TracyDebug( "sched_waking id: %i\n", wakingId );
TracyDebug( "drm_vblank_event id: %i\n", vsyncId );
#ifdef TRACY_NO_SAMPLING
@@ -831,7 +837,7 @@ bool SysTraceStart( int64_t& samplingPeriod )
2 + // CPU cycles + instructions retired
2 + // cache reference + miss
2 + // branch retired + miss
2 + // context switches + wakeups
2 + // context switches + waking ups
1 // vsync
);
s_ring = (RingBuffer*)tracy_malloc( sizeof( RingBuffer ) * maxNumBuffers );
@@ -1076,18 +1082,31 @@ bool SysTraceStart( int64_t& samplingPeriod )
}
}
if( wakeupId != -1 )
if( wakingId != -1 )
{
pe.config = wakeupId;
pe.config &= ~PERF_SAMPLE_CALLCHAIN;
pe = {};
pe.type = PERF_TYPE_TRACEPOINT;
pe.size = sizeof( perf_event_attr );
pe.sample_period = 1;
pe.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_RAW;
// Coult ask for callstack here
//pe.sample_type |= PERF_SAMPLE_CALLCHAIN;
pe.disabled = 1;
pe.inherit = 1;
pe.config = wakingId;
pe.read_format = 0;
#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 )
pe.use_clockid = 1;
pe.clockid = CLOCK_MONOTONIC_RAW;
#endif
TracyDebug( "Setup wakeup capture\n" );
TracyDebug( "Setup waking up capture\n" );
for( int i=0; i<s_numCpus; i++ )
{
const int fd = perf_event_open( &pe, -1, i, -1, PERF_FLAG_FD_CLOEXEC );
if( fd != -1 )
{
new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventWakeup, i );
new( s_ring+s_numBuffers ) RingBuffer( 64*1024, fd, EventWaking, i );
if( s_ring[s_numBuffers].IsValid() )
{
s_numBuffers++;
@@ -1332,6 +1351,7 @@ void SysTraceWorker( void* ptr )
hadData = true;
while( activeNum > 0 )
{
// Find the earliest event from the active buffers
int sel = -1;
int selPos;
int64_t t0 = std::numeric_limits<int64_t>::max();
@@ -1369,6 +1389,7 @@ void SysTraceWorker( void* ptr )
}
}
}
// Found any event
if( sel >= 0 )
{
auto& ring = ringArray[ctxBufferIdx + sel];
@@ -1384,10 +1405,10 @@ void SysTraceWorker( void* ptr )
const auto rid = ring.GetId();
if( rid == EventContextSwitch )
{
// Layout:
// u64 time
// u64 cnt
// u64 ip[cnt]
// Layout: See /sys/kernel/debug/tracing/events/sched/sched_switch/format
// u64 time // PERF_SAMPLE_TIME
// u64 cnt // PERF_SAMPLE_CALLCHAIN
// u64 ip[cnt] // PERF_SAMPLE_CALLCHAIN
// u32 size
// u8 data[size]
// Data (not ABI stable, but has not changed since it was added, in 2009):
@@ -1408,35 +1429,43 @@ void SysTraceWorker( void* ptr )
const auto traceOffset = offset;
offset += sizeof( uint64_t ) * cnt + sizeof( uint32_t ) + 8 + 16;
uint32_t prev_pid, next_pid;
uint32_t prev_pid, prev_prio;
uint32_t next_pid, next_prio;
long prev_state;
ring.Read( &prev_pid, offset, sizeof( uint32_t ) );
offset += sizeof( uint32_t ) + sizeof( uint32_t );
offset += sizeof( uint32_t );
ring.Read( &prev_prio, offset, sizeof( uint32_t ) );
offset += sizeof( uint32_t );
ring.Read( &prev_state, offset, sizeof( long ) );
offset += sizeof( long ) + 16;
ring.Read( &next_pid, offset, sizeof( uint32_t ) );
offset += sizeof( uint32_t );
ring.Read( &next_prio, offset, sizeof( uint32_t ) );
uint8_t reason = 100;
uint8_t state;
uint8_t oldThreadWaitReason = 100;
uint8_t oldThreadState;
if( prev_state & 0x0001 ) state = 104;
else if( prev_state & 0x0002 ) state = 101;
else if( prev_state & 0x0004 ) state = 105;
else if( prev_state & 0x0008 ) state = 106;
else if( prev_state & 0x0010 ) state = 108;
else if( prev_state & 0x0020 ) state = 109;
else if( prev_state & 0x0040 ) state = 110;
else if( prev_state & 0x0080 ) state = 102;
else state = 103;
if( prev_state & 0x0001 ) oldThreadState = 104;
else if( prev_state & 0x0002 ) oldThreadState = 101;
else if( prev_state & 0x0004 ) oldThreadState = 105;
else if( prev_state & 0x0008 ) oldThreadState = 106;
else if( prev_state & 0x0010 ) oldThreadState = 108;
else if( prev_state & 0x0020 ) oldThreadState = 109;
else if( prev_state & 0x0040 ) oldThreadState = 110;
else if( prev_state & 0x0080 ) oldThreadState = 102;
else oldThreadState = 103;
TracyLfqPrepare( QueueType::ContextSwitch );
MemWrite( &item->contextSwitch.time, t0 );
MemWrite( &item->contextSwitch.oldThread, prev_pid );
MemWrite( &item->contextSwitch.newThread, next_pid );
MemWrite( &item->contextSwitch.cpu, uint8_t( ring.GetCpu() ) );
MemWrite( &item->contextSwitch.reason, reason );
MemWrite( &item->contextSwitch.state, state );
MemWrite( &item->contextSwitch.oldThreadWaitReason, oldThreadWaitReason );
MemWrite( &item->contextSwitch.oldThreadState, oldThreadState );
MemWrite( &item->contextSwitch.previousCState, uint8_t( 0 ) );
MemWrite( &item->contextSwitch.newThreadPriority, int8_t( next_prio ) );
MemWrite( &item->contextSwitch.oldThreadPriority, int8_t( prev_prio ) );
TracyLfqCommit;
if( cnt > 0 && prev_pid != 0 && CurrentProcOwnsThread( prev_pid ) )
@@ -1450,27 +1479,33 @@ void SysTraceWorker( void* ptr )
TracyLfqCommit;
}
}
else if( rid == EventWakeup )
else if( rid == EventWaking)
{
// See /sys/kernel/debug/tracing/events/sched/sched_waking/format
// Layout:
// u64 time
// u64 time // PERF_SAMPLE_TIME
// u32 size
// u8 data[size]
// Data:
// u8 hdr[8]
// u8 comm[16]
// u32 pid
// u32 prio
// u64 target_cpu
offset += sizeof( perf_event_header ) + sizeof( uint64_t ) + sizeof( uint32_t ) + 8 + 16;
// i32 prio
// i32 target_cpu
const uint32_t dataOffset = sizeof( perf_event_header ) + sizeof( uint64_t ) + sizeof( uint32_t );
offset += dataOffset + 8 + 16;
uint32_t pid;
ring.Read( &pid, offset, sizeof( uint32_t ) );
TracyLfqPrepare( QueueType::ThreadWakeup );
MemWrite( &item->threadWakeup.time, t0 );
MemWrite( &item->threadWakeup.thread, pid );
MemWrite( &item->threadWakeup.cpu, (uint8_t)ring.GetCpu() );
int8_t adjustReason = -1; // Does not exist on Linux
int8_t adjustIncrement = 0; // Should perhaps store the new prio?
MemWrite( &item->threadWakeup.adjustReason, adjustReason );
MemWrite( &item->threadWakeup.adjustIncrement, adjustIncrement );
TracyLfqCommit;
}
else

View File

@@ -690,7 +690,9 @@ static pthread_key_t _memory_thread_heap;
# define _Thread_local __declspec(thread)
# define TLS_MODEL
# else
# ifndef __HAIKU__
# if defined(__ANDROID__) && __ANDROID_API__ >= 29 && defined(__NDK_MAJOR__) && __NDK_MAJOR__ >= 26
# define TLS_MODEL __attribute__((tls_model("local-dynamic")))
# elif !defined(__HAIKU__)
# define TLS_MODEL __attribute__((tls_model("initial-exec")))
# else
# define TLS_MODEL