Keep context switch sample vectors sorted.

Context switch samples were appended in arrival order. Samples which
were postponed due to missing context switch data are replayed after
newer samples were already classified, so the vector could become
unordered. Everything that reads it assumes time order: the wait stacks
range filter, the sampling statistics percentage denominator, and the
context switch sample filters in the trace load jobs. In the load jobs
an unordered vector could silently disable the filtering for the rest
of a thread, reintroducing the context switch samples into the symbol
and child sample maps.

Use a SortedVector and restore the ordering at the points where it can
break: after the postponed sample replay and when saving a trace. The
save file version is bumped, so that the sort order check on load is
only performed for traces saved by previous versions.
This commit is contained in:
Bartosz Taudul
2026-07-25 21:25:58 +02:00
parent 5563461201
commit b68fe43335
4 changed files with 10 additions and 3 deletions

View File

@@ -163,7 +163,7 @@ void View::DrawSamplesStatistics( Vector<SymList>& data, int64_t timeRange, Accu
uint64_t totalSamples;
if( m_statRange.active )
{
static const auto CountInRange = []( const Vector<SampleData>& vec, int64_t min, int64_t max ) -> uint64_t {
static const auto CountInRange = []( const auto& vec, int64_t min, int64_t max ) -> uint64_t {
auto it = std::lower_bound( vec.begin(), vec.end(), min, []( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
auto end = std::lower_bound( it, vec.end(), max, []( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
return end - it;

View File

@@ -5,7 +5,7 @@ namespace tracy::Version
{
constexpr int Major = 0;
constexpr int Minor = 13;
constexpr int Patch = 5;
constexpr int Patch = 6;
}
#endif

View File

@@ -714,7 +714,7 @@ struct ThreadData
#endif
Vector<SampleData> samples;
SampleData pendingSample;
Vector<SampleData> ctxSwitchSamples;
SortedVector<SampleData, SampleDataSort> ctxSwitchSamples;
uint64_t kernelSampleCnt;
uint8_t isFiber;
ThreadData* fiber;

View File

@@ -1100,6 +1100,11 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks, bool allow
f.Read( &ptr->callstack, sizeof( ptr->callstack ) );
ptr++;
}
if( fileVer < FileVersion( 0, 13, 6 ) && !std::is_sorted( td->ctxSwitchSamples.begin(), td->ctxSwitchSamples.end(), SampleDataSort() ) )
{
td->ctxSwitchSamples.mark_unsorted();
td->ctxSwitchSamples.ensure_sorted();
}
}
else
{
@@ -4379,6 +4384,7 @@ void Worker::DoPostponedWork()
{
td->postponedSamples.erase( td->postponedSamples.begin(), sit );
}
td->ctxSwitchSamples.ensure_sorted();
}
}
}
@@ -8494,6 +8500,7 @@ void Worker::Write( FileWrite& f, bool fiDict )
auto ptr = uint64_t( (MessageData*)v );
f.Write( &ptr, sizeof( ptr ) );
}
thread->ctxSwitchSamples.ensure_sorted();
sz = thread->ctxSwitchSamples.size();
f.Write( &sz, sizeof( sz ) );
refTime = 0;