diff --git a/CMakeLists.txt b/CMakeLists.txt index 712e0975..f614d0d3 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) @@ -159,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) diff --git a/meson.build b/meson.build index 7b81aedb..e5c06a9f 100644 --- a/meson.build +++ b/meson.build @@ -93,6 +93,10 @@ 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..7ddd244a 100644 --- a/public/client/TracyProfiler.hpp +++ b/public/client/TracyProfiler.hpp @@ -28,8 +28,18 @@ # 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 ) ) -# 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 d012c417..0d80e5b8 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -596,6 +596,15 @@ 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 TRACY_HAS_RDTSC + useMonotonicClockRaw = true; +#endif + if( useMonotonicClockRaw ) + { + TracyDebug( "Using CLOCK_MONOTONIC_RAW for Linux perf events." ); + } + #ifdef TRACY_NO_SAMPLING const bool noSoftwareSampling = true; #else @@ -667,10 +676,11 @@ bool SysTraceStart( int64_t& samplingPeriod ) 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 + if( useMonotonicClockRaw ) + { + pe.use_clockid = 1; + pe.clockid = CLOCK_MONOTONIC_RAW; + } if( !noSoftwareSampling ) { @@ -712,10 +722,11 @@ bool SysTraceStart( int64_t& samplingPeriod ) 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 + if( useMonotonicClockRaw ) + { + pe.use_clockid = 1; + pe.clockid = CLOCK_MONOTONIC_RAW; + } if( !noRetirement ) { @@ -838,10 +849,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 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 ); @@ -1089,7 +1103,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; @@ -1209,7 +1223,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