mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-12 19:31:47 +00:00
Add support for Vsync capture on Linux.
This commit is contained in:
parent
91b002267e
commit
e0f813d9e9
@ -661,6 +661,7 @@ enum TraceEventId
|
|||||||
EventCacheMiss,
|
EventCacheMiss,
|
||||||
EventBranchRetired,
|
EventBranchRetired,
|
||||||
EventBranchMiss,
|
EventBranchMiss,
|
||||||
|
EventVsync,
|
||||||
EventContextSwitch,
|
EventContextSwitch,
|
||||||
EventWakeup,
|
EventWakeup,
|
||||||
};
|
};
|
||||||
@ -751,13 +752,17 @@ bool SysTraceStart( int64_t& samplingPeriod )
|
|||||||
TracyDebug( "perf_event_paranoid: %i\n", paranoidLevel );
|
TracyDebug( "perf_event_paranoid: %i\n", paranoidLevel );
|
||||||
#endif
|
#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" );
|
const auto switchIdStr = ReadFile( "/sys/kernel/debug/tracing/events/sched/sched_switch/id" );
|
||||||
if( switchIdStr ) switchId = atoi( switchIdStr );
|
if( switchIdStr ) switchId = atoi( switchIdStr );
|
||||||
const auto wakeupIdStr = ReadFile( "/sys/kernel/debug/tracing/events/sched/sched_wakeup/id" );
|
const auto wakeupIdStr = ReadFile( "/sys/kernel/debug/tracing/events/sched/sched_wakeup/id" );
|
||||||
if( wakeupIdStr ) wakeupId = atoi( wakeupIdStr );
|
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
|
#ifdef TRACY_NO_SAMPLE_RETIREMENT
|
||||||
const bool noRetirement = true;
|
const bool noRetirement = true;
|
||||||
@ -787,6 +792,13 @@ bool SysTraceStart( int64_t& samplingPeriod )
|
|||||||
const bool noCtxSwitch = noCtxSwitchEnv && noCtxSwitchEnv[0] == '1';
|
const bool noCtxSwitch = noCtxSwitchEnv && noCtxSwitchEnv[0] == '1';
|
||||||
#endif
|
#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();
|
samplingPeriod = GetSamplingPeriod();
|
||||||
uint32_t currentPid = (uint32_t)getpid();
|
uint32_t currentPid = (uint32_t)getpid();
|
||||||
|
|
||||||
@ -797,7 +809,8 @@ bool SysTraceStart( int64_t& samplingPeriod )
|
|||||||
2 + // CPU cycles + instructions retired
|
2 + // CPU cycles + instructions retired
|
||||||
2 + // cache reference + miss
|
2 + // cache reference + miss
|
||||||
2 + // branch retired + miss
|
2 + // branch retired + miss
|
||||||
2 // context switches + wakeups
|
2 + // context switches + wakeups
|
||||||
|
1 // vsync
|
||||||
);
|
);
|
||||||
s_ring = (RingBuffer*)tracy_malloc( sizeof( RingBuffer ) * maxNumBuffers );
|
s_ring = (RingBuffer*)tracy_malloc( sizeof( RingBuffer ) * maxNumBuffers );
|
||||||
s_numBuffers = 0;
|
s_numBuffers = 0;
|
||||||
@ -973,6 +986,37 @@ bool SysTraceStart( int64_t& samplingPeriod )
|
|||||||
|
|
||||||
s_ctxBufferIdx = s_numBuffers;
|
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
|
// context switches
|
||||||
if( !noCtxSwitch && switchId != -1 )
|
if( !noCtxSwitch && switchId != -1 )
|
||||||
{
|
{
|
||||||
@ -1307,7 +1351,8 @@ void SysTraceWorker( void* ptr )
|
|||||||
t0 = ring.ConvertTimeToTsc( t0 );
|
t0 = ring.ConvertTimeToTsc( t0 );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( ring.GetId() == EventContextSwitch )
|
const auto rid = ring.GetId();
|
||||||
|
if( rid == EventContextSwitch )
|
||||||
{
|
{
|
||||||
// Layout:
|
// Layout:
|
||||||
// u64 time
|
// u64 time
|
||||||
@ -1375,10 +1420,8 @@ void SysTraceWorker( void* ptr )
|
|||||||
TracyLfqCommit;
|
TracyLfqCommit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if( rid == EventWakeup )
|
||||||
{
|
{
|
||||||
assert( ring.GetId() == EventWakeup );
|
|
||||||
|
|
||||||
// Layout:
|
// Layout:
|
||||||
// u64 time
|
// u64 time
|
||||||
// u32 size
|
// u32 size
|
||||||
@ -1400,6 +1443,40 @@ void SysTraceWorker( void* ptr )
|
|||||||
MemWrite( &item->threadWakeup.thread, pid );
|
MemWrite( &item->threadWakeup.thread, pid );
|
||||||
TracyLfqCommit;
|
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;
|
rbPos += hdr.size;
|
||||||
if( rbPos == end[sel] )
|
if( rbPos == end[sel] )
|
||||||
|
Loading…
Reference in New Issue
Block a user