Detect context switch callstack samples.

Context switch callstack samples are not included in the sampling data
statistics (as these don't represent random sampling), but are rather put into
a separate dedicated data structure.

For this to work, a complete context switch data has to be available for the
callstack timestamp. There is no guarantee it will be present at the time it
is needed, so a second structure is added to allow postponing qualification of
callstacks.
This commit is contained in:
Bartosz Taudul 2021-11-13 02:40:32 +01:00
parent 5b799e0e45
commit 745b795d50
No known key found for this signature in database
GPG Key ID: B7FE2008B7575DF3
3 changed files with 91 additions and 50 deletions

View File

@ -666,9 +666,11 @@ struct ThreadData
Vector<int64_t> childTimeStack; Vector<int64_t> childTimeStack;
Vector<GhostZone> ghostZones; Vector<GhostZone> ghostZones;
uint64_t ghostIdx; uint64_t ghostIdx;
Vector<SampleData> postponedSamples;
#endif #endif
Vector<SampleData> samples; Vector<SampleData> samples;
SampleData pendingSample; SampleData pendingSample;
Vector<SampleData> ctxSwitchSamples;
uint64_t kernelSampleCnt; uint64_t kernelSampleCnt;
uint8_t isFiber; uint8_t isFiber;
ThreadData* fiber; ThreadData* fiber;

View File

@ -6162,7 +6162,43 @@ void Worker::ProcessCallstackSampleImpl( const SampleData& sd, ThreadData& td )
} }
#ifndef TRACY_NO_STATISTICS #ifndef TRACY_NO_STATISTICS
bool postpone = false;
auto ctx = GetContextSwitchData( td.id );
if( !ctx )
{ {
postpone = true;
}
else
{
auto it = std::lower_bound( ctx->v.begin(), ctx->v.end(), sd.time.Val(), [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } );
if( it == ctx->v.end() )
{
postpone = true;
}
else if( sd.time.Val() == it->Start() )
{
td.ctxSwitchSamples.push_back( sd );
}
else
{
ProcessCallstackSampleImplStats( sd, td );
}
}
if( postpone )
{
td.postponedSamples.push_back( sd );
}
#endif
}
#ifndef TRACY_NO_STATISTICS
void Worker::ProcessCallstackSampleImplStats( const SampleData& sd, ThreadData& td )
{
const auto t = sd.time.Val();
const auto callstack = sd.callstack.Val();
const auto& cs = GetCallstack( callstack );
const auto& ip = cs[0];
uint16_t tid = CompressThread( td.id ); uint16_t tid = CompressThread( td.id );
auto frame = GetCallstackFrame( ip ); auto frame = GetCallstackFrame( ip );
@ -6225,7 +6261,7 @@ void Worker::ProcessCallstackSampleImpl( const SampleData& sd, ThreadData& td )
sit->second.push_back_non_empty( SampleDataRange { sd.time, tid, ip } ); sit->second.push_back_non_empty( SampleDataRange { sd.time, tid, ip } );
} }
} }
}
for( uint16_t i=1; i<cs.size(); i++ ) for( uint16_t i=1; i<cs.size(); i++ )
{ {
auto addr = GetCanonicalPointer( cs[i] ); auto addr = GetCanonicalPointer( cs[i] );
@ -6251,8 +6287,8 @@ void Worker::ProcessCallstackSampleImpl( const SampleData& sd, ThreadData& td )
{ {
m_data.ghostZonesPostponed = true; m_data.ghostZonesPostponed = true;
} }
#endif
} }
#endif
void Worker::ProcessCallstackSample( const QueueCallstackSample& ev ) void Worker::ProcessCallstackSample( const QueueCallstackSample& ev )
{ {

View File

@ -720,6 +720,9 @@ private:
tracy_force_inline MemEvent* ProcessMemAllocImpl( uint64_t memname, MemData& memdata, const QueueMemAlloc& ev ); tracy_force_inline MemEvent* ProcessMemAllocImpl( uint64_t memname, MemData& memdata, const QueueMemAlloc& ev );
tracy_force_inline MemEvent* ProcessMemFreeImpl( uint64_t memname, MemData& memdata, const QueueMemFree& ev ); tracy_force_inline MemEvent* ProcessMemFreeImpl( uint64_t memname, MemData& memdata, const QueueMemFree& ev );
tracy_force_inline void ProcessCallstackSampleImpl( const SampleData& sd, ThreadData& td ); tracy_force_inline void ProcessCallstackSampleImpl( const SampleData& sd, ThreadData& td );
#ifndef TRACY_NO_STATISTICS
tracy_force_inline void ProcessCallstackSampleImplStats( const SampleData& sd, ThreadData& td );
#endif
void ZoneStackFailure( uint64_t thread, const ZoneEvent* ev ); void ZoneStackFailure( uint64_t thread, const ZoneEvent* ev );
void ZoneDoubleEndFailure( uint64_t thread, const ZoneEvent* ev ); void ZoneDoubleEndFailure( uint64_t thread, const ZoneEvent* ev );