From 4e520cfc187b7811901ecc109655ff919247d041 Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Sun, 30 Aug 2026 16:08:49 +0200 Subject: [PATCH] Add the external target API. --- monitor/src/monitor.cpp | 9 +++- public/client/TracyCallstack.cpp | 83 ++++++++++++++++++++++++++++---- public/client/TracyCallstack.hpp | 5 +- 3 files changed, 85 insertions(+), 12 deletions(-) diff --git a/monitor/src/monitor.cpp b/monitor/src/monitor.cpp index 0a3a864d..c2c95512 100644 --- a/monitor/src/monitor.cpp +++ b/monitor/src/monitor.cpp @@ -167,7 +167,7 @@ static int RunAttached( pid_t pid ) if( !PreflightPerfEventOpen( pid ) ) return 1; - tracy::InitExternalImageCache( pid ); + if( !tracy::InitExternalTarget( pid ) ) return 1; tracy::___tracy_magic_pid_override = (uint32_t)pid; tracy::StartupProfiler(); @@ -272,7 +272,12 @@ static int RunForked( int argc, char** argv ) } // Initialize the external image cache (target's /proc/pid/maps) - tracy::InitExternalImageCache( childPid ); + if( !tracy::InitExternalTarget( childPid ) ) + { + kill( childPid, SIGKILL ); + waitpid( childPid, nullptr, 0 ); + return 1; + } // Set up the profiler to target the child tracy::___tracy_magic_pid_override = (uint32_t)childPid; diff --git a/public/client/TracyCallstack.cpp b/public/client/TracyCallstack.cpp index 9944a861..76486cb1 100644 --- a/public/client/TracyCallstack.cpp +++ b/public/client/TracyCallstack.cpp @@ -347,6 +347,12 @@ void DestroyImageCaches() #ifdef __linux__ +# include +# include +# include +# include +# include + static constexpr uint32_t ExtPT_LOAD = 1; @@ -361,7 +367,9 @@ struct ExternalImageEntry }; static FastVector* s_extImages = nullptr; -static pid_t s_externalPid = 0; +static pid_t s_externalTargetPid = 0; +static char s_externalTargetName[64] = {}; +static uint64_t s_externalTargetExeMtime = 0; static bool s_extImagesSorted = true; // Wall-clock second of the last /proc//maps re-parse. Used to rate-limit // refreshes so addresses that never resolve (JIT, vDSO, stack) do not trigger @@ -495,13 +503,13 @@ static const ExternalImageEntry* FindExternalImageRefresh( uint64_t address ) auto entry = FindExternalImage( address ); if( entry ) return entry; - if( s_externalPid != 0 ) + if( s_externalTargetPid != 0 ) { const int64_t now = (int64_t)time( nullptr ); if( now != s_lastMapsRefresh ) { s_lastMapsRefresh = now; - ParseExternalProcMaps( s_externalPid ); + ParseExternalProcMaps( s_externalTargetPid ); return FindExternalImage( address ); } } @@ -567,15 +575,72 @@ static void ExternalSymInfoCb( void* data, uintptr_t pc, const char* symname, ui sd.symsize = symsize; } -void InitExternalImageCache( pid_t pid ) +bool InitExternalTarget( pid_t targetPid ) { - s_externalPid = pid; + if( kill( targetPid, 0 ) != 0 ) + { + fprintf( stderr, "Tracy: cannot profile pid %d: %s\n", (int)targetPid, strerror( errno ) ); + return false; + } + + char path[64]; + snprintf( path, sizeof( path ), "/proc/%d/comm", (int)targetPid ); + FILE* f = fopen( path, "r" ); + if( !f ) + { + fprintf( stderr, "Tracy: cannot read %s: %s\n", path, strerror( errno ) ); + return false; + } + char comm[64] = {}; + if( !fgets( comm, sizeof( comm ), f ) ) + { + fclose( f ); + fprintf( stderr, "Tracy: cannot read %s: %s\n", path, strerror( errno ) ); + return false; + } + fclose( f ); + size_t len = strlen( comm ); + while( len > 0 && ( comm[len-1] == '\n' || comm[len-1] == '\r' ) ) len--; + if( len >= sizeof( s_externalTargetName ) ) len = sizeof( s_externalTargetName ) - 1; + memcpy( s_externalTargetName, comm, len ); + s_externalTargetName[len] = '\0'; + + snprintf( path, sizeof( path ), "/proc/%d/exe", (int)targetPid ); + { + const int exeFd = open( path, O_RDONLY ); + if( exeFd < 0 ) + { + fprintf( stderr, "Tracy: cannot read %s: %s\n", path, strerror( errno ) ); + return false; + } + struct stat exeSt; + if( fstat( exeFd, &exeSt ) == 0 ) s_externalTargetExeMtime = (uint64_t)exeSt.st_mtime; + close( exeFd ); + } + + s_externalTargetPid = targetPid; if( !s_extImages ) { s_extImages = (FastVector*)tracy_malloc( sizeof( FastVector ) ); new (s_extImages) FastVector( 64 ); } - ParseExternalProcMaps( pid ); + ParseExternalProcMaps( targetPid ); + return true; +} + +uint32_t GetExternalTargetPid() +{ + return (uint32_t)s_externalTargetPid; +} + +const char* GetExternalTargetName() +{ + return s_externalTargetName; +} + +uint64_t GetExternalTargetExeTime() +{ + return s_externalTargetExeMtime; } #endif // __linux__ @@ -1485,7 +1550,7 @@ const char* DecodeCallstackPtrFast( uint64_t ptr ) static char ret[1024]; #ifdef __linux__ - if( s_externalPid != 0 && s_extImages ) return DecodeCallstackPtrFastExternal( ptr ); + if( s_externalTargetPid != 0 && s_extImages ) return DecodeCallstackPtrFastExternal( ptr ); #endif auto vptr = (void*)ptr; @@ -1560,7 +1625,7 @@ CallstackSymbolData DecodeSymbolAddress( uint64_t ptr ) CallstackSymbolData sym; #ifdef __linux__ - if( s_externalPid != 0 && s_extImages ) return DecodeSymbolAddressExternal( ptr ); + if( s_externalTargetPid != 0 && s_extImages ) return DecodeSymbolAddressExternal( ptr ); #endif if( cb_bts ) @@ -1801,7 +1866,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr ) if( !IsKernelAddress( ptr ) ) { #ifdef __linux__ - if( s_externalPid != 0 && s_extImages ) return DecodeCallstackPtrExternal( ptr ); + if( s_externalTargetPid != 0 && s_extImages ) return DecodeCallstackPtrExternal( ptr ); #endif const char* imageName = nullptr; diff --git a/public/client/TracyCallstack.hpp b/public/client/TracyCallstack.hpp index 221c9895..41ac5826 100644 --- a/public/client/TracyCallstack.hpp +++ b/public/client/TracyCallstack.hpp @@ -89,7 +89,10 @@ void EndCallstack(); const char* GetKernelModulePath( uint64_t addr ); #ifdef __linux__ -void InitExternalImageCache( pid_t pid ); +bool InitExternalTarget( pid_t targetPid ); +uint32_t GetExternalTargetPid(); +const char* GetExternalTargetName(); +uint64_t GetExternalTargetExeTime(); #endif #ifdef TRACY_DEBUGINFOD