From e0f813d9e901afa5bdb30fc2de0b5e7d01b87ed5 Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Sat, 30 Jul 2022 21:29:44 +0200 Subject: [PATCH] Add support for Vsync capture on Linux. --- public/client/TracySysTrace.cpp | 91 ++++++++++++++++++++++++++++++--- 1 file 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; ithreadWakeup.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] )