From b68fe43335538cbb208fea3050986d4e65ac5ee8 Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Sat, 25 Jul 2026 21:25:58 +0200 Subject: [PATCH] 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. --- profiler/src/profiler/TracyView_Samples.cpp | 2 +- public/common/TracyVersion.hpp | 2 +- server/TracyEvent.hpp | 2 +- server/TracyWorker.cpp | 7 +++++++ 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/profiler/src/profiler/TracyView_Samples.cpp b/profiler/src/profiler/TracyView_Samples.cpp index 979fdaf0..c3420dc6 100644 --- a/profiler/src/profiler/TracyView_Samples.cpp +++ b/profiler/src/profiler/TracyView_Samples.cpp @@ -163,7 +163,7 @@ void View::DrawSamplesStatistics( Vector& data, int64_t timeRange, Accu uint64_t totalSamples; if( m_statRange.active ) { - static const auto CountInRange = []( const Vector& 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; diff --git a/public/common/TracyVersion.hpp b/public/common/TracyVersion.hpp index adb0850b..62d4d07f 100644 --- a/public/common/TracyVersion.hpp +++ b/public/common/TracyVersion.hpp @@ -5,7 +5,7 @@ namespace tracy::Version { constexpr int Major = 0; constexpr int Minor = 13; -constexpr int Patch = 5; +constexpr int Patch = 6; } #endif diff --git a/server/TracyEvent.hpp b/server/TracyEvent.hpp index bbb26d63..40d8df14 100644 --- a/server/TracyEvent.hpp +++ b/server/TracyEvent.hpp @@ -714,7 +714,7 @@ struct ThreadData #endif Vector samples; SampleData pendingSample; - Vector ctxSwitchSamples; + SortedVector ctxSwitchSamples; uint64_t kernelSampleCnt; uint8_t isFiber; ThreadData* fiber; diff --git a/server/TracyWorker.cpp b/server/TracyWorker.cpp index bc02f41a..60cea678 100644 --- a/server/TracyWorker.cpp +++ b/server/TracyWorker.cpp @@ -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;