mirror of
https://github.com/wolfpld/tracy.git
synced 2026-10-01 06:25:22 +00:00
Sort child sample vectors lazily.
During live capture, child samples were appended to their per-address vectors in arrival order. Samples postponed due to missing context switch data are replayed after newer samples were already processed, so the vectors could become unordered. All range-limited queries binary search these vectors by time and would silently return wrong results. Inserting in sorted order at collection time would require a mid-vector insertion for every stack frame of every replayed sample, so instead the vectors are now SortedVector and are sorted lazily when accessed, following what the inline symbol list already does. This also restores proper query results for traces with inconsistent sample order.
This commit is contained in:
@@ -863,7 +863,7 @@ void GatherIpStats( uint64_t baseAddr, AddrStatData& as, const Worker& worker, b
|
||||
}
|
||||
}
|
||||
|
||||
void GatherAdditionalIpStats( uint64_t baseAddr, AddrStatData& as, const Worker& worker, bool limitView, const View& view, const char* filename, bool propagateInlines )
|
||||
void GatherAdditionalIpStats( uint64_t baseAddr, AddrStatData& as, Worker& worker, bool limitView, const View& view, const char* filename, bool propagateInlines )
|
||||
{
|
||||
if( !worker.AreSymbolSamplesReady() ) return;
|
||||
auto sym = worker.GetSymbolData( baseAddr );
|
||||
|
||||
@@ -138,7 +138,7 @@ std::string FormatDisassemblyLine( const AsmLine& opcode, Worker& worker, std::v
|
||||
nlohmann::json JsonDisassembly( uint64_t symAddr, Worker& worker, const View& view );
|
||||
|
||||
void GatherIpStats( uint64_t baseAddr, AddrStatData& as, const Worker& worker, bool limitView, const View& view, const char* filename, bool propagateInlines );
|
||||
void GatherAdditionalIpStats( uint64_t baseAddr, AddrStatData& as, const Worker& worker, bool limitView, const View& view, const char* filename, bool propagateInlines );
|
||||
void GatherAdditionalIpStats( uint64_t baseAddr, AddrStatData& as, Worker& worker, bool limitView, const View& view, const char* filename, bool propagateInlines );
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -685,6 +685,8 @@ struct ChildSample
|
||||
uint64_t addr;
|
||||
};
|
||||
|
||||
struct ChildSampleSort { bool operator()( const ChildSample& lhs, const ChildSample& rhs ) const { return lhs.time.Val() < rhs.time.Val(); }; };
|
||||
|
||||
|
||||
struct SectionItem
|
||||
{
|
||||
|
||||
@@ -1957,11 +1957,11 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks, bool allow
|
||||
auto it = m_data.childSamples.find( addr );
|
||||
if( it == m_data.childSamples.end() )
|
||||
{
|
||||
m_data.childSamples.emplace( addr, Vector<ChildSample>( ChildSample { time, childAddr } ) );
|
||||
m_data.childSamples.emplace( addr, SortedVector<ChildSample, ChildSampleSort>( ChildSample { time, childAddr } ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.push_back_non_empty( ChildSample { time, childAddr } );
|
||||
it->second.push_back( ChildSample { time, childAddr } );
|
||||
}
|
||||
childAddr = addr;
|
||||
}
|
||||
@@ -1973,7 +1973,7 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks, bool allow
|
||||
}
|
||||
for( auto& v : m_data.childSamples )
|
||||
{
|
||||
pdqsort_branchless( v.second.begin(), v.second.end(), []( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs.time.Val(); } );
|
||||
v.second.ensure_sorted();
|
||||
}
|
||||
std::lock_guard<std::mutex> lock( m_data.lock );
|
||||
m_data.symbolSamplesReady = true;
|
||||
@@ -2321,11 +2321,15 @@ const Vector<SampleDataRange>* Worker::GetSamplesForSymbol( uint64_t symAddr ) c
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
const Vector<ChildSample>* Worker::GetChildSamples( uint64_t addr ) const
|
||||
const SortedVector<ChildSample, ChildSampleSort>* Worker::GetChildSamples( uint64_t addr )
|
||||
{
|
||||
assert( m_data.symbolSamplesReady );
|
||||
auto it = m_data.childSamples.find( addr );
|
||||
if( it == m_data.childSamples.end() ) return nullptr;
|
||||
// Out-of-order insertions may happen during live capture, e.g. when samples postponed
|
||||
// due to missing context switch data are finally processed. Sorting is done lazily, as
|
||||
// the vectors are only ever read here.
|
||||
it->second.ensure_sorted();
|
||||
return &it->second;
|
||||
}
|
||||
#endif
|
||||
@@ -6674,11 +6678,11 @@ void Worker::ProcessCallstackSampleImplStats( const SampleData& sd, ThreadData&
|
||||
auto it = m_data.childSamples.find( addr );
|
||||
if( it == m_data.childSamples.end() )
|
||||
{
|
||||
m_data.childSamples.emplace( addr, Vector<ChildSample>( ChildSample { sd.time, childAddr } ) );
|
||||
m_data.childSamples.emplace( addr, SortedVector<ChildSample, ChildSampleSort>( ChildSample { sd.time, childAddr } ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.push_back_non_empty( ChildSample { sd.time, childAddr } );
|
||||
it->second.push_back( ChildSample { sd.time, childAddr } );
|
||||
}
|
||||
childAddr = addr;
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ private:
|
||||
unordered_flat_map<uint64_t, unordered_flat_map<CallstackFrameId, uint32_t, CallstackFrameIdHash, CallstackFrameIdCompare>> instructionPointersMap;
|
||||
unordered_flat_map<uint64_t, Vector<SampleDataRange>> symbolSamples;
|
||||
unordered_flat_map<CallstackFrameId, Vector<SampleDataRange>, CallstackFrameIdHash, CallstackFrameIdCompare> pendingSymbolSamples;
|
||||
unordered_flat_map<uint64_t, Vector<ChildSample>> childSamples;
|
||||
unordered_flat_map<uint64_t, SortedVector<ChildSample, ChildSampleSort>> childSamples;
|
||||
bool newFramesWereReceived = false;
|
||||
bool callstackSamplesReady = false;
|
||||
bool newContextSwitchesReceived = false;
|
||||
@@ -598,7 +598,7 @@ public:
|
||||
const VarArray<CallstackFrameId>& GetSyntheticCallstack( uint32_t idx ) const { return *m_data.syntheticCallstackPayload[idx]; }
|
||||
const CallstackFrameData* GetSyntheticCallstackFrame( const CallstackFrameId& ptr ) const;
|
||||
const Vector<SampleDataRange>* GetSamplesForSymbol( uint64_t symAddr ) const;
|
||||
const Vector<ChildSample>* GetChildSamples( uint64_t addr ) const;
|
||||
const SortedVector<ChildSample, ChildSampleSort>* GetChildSamples( uint64_t addr );
|
||||
#endif
|
||||
|
||||
const CrashEvent& GetCrashEvent() const { return m_data.crashEvent; }
|
||||
|
||||
Reference in New Issue
Block a user