From 79cb60025d6523fc103df2362803793dad12ca7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gr=C3=A9goire?= Date: Mon, 2 Feb 2026 15:21:52 +0100 Subject: [PATCH 1/7] Monotonic clock fallback for systrace --- public/client/TracySysTrace.cpp | 55 ++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index d012c417..074344ca 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -596,6 +596,11 @@ bool SysTraceStart( int64_t& samplingPeriod ) TracyDebug( "sched_waking id: %i", wakingId ); TracyDebug( "drm_vblank_event id: %i", vsyncId ); + bool useMonotonicClockRaw = !HardwareSupportsInvariantTSC(); +#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) + useMonotonicClockRaw = true; +#endif + #ifdef TRACY_NO_SAMPLING const bool noSoftwareSampling = true; #else @@ -666,11 +671,12 @@ bool SysTraceStart( int64_t& samplingPeriod ) #endif pe.disabled = 1; pe.freq = 1; - pe.inherit = 1; -#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 + pe.inherit = 1; + if( useMonotonicClockRaw ) + { + pe.use_clockid = 1; + pe.clockid = CLOCK_MONOTONIC_RAW; + } if( !noSoftwareSampling ) { @@ -711,11 +717,12 @@ bool SysTraceStart( int64_t& samplingPeriod ) pe.exclude_guest = 1; pe.exclude_hv = 1; pe.freq = 1; - pe.inherit = 1; -#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 + pe.inherit = 1; + if( useMonotonicClockRaw ) + { + pe.use_clockid = 1; + pe.clockid = CLOCK_MONOTONIC_RAW; + } if( !noRetirement ) { @@ -838,10 +845,11 @@ bool SysTraceStart( int64_t& samplingPeriod ) pe.sample_type = PERF_SAMPLE_TIME | PERF_SAMPLE_RAW; pe.disabled = 1; pe.config = vsyncId; -#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 + if( useMonotonicClockRaw ) + { + pe.use_clockid = 1; + pe.clockid = CLOCK_MONOTONIC_RAW; + } TracyDebug( "Setup vsync capture" ); for( int i=0; i Date: Mon, 2 Feb 2026 16:10:36 +0100 Subject: [PATCH 2/7] Add TRACY_DISALLOW_HW_TIMER for VMs / WSL2 --- CMakeLists.txt | 1 + meson.build | 5 +++++ meson.options | 1 + public/client/TracyProfiler.hpp | 2 +- public/client/TracySysTrace.cpp | 4 ++++ 5 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 712e0975..4bcd40e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,6 +137,7 @@ set_option(TRACY_MANUAL_LIFETIME "Enable the manual lifetime management of the p set_option(TRACY_FIBERS "Enable fibers support" OFF) set_option(TRACY_NO_CRASH_HANDLER "Disable crash handling" OFF) set_option(TRACY_TIMER_FALLBACK "Use lower resolution timers" OFF) +set_option(TRACY_DISALLOW_HW_TIMER "Disallow hardware timer (may be useful on VMs). Requires TRACY_TIMER_FALLBACK=ON" OFF) set_option(TRACY_LIBUNWIND_BACKTRACE "Use libunwind backtracing where supported" OFF) set_option(TRACY_SYMBOL_OFFLINE_RESOLVE "Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution" OFF) set_option(TRACY_LIBBACKTRACE_ELF_DYNLOAD_SUPPORT "Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation" OFF) diff --git a/meson.build b/meson.build index 7b81aedb..8c23250a 100644 --- a/meson.build +++ b/meson.build @@ -93,6 +93,11 @@ if get_option('timer_fallback') tracy_common_args += ['-DTRACY_TIMER_FALLBACK'] endif + +if get_option('disallow_hw_timer') + tracy_common_args += ['-DTRACY_DISALLOW_HW_TIMER'] +endif + if get_option('no_crash_handler') tracy_common_args += ['-DTRACY_NO_CRASH_HANDLER'] endif diff --git a/meson.options b/meson.options index d57d6b27..d8025055 100644 --- a/meson.options +++ b/meson.options @@ -16,6 +16,7 @@ option('no_frame_image', type : 'boolean', value : false, description : 'Disable option('no_system_tracing', type : 'boolean', value : false, description : 'Disable systrace sampling') option('patchable_nopsleds', type : 'boolean', value : false, description : 'Enable nopsleds for efficient patching by system-level tools (e.g. rr)') option('timer_fallback', type : 'boolean', value : false, description : 'Use lower resolution timers') +option('disallow_hw_timer', type : 'boolean', value : false, description : 'Disallow hardware timer (may be useful on VMs). Requires timer_fallback.') option('libunwind_backtrace', type : 'boolean', value : false, description : 'Use libunwind backtracing where supported') option('symbol_offline_resolve', type : 'boolean', value : false, description : 'Instead of full runtime symbol resolution, only resolve the image path and offset to enable offline symbol resolution') option('libbacktrace_elf_dynload_support', type : 'boolean', value : false, description : 'Enable libbacktrace to support dynamically loaded elfs in symbol resolution resolution after the first symbol resolve operation') diff --git a/public/client/TracyProfiler.hpp b/public/client/TracyProfiler.hpp index 88598fc1..80cbec51 100644 --- a/public/client/TracyProfiler.hpp +++ b/public/client/TracyProfiler.hpp @@ -28,7 +28,7 @@ # include #endif -#if ( (defined _WIN32 && !(defined _M_ARM64 || defined _M_ARM)) || ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) || ( defined TARGET_OS_IOS && TARGET_OS_IOS == 1 ) || ( defined __APPLE__ && defined __MACH__ && TARGET_CPU_ARM64 ) ) +#if !defined TRACY_DISALLOW_HW_TIMER && ( (defined _WIN32 && !(defined _M_ARM64 || defined _M_ARM)) || ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) || ( defined TARGET_OS_IOS && TARGET_OS_IOS == 1 ) || ( defined __APPLE__ && defined __MACH__ && TARGET_CPU_ARM64 ) ) # define TRACY_HW_TIMER #endif diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index 074344ca..27b246c1 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -600,6 +600,10 @@ bool SysTraceStart( int64_t& samplingPeriod ) #if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) useMonotonicClockRaw = true; #endif + if( useMonotonicClockRaw ) + { + TracyDebug( "Using CLOCK_MONOTONIC_RAW for Linux perf events." ); + } #ifdef TRACY_NO_SAMPLING const bool noSoftwareSampling = true; From 2b2fafbcfc139d04fb017bd1c162eff86a8c0e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gr=C3=A9goire?= Date: Mon, 9 Feb 2026 11:30:24 +0100 Subject: [PATCH 3/7] Start cleaning TRACY_HW_TIMER checks. Ideally I think we might want to have TRACY_HW_TIMER mean only TSC/CNTVCT, and define TRACY_TIMER_FALLBACK for platforms that don't have them or have a special case such as iOS. But for now, keep the same behaviour. --- public/client/TracyProfiler.hpp | 16 +++++++++++++--- public/client/TracySysTrace.cpp | 8 ++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/public/client/TracyProfiler.hpp b/public/client/TracyProfiler.hpp index 80cbec51..7ddd244a 100644 --- a/public/client/TracyProfiler.hpp +++ b/public/client/TracyProfiler.hpp @@ -28,8 +28,18 @@ # include #endif -#if !defined TRACY_DISALLOW_HW_TIMER && ( (defined _WIN32 && !(defined _M_ARM64 || defined _M_ARM)) || ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) || ( defined TARGET_OS_IOS && TARGET_OS_IOS == 1 ) || ( defined __APPLE__ && defined __MACH__ && TARGET_CPU_ARM64 ) ) -# define TRACY_HW_TIMER +#if ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) +# define TRACY_HAS_RDTSC +#elif defined __APPLE__ && defined __MACH__ && TARGET_CPU_ARM64 // For now only supported on Apple devices +# define TRACY_HAS_CNTVCT +#endif + +#if !defined TRACY_DISALLOW_HW_TIMER +# if ( defined TRACY_HAS_RDTSC || defined TRACY_HAS_CNTVCT ) +# define TRACY_HW_TIMER +# elif defined TARGET_OS_IOS && TARGET_OS_IOS == 1 // For now, !defined(TRACY_HW_TIMER) implies TRACY_TIMER_FALLBACK, so define TRACY_HW_TIMER to use mach_absolute_time() on iOS +# define TRACY_HW_TIMER +# endif #endif #ifdef __linux__ @@ -81,7 +91,7 @@ TRACY_API bool ProfilerAvailable(); TRACY_API bool ProfilerAllocatorAvailable(); TRACY_API int64_t GetFrequencyQpc(); -#if defined TRACY_TIMER_FALLBACK && defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) +#if defined TRACY_TIMER_FALLBACK && defined TRACY_HW_TIMER && defined TRACY_HAS_RDTSC TRACY_API bool HardwareSupportsInvariantTSC(); // check, if we need fallback scenario #else # if defined TRACY_HW_TIMER diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index 27b246c1..79240f02 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -597,7 +597,7 @@ bool SysTraceStart( int64_t& samplingPeriod ) TracyDebug( "drm_vblank_event id: %i", vsyncId ); bool useMonotonicClockRaw = !HardwareSupportsInvariantTSC(); -#if !defined TRACY_HW_TIMER || !( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) +#if !defined TRACY_HW_TIMER || !defined TRACY_HAS_RDTSC useMonotonicClockRaw = true; #endif if( useMonotonicClockRaw ) @@ -1070,7 +1070,7 @@ void SysTraceWorker( void* ptr ) if( cnt > 0 ) { -#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) +#if defined TRACY_HW_TIMER && defined TRACY_HAS_RDTSC t0 = ring.ConvertTimeToTsc( t0 ); #endif auto trace = GetCallstackBlock( cnt, ring, offset ); @@ -1104,7 +1104,7 @@ void SysTraceWorker( void* ptr ) offset += sizeof( uint64_t ); ring.Read( &t0, offset, sizeof( uint64_t ) ); -#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) +#if defined TRACY_HW_TIMER && defined TRACY_HAS_RDTSC t0 = ring.ConvertTimeToTsc( t0 ); #endif QueueType type; @@ -1224,7 +1224,7 @@ void SysTraceWorker( void* ptr ) perf_event_header hdr; ring.Read( &hdr, offset, sizeof( perf_event_header ) ); -#if defined TRACY_HW_TIMER && ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) +#if defined TRACY_HW_TIMER && defined TRACY_HAS_RDTSC t0 = ring.ConvertTimeToTsc( t0 ); #endif From b778b67676b26a7f49abc1530183649b00ae887e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gr=C3=A9goire?= Date: Mon, 9 Feb 2026 11:37:07 +0100 Subject: [PATCH 4/7] Fix trailing whitespace --- public/client/TracySysTrace.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index 79240f02..9bee5300 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -675,7 +675,7 @@ bool SysTraceStart( int64_t& samplingPeriod ) #endif pe.disabled = 1; pe.freq = 1; - pe.inherit = 1; + pe.inherit = 1; if( useMonotonicClockRaw ) { pe.use_clockid = 1; @@ -721,7 +721,7 @@ bool SysTraceStart( int64_t& samplingPeriod ) pe.exclude_guest = 1; pe.exclude_hv = 1; pe.freq = 1; - pe.inherit = 1; + pe.inherit = 1; if( useMonotonicClockRaw ) { pe.use_clockid = 1; From d089c3e1b09ed16336b22cbc3ac3ceb688649062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gr=C3=A9goire?= Date: Mon, 9 Feb 2026 11:40:07 +0100 Subject: [PATCH 5/7] CMake: Enforce TRACY_TIMER_FALLBACK when TRACY_DISALLOW_HW_TIMER is set. --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bcd40e0..f614d0d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,6 +160,9 @@ endif() if(TRACY_MANUAL_LIFETIME AND NOT TRACY_DELAYED_INIT) message(FATAL_ERROR "TRACY_MANUAL_LIFETIME can not be activated with disabled TRACY_DELAYED_INIT") endif() +if(TRACY_DISALLOW_HW_TIMER AND NOT TRACY_TIMER_FALLBACK) + message(FATAL_ERROR "TRACY_DISALLOW_HW_TIMER can not be activated with disabled TRACY_TIMER_FALLBACK") +endif() if(NOT TRACY_STATIC) target_compile_definitions(TracyClient PRIVATE TRACY_EXPORTS) From e9073800d511c68f1a7d40099333617043abb752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gr=C3=A9goire?= Date: Mon, 9 Feb 2026 11:41:11 +0100 Subject: [PATCH 6/7] Remove extraneous newline in meson.build --- meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/meson.build b/meson.build index 8c23250a..e5c06a9f 100644 --- a/meson.build +++ b/meson.build @@ -93,7 +93,6 @@ if get_option('timer_fallback') tracy_common_args += ['-DTRACY_TIMER_FALLBACK'] endif - if get_option('disallow_hw_timer') tracy_common_args += ['-DTRACY_DISALLOW_HW_TIMER'] endif From b890719fdddeacd41bcdbdc95a793ddcae706e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Gr=C3=A9goire?= Date: Mon, 9 Feb 2026 11:44:16 +0100 Subject: [PATCH 7/7] Remove stray newline in TracySysTrace.cpp --- public/client/TracySysTrace.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index 9bee5300..0d80e5b8 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -885,7 +885,6 @@ bool SysTraceStart( int64_t& samplingPeriod ) pe.disabled = 1; pe.inherit = 1; pe.config = switchId; - if( useMonotonicClockRaw ) { pe.use_clockid = 1;