diff options
author | Daniil Brychikov <d_brychikov@wargaming.net> | 2022-02-11 17:01:56 +0300 |
---|---|---|
committer | Daniil Brychikov <d_brychikov@wargaming.net> | 2022-02-16 15:18:45 +0300 |
commit | 73f6c66cdefc7c6bc5d11994e3559d4a70f1acc1 (patch) | |
tree | 56ab2e45c0e6f762fdca12bd19ec86a8417904d3 | |
parent | 92b182d47e51e59064778819db08aba0d7017c1e (diff) |
Automatic timer fallback
-rw-r--r-- | client/TracyProfiler.cpp | 87 | ||||
-rw-r--r-- | client/TracyProfiler.hpp | 55 |
2 files changed, 105 insertions, 37 deletions
diff --git a/client/TracyProfiler.cpp b/client/TracyProfiler.cpp index ff9ce9c7..73384eab 100644 --- a/client/TracyProfiler.cpp +++ b/client/TracyProfiler.cpp @@ -322,24 +322,50 @@ static void InitFailure( const char* msg ) exit( 1 ); } -static int64_t SetupHwTimer() +static bool checkHardwareSupportsInvariantTSC() { -#if !defined TRACY_TIMER_QPC && !defined TRACY_TIMER_FALLBACK + const char* noCheck = GetEnvVar( "TRACY_NO_INVARIANT_CHECK" ); + if( noCheck && noCheck[0] == '1' ) + { + return true; + } + uint32_t regs[4]; CpuId( regs, 1 ); - if( !( regs[3] & ( 1 << 4 ) ) ) InitFailure( "CPU doesn't support RDTSC instruction." ); + if( !( regs[3] & ( 1 << 4 ) ) ) + { +#if !defined TRACY_TIMER_QPC && !defined TRACY_TIMER_FALLBACK + InitFailure( "CPU doesn't support RDTSC instruction." ); +#endif + return false; + } CpuId( regs, 0x80000007 ); - if( !( regs[3] & ( 1 << 8 ) ) ) + if( regs[3] & ( 1 << 8 ) ) + { + return true; + } + + return false; +} + +#if defined TRACY_TIMER_FALLBACK && defined TRACY_HW_TIMER +bool hardwareSupportsInvariantTSC() +{ + static bool cachedResult = checkHardwareSupportsInvariantTSC(); + return cachedResult; +} +#endif + +static int64_t SetupHwTimer() +{ +#if !defined TRACY_TIMER_QPC && !defined TRACY_TIMER_FALLBACK + if(!checkHardwareSupportsInvariantTSC()) { - const char* noCheck = GetEnvVar( "TRACY_NO_INVARIANT_CHECK" ); - if( !noCheck || noCheck[0] != '1' ) - { #if defined _WIN32 - InitFailure( "CPU doesn't support invariant TSC.\nDefine TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*.\nAlternatively you may rebuild the application with the TRACY_TIMER_QPC or TRACY_TIMER_FALLBACK define to use lower resolution timer." ); + InitFailure( "CPU doesn't support invariant TSC.\nDefine TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*.\nAlternatively you may rebuild the application with the TRACY_TIMER_QPC or TRACY_TIMER_FALLBACK define to use lower resolution timer." ); #else - InitFailure( "CPU doesn't support invariant TSC.\nDefine TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*.\nAlternatively you may rebuild the application with the TRACY_TIMER_FALLBACK define to use lower resolution timer." ); + InitFailure( "CPU doesn't support invariant TSC.\nDefine TRACY_NO_INVARIANT_CHECK=1 to ignore this error, *if you know what you are doing*.\nAlternatively you may rebuild the application with the TRACY_TIMER_FALLBACK define to use lower resolution timer." ); #endif - } } #endif @@ -3451,23 +3477,32 @@ void Profiler::HandleDisconnect() void Profiler::CalibrateTimer() { -#ifdef TRACY_HW_TIMER - std::atomic_signal_fence( std::memory_order_acq_rel ); - const auto t0 = std::chrono::high_resolution_clock::now(); - const auto r0 = GetTime(); - std::atomic_signal_fence( std::memory_order_acq_rel ); - std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) ); - std::atomic_signal_fence( std::memory_order_acq_rel ); - const auto t1 = std::chrono::high_resolution_clock::now(); - const auto r1 = GetTime(); - std::atomic_signal_fence( std::memory_order_acq_rel ); - - const auto dt = std::chrono::duration_cast<std::chrono::nanoseconds>( t1 - t0 ).count(); - const auto dr = r1 - r0; - - m_timerMul = double( dt ) / double( dr ); -#else m_timerMul = 1.; + +#ifdef TRACY_HW_TIMER + +# if !defined TRACY_TIMER_QPC && defined TRACY_TIMER_FALLBACK + const bool needCalibration = hardwareSupportsInvariantTSC(); +# else + const bool needCalibration = true; +# endif + if (needCalibration) + { + std::atomic_signal_fence( std::memory_order_acq_rel ); + const auto t0 = std::chrono::high_resolution_clock::now(); + const auto r0 = GetTime(); + std::atomic_signal_fence( std::memory_order_acq_rel ); + std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) ); + std::atomic_signal_fence( std::memory_order_acq_rel ); + const auto t1 = std::chrono::high_resolution_clock::now(); + const auto r1 = GetTime(); + std::atomic_signal_fence( std::memory_order_acq_rel ); + + const auto dt = std::chrono::duration_cast<std::chrono::nanoseconds>( t1 - t0 ).count(); + const auto dr = r1 - r0; + + m_timerMul = double( dt ) / double( dr ); + } #endif } diff --git a/client/TracyProfiler.hpp b/client/TracyProfiler.hpp index 005feb6e..ca50dd24 100644 --- a/client/TracyProfiler.hpp +++ b/client/TracyProfiler.hpp @@ -26,11 +26,11 @@ # include <mach/mach_time.h> #endif -#if !defined TRACY_TIMER_FALLBACK && ( defined _WIN32 || ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) || ( defined TARGET_OS_IOS && TARGET_OS_IOS == 1 ) ) +#if ( defined _WIN32 || ( defined __i386 || defined _M_IX86 || defined __x86_64__ || defined _M_X64 ) || ( defined TARGET_OS_IOS && TARGET_OS_IOS == 1 ) ) # define TRACY_HW_TIMER #endif -#if !defined TRACY_HW_TIMER +#if defined TRACY_TIMER_FALLBACK || !defined TRACY_HW_TIMER # include <chrono> #endif @@ -67,6 +67,23 @@ TRACY_API uint32_t GetThreadHandle(); TRACY_API bool ProfilerAvailable(); 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 ) +TRACY_API bool hardwareSupportsInvariantTSC(); // check, if we need fallback scenario +#else +# if defined TRACY_HW_TIMER +tracy_force_inline bool hardwareSupportsInvariantTSC() +{ + return true; // this is checked at startup +} +# else +tracy_force_inline bool hardwareSupportsInvariantTSC() +{ + return false; +} +# endif +#endif + + struct SourceLocationData { const char* name; @@ -166,25 +183,39 @@ public: { #ifdef TRACY_HW_TIMER # if defined TARGET_OS_IOS && TARGET_OS_IOS == 1 - return mach_absolute_time(); + if (hardwareSupportsInvariantTSC()) + { + return mach_absolute_time(); + } # elif defined _WIN32 # ifdef TRACY_TIMER_QPC return GetTimeQpc(); # else - return int64_t( __rdtsc() ); + if (hardwareSupportsInvariantTSC()) + { + return int64_t( __rdtsc() ); + } # endif # elif defined __i386 || defined _M_IX86 - uint32_t eax, edx; - asm volatile ( "rdtsc" : "=a" (eax), "=d" (edx) ); - return ( uint64_t( edx ) << 32 ) + uint64_t( eax ); + if (hardwareSupportsInvariantTSC()) + { + uint32_t eax, edx; + asm volatile ( "rdtsc" : "=a" (eax), "=d" (edx) ); + return ( uint64_t( edx ) << 32 ) + uint64_t( eax ); + } # elif defined __x86_64__ || defined _M_X64 - uint64_t rax, rdx; - asm volatile ( "rdtsc" : "=a" (rax), "=d" (rdx) ); - return (int64_t)(( rdx << 32 ) + rax); + if (hardwareSupportsInvariantTSC()) + { + uint64_t rax, rdx; + asm volatile ( "rdtsc" : "=a" (rax), "=d" (rdx) ); + return (int64_t)(( rdx << 32 ) + rax); + } # else # error "TRACY_HW_TIMER detection logic needs fixing" # endif -#else +#endif + +#if !defined TRACY_HW_TIMER || defined TRACY_TIMER_FALLBACK # if defined __linux__ && defined CLOCK_MONOTONIC_RAW struct timespec ts; clock_gettime( CLOCK_MONOTONIC_RAW, &ts ); @@ -193,6 +224,8 @@ public: return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); # endif #endif + + return 0; // unreacheble branch } tracy_force_inline uint32_t GetNextZoneId() |