Make find zone sample percentages relative to the matched zones.

The find zone samples list shares the drawing code with the sampling
statistics window, which computed the percentage denominator from its
own state: the whole-trace sample count, or the statistics range
filter, if one was active. The find zone counts are scoped to the
matched zones, so the percentages mixed two meanings in one table: the
time column was relative to the zone selection while the count column
was relative to the whole trace, and changing the range filter in the
statistics window silently rescaled it.

Pass the denominator from the caller. Find zone sums its zone-scoped
counts, so both columns are now relative to the selection, and the
statistics window computes the same denominator as before.
This commit is contained in:
Bartosz Taudul
2026-07-25 22:29:35 +02:00
parent c2c1c4e2b7
commit 26d61dfdba
4 changed files with 36 additions and 31 deletions

View File

@@ -332,7 +332,7 @@ private:
void DrawFindZone();
void AccumulationModeComboBox();
void DrawStatistics();
void DrawSamplesStatistics(Vector<SymList>& data, int64_t timeRange, AccumulationMode accumulationMode);
void DrawSamplesStatistics(Vector<SymList>& data, int64_t timeRange, uint64_t totalSamples, AccumulationMode accumulationMode);
void DrawMemory();
void DrawAllocList();
void DrawCompare();

View File

@@ -2136,9 +2136,14 @@ void View::DrawFindZone()
Vector<SymList> data;
data.reserve( m_findZone.samples.counts.size() );
for( auto it: m_findZone.samples.counts ) data.push_back_no_space_check( it );
uint64_t totalSamples = 0;
for( auto it: m_findZone.samples.counts )
{
data.push_back_no_space_check( it );
totalSamples += it.excl;
}
int64_t timeRange = ( m_findZone.selGroup != m_findZone.Unselected ) ? m_findZone.selTotal : m_findZone.total;
DrawSamplesStatistics( data, timeRange, AccumulationMode::SelfOnly );
DrawSamplesStatistics( data, timeRange, totalSamples, AccumulationMode::SelfOnly );
ImGui::TreePop();
}

View File

@@ -85,7 +85,7 @@ void View::DrawSampleList( const TimelineContext& ctx, const std::vector<Samples
}
}
void View::DrawSamplesStatistics( Vector<SymList>& data, int64_t timeRange, AccumulationMode accumulationMode )
void View::DrawSamplesStatistics( Vector<SymList>& data, int64_t timeRange, uint64_t totalSamples, AccumulationMode accumulationMode )
{
static unordered_flat_map<uint64_t, SymList> inlineMap;
assert( inlineMap.empty() );
@@ -156,32 +156,6 @@ void View::DrawSamplesStatistics( Vector<SymList>& data, int64_t timeRange, Accu
ImGui::TableSetupColumn( "Code size", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize );
ImGui::TableHeadersRow();
// The denominator is the number of collected samples, excluding context
// switch samples, which do not participate in the sampling statistics. This
// way the percentages have the same meaning with and without an active
// range filter.
uint64_t totalSamples;
if( m_statRange.active )
{
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;
};
totalSamples = 0;
for( auto& td : m_worker.GetThreadData() )
{
const auto cnt = CountInRange( td->samples, m_statRange.min, m_statRange.max );
const auto ctx = CountInRange( td->ctxSwitchSamples, m_statRange.min, m_statRange.max );
if( cnt > ctx ) totalSamples += cnt - ctx;
}
}
else
{
const auto cnt = m_worker.GetCallstackSampleCount();
const auto ctx = m_worker.GetContextSwitchSampleCount();
totalSamples = cnt > ctx ? cnt - ctx : 0;
}
const double revSampleCount100 = totalSamples == 0 ? 0 : 100. / totalSamples;
const bool showAll = m_showAllSymbols;

View File

@@ -1000,7 +1000,33 @@ void View::DrawStatistics()
}
}
DrawSamplesStatistics( data, timeRange, m_statAccumulationMode );
// The denominator is the number of collected samples, excluding context
// switch samples, which do not participate in the sampling statistics. This
// way the percentages have the same meaning with and without an active
// range filter.
uint64_t totalSamples;
if( m_statRange.active )
{
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;
};
totalSamples = 0;
for( auto& td : m_worker.GetThreadData() )
{
const auto cnt = CountInRange( td->samples, m_statRange.min, m_statRange.max );
const auto ctx = CountInRange( td->ctxSwitchSamples, m_statRange.min, m_statRange.max );
if( cnt > ctx ) totalSamples += cnt - ctx;
}
}
else
{
const auto cnt = m_worker.GetCallstackSampleCount();
const auto ctx = m_worker.GetContextSwitchSampleCount();
totalSamples = cnt > ctx ? cnt - ctx : 0;
}
DrawSamplesStatistics( data, timeRange, totalSamples, m_statAccumulationMode );
}
ImGui::End();
}