mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-26 16:04:34 +00:00
Store instruction pointers in per-symbol sample data.
This commit is contained in:
parent
85f54499fe
commit
7a4ecc5417
@ -212,6 +212,25 @@ struct ZoneExtra
|
|||||||
enum { ZoneExtraSize = sizeof( ZoneExtra ) };
|
enum { ZoneExtraSize = sizeof( ZoneExtra ) };
|
||||||
|
|
||||||
|
|
||||||
|
// This union exploits the fact that the current implementations of x64 and arm64 do not provide
|
||||||
|
// full 64 bit address space. The high bits must be bit-extended, so 0x80... is an invalid pointer.
|
||||||
|
// This allows using the highest bit as a selector between a native pointer and a table index here.
|
||||||
|
union CallstackFrameId
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint64_t idx : 62;
|
||||||
|
uint64_t sel : 1;
|
||||||
|
uint64_t custom : 1;
|
||||||
|
};
|
||||||
|
uint64_t data;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { CallstackFrameIdSize = sizeof( CallstackFrameId ) };
|
||||||
|
|
||||||
|
static tracy_force_inline bool operator==( const CallstackFrameId& lhs, const CallstackFrameId& rhs ) { return lhs.data == rhs.data; }
|
||||||
|
|
||||||
|
|
||||||
struct SampleData
|
struct SampleData
|
||||||
{
|
{
|
||||||
Int48 time;
|
Int48 time;
|
||||||
@ -221,6 +240,15 @@ struct SampleData
|
|||||||
enum { SampleDataSize = sizeof( SampleData ) };
|
enum { SampleDataSize = sizeof( SampleData ) };
|
||||||
|
|
||||||
|
|
||||||
|
struct SampleDataRange
|
||||||
|
{
|
||||||
|
Int48 time;
|
||||||
|
CallstackFrameId ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { SampleDataRangeSize = sizeof( SampleDataRange ) };
|
||||||
|
|
||||||
|
|
||||||
struct LockEvent
|
struct LockEvent
|
||||||
{
|
{
|
||||||
enum class Type : uint8_t
|
enum class Type : uint8_t
|
||||||
@ -368,24 +396,6 @@ struct CallstackFrameData
|
|||||||
|
|
||||||
enum { CallstackFrameDataSize = sizeof( CallstackFrameData ) };
|
enum { CallstackFrameDataSize = sizeof( CallstackFrameData ) };
|
||||||
|
|
||||||
// This union exploits the fact that the current implementations of x64 and arm64 do not provide
|
|
||||||
// full 64 bit address space. The high bits must be bit-extended, so 0x80... is an invalid pointer.
|
|
||||||
// This allows using the highest bit as a selector between a native pointer and a table index here.
|
|
||||||
union CallstackFrameId
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint64_t idx : 62;
|
|
||||||
uint64_t sel : 1;
|
|
||||||
uint64_t custom : 1;
|
|
||||||
};
|
|
||||||
uint64_t data;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { CallstackFrameIdSize = sizeof( CallstackFrameId ) };
|
|
||||||
|
|
||||||
static tracy_force_inline bool operator==( const CallstackFrameId& lhs, const CallstackFrameId& rhs ) { return lhs.data == rhs.data; }
|
|
||||||
|
|
||||||
|
|
||||||
struct CallstackFrameTree
|
struct CallstackFrameTree
|
||||||
{
|
{
|
||||||
|
@ -12048,10 +12048,10 @@ void View::DrawStatistics()
|
|||||||
auto samples = m_worker.GetSamplesForSymbol( v.first );
|
auto samples = m_worker.GetSamplesForSymbol( v.first );
|
||||||
if( samples )
|
if( samples )
|
||||||
{
|
{
|
||||||
auto it = std::lower_bound( samples->begin(), samples->end(), m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs; } );
|
auto it = std::lower_bound( samples->begin(), samples->end(), m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
|
||||||
if( it != samples->end() )
|
if( it != samples->end() )
|
||||||
{
|
{
|
||||||
auto end = std::lower_bound( it, samples->end(), m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs; } );
|
auto end = std::lower_bound( it, samples->end(), m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
|
||||||
const auto count = uint32_t( end - it );
|
const auto count = uint32_t( end - it );
|
||||||
data.push_back_no_space_check( SymList { v.first, 0, count } );
|
data.push_back_no_space_check( SymList { v.first, 0, count } );
|
||||||
}
|
}
|
||||||
@ -12089,10 +12089,10 @@ void View::DrawStatistics()
|
|||||||
auto samples = m_worker.GetSamplesForSymbol( v.first );
|
auto samples = m_worker.GetSamplesForSymbol( v.first );
|
||||||
if( samples )
|
if( samples )
|
||||||
{
|
{
|
||||||
auto it = std::lower_bound( samples->begin(), samples->end(), m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs; } );
|
auto it = std::lower_bound( samples->begin(), samples->end(), m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
|
||||||
if( it != samples->end() )
|
if( it != samples->end() )
|
||||||
{
|
{
|
||||||
auto end = std::lower_bound( it, samples->end(), m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs; } );
|
auto end = std::lower_bound( it, samples->end(), m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
|
||||||
const auto count = uint32_t( end - it );
|
const auto count = uint32_t( end - it );
|
||||||
data.push_back_no_space_check( SymList { v.first, 0, count } );
|
data.push_back_no_space_check( SymList { v.first, 0, count } );
|
||||||
}
|
}
|
||||||
@ -12146,10 +12146,10 @@ void View::DrawStatistics()
|
|||||||
auto samples = m_worker.GetSamplesForSymbol( v.first );
|
auto samples = m_worker.GetSamplesForSymbol( v.first );
|
||||||
if( samples )
|
if( samples )
|
||||||
{
|
{
|
||||||
auto it = std::lower_bound( samples->begin(), samples->end(), m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs; } );
|
auto it = std::lower_bound( samples->begin(), samples->end(), m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
|
||||||
if( it != samples->end() )
|
if( it != samples->end() )
|
||||||
{
|
{
|
||||||
auto end = std::lower_bound( it, samples->end(), m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs; } );
|
auto end = std::lower_bound( it, samples->end(), m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
|
||||||
const auto count = uint32_t( end - it );
|
const auto count = uint32_t( end - it );
|
||||||
data.push_back_no_space_check( SymList { v.first, 0, count } );
|
data.push_back_no_space_check( SymList { v.first, 0, count } );
|
||||||
}
|
}
|
||||||
@ -12172,10 +12172,10 @@ void View::DrawStatistics()
|
|||||||
auto samples = m_worker.GetSamplesForSymbol( v.first );
|
auto samples = m_worker.GetSamplesForSymbol( v.first );
|
||||||
if( samples )
|
if( samples )
|
||||||
{
|
{
|
||||||
auto it = std::lower_bound( samples->begin(), samples->end(), m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs; } );
|
auto it = std::lower_bound( samples->begin(), samples->end(), m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
|
||||||
if( it != samples->end() )
|
if( it != samples->end() )
|
||||||
{
|
{
|
||||||
auto end = std::lower_bound( it, samples->end(), m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs; } );
|
auto end = std::lower_bound( it, samples->end(), m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
|
||||||
const auto count = uint32_t( end - it );
|
const auto count = uint32_t( end - it );
|
||||||
data.push_back_no_space_check( SymList { v.first, 0, count } );
|
data.push_back_no_space_check( SymList { v.first, 0, count } );
|
||||||
}
|
}
|
||||||
|
@ -1687,18 +1687,18 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks )
|
|||||||
auto it = m_data.symbolSamples.find( symAddr );
|
auto it = m_data.symbolSamples.find( symAddr );
|
||||||
if( it == m_data.symbolSamples.end() )
|
if( it == m_data.symbolSamples.end() )
|
||||||
{
|
{
|
||||||
m_data.symbolSamples.emplace( symAddr, Vector<Int48>( time ) );
|
m_data.symbolSamples.emplace( symAddr, Vector<SampleDataRange>( SampleDataRange { time, ip } ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
it->second.push_back_non_empty( time );
|
it->second.push_back_non_empty( SampleDataRange { time, ip } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for( auto& v : m_data.symbolSamples )
|
for( auto& v : m_data.symbolSamples )
|
||||||
{
|
{
|
||||||
pdqsort_branchless( v.second.begin(), v.second.end(), []( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs.Val(); } );
|
pdqsort_branchless( v.second.begin(), v.second.end(), []( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs.time.Val(); } );
|
||||||
}
|
}
|
||||||
std::lock_guard<std::shared_mutex> lock( m_data.lock );
|
std::lock_guard<std::shared_mutex> lock( m_data.lock );
|
||||||
m_data.symbolSamplesReady = true;
|
m_data.symbolSamplesReady = true;
|
||||||
@ -2058,7 +2058,7 @@ const CallstackFrameData* Worker::GetParentCallstackFrame( const CallstackFrameI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Vector<Int48>* Worker::GetSamplesForSymbol( uint64_t symAddr ) const
|
const Vector<SampleDataRange>* Worker::GetSamplesForSymbol( uint64_t symAddr ) const
|
||||||
{
|
{
|
||||||
assert( m_data.symbolSamplesReady );
|
assert( m_data.symbolSamplesReady );
|
||||||
auto it = m_data.symbolSamples.find( symAddr );
|
auto it = m_data.symbolSamples.find( symAddr );
|
||||||
@ -5383,18 +5383,18 @@ void Worker::ProcessCallstackSample( const QueueCallstackSample& ev )
|
|||||||
auto sit = m_data.symbolSamples.find( symAddr );
|
auto sit = m_data.symbolSamples.find( symAddr );
|
||||||
if( sit == m_data.symbolSamples.end() )
|
if( sit == m_data.symbolSamples.end() )
|
||||||
{
|
{
|
||||||
m_data.symbolSamples.emplace( symAddr, Vector<Int48>( sd.time ) );
|
m_data.symbolSamples.emplace( symAddr, Vector<SampleDataRange>( SampleDataRange { sd.time, ip } ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( sit->second.back().Val() <= sd.time.Val() )
|
if( sit->second.back().time.Val() <= sd.time.Val() )
|
||||||
{
|
{
|
||||||
sit->second.push_back_non_empty( sd.time );
|
sit->second.push_back_non_empty( SampleDataRange { sd.time, ip } );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto iit = std::upper_bound( sit->second.begin(), sit->second.end(), sd.time.Val(), [] ( const auto& lhs, const auto& rhs ) { return lhs < rhs.Val(); } );
|
auto iit = std::upper_bound( sit->second.begin(), sit->second.end(), sd.time.Val(), [] ( const auto& lhs, const auto& rhs ) { return lhs < rhs.time.Val(); } );
|
||||||
sit->second.insert( iit, sd.time );
|
sit->second.insert( iit, SampleDataRange { sd.time, ip } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5412,11 +5412,11 @@ void Worker::ProcessCallstackSample( const QueueCallstackSample& ev )
|
|||||||
auto sit = m_data.pendingSymbolSamples.find( ip );
|
auto sit = m_data.pendingSymbolSamples.find( ip );
|
||||||
if( sit == m_data.pendingSymbolSamples.end() )
|
if( sit == m_data.pendingSymbolSamples.end() )
|
||||||
{
|
{
|
||||||
m_data.pendingSymbolSamples.emplace( ip, Vector<Int48>( sd.time ) );
|
m_data.pendingSymbolSamples.emplace( ip, Vector<SampleDataRange>( SampleDataRange { sd.time, ip } ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sit->second.push_back_non_empty( sd.time );
|
sit->second.push_back_non_empty( SampleDataRange { sd.time, ip } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5517,20 +5517,20 @@ void Worker::ProcessCallstackFrame( const QueueCallstackFrame& ev )
|
|||||||
auto sit = m_data.symbolSamples.find( ev.symAddr );
|
auto sit = m_data.symbolSamples.find( ev.symAddr );
|
||||||
if( sit == m_data.symbolSamples.end() )
|
if( sit == m_data.symbolSamples.end() )
|
||||||
{
|
{
|
||||||
pdqsort_branchless( pit->second.begin(), pit->second.end(), [] ( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs.Val(); } );
|
pdqsort_branchless( pit->second.begin(), pit->second.end(), [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs.time.Val(); } );
|
||||||
m_data.symbolSamples.emplace( ev.symAddr, std::move( pit->second ) );
|
m_data.symbolSamples.emplace( ev.symAddr, std::move( pit->second ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for( auto& v : pit->second )
|
for( auto& v : pit->second )
|
||||||
{
|
{
|
||||||
if( sit->second.back().Val() <= v.Val() )
|
if( sit->second.back().time.Val() <= v.time.Val() )
|
||||||
{
|
{
|
||||||
sit->second.push_back_non_empty( v );
|
sit->second.push_back_non_empty( v );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto iit = std::upper_bound( sit->second.begin(), sit->second.end(), v.Val(), [] ( const auto& lhs, const auto& rhs ) { return lhs < rhs.Val(); } );
|
auto iit = std::upper_bound( sit->second.begin(), sit->second.end(), v.time.Val(), [] ( const auto& lhs, const auto& rhs ) { return lhs < rhs.time.Val(); } );
|
||||||
sit->second.insert( iit, v );
|
sit->second.insert( iit, v );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,8 +288,8 @@ private:
|
|||||||
unordered_flat_map<uint32_t, uint32_t> postponedSamples;
|
unordered_flat_map<uint32_t, uint32_t> postponedSamples;
|
||||||
unordered_flat_map<CallstackFrameId, uint32_t, CallstackFrameIdHash, CallstackFrameIdCompare> pendingInstructionPointers;
|
unordered_flat_map<CallstackFrameId, uint32_t, CallstackFrameIdHash, CallstackFrameIdCompare> pendingInstructionPointers;
|
||||||
unordered_flat_map<uint64_t, unordered_flat_map<CallstackFrameId, uint32_t, CallstackFrameIdHash, CallstackFrameIdCompare>> instructionPointersMap;
|
unordered_flat_map<uint64_t, unordered_flat_map<CallstackFrameId, uint32_t, CallstackFrameIdHash, CallstackFrameIdCompare>> instructionPointersMap;
|
||||||
unordered_flat_map<uint64_t, Vector<Int48>> symbolSamples;
|
unordered_flat_map<uint64_t, Vector<SampleDataRange>> symbolSamples;
|
||||||
unordered_flat_map<CallstackFrameId, Vector<Int48>, CallstackFrameIdHash, CallstackFrameIdCompare> pendingSymbolSamples;
|
unordered_flat_map<CallstackFrameId, Vector<SampleDataRange>, CallstackFrameIdHash, CallstackFrameIdCompare> pendingSymbolSamples;
|
||||||
bool newFramesWereReceived = false;
|
bool newFramesWereReceived = false;
|
||||||
bool callstackSamplesReady = false;
|
bool callstackSamplesReady = false;
|
||||||
bool ghostZonesReady = false;
|
bool ghostZonesReady = false;
|
||||||
@ -503,7 +503,7 @@ public:
|
|||||||
#ifndef TRACY_NO_STATISTICS
|
#ifndef TRACY_NO_STATISTICS
|
||||||
const VarArray<CallstackFrameId>& GetParentCallstack( uint32_t idx ) const { return *m_data.parentCallstackPayload[idx]; }
|
const VarArray<CallstackFrameId>& GetParentCallstack( uint32_t idx ) const { return *m_data.parentCallstackPayload[idx]; }
|
||||||
const CallstackFrameData* GetParentCallstackFrame( const CallstackFrameId& ptr ) const;
|
const CallstackFrameData* GetParentCallstackFrame( const CallstackFrameId& ptr ) const;
|
||||||
const Vector<Int48>* GetSamplesForSymbol( uint64_t symAddr ) const;
|
const Vector<SampleDataRange>* GetSamplesForSymbol( uint64_t symAddr ) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const CrashEvent& GetCrashEvent() const { return m_data.crashEvent; }
|
const CrashEvent& GetCrashEvent() const { return m_data.crashEvent; }
|
||||||
|
Loading…
Reference in New Issue
Block a user