diff options
author | Bartosz Taudul <wolf@nereid.pl> | 2022-07-30 22:29:44 +0300 |
---|---|---|
committer | Bartosz Taudul <wolf@nereid.pl> | 2022-07-30 22:29:44 +0300 |
commit | e0f813d9e901afa5bdb30fc2de0b5e7d01b87ed5 (patch) | |
tree | 8cef9a5e2a3a9190c301059cb3c5e91fb2a0130f | |
parent | 91b002267ea5511cab5d6537b3ab7e5be5392cb9 (diff) |
Add support for Vsync capture on Linux.
-rw-r--r-- | public/client/TracySysTrace.cpp | 91 |
1 files changed, 84 insertions, 7 deletions
diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index 2198536d..9fc07117 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -661,6 +661,7 @@ enum TraceEventId EventCacheMiss, EventBranchRetired, EventBranchMiss, + EventVsync, EventContextSwitch, EventWakeup, }; @@ -751,13 +752,17 @@ bool SysTraceStart( int64_t& samplingPeriod ) TracyDebug( "perf_event_paranoid: %i\n", paranoidLevel ); #endif - int switchId = -1, wakeupId = -1; + int switchId = -1, wakeupId = -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 vsyncIdStr = ReadFile( "/sys/kernel/debug/tracing/events/drm/drm_vblank_event/id" ); + if( vsyncIdStr ) vsyncId = atoi( vsyncIdStr ); - TracyDebug( "sched_switch id: %i\nsched_wakeup id: %i\n", switchId, wakeupId ); + TracyDebug( "sched_switch id: %i\n", switchId ); + TracyDebug( "sched_wakeup id: %i\n", wakeupId ); + TracyDebug( "drm_vblank_event id: %i\n", vsyncId ); #ifdef TRACY_NO_SAMPLE_RETIREMENT const bool noRetirement = true; @@ -787,6 +792,13 @@ bool SysTraceStart( int64_t& samplingPeriod ) const bool noCtxSwitch = noCtxSwitchEnv && noCtxSwitchEnv[0] == '1'; #endif +#ifdef TRACY_NO_VSYNC_CAPTURE + const bool noVsync = true; +#else + const char* noVsyncEnv = GetEnvVar( "TRACY_NO_VSYNC_CAPTURE" ); + const bool noVsync = noVsyncEnv && noVsyncEnv[0] == '1'; +#endif + samplingPeriod = GetSamplingPeriod(); uint32_t currentPid = (uint32_t)getpid(); @@ -797,7 +809,8 @@ 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 + wakeups + 1 // vsync ); s_ring = (RingBuffer*)tracy_malloc( sizeof( RingBuffer ) * maxNumBuffers ); s_numBuffers = 0; @@ -973,6 +986,37 @@ bool SysTraceStart( int64_t& samplingPeriod ) s_ctxBufferIdx = s_numBuffers; + // vsync + if( !noVsync && vsyncId != -1 ) + { + 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; + 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 + + TracyDebug( "Setup vsync 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, EventVsync, i ); + if( s_ring[s_numBuffers].IsValid() ) + { + s_numBuffers++; + TracyDebug( " Core %i ok\n", i ); + } + } + } + } + // context switches if( !noCtxSwitch && switchId != -1 ) { @@ -1307,7 +1351,8 @@ void SysTraceWorker( void* ptr ) t0 = ring.ConvertTimeToTsc( t0 ); #endif - if( ring.GetId() == EventContextSwitch ) + const auto rid = ring.GetId(); + if( rid == EventContextSwitch ) { // Layout: // u64 time @@ -1375,10 +1420,8 @@ void SysTraceWorker( void* ptr ) TracyLfqCommit; } } - else + else if( rid == EventWakeup ) { - assert( ring.GetId() == EventWakeup ); - // Layout: // u64 time // u32 size @@ -1400,6 +1443,40 @@ void SysTraceWorker( void* ptr ) MemWrite( &item->threadWakeup.thread, pid ); TracyLfqCommit; } + else + { + assert( rid == EventVsync ); + // Layout: + // u64 time + // u32 size + // u8 data[size] + // Data (not ABI stable): + // u8 hdr[8] + // i32 crtc + // u32 seq + // i64 ktime + // u8 high precision + + offset += sizeof( perf_event_header ) + sizeof( uint64_t ) + sizeof( uint32_t ) + 8; + + int32_t crtc; + ring.Read( &crtc, offset, sizeof( int32_t ) ); + + // Note: The timestamp value t0 might be off by a number of microseconds from the + // true hardware vblank event. The ktime value should be used instead, but it is + // measured in CLOCK_MONOTONIC time. Tracy only supports the timestamp counter + // register (TSC) or CLOCK_MONOTONIC_RAW clock. +#if 0 + offset += sizeof( uint32_t ) * 2; + int64_t ktime; + ring.Read( &ktime, offset, sizeof( int64_t ) ); +#endif + + TracyLfqPrepare( QueueType::FrameVsync ); + MemWrite( &item->frameVsync.id, crtc ); + MemWrite( &item->frameVsync.time, t0 ); + TracyLfqCommit; + } rbPos += hdr.size; if( rbPos == end[sel] ) |