tracy/server/TracyView_Statistics.cpp

969 lines
44 KiB
C++

#include <sstream>
#include "TracyFilesystem.hpp"
#include "TracyImGui.hpp"
#include "TracyPrint.hpp"
#include "TracyView.hpp"
namespace tracy
{
extern double s_time;
struct SrcLocZonesSlim
{
int16_t srcloc;
uint16_t numThreads;
size_t numZones;
int64_t total;
};
void View::AccumulationModeComboBox()
{
ImGui::TextUnformatted( "Timing" );
ImGui::SameLine();
const char* accumulationModeTable = m_statMode == 1 ? "Self only\0With children\0" : "Self only\0With children\0Non-reentrant\0";
ImGui::SetNextItemWidth( ImGui::CalcTextSize( "Non-reentrant" ).x + ImGui::GetTextLineHeight() * 2 );
if( m_statMode == 1 && m_statAccumulationMode == AccumulationMode::NonReentrantChildren )
{
m_statAccumulationMode = AccumulationMode::SelfOnly;
}
int accumulationMode = static_cast<int>( m_statAccumulationMode );
ImGui::Combo( "##accumulationMode", &accumulationMode, accumulationModeTable );
m_statAccumulationMode = static_cast<AccumulationMode>( accumulationMode );
}
void View::DrawStatistics()
{
const auto scale = GetScale();
ImGui::SetNextWindowSize( ImVec2( 1400 * scale, 600 * scale ), ImGuiCond_FirstUseEver );
ImGui::Begin( "Statistics", &m_showStatistics, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse );
if( ImGui::GetCurrentWindowRead()->SkipItems ) { ImGui::End(); return; }
#ifdef TRACY_NO_STATISTICS
ImGui::TextWrapped( "Collection of statistical data is disabled in this build." );
ImGui::TextWrapped( "Rebuild without the TRACY_NO_STATISTICS macro to enable statistics view." );
#else
if( !m_worker.AreSourceLocationZonesReady() && ( !m_worker.AreCallstackSamplesReady() || m_worker.GetCallstackSampleCount() == 0 ) )
{
ImGui::TextWrapped( "Please wait, computing data..." );
DrawWaitingDots( s_time );
ImGui::End();
return;
}
ImGui::PushStyleVar( ImGuiStyleVar_FramePadding, ImVec2( 2, 2 ) );
ImGui::RadioButton( ICON_FA_SYRINGE " Instrumentation", &m_statMode, 0 );
if( m_worker.AreCallstackSamplesReady() )
{
ImGui::SameLine();
if( m_worker.GetCallstackSampleCount() > 0 )
{
ImGui::Spacing();
ImGui::SameLine();
ImGui::RadioButton( ICON_FA_EYE_DROPPER " Sampling", &m_statMode, 1 );
}
else if( m_worker.GetSymbolsCount() > 0 )
{
ImGui::Spacing();
ImGui::SameLine();
ImGui::RadioButton( ICON_FA_PUZZLE_PIECE " Symbols", &m_statMode, 1 );
}
}
if( m_worker.GetGpuZoneCount() > 0 )
{
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::RadioButton( ICON_FA_EYE " GPU", &m_statMode, 2 );
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::SeparatorEx( ImGuiSeparatorFlags_Vertical );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
Vector<SrcLocZonesSlim> srcloc;
bool copySrclocsToClipboard = false;
if( m_statMode == 0 )
{
if( !m_worker.AreSourceLocationZonesReady() )
{
ImGui::Spacing();
ImGui::Separator();
ImGui::PopStyleVar();
ImGui::TextWrapped( "Please wait, computing data..." );
DrawWaitingDots( s_time );
ImGui::End();
return;
}
const auto filterActive = m_statisticsFilter.IsActive();
auto& slz = m_worker.GetSourceLocationZones();
srcloc.reserve( slz.size() );
uint32_t slzcnt = 0;
if( m_statRange.active )
{
const auto min = m_statRange.min;
const auto max = m_statRange.max;
const auto st = max - min;
for( auto it = slz.begin(); it != slz.end(); ++it )
{
if( it->second.total != 0 && it->second.min <= st )
{
if( !filterActive )
{
auto cit = m_statCache.find( it->first );
if( cit != m_statCache.end() && cit->second.range == m_statRange && cit->second.accumulationMode == m_statAccumulationMode && cit->second.sourceCount == it->second.zones.size() )
{
if( cit->second.count != 0 )
{
slzcnt++;
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, cit->second.threadNum, cit->second.count, cit->second.total } );
}
}
else
{
unordered_flat_set<uint16_t> threads;
size_t cnt = 0;
int64_t total = 0;
for( auto& v : it->second.zones )
{
auto& z = *v.Zone();
const auto start = z.Start();
const auto end = z.End();
if( start >= min && end <= max )
{
const auto zt = end - start;
if( m_statAccumulationMode == AccumulationMode::SelfOnly )
{
total += zt - GetZoneChildTimeFast( z );
cnt++;
threads.emplace( v.Thread() );
}
else if( m_statAccumulationMode == AccumulationMode::AllChildren || !IsZoneReentry( z ) )
{
total += zt;
cnt++;
threads.emplace( v.Thread() );
}
}
}
const auto threadNum = (uint16_t)threads.size();
if( cnt != 0 )
{
slzcnt++;
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, threadNum, cnt, total } );
}
m_statCache[it->first] = StatisticsCache { RangeSlim { m_statRange.min, m_statRange.max, m_statRange.active }, m_statAccumulationMode, it->second.zones.size(), cnt, total, threadNum };
}
}
else
{
slzcnt++;
auto& sl = m_worker.GetSourceLocation( it->first );
auto name = m_worker.GetString( sl.name.active ? sl.name : sl.function );
if( m_statisticsFilter.PassFilter( name ) )
{
auto cit = m_statCache.find( it->first );
if( cit != m_statCache.end() && cit->second.range == m_statRange && cit->second.accumulationMode == m_statAccumulationMode && cit->second.sourceCount == it->second.zones.size() )
{
if( cit->second.count != 0 )
{
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, cit->second.threadNum, cit->second.count, cit->second.total } );
}
}
else
{
unordered_flat_set<uint16_t> threads;
size_t cnt = 0;
int64_t total = 0;
for( auto& v : it->second.zones )
{
auto& z = *v.Zone();
const auto start = z.Start();
const auto end = z.End();
if( start >= min && end <= max )
{
const auto zt = end - start;
if( m_statAccumulationMode == AccumulationMode::SelfOnly )
{
total += zt - GetZoneChildTimeFast( z );
cnt++;
threads.emplace( v.Thread() );
}
else if( m_statAccumulationMode == AccumulationMode::AllChildren || !IsZoneReentry( z ) )
{
total += zt;
cnt++;
threads.emplace( v.Thread() );
}
}
}
const auto threadNum = (uint16_t)threads.size();
if( cnt != 0 )
{
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, threadNum, cnt, total } );
}
m_statCache[it->first] = StatisticsCache { RangeSlim { m_statRange.min, m_statRange.max, m_statRange.active }, m_statAccumulationMode, it->second.zones.size(), cnt, total, threadNum };
}
}
}
}
}
}
else
{
for( auto it = slz.begin(); it != slz.end(); ++it )
{
if( it->second.total != 0 )
{
slzcnt++;
size_t count;
int64_t total;
switch( m_statAccumulationMode )
{
case AccumulationMode::SelfOnly:
count = it->second.zones.size();
total = it->second.selfTotal;
break;
case AccumulationMode::AllChildren:
count = it->second.zones.size();
total = it->second.total;
break;
case AccumulationMode::NonReentrantChildren:
count = it->second.nonReentrantCount;
total = it->second.nonReentrantTotal;
break;
}
if( !filterActive )
{
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, (uint16_t)it->second.threadCnt.size(), count, total } );
}
else
{
auto& sl = m_worker.GetSourceLocation( it->first );
auto name = m_worker.GetString( sl.name.active ? sl.name : sl.function );
if( m_statisticsFilter.PassFilter( name ) )
{
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, (uint16_t)it->second.threadCnt.size(), count, total } );
}
}
}
}
}
TextFocused( "Total zone count:", RealToString( slzcnt ) );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
TextFocused( "Visible zones:", RealToString( srcloc.size() ) );
ImGui::SameLine();
copySrclocsToClipboard = ClipboardButton();
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
AccumulationModeComboBox();
}
else if( m_statMode == 1 )
{
ImGui::Checkbox( ICON_FA_STOPWATCH " Show time", &m_statSampleTime );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
if( m_statRange.active )
{
ImGui::BeginDisabled();
m_statAccumulationMode = AccumulationMode::SelfOnly;
AccumulationModeComboBox();
ImGui::EndDisabled();
}
else
{
AccumulationModeComboBox();
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::Checkbox( ICON_FA_EYE_SLASH " Hide unknown", &m_statHideUnknown );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::Checkbox( ICON_FA_PUZZLE_PIECE " Show all", &m_showAllSymbols );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::Checkbox( ICON_FA_SITEMAP " Inlines", &m_statSeparateInlines );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::Checkbox( ICON_FA_AT " Address", &m_statShowAddress );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::TextUnformatted( "Location:" );
ImGui::SameLine();
const char* locationTable = "Entry\0Sample\0Smart\0";
ImGui::SetNextItemWidth( ImGui::CalcTextSize( "Sample" ).x + ImGui::GetTextLineHeight() * 2 );
ImGui::Combo( "##location", &m_statSampleLocation, locationTable );
}
else
{
assert( m_statMode == 2 );
if( !m_worker.AreGpuSourceLocationZonesReady() )
{
ImGui::Spacing();
ImGui::Separator();
ImGui::PopStyleVar();
ImGui::TextWrapped( "Please wait, computing data..." );
DrawWaitingDots( s_time );
ImGui::End();
return;
}
const auto filterActive = m_statisticsFilter.IsActive();
auto& slz = m_worker.GetGpuSourceLocationZones();
srcloc.reserve( slz.size() );
uint32_t slzcnt = 0;
if( m_statRange.active )
{
const auto min = m_statRange.min;
const auto max = m_statRange.max;
const auto st = max - min;
for( auto it = slz.begin(); it != slz.end(); ++it )
{
if( it->second.total != 0 && it->second.min <= st )
{
if( !filterActive )
{
auto cit = m_gpuStatCache.find( it->first );
if( cit != m_gpuStatCache.end() && cit->second.range == m_statRange && cit->second.accumulationMode == m_statAccumulationMode && cit->second.sourceCount == it->second.zones.size() )
{
if( cit->second.count != 0 )
{
slzcnt++;
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, 0, cit->second.count, cit->second.total } );
}
}
else
{
size_t cnt = 0;
int64_t total = 0;
for( auto& v : it->second.zones )
{
auto& z = *v.Zone();
const auto start = z.GpuStart();
const auto end = z.GpuEnd();
if( start >= min && end <= max )
{
const auto zt = end - start;
total += zt;
cnt++;
}
}
if( cnt != 0 )
{
slzcnt++;
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, 0, cnt, total } );
}
m_gpuStatCache[it->first] = StatisticsCache { RangeSlim { m_statRange.min, m_statRange.max, m_statRange.active }, m_statAccumulationMode, it->second.zones.size(), cnt, total };
}
}
else
{
slzcnt++;
auto& sl = m_worker.GetSourceLocation( it->first );
auto name = m_worker.GetString( sl.name.active ? sl.name : sl.function );
if( m_statisticsFilter.PassFilter( name ) )
{
auto cit = m_gpuStatCache.find( it->first );
if( cit != m_gpuStatCache.end() && cit->second.range == m_statRange && cit->second.accumulationMode == m_statAccumulationMode && cit->second.sourceCount == it->second.zones.size() )
{
if( cit->second.count != 0 )
{
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, 0, cit->second.count, cit->second.total } );
}
}
else
{
size_t cnt = 0;
int64_t total = 0;
for( auto& v : it->second.zones )
{
auto& z = *v.Zone();
const auto start = z.GpuStart();
const auto end = z.GpuEnd();
if( start >= min && end <= max )
{
const auto zt = end - start;
total += zt;
cnt++;
}
}
if( cnt != 0 )
{
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, 0, cnt, total } );
}
m_gpuStatCache[it->first] = StatisticsCache { RangeSlim { m_statRange.min, m_statRange.max, m_statRange.active }, m_statAccumulationMode, it->second.zones.size(), cnt, total };
}
}
}
}
}
}
else
{
for( auto it = slz.begin(); it != slz.end(); ++it )
{
if( it->second.total != 0 )
{
slzcnt++;
size_t count = it->second.zones.size();
int64_t total = it->second.total;
if( !filterActive )
{
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, 0, count, total } );
}
else
{
auto& sl = m_worker.GetSourceLocation( it->first );
auto name = m_worker.GetString( sl.name.active ? sl.name : sl.function );
if( m_statisticsFilter.PassFilter( name ) )
{
srcloc.push_back_no_space_check( SrcLocZonesSlim { it->first, 0, count, total } );
}
}
}
}
}
TextFocused( "Total zone count:", RealToString( slzcnt ) );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
TextFocused( "Visible zones:", RealToString( srcloc.size() ) );
ImGui::SameLine();
copySrclocsToClipboard = ClipboardButton();
}
ImGui::Separator();
ImGui::AlignTextToFramePadding();
TextDisabledUnformatted( "Name" );
ImGui::SameLine();
m_statisticsFilter.Draw( ICON_FA_FILTER "###resultFilter", 200 );
ImGui::SameLine();
if( ImGui::Button( ICON_FA_DELETE_LEFT " Clear" ) )
{
m_statisticsFilter.Clear();
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
if( m_statMode == 1 )
{
TextDisabledUnformatted( "Image" );
ImGui::SameLine();
m_statisticsImageFilter.Draw( ICON_FA_FILTER "###imageFilter", 200 );
ImGui::SameLine();
if( ImGui::BeginCombo( "###imageCombo", nullptr, ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLarge ) )
{
unordered_flat_set<StringIdx, StringIdxHasher, StringIdxComparator> set;
std::vector<const char*> imgNames;
for( auto& v : m_worker.GetSymbolMap() )
{
auto it = set.find( v.second.imageName );
if( it == set.end() )
{
set.emplace( v.second.imageName );
}
}
imgNames.reserve( set.size() );
for( auto& img : set )
{
imgNames.emplace_back( m_worker.GetString( img ) );
}
std::sort( imgNames.begin(), imgNames.end(), [] ( const auto& lhs, const auto& rhs ) { return strcmp( lhs, rhs ) < 0; } );
for( auto& img : imgNames )
{
bool sel = false;
if( ImGui::Selectable( img, &sel ) )
{
auto len = std::min<size_t>( 255, strlen( img ) );
memcpy( m_statisticsImageFilter.InputBuf, img, len );
m_statisticsImageFilter.InputBuf[len] = 0;
m_statisticsImageFilter.Build();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
if( ImGui::Button( ICON_FA_DELETE_LEFT " Clear###image" ) )
{
m_statisticsImageFilter.Clear();
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
}
if( m_statMode == 1 && !m_worker.AreSymbolSamplesReady() )
{
m_statRange.active = false;
bool val = false;
ImGui::PushItemFlag( ImGuiItemFlags_Disabled, true );
ImGui::PushStyleVar( ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f );
ImGui::Checkbox( "Limit range", &val );
ImGui::PopItemFlag();
ImGui::PopStyleVar();
TooltipIfHovered( "Waiting for background tasks to finish" );
}
else
{
if( ImGui::Checkbox( "Limit range", &m_statRange.active ) )
{
if( m_statRange.active && m_statRange.min == 0 && m_statRange.max == 0 )
{
m_statRange.min = m_vd.zvStart;
m_statRange.max = m_vd.zvEnd;
}
}
if( m_statRange.active )
{
ImGui::SameLine();
TextColoredUnformatted( 0xFF00FFFF, ICON_FA_TRIANGLE_EXCLAMATION );
ImGui::SameLine();
ToggleButton( ICON_FA_RULER " Limits", m_showRanges );
}
}
if( m_statMode == 1 )
{
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::SeparatorEx( ImGuiSeparatorFlags_Vertical );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
if( m_statSeparateInlines ) ImGui::BeginDisabled();
ImGui::TextUnformatted( "Inlines" );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::Checkbox( ICON_FA_LAYER_GROUP " Aggregate", &m_mergeInlines );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::Checkbox( ICON_FA_LINK " Base relative", &m_relativeInlines );
if( m_statSeparateInlines ) ImGui::EndDisabled();
}
ImGui::Separator();
ImGui::PopStyleVar();
int64_t timeRange;
if( m_statRange.active )
{
const auto st = m_statRange.max - m_statRange.min;
timeRange = st == 0 ? 1 : st;
}
else
{
timeRange = m_worker.GetLastTime() - m_worker.GetFirstTime();
}
if( m_statMode == 0 || m_statMode == 2 )
{
if( srcloc.empty() )
{
ImGui::TextUnformatted( "No entries to be displayed." );
}
else
{
ImGui::BeginChild( "##statistics" );
if( ImGui::BeginTable( "##statistics", m_statMode == 0 ? 6 : 5,
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_ScrollY ) )
{
ImGui::TableSetupScrollFreeze( 0, 1 );
ImGui::TableSetupColumn( "Name", ImGuiTableColumnFlags_NoHide );
ImGui::TableSetupColumn( "Location" );
ImGui::TableSetupColumn( "Total time", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize );
ImGui::TableSetupColumn( "Counts", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize );
ImGui::TableSetupColumn( "MTPC", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize );
if( m_statMode == 0 ) ImGui::TableSetupColumn( ICON_FA_SHUFFLE, ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize );
ImGui::TableHeadersRow();
const auto& sortspec = *ImGui::TableGetSortSpecs()->Specs;
switch( sortspec.ColumnIndex )
{
case 0:
if( sortspec.SortDirection == ImGuiSortDirection_Ascending )
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), [this]( const auto& lhs, const auto& rhs ) { return strcmp( m_worker.GetZoneName( m_worker.GetSourceLocation( lhs.srcloc ) ), m_worker.GetZoneName( m_worker.GetSourceLocation( rhs.srcloc ) ) ) < 0; } );
}
else
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), [this]( const auto& lhs, const auto& rhs ) { return strcmp( m_worker.GetZoneName( m_worker.GetSourceLocation( lhs.srcloc ) ), m_worker.GetZoneName( m_worker.GetSourceLocation( rhs.srcloc ) ) ) > 0; } );
}
break;
case 1:
if( sortspec.SortDirection == ImGuiSortDirection_Ascending )
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), [this]( const auto& lhs, const auto& rhs ) {
const auto& sll = m_worker.GetSourceLocation( lhs.srcloc );
const auto& slr = m_worker.GetSourceLocation( rhs.srcloc );
const auto cmp = strcmp( m_worker.GetString( sll.file ), m_worker.GetString( slr.file ) );
if( cmp == 0 ) return sll.line < slr.line;
return cmp < 0;
} );
}
else
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), [this]( const auto& lhs, const auto& rhs ) {
const auto& sll = m_worker.GetSourceLocation( lhs.srcloc );
const auto& slr = m_worker.GetSourceLocation( rhs.srcloc );
const auto cmp = strcmp( m_worker.GetString( sll.file ), m_worker.GetString( slr.file ) );
if( cmp == 0 ) return sll.line > slr.line;
return cmp > 0;
} );
}
break;
case 2:
if( sortspec.SortDirection == ImGuiSortDirection_Ascending )
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), []( const auto& lhs, const auto& rhs ) { return lhs.total < rhs.total; } );
}
else
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), []( const auto& lhs, const auto& rhs ) { return lhs.total > rhs.total; } );
}
break;
case 3:
if( sortspec.SortDirection == ImGuiSortDirection_Ascending )
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), []( const auto& lhs, const auto& rhs ) { return lhs.numZones < rhs.numZones; } );
}
else
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), []( const auto& lhs, const auto& rhs ) { return lhs.numZones > rhs.numZones; } );
}
break;
case 4:
if( sortspec.SortDirection == ImGuiSortDirection_Ascending )
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), []( const auto& lhs, const auto& rhs ) { return lhs.total / lhs.numZones < rhs.total / rhs.numZones; } );
}
else
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), []( const auto& lhs, const auto& rhs ) { return lhs.total / lhs.numZones > rhs.total / rhs.numZones; } );
}
break;
case 5:
if( sortspec.SortDirection == ImGuiSortDirection_Ascending )
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), []( const auto& lhs, const auto& rhs ) { return lhs.numThreads < rhs.numThreads; } );
}
else
{
pdqsort_branchless( srcloc.begin(), srcloc.end(), []( const auto& lhs, const auto& rhs ) { return lhs.numThreads > rhs.numThreads; } );
}
break;
default:
assert( false );
break;
}
std::ostringstream clipboardCSV;
if( copySrclocsToClipboard )
{
clipboardCSV << "name" << ',' << "src_file" << ',' << "src_line" << ',' << "total_ns" << ',' << "counts" << "\n";
}
for( auto& v : srcloc )
{
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushID( v.srcloc );
auto& srcloc = m_worker.GetSourceLocation( v.srcloc );
auto name = m_worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function );
SmallColorBox( GetSrcLocColor( srcloc, 0 ) );
ImGui::SameLine();
if( m_statMode == 0 )
{
if( ImGui::Selectable( name, m_findZone.show && !m_findZone.match.empty() && m_findZone.match[m_findZone.selMatch] == v.srcloc, ImGuiSelectableFlags_SpanAllColumns ) )
{
m_findZone.ShowZone( v.srcloc, name );
}
}
else
{
ImGui::TextUnformatted( name );
}
ImGui::TableNextColumn();
float indentVal = 0.f;
if( m_statBuzzAnim.Match( v.srcloc ) )
{
const auto time = m_statBuzzAnim.Time();
indentVal = sin( time * 60.f ) * 10.f * time;
ImGui::Indent( indentVal );
}
const auto file = m_worker.GetString( srcloc.file );
TextDisabledUnformatted( LocationToString( file, srcloc.line ) );
if( ImGui::IsItemHovered() )
{
DrawSourceTooltip( file, srcloc.line );
if( ImGui::IsItemClicked( 1 ) )
{
if( SourceFileValid( file, m_worker.GetCaptureTime(), *this, m_worker ) )
{
ViewSourceCheckKeyMod( file, srcloc.line, m_worker.GetString( srcloc.function ) );
}
else
{
m_statBuzzAnim.Enable( v.srcloc, 0.5f );
}
}
}
if( indentVal != 0.f )
{
ImGui::Unindent( indentVal );
}
ImGui::TableNextColumn();
const auto time = v.total;
ImGui::TextUnformatted( TimeToString( time ) );
ImGui::SameLine();
char buf[64];
PrintStringPercent( buf, 100. * time / timeRange );
TextDisabledUnformatted( buf );
ImGui::TableNextColumn();
ImGui::TextUnformatted( RealToString( v.numZones ) );
ImGui::TableNextColumn();
ImGui::TextUnformatted( TimeToString( time / v.numZones ) );
if( m_statMode == 0 )
{
ImGui::TableNextColumn();
ImGui::TextUnformatted( RealToString( v.numThreads ) );
}
ImGui::PopID();
if( copySrclocsToClipboard )
{
clipboardCSV << name << ',' << file << ',' << srcloc.line << ',' << v.total << ',' << v.numZones << '\n';
}
}
ImGui::EndTable();
if( copySrclocsToClipboard )
{
std::string clipboardCSVString = clipboardCSV.str();
ImGui::SetClipboardText( clipboardCSVString.c_str() );
}
}
ImGui::EndChild();
}
}
else
{
assert( m_statMode == 1 );
const auto& symMap = m_worker.GetSymbolMap();
const auto& symStat = m_worker.GetSymbolStats();
Vector<SymList> data;
if( m_showAllSymbols )
{
data.reserve( symMap.size() );
if( m_statisticsFilter.IsActive() || m_statisticsImageFilter.IsActive() || !m_statShowKernel )
{
for( auto& v : symMap )
{
const auto name = m_worker.GetString( v.second.name );
const auto image = m_worker.GetString( v.second.imageName );
bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ) && m_statisticsFilter.PassFilter( name ) && m_statisticsImageFilter.PassFilter( image );
if( !pass && v.second.size.Val() == 0 )
{
const auto parentAddr = m_worker.GetSymbolForAddress( v.first );
if( parentAddr != 0 )
{
auto pit = symMap.find( parentAddr );
if( pit != symMap.end() )
{
const auto parentName = m_worker.GetString( pit->second.name );
pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ) && m_statisticsFilter.PassFilter( parentName ) && m_statisticsImageFilter.PassFilter( image );
}
}
}
if( pass )
{
auto it = symStat.find( v.first );
if( it == symStat.end() )
{
data.push_back_no_space_check( SymList { v.first, 0, 0 } );
}
else
{
if( m_statRange.active )
{
auto samples = m_worker.GetSamplesForSymbol( v.first );
if( samples )
{
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() )
{
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 );
data.push_back_no_space_check( SymList { v.first, 0, count } );
}
else
{
data.push_back_no_space_check( SymList { v.first, 0, 0 } );
}
}
else
{
data.push_back_no_space_check( SymList { v.first, 0, 0 } );
}
}
else
{
data.push_back_no_space_check( SymList { v.first, it->second.incl, it->second.excl } );
}
}
}
}
}
else
{
for( auto& v : symMap )
{
auto it = symStat.find( v.first );
if( it == symStat.end() )
{
data.push_back_no_space_check( SymList { v.first, 0, 0 } );
}
else
{
if( m_statRange.active )
{
auto samples = m_worker.GetSamplesForSymbol( v.first );
if( samples )
{
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() )
{
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 );
data.push_back_no_space_check( SymList { v.first, 0, count } );
}
else
{
data.push_back_no_space_check( SymList { v.first, 0, 0 } );
}
}
else
{
data.push_back_no_space_check( SymList { v.first, 0, 0 } );
}
}
else
{
data.push_back_no_space_check( SymList { v.first, it->second.incl, it->second.excl } );
}
}
}
}
}
else
{
data.reserve( symStat.size() );
if( m_statisticsFilter.IsActive() || m_statisticsImageFilter.IsActive() || !m_statShowKernel )
{
for( auto& v : symStat )
{
auto sit = symMap.find( v.first );
if( sit != symMap.end() )
{
const auto name = m_worker.GetString( sit->second.name );
const auto image = m_worker.GetString( sit->second.imageName );
bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ) && m_statisticsFilter.PassFilter( name ) && m_statisticsImageFilter.PassFilter( image );
if( !pass && sit->second.size.Val() == 0 )
{
const auto parentAddr = m_worker.GetSymbolForAddress( v.first );
if( parentAddr != 0 )
{
auto pit = symMap.find( parentAddr );
if( pit != symMap.end() )
{
const auto parentName = m_worker.GetString( pit->second.name );
pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ) && m_statisticsFilter.PassFilter( parentName ) && m_statisticsImageFilter.PassFilter( image );
}
}
}
if( pass )
{
if( m_statRange.active )
{
auto samples = m_worker.GetSamplesForSymbol( v.first );
if( samples )
{
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() )
{
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 );
data.push_back_no_space_check( SymList { v.first, 0, count } );
}
}
}
else
{
data.push_back_no_space_check( SymList { v.first, v.second.incl, v.second.excl } );
}
}
}
}
}
else
{
if( m_statRange.active )
{
for( auto& v : symStat )
{
auto samples = m_worker.GetSamplesForSymbol( v.first );
if( samples )
{
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() )
{
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 );
data.push_back_no_space_check( SymList { v.first, 0, count } );
}
}
}
}
else
{
for( auto& v : symStat )
{
data.push_back_no_space_check( SymList { v.first, v.second.incl, v.second.excl } );
}
}
}
}
DrawSamplesStatistics( data, timeRange, m_statAccumulationMode );
}
#endif
ImGui::End();
}
}