From 6b901a7156057a42e7956202552db9eb97b97edc Mon Sep 17 00:00:00 2001 From: xavier Date: Sat, 4 Sep 2021 16:03:42 +0200 Subject: [PATCH 1/9] Extract DrawSamplesStatistics() --- server/TracyView.cpp | 771 ++++++++++++++++++++++--------------------- server/TracyView.hpp | 8 + 2 files changed, 394 insertions(+), 385 deletions(-) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index 2fe03842..2c89e0bf 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -12810,13 +12810,6 @@ void View::DrawStatistics() const auto& symMap = m_worker.GetSymbolMap(); const auto& symStat = m_worker.GetSymbolStats(); - struct SymList - { - uint64_t symAddr; - uint32_t incl, excl; - uint32_t count; - }; - Vector data; if( m_showAllSymbols ) { @@ -13000,465 +12993,473 @@ void View::DrawStatistics() } } - static unordered_flat_map inlineMap; - assert( inlineMap.empty() ); - if( !m_statSeparateInlines ) - { - static unordered_flat_map baseMap; - assert( baseMap.empty() ); - for( auto& v : data ) - { - auto sym = m_worker.GetSymbolData( v.symAddr ); - const auto symAddr = ( sym && sym->isInline ) ? m_worker.GetSymbolForAddress( v.symAddr ) : v.symAddr; - auto it = baseMap.find( symAddr ); - if( it == baseMap.end() ) - { - baseMap.emplace( symAddr, SymList { symAddr, v.incl, v.excl, 0 } ); - } - else - { - assert( symAddr == it->second.symAddr ); - it->second.incl += v.incl; - it->second.excl += v.excl; - it->second.count++; - } - } - for( auto& v : data ) inlineMap.emplace( v.symAddr, SymList { v.symAddr, v.incl, v.excl, v.count } ); - data.clear(); - for( auto& v : baseMap ) - { - data.push_back_no_space_check( v.second ); - } - baseMap.clear(); - } + DrawSamplesStatistics(data, timeRange); + } +#endif + ImGui::End(); +} - if( data.empty() ) + +void View::DrawSamplesStatistics(Vector& data, int64_t timeRange) +{ + static unordered_flat_map inlineMap; + assert( inlineMap.empty() ); + if( !m_statSeparateInlines ) + { + static unordered_flat_map baseMap; + assert( baseMap.empty() ); + for( auto& v : data ) { - ImGui::TextUnformatted( "No entries to be displayed." ); - } - else - { - if( m_statAccumulationMode == AccumulationMode::SelfOnly ) + auto sym = m_worker.GetSymbolData( v.symAddr ); + const auto symAddr = ( sym && sym->isInline ) ? m_worker.GetSymbolForAddress( v.symAddr ) : v.symAddr; + auto it = baseMap.find( symAddr ); + if( it == baseMap.end() ) { - pdqsort_branchless( data.begin(), data.end(), []( const auto& l, const auto& r ) { return l.excl != r.excl ? l.excl > r.excl : l.symAddr < r.symAddr; } ); + baseMap.emplace( symAddr, SymList { symAddr, v.incl, v.excl, 0 } ); } else { - pdqsort_branchless( data.begin(), data.end(), []( const auto& l, const auto& r ) { return l.incl != r.incl ? l.incl > r.incl : l.symAddr < r.symAddr; } ); + assert( symAddr == it->second.symAddr ); + it->second.incl += v.incl; + it->second.excl += v.excl; + it->second.count++; + } + } + for( auto& v : data ) inlineMap.emplace( v.symAddr, SymList { v.symAddr, v.incl, v.excl, v.count } ); + data.clear(); + for( auto& v : baseMap ) + { + data.push_back_no_space_check( v.second ); + } + baseMap.clear(); + } + + if( data.empty() ) + { + ImGui::TextUnformatted( "No entries to be displayed." ); + } + else + { + const auto& symMap = m_worker.GetSymbolMap(); + + if( m_statAccumulationMode == AccumulationMode::SelfOnly ) + { + pdqsort_branchless( data.begin(), data.end(), []( const auto& l, const auto& r ) { return l.excl != r.excl ? l.excl > r.excl : l.symAddr < r.symAddr; } ); + } + else + { + pdqsort_branchless( data.begin(), data.end(), []( const auto& l, const auto& r ) { return l.incl != r.incl ? l.incl > r.incl : l.symAddr < r.symAddr; } ); + } + + ImGui::BeginChild( "##statisticsSampling" ); + if( ImGui::BeginTable( "##statisticsSampling", 5, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_ScrollY ) ) + { + ImGui::TableSetupScrollFreeze( 0, 1 ); + ImGui::TableSetupColumn( "Name", ImGuiTableColumnFlags_NoHide ); + ImGui::TableSetupColumn( "Location", ImGuiTableColumnFlags_NoSort ); + ImGui::TableSetupColumn( "Image" ); + ImGui::TableSetupColumn( m_statSampleTime ? "Time" : "Count", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize ); + ImGui::TableSetupColumn( "Code size", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize ); + ImGui::TableHeadersRow(); + + double revSampleCount100; + if( m_statRange.active && m_worker.GetSamplingPeriod() != 0 ) + { + const auto st = m_statRange.max - m_statRange.min; + const auto cnt = st / m_worker.GetSamplingPeriod(); + revSampleCount100 = 100. / cnt; + } + else + { + revSampleCount100 = 100. / m_worker.GetCallstackSampleCount(); } - ImGui::BeginChild( "##statisticsSampling" ); - if( ImGui::BeginTable( "##statisticsSampling", 5, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_ScrollY ) ) + const bool showAll = m_showAllSymbols; + const auto period = m_worker.GetSamplingPeriod(); + int idx = 0; + for( auto& v : data ) { - ImGui::TableSetupScrollFreeze( 0, 1 ); - ImGui::TableSetupColumn( "Name", ImGuiTableColumnFlags_NoHide ); - ImGui::TableSetupColumn( "Location", ImGuiTableColumnFlags_NoSort ); - ImGui::TableSetupColumn( "Image" ); - ImGui::TableSetupColumn( m_statSampleTime ? "Time" : "Count", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize ); - ImGui::TableSetupColumn( "Code size", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoResize ); - ImGui::TableHeadersRow(); + const auto cnt = m_statAccumulationMode == AccumulationMode::SelfOnly ? v.excl : v.incl; + if( cnt > 0 || showAll ) + { + const char* name = "[unknown]"; + const char* file = "[unknown]"; + const char* imageName = "[unknown]"; + uint32_t line = 0; + bool isInline = false; + uint32_t symlen = 0; + auto codeAddr = v.symAddr; - double revSampleCount100; - if( m_statRange.active && m_worker.GetSamplingPeriod() != 0 ) - { - const auto st = m_statRange.max - m_statRange.min; - const auto cnt = st / m_worker.GetSamplingPeriod(); - revSampleCount100 = 100. / cnt; - } - else - { - revSampleCount100 = 100. / m_worker.GetCallstackSampleCount(); - } - - const bool showAll = m_showAllSymbols; - const auto period = m_worker.GetSamplingPeriod(); - int idx = 0; - for( auto& v : data ) - { - const auto cnt = m_statAccumulationMode == AccumulationMode::SelfOnly ? v.excl : v.incl; - if( cnt > 0 || showAll ) + auto sit = symMap.find( v.symAddr ); + if( sit != symMap.end() ) { - const char* name = "[unknown]"; - const char* file = "[unknown]"; - const char* imageName = "[unknown]"; - uint32_t line = 0; - bool isInline = false; - uint32_t symlen = 0; - auto codeAddr = v.symAddr; - - auto sit = symMap.find( v.symAddr ); - if( sit != symMap.end() ) + name = m_worker.GetString( sit->second.name ); + imageName = m_worker.GetString( sit->second.imageName ); + isInline = sit->second.isInline; + switch( m_statSampleLocation ) { - name = m_worker.GetString( sit->second.name ); - imageName = m_worker.GetString( sit->second.imageName ); - isInline = sit->second.isInline; - switch( m_statSampleLocation ) + case 0: + file = m_worker.GetString( sit->second.file ); + line = sit->second.line; + break; + case 1: + file = m_worker.GetString( sit->second.callFile ); + line = sit->second.callLine; + break; + case 2: + if( sit->second.isInline ) { - case 0: - file = m_worker.GetString( sit->second.file ); - line = sit->second.line; - break; - case 1: file = m_worker.GetString( sit->second.callFile ); line = sit->second.callLine; - break; - case 2: - if( sit->second.isInline ) - { - file = m_worker.GetString( sit->second.callFile ); - line = sit->second.callLine; - } - else - { - file = m_worker.GetString( sit->second.file ); - line = sit->second.line; - } - break; - default: - assert( false ); - break; - } - if( m_statHideUnknown && file[0] == '[' ) continue; - symlen = sit->second.size.Val(); - } - else if( m_statHideUnknown ) - { - continue; - } - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - - const bool isKernel = v.symAddr >> 63 != 0; - const char* parentName = nullptr; - if( symlen == 0 && !isKernel ) - { - const auto parentAddr = m_worker.GetSymbolForAddress( v.symAddr ); - if( parentAddr != 0 ) - { - auto pit = symMap.find( parentAddr ); - if( pit != symMap.end() ) - { - codeAddr = parentAddr; - symlen = pit->second.size.Val(); - parentName = m_worker.GetString( pit->second.name ); - } - } - } - - bool expand = false; - if( !m_statSeparateInlines ) - { - if( v.count > 0 && v.symAddr != 0 ) - { - ImGui::PushID( v.symAddr ); - expand = ImGui::TreeNodeEx( "", v.count == 0 ? ImGuiTreeNodeFlags_Leaf : 0 ); - ImGui::PopID(); - ImGui::SameLine(); - } - } - else if( isInline ) - { - TextDisabledUnformatted( ICON_FA_CARET_RIGHT ); - ImGui::SameLine(); - } - uint32_t excl; - if( m_statSeparateInlines ) - { - excl = v.excl; - } - else - { - auto it = inlineMap.find( v.symAddr ); - excl = it != inlineMap.end() ? it->second.excl : 0; - } - if( v.symAddr == 0 || excl == 0 ) - { - if( isKernel ) - { - TextColoredUnformatted( 0xFF8888FF, name ); } else { - ImGui::TextUnformatted( name ); + file = m_worker.GetString( sit->second.file ); + line = sit->second.line; + } + break; + default: + assert( false ); + break; + } + if( m_statHideUnknown && file[0] == '[' ) continue; + symlen = sit->second.size.Val(); + } + else if( m_statHideUnknown ) + { + continue; + } + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + const bool isKernel = v.symAddr >> 63 != 0; + const char* parentName = nullptr; + if( symlen == 0 && !isKernel ) + { + const auto parentAddr = m_worker.GetSymbolForAddress( v.symAddr ); + if( parentAddr != 0 ) + { + auto pit = symMap.find( parentAddr ); + if( pit != symMap.end() ) + { + codeAddr = parentAddr; + symlen = pit->second.size.Val(); + parentName = m_worker.GetString( pit->second.name ); } } - else + } + + bool expand = false; + if( !m_statSeparateInlines ) + { + if( v.count > 0 && v.symAddr != 0 ) { - ImGui::PushID( idx++ ); - if( isKernel ) ImGui::PushStyleColor( ImGuiCol_Text, 0xFF8888FF ); - const auto clicked = ImGui::Selectable( name, m_sampleParents.symAddr == v.symAddr, ImGuiSelectableFlags_SpanAllColumns ); - if( isKernel ) ImGui::PopStyleColor(); - if( clicked ) ShowSampleParents( v.symAddr ); + ImGui::PushID( v.symAddr ); + expand = ImGui::TreeNodeEx( "", v.count == 0 ? ImGuiTreeNodeFlags_Leaf : 0 ); ImGui::PopID(); - } - if( parentName ) - { ImGui::SameLine(); - ImGui::TextDisabled( "(%s)", parentName ); } - if( !m_statSeparateInlines && v.count > 0 && v.symAddr != 0 ) + } + else if( isInline ) + { + TextDisabledUnformatted( ICON_FA_CARET_RIGHT ); + ImGui::SameLine(); + } + uint32_t excl; + if( m_statSeparateInlines ) + { + excl = v.excl; + } + else + { + auto it = inlineMap.find( v.symAddr ); + excl = it != inlineMap.end() ? it->second.excl : 0; + } + if( v.symAddr == 0 || excl == 0 ) + { + if( isKernel ) { - ImGui::SameLine(); - ImGui::TextDisabled( "(+%s)", RealToString( v.count ) ); - } - ImGui::TableNextColumn(); - float indentVal = 0.f; - if( m_statBuzzAnim.Match( v.symAddr ) ) - { - const auto time = m_statBuzzAnim.Time(); - indentVal = sin( time * 60.f ) * 10.f * time; - ImGui::Indent( indentVal ); - } - if( m_statShowAddress ) - { - ImGui::TextDisabled( "0x%" PRIx64, v.symAddr ); + TextColoredUnformatted( 0xFF8888FF, name ); } else { - TextDisabledUnformatted( LocationToString( file, line ) ); + ImGui::TextUnformatted( name ); } - if( ImGui::IsItemHovered() ) + } + else + { + ImGui::PushID( idx++ ); + if( isKernel ) ImGui::PushStyleColor( ImGuiCol_Text, 0xFF8888FF ); + const auto clicked = ImGui::Selectable( name, m_sampleParents.symAddr == v.symAddr, ImGuiSelectableFlags_SpanAllColumns ); + if( isKernel ) ImGui::PopStyleColor(); + if( clicked ) ShowSampleParents( v.symAddr ); + ImGui::PopID(); + } + if( parentName ) + { + ImGui::SameLine(); + ImGui::TextDisabled( "(%s)", parentName ); + } + if( !m_statSeparateInlines && v.count > 0 && v.symAddr != 0 ) + { + ImGui::SameLine(); + ImGui::TextDisabled( "(+%s)", RealToString( v.count ) ); + } + ImGui::TableNextColumn(); + float indentVal = 0.f; + if( m_statBuzzAnim.Match( v.symAddr ) ) + { + const auto time = m_statBuzzAnim.Time(); + indentVal = sin( time * 60.f ) * 10.f * time; + ImGui::Indent( indentVal ); + } + if( m_statShowAddress ) + { + ImGui::TextDisabled( "0x%" PRIx64, v.symAddr ); + } + else + { + TextDisabledUnformatted( LocationToString( file, line ) ); + } + if( ImGui::IsItemHovered() ) + { + DrawSourceTooltip( file, line ); + if( ImGui::IsItemClicked( 1 ) ) { - DrawSourceTooltip( file, line ); - if( ImGui::IsItemClicked( 1 ) ) + if( SourceFileValid( file, m_worker.GetCaptureTime(), *this, m_worker ) ) { - if( SourceFileValid( file, m_worker.GetCaptureTime(), *this, m_worker ) ) + ViewSymbol( file, line, codeAddr, v.symAddr ); + if( !m_statSeparateInlines ) m_sourceView->CalcInlineStats( false ); + } + else if( symlen != 0 ) + { + uint32_t len; + if( m_worker.GetSymbolCode( codeAddr, len ) ) { - ViewSymbol( file, line, codeAddr, v.symAddr ); + ViewSymbol( nullptr, 0, codeAddr, v.symAddr ); if( !m_statSeparateInlines ) m_sourceView->CalcInlineStats( false ); } - else if( symlen != 0 ) - { - uint32_t len; - if( m_worker.GetSymbolCode( codeAddr, len ) ) - { - ViewSymbol( nullptr, 0, codeAddr, v.symAddr ); - if( !m_statSeparateInlines ) m_sourceView->CalcInlineStats( false ); - } - else - { - m_statBuzzAnim.Enable( v.symAddr, 0.5f ); - } - } else { m_statBuzzAnim.Enable( v.symAddr, 0.5f ); } } - } - if( indentVal != 0.f ) - { - ImGui::Unindent( indentVal ); - } - ImGui::TableNextColumn(); - TextDisabledUnformatted( imageName ); - ImGui::TableNextColumn(); - if( cnt > 0 ) - { - char buf[64]; - if( m_statSampleTime ) + else { - const auto t = cnt * period; - ImGui::TextUnformatted( TimeToString( t ) ); - PrintStringPercent( buf, 100. * t / timeRange ); + m_statBuzzAnim.Enable( v.symAddr, 0.5f ); + } + } + } + if( indentVal != 0.f ) + { + ImGui::Unindent( indentVal ); + } + ImGui::TableNextColumn(); + TextDisabledUnformatted( imageName ); + ImGui::TableNextColumn(); + if( cnt > 0 ) + { + char buf[64]; + if( m_statSampleTime ) + { + const auto t = cnt * period; + ImGui::TextUnformatted( TimeToString( t ) ); + PrintStringPercent( buf, 100. * t / timeRange ); + } + else + { + ImGui::TextUnformatted( RealToString( cnt ) ); + PrintStringPercent( buf, cnt * revSampleCount100 ); + } + ImGui::SameLine(); + TextDisabledUnformatted( buf ); + } + ImGui::TableNextColumn(); + if( symlen != 0 ) + { + if( m_worker.HasSymbolCode( codeAddr ) ) + { + TextDisabledUnformatted( ICON_FA_DATABASE ); + ImGui::SameLine(); + } + if( isInline ) + { + TextDisabledUnformatted( "<" ); + ImGui::SameLine(); + } + TextDisabledUnformatted( MemSizeToString( symlen ) ); + } + + if( !m_statSeparateInlines && expand ) + { + assert( v.count > 0 ); + assert( symlen != 0 ); + auto inSym = m_worker.GetInlineSymbolList( v.symAddr, symlen ); + assert( inSym != 0 ); + const auto symEnd = v.symAddr + symlen; + Vector inSymList; + while( *inSym < symEnd ) + { + auto sit = inlineMap.find( *inSym ); + if( sit != inlineMap.end() ) + { + inSymList.push_back( SymList { *inSym, sit->second.incl, sit->second.excl } ); } else { - ImGui::TextUnformatted( RealToString( cnt ) ); - PrintStringPercent( buf, cnt * revSampleCount100 ); + inSymList.push_back( SymList { *inSym, 0, 0 } ); } - ImGui::SameLine(); - TextDisabledUnformatted( buf ); + inSym++; } - ImGui::TableNextColumn(); - if( symlen != 0 ) + auto statIt = inlineMap.find( v.symAddr ); + if( statIt != inlineMap.end() ) { - if( m_worker.HasSymbolCode( codeAddr ) ) - { - TextDisabledUnformatted( ICON_FA_DATABASE ); - ImGui::SameLine(); - } - if( isInline ) - { - TextDisabledUnformatted( "<" ); - ImGui::SameLine(); - } - TextDisabledUnformatted( MemSizeToString( symlen ) ); + inSymList.push_back( SymList { v.symAddr, statIt->second.incl, statIt->second.excl } ); } - if( !m_statSeparateInlines && expand ) + if( m_statAccumulationMode == AccumulationMode::SelfOnly ) { - assert( v.count > 0 ); - assert( symlen != 0 ); - auto inSym = m_worker.GetInlineSymbolList( v.symAddr, symlen ); - assert( inSym != 0 ); - const auto symEnd = v.symAddr + symlen; - Vector inSymList; - while( *inSym < symEnd ) + pdqsort_branchless( inSymList.begin(), inSymList.end(), []( const auto& l, const auto& r ) { return l.excl != r.excl ? l.excl > r.excl : l.symAddr < r.symAddr; } ); + } + else + { + pdqsort_branchless( inSymList.begin(), inSymList.end(), []( const auto& l, const auto& r ) { return l.incl != l.incl ? l.incl > r.incl : l.symAddr < r.symAddr; } ); + } + + ImGui::Indent(); + for( auto& iv : inSymList ) + { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + const auto cnt = m_statAccumulationMode == AccumulationMode::SelfOnly ? iv.excl : iv.incl; + if( cnt > 0 || showAll ) { - auto sit = inlineMap.find( *inSym ); - if( sit != inlineMap.end() ) + auto sit = symMap.find( iv.symAddr ); + assert( sit != symMap.end() ); + name = m_worker.GetString( sit->second.name ); + switch( m_statSampleLocation ) { - inSymList.push_back( SymList { *inSym, sit->second.incl, sit->second.excl } ); + case 0: + file = m_worker.GetString( sit->second.file ); + line = sit->second.line; + break; + case 1: + file = m_worker.GetString( sit->second.callFile ); + line = sit->second.callLine; + break; + case 2: + if( sit->second.isInline ) + { + file = m_worker.GetString( sit->second.callFile ); + line = sit->second.callLine; + } + else + { + file = m_worker.GetString( sit->second.file ); + line = sit->second.line; + } + break; + default: + assert( false ); + break; + } + + const auto sn = iv.symAddr == v.symAddr ? "[ - self - ]" : name; + if( iv.excl == 0 ) + { + ImGui::TextUnformatted( sn ); } else { - inSymList.push_back( SymList { *inSym, 0, 0 } ); + ImGui::PushID( idx++ ); + if( ImGui::Selectable( sn, m_sampleParents.symAddr == iv.symAddr, ImGuiSelectableFlags_SpanAllColumns ) ) + { + ShowSampleParents( iv.symAddr ); + } + ImGui::PopID(); } - inSym++; - } - auto statIt = inlineMap.find( v.symAddr ); - if( statIt != inlineMap.end() ) - { - inSymList.push_back( SymList { v.symAddr, statIt->second.incl, statIt->second.excl } ); - } - - if( m_statAccumulationMode == AccumulationMode::SelfOnly ) - { - pdqsort_branchless( inSymList.begin(), inSymList.end(), []( const auto& l, const auto& r ) { return l.excl != r.excl ? l.excl > r.excl : l.symAddr < r.symAddr; } ); - } - else - { - pdqsort_branchless( inSymList.begin(), inSymList.end(), []( const auto& l, const auto& r ) { return l.incl != l.incl ? l.incl > r.incl : l.symAddr < r.symAddr; } ); - } - - ImGui::Indent(); - for( auto& iv : inSymList ) - { - ImGui::TableNextRow(); ImGui::TableNextColumn(); - const auto cnt = m_statAccumulationMode == AccumulationMode::SelfOnly ? iv.excl : iv.incl; - if( cnt > 0 || showAll ) + float indentVal = 0.f; + if( m_statBuzzAnim.Match( iv.symAddr ) ) { - auto sit = symMap.find( iv.symAddr ); - assert( sit != symMap.end() ); - name = m_worker.GetString( sit->second.name ); - switch( m_statSampleLocation ) + const auto time = m_statBuzzAnim.Time(); + indentVal = sin( time * 60.f ) * 10.f * time; + ImGui::Indent( indentVal ); + } + if( m_statShowAddress ) + { + ImGui::TextDisabled( "0x%" PRIx64, iv.symAddr ); + } + else + { + TextDisabledUnformatted( LocationToString( file, line ) ); + } + if( ImGui::IsItemHovered() ) + { + DrawSourceTooltip( file, line ); + if( ImGui::IsItemClicked( 1 ) ) { - case 0: - file = m_worker.GetString( sit->second.file ); - line = sit->second.line; - break; - case 1: - file = m_worker.GetString( sit->second.callFile ); - line = sit->second.callLine; - break; - case 2: - if( sit->second.isInline ) + if( SourceFileValid( file, m_worker.GetCaptureTime(), *this, m_worker ) ) { - file = m_worker.GetString( sit->second.callFile ); - line = sit->second.callLine; + ViewSymbol( file, line, codeAddr, iv.symAddr ); + if( !m_statSeparateInlines ) m_sourceView->CalcInlineStats( true ); } - else + else if( symlen != 0 ) { - file = m_worker.GetString( sit->second.file ); - line = sit->second.line; - } - break; - default: - assert( false ); - break; - } - - const auto sn = iv.symAddr == v.symAddr ? "[ - self - ]" : name; - if( iv.excl == 0 ) - { - ImGui::TextUnformatted( sn ); - } - else - { - ImGui::PushID( idx++ ); - if( ImGui::Selectable( sn, m_sampleParents.symAddr == iv.symAddr, ImGuiSelectableFlags_SpanAllColumns ) ) - { - ShowSampleParents( iv.symAddr ); - } - ImGui::PopID(); - } - ImGui::TableNextColumn(); - float indentVal = 0.f; - if( m_statBuzzAnim.Match( iv.symAddr ) ) - { - const auto time = m_statBuzzAnim.Time(); - indentVal = sin( time * 60.f ) * 10.f * time; - ImGui::Indent( indentVal ); - } - if( m_statShowAddress ) - { - ImGui::TextDisabled( "0x%" PRIx64, iv.symAddr ); - } - else - { - TextDisabledUnformatted( LocationToString( file, line ) ); - } - if( ImGui::IsItemHovered() ) - { - DrawSourceTooltip( file, line ); - if( ImGui::IsItemClicked( 1 ) ) - { - if( SourceFileValid( file, m_worker.GetCaptureTime(), *this, m_worker ) ) + uint32_t len; + if( m_worker.GetSymbolCode( codeAddr, len ) ) { - ViewSymbol( file, line, codeAddr, iv.symAddr ); + ViewSymbol( nullptr, 0, codeAddr, iv.symAddr ); if( !m_statSeparateInlines ) m_sourceView->CalcInlineStats( true ); } - else if( symlen != 0 ) - { - uint32_t len; - if( m_worker.GetSymbolCode( codeAddr, len ) ) - { - ViewSymbol( nullptr, 0, codeAddr, iv.symAddr ); - if( !m_statSeparateInlines ) m_sourceView->CalcInlineStats( true ); - } - else - { - m_statBuzzAnim.Enable( iv.symAddr, 0.5f ); - } - } else { m_statBuzzAnim.Enable( iv.symAddr, 0.5f ); } } - } - if( indentVal != 0.f ) - { - ImGui::Unindent( indentVal ); - } - ImGui::TableNextColumn(); - ImGui::TableNextColumn(); - if( cnt > 0 ) - { - char buf[64]; - if( m_statSampleTime ) - { - const auto t = cnt * period; - ImGui::TextUnformatted( TimeToString( t ) ); - PrintStringPercent( buf, 100. * t / timeRange ); - } else { - ImGui::TextUnformatted( RealToString( cnt ) ); - PrintStringPercent( buf, cnt * revSampleCount100 ); + m_statBuzzAnim.Enable( iv.symAddr, 0.5f ); } - ImGui::SameLine(); - TextDisabledUnformatted( buf ); } } + if( indentVal != 0.f ) + { + ImGui::Unindent( indentVal ); + } + ImGui::TableNextColumn(); + ImGui::TableNextColumn(); + if( cnt > 0 ) + { + char buf[64]; + if( m_statSampleTime ) + { + const auto t = cnt * period; + ImGui::TextUnformatted( TimeToString( t ) ); + PrintStringPercent( buf, 100. * t / timeRange ); + } + else + { + ImGui::TextUnformatted( RealToString( cnt ) ); + PrintStringPercent( buf, cnt * revSampleCount100 ); + } + ImGui::SameLine(); + TextDisabledUnformatted( buf ); + } } - ImGui::Unindent(); - ImGui::TreePop(); } + ImGui::Unindent(); + ImGui::TreePop(); } } - ImGui::EndTable(); } - ImGui::EndChild(); - - inlineMap.clear(); + ImGui::EndTable(); } + ImGui::EndChild(); + + inlineMap.clear(); } -#endif - ImGui::End(); } void View::DrawCallstackWindow() diff --git a/server/TracyView.hpp b/server/TracyView.hpp index c16b66f9..da50668e 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -153,6 +153,13 @@ private: bool highlight; }; + struct SymList + { + uint64_t symAddr; + uint32_t incl, excl; + uint32_t count; + }; + void InitMemory(); void InitTextEditor( ImFont* font ); @@ -196,6 +203,7 @@ private: void DrawFindZone(); void AccumulationModeComboBox(); void DrawStatistics(); + void DrawSamplesStatistics(Vector& data, int64_t timeRange); void DrawMemory(); void DrawAllocList(); void DrawCompare(); From e4ce9f0f4136127dd359edb3e23412de60c769fd Mon Sep 17 00:00:00 2001 From: xavier Date: Sat, 4 Sep 2021 16:11:41 +0200 Subject: [PATCH 2/9] Include threadid in SampleDataRange TODO: maybe make lists per thread to avoid increasing the packed structure by 2 bytes? --- server/TracyEvent.hpp | 1 + server/TracyWorker.cpp | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/server/TracyEvent.hpp b/server/TracyEvent.hpp index edb5ba67..499778ea 100644 --- a/server/TracyEvent.hpp +++ b/server/TracyEvent.hpp @@ -268,6 +268,7 @@ enum { SampleDataSize = sizeof( SampleData ) }; struct SampleDataRange { Int48 time; + uint16_t thread; CallstackFrameId ip; }; diff --git a/server/TracyWorker.cpp b/server/TracyWorker.cpp index 754c403a..306f9d27 100644 --- a/server/TracyWorker.cpp +++ b/server/TracyWorker.cpp @@ -1931,6 +1931,7 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks ) jobs.emplace_back( std::thread( [this] { for( auto& t : m_data.threads ) { + uint16_t tid = CompressThread( t->id ); for( auto& v : t->samples ) { const auto& time = v.time; @@ -1944,11 +1945,11 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks ) auto it = m_data.symbolSamples.find( symAddr ); if( it == m_data.symbolSamples.end() ) { - m_data.symbolSamples.emplace( symAddr, Vector( SampleDataRange { time, ip } ) ); + m_data.symbolSamples.emplace( symAddr, Vector( SampleDataRange { time, tid, ip } ) ); } else { - it->second.push_back_non_empty( SampleDataRange { time, ip } ); + it->second.push_back_non_empty( SampleDataRange { time, tid, ip } ); } } for( uint16_t i=1; i( SampleDataRange { sd.time, ip } ) ); + m_data.symbolSamples.emplace( symAddr, Vector( SampleDataRange { sd.time, tid, ip } ) ); } else { if( sit->second.back().time.Val() <= sd.time.Val() ) { - sit->second.push_back_non_empty( SampleDataRange { sd.time, ip } ); + sit->second.push_back_non_empty( SampleDataRange { sd.time, tid, ip } ); } else { auto iit = std::upper_bound( sit->second.begin(), sit->second.end(), sd.time.Val(), [] ( const auto& lhs, const auto& rhs ) { return lhs < rhs.time.Val(); } ); - sit->second.insert( iit, SampleDataRange { sd.time, ip } ); + sit->second.insert( iit, SampleDataRange { sd.time, tid, ip } ); } } } @@ -6023,11 +6026,11 @@ void Worker::ProcessCallstackSampleImpl( const SampleData& sd, ThreadData& td, i auto sit = m_data.pendingSymbolSamples.find( ip ); if( sit == m_data.pendingSymbolSamples.end() ) { - m_data.pendingSymbolSamples.emplace( ip, Vector( SampleDataRange { sd.time, ip } ) ); + m_data.pendingSymbolSamples.emplace( ip, Vector( SampleDataRange { sd.time, tid, ip } ) ); } else { - sit->second.push_back_non_empty( SampleDataRange { sd.time, ip } ); + sit->second.push_back_non_empty( SampleDataRange { sd.time, tid, ip } ); } } } From ed42c2388ccb356bffdcdc2db8e56dd27d1c2df4 Mon Sep 17 00:00:00 2001 From: xavier Date: Sat, 4 Sep 2021 16:07:09 +0200 Subject: [PATCH 3/9] Add samples statistics to the "find zone" window --- server/TracyView.cpp | 88 +++++++++++++++++++++++++++++++++++++++++--- server/TracyView.hpp | 4 +- 2 files changed, 85 insertions(+), 7 deletions(-) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index 2c89e0bf..22970f95 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -10753,6 +10753,8 @@ void View::DrawFindZone() const auto limitRange = m_findZone.range.active; FindZone::Group* group = nullptr; uint64_t lastGid = std::numeric_limits::max() - 1; + Vector>* threadZones = nullptr; + uint16_t lastTid = std::numeric_limits::max(); auto zptr = zones.data() + m_findZone.processed; const auto zend = zones.data() + zones.size(); while( zptr < zend ) @@ -10853,6 +10855,13 @@ void View::DrawFindZone() } group->time += timespan; group->zones.push_back_non_empty( ev.Zone() ); + + if (lastTid != ev.Thread()) { + lastTid = ev.Thread(); + threadZones = &m_findZone.samplesCache.threads[lastTid]; + threadZones->reserve( 1024 ); + } + threadZones->push_back_non_empty(ev.Zone()); } m_findZone.processed = zptr - zones.data(); @@ -11070,6 +11079,73 @@ void View::DrawFindZone() } } } + + if( ImGui::TreeNodeEx( "Samples", ImGuiTreeNodeFlags_None ) ) + { + { + ImGui::Checkbox( ICON_FA_STOPWATCH " Show time", &m_statSampleTime ); + 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_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::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel ); + } + + for (auto& t: m_findZone.threads) { + pdqsort_branchless( t.second.begin(), t.second.end(), []( const auto& lhs, const auto& rhs ) { return (*lhs).Start() < (*rhs).Start(); } ); + } + + const auto& symMap = m_worker.GetSymbolMap(); + Vector data; + data.reserve( symMap.size() ); + for( auto& v : symMap ) + { + bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ); + 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() ) + { + pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ); + } + } + } + if (!pass) continue; + + auto samples = m_worker.GetSamplesForSymbol( v.first ); + if( !samples ) continue; + + uint32_t count = 0; + for (auto it: *samples) { + const auto time = it.time.Val(); + const auto& zones = m_findZone.threads[it.thread]; + auto z = std::lower_bound( zones.begin(), zones.end(), time, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); + if( z == zones.end() ) continue; + if (z != zones.begin()) --z; + if (time >= (*z)->Start() && time < (*z)->End()) + count++; + } + if (count > 0) + data.push_back_no_space_check( SymList { v.first, 0, count } ); + } + DrawSamplesStatistics(data, m_worker.GetLastTime(), AccumulationMode::SelfOnly); + ImGui::TreePop(); + } + ImGui::EndChild(); } #endif @@ -12993,14 +13069,14 @@ void View::DrawStatistics() } } - DrawSamplesStatistics(data, timeRange); + DrawSamplesStatistics(data, timeRange, m_statAccumulationMode); } #endif ImGui::End(); } -void View::DrawSamplesStatistics(Vector& data, int64_t timeRange) +void View::DrawSamplesStatistics(Vector& data, int64_t timeRange, AccumulationMode accumulationMode) { static unordered_flat_map inlineMap; assert( inlineMap.empty() ); @@ -13042,7 +13118,7 @@ void View::DrawSamplesStatistics(Vector& data, int64_t timeRange) { const auto& symMap = m_worker.GetSymbolMap(); - if( m_statAccumulationMode == AccumulationMode::SelfOnly ) + if( accumulationMode == AccumulationMode::SelfOnly ) { pdqsort_branchless( data.begin(), data.end(), []( const auto& l, const auto& r ) { return l.excl != r.excl ? l.excl > r.excl : l.symAddr < r.symAddr; } ); } @@ -13079,7 +13155,7 @@ void View::DrawSamplesStatistics(Vector& data, int64_t timeRange) int idx = 0; for( auto& v : data ) { - const auto cnt = m_statAccumulationMode == AccumulationMode::SelfOnly ? v.excl : v.incl; + const auto cnt = accumulationMode == AccumulationMode::SelfOnly ? v.excl : v.incl; if( cnt > 0 || showAll ) { const char* name = "[unknown]"; @@ -13318,7 +13394,7 @@ void View::DrawSamplesStatistics(Vector& data, int64_t timeRange) inSymList.push_back( SymList { v.symAddr, statIt->second.incl, statIt->second.excl } ); } - if( m_statAccumulationMode == AccumulationMode::SelfOnly ) + if( accumulationMode == AccumulationMode::SelfOnly ) { pdqsort_branchless( inSymList.begin(), inSymList.end(), []( const auto& l, const auto& r ) { return l.excl != r.excl ? l.excl > r.excl : l.symAddr < r.symAddr; } ); } @@ -13332,7 +13408,7 @@ void View::DrawSamplesStatistics(Vector& data, int64_t timeRange) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - const auto cnt = m_statAccumulationMode == AccumulationMode::SelfOnly ? iv.excl : iv.incl; + const auto cnt = accumulationMode == AccumulationMode::SelfOnly ? iv.excl : iv.incl; if( cnt > 0 || showAll ) { auto sit = symMap.find( iv.symAddr ); diff --git a/server/TracyView.hpp b/server/TracyView.hpp index da50668e..2b552685 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -203,7 +203,7 @@ private: void DrawFindZone(); void AccumulationModeComboBox(); void DrawStatistics(); - void DrawSamplesStatistics(Vector& data, int64_t timeRange); + void DrawSamplesStatistics(Vector& data, int64_t timeRange, AccumulationMode accumulationMode); void DrawMemory(); void DrawAllocList(); void DrawCompare(); @@ -523,6 +523,7 @@ private: bool ignoreCase = false; std::vector match; unordered_flat_map groups; + unordered_flat_map> > threads; size_t processed; uint16_t groupId; int selMatch = 0; @@ -587,6 +588,7 @@ private: { ResetSelection(); groups.clear(); + threads.clear(); processed = 0; groupId = 0; selCs = 0; From 0089c832f767e30c96045216d87ebabdce763045 Mon Sep 17 00:00:00 2001 From: xavier Date: Sat, 4 Sep 2021 22:16:20 +0200 Subject: [PATCH 4/9] Cache samples statistics in the "find zone" window --- server/TracyView.cpp | 92 ++++++++++++++++++++++++++++---------------- server/TracyView.hpp | 11 +++++- 2 files changed, 68 insertions(+), 35 deletions(-) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index 22970f95..fe524488 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -10862,6 +10862,7 @@ void View::DrawFindZone() threadZones->reserve( 1024 ); } threadZones->push_back_non_empty(ev.Zone()); + m_findZone.samplesCache.scheduleUpdate = true; } m_findZone.processed = zptr - zones.data(); @@ -11099,50 +11100,75 @@ void View::DrawFindZone() ImGui::SameLine(); ImGui::Spacing(); ImGui::SameLine(); - ImGui::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel ); + if( ImGui::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel )) + { + m_findZone.samplesCache.scheduleUpdate = true; + } } - for (auto& t: m_findZone.threads) { - pdqsort_branchless( t.second.begin(), t.second.end(), []( const auto& lhs, const auto& rhs ) { return (*lhs).Start() < (*rhs).Start(); } ); - } + if (m_findZone.samplesCache.scheduleUpdate && !m_findZone.scheduleResetMatch) { + m_findZone.samplesCache.scheduleUpdate = false; - const auto& symMap = m_worker.GetSymbolMap(); - Vector data; - data.reserve( symMap.size() ); - for( auto& v : symMap ) - { - bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ); - if( !pass && v.second.size.Val() == 0 ) - { - const auto parentAddr = m_worker.GetSymbolForAddress( v.first ); - if( parentAddr != 0 ) + m_findZone.samplesCache.timeRange = 0; + for (auto& t: m_findZone.samplesCache.threads) { + pdqsort_branchless( t.second.begin(), t.second.end(), []( const auto& lhs, const auto& rhs ) { return (*lhs).Start() < (*rhs).Start(); } ); + int64_t prevEnd = 0; + for (const auto& it : t.second) { - auto pit = symMap.find( parentAddr ); - if( pit != symMap.end() ) - { - pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ); + int64_t start = (*it).Start(); + int64_t end = (*it).End(); + if (start < prevEnd) start = prevEnd; + if (start < end) { + prevEnd = end; + m_findZone.samplesCache.timeRange += end - start; } } } - if (!pass) continue; - auto samples = m_worker.GetSamplesForSymbol( v.first ); - if( !samples ) continue; + const auto& symMap = m_worker.GetSymbolMap(); + m_findZone.samplesCache.counts.clear(); + m_findZone.samplesCache.counts.reserve( symMap.size() ); - uint32_t count = 0; - for (auto it: *samples) { - const auto time = it.time.Val(); - const auto& zones = m_findZone.threads[it.thread]; - auto z = std::lower_bound( zones.begin(), zones.end(), time, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); - if( z == zones.end() ) continue; - if (z != zones.begin()) --z; - if (time >= (*z)->Start() && time < (*z)->End()) - count++; + for( auto& v : symMap ) + { + bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ); + 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() ) + { + pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ); + } + } + } + if (!pass) continue; + + auto samples = m_worker.GetSamplesForSymbol( v.first ); + if( !samples ) continue; + + uint32_t count = 0; + for (auto it: *samples) { + const auto time = it.time.Val(); + const auto& zones = m_findZone.samplesCache.threads[it.thread]; + auto z = std::lower_bound( zones.begin(), zones.end(), time, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); + if( z == zones.end() ) continue; + if (z != zones.begin()) --z; + if (time >= (*z)->Start() && time < (*z)->End()) + count++; + } + if (count > 0) + m_findZone.samplesCache.counts.push_back_no_space_check( SymList { v.first, 0, count } ); } - if (count > 0) - data.push_back_no_space_check( SymList { v.first, 0, count } ); } - DrawSamplesStatistics(data, m_worker.GetLastTime(), AccumulationMode::SelfOnly); + + Vector data; + data.reserve(m_findZone.samplesCache.counts.size()); + for (auto it: m_findZone.samplesCache.counts) data.push_back_no_space_check(it); + DrawSamplesStatistics(data, m_findZone.samplesCache.timeRange, AccumulationMode::SelfOnly); + ImGui::TreePop(); } diff --git a/server/TracyView.hpp b/server/TracyView.hpp index 2b552685..97af5fba 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -523,7 +523,6 @@ private: bool ignoreCase = false; std::vector match; unordered_flat_map groups; - unordered_flat_map> > threads; size_t processed; uint16_t groupId; int selMatch = 0; @@ -563,6 +562,13 @@ private: ptrdiff_t distEnd; } binCache; + struct { + unordered_flat_map> > threads; + Vector counts; + int64_t timeRange = 0; + bool scheduleUpdate = false; + } samplesCache; + void Reset() { ResetMatch(); @@ -588,7 +594,8 @@ private: { ResetSelection(); groups.clear(); - threads.clear(); + samplesCache.threads.clear(); + samplesCache.counts.clear(); processed = 0; groupId = 0; selCs = 0; From 1233b39b6961236380cbe6244174f902ea297e26 Mon Sep 17 00:00:00 2001 From: xavier Date: Sun, 5 Sep 2021 09:12:35 +0200 Subject: [PATCH 5/9] Move samples before groups in "find zone" window and fix style --- server/TracyView.cpp | 193 ++++++++++++++++++++++--------------------- 1 file changed, 100 insertions(+), 93 deletions(-) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index fe524488..42e50812 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -10698,6 +10698,103 @@ void View::DrawFindZone() ImGui::Separator(); SmallCheckbox( "Show zone time in frames", &m_findZone.showZoneInFrames ); ImGui::Separator(); + + if( ImGui::TreeNodeEx( "Samples", ImGuiTreeNodeFlags_None ) ) + { + { + ImGui::Checkbox( ICON_FA_STOPWATCH " Show time", &m_statSampleTime ); + 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_SITEMAP " Inlines", &m_statSeparateInlines ); + ImGui::SameLine(); + ImGui::Spacing(); + ImGui::SameLine(); + ImGui::Checkbox( ICON_FA_AT " Address", &m_statShowAddress ); + ImGui::SameLine(); + ImGui::Spacing(); + ImGui::SameLine(); + if( ImGui::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel )) + { + m_findZone.samplesCache.scheduleUpdate = true; + } + } + + if( m_findZone.samplesCache.scheduleUpdate && !m_findZone.scheduleResetMatch ) + { + m_findZone.samplesCache.scheduleUpdate = false; + + m_findZone.samplesCache.timeRange = 0; + for( auto& t: m_findZone.samplesCache.threads ) + { + pdqsort_branchless( t.second.begin(), t.second.end(), []( const auto& lhs, const auto& rhs ) { return (*lhs).Start() < (*rhs).Start(); } ); + + int64_t prevEnd = 0; + for( const auto& it : t.second ) + { + int64_t start = (*it).Start(); + int64_t end = (*it).End(); + if( start < prevEnd ) start = prevEnd; + if( start < end ) + { + prevEnd = end; + m_findZone.samplesCache.timeRange += end - start; + } + } + } + + const auto& symMap = m_worker.GetSymbolMap(); + m_findZone.samplesCache.counts.clear(); + m_findZone.samplesCache.counts.reserve( symMap.size() ); + + for( auto& v : symMap ) + { + bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ); + 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() ) + { + pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ); + } + } + } + if( !pass ) continue; + + auto samples = m_worker.GetSamplesForSymbol( v.first ); + if( !samples ) continue; + + uint32_t count = 0; + for( auto it: *samples ) + { + const auto time = it.time.Val(); + const auto& zones = m_findZone.samplesCache.threads[it.thread]; + auto z = std::lower_bound( zones.begin(), zones.end(), time, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); + if( z == zones.end() ) continue; + if( z != zones.begin() ) --z; + if( time >= (*z)->Start() && time < (*z)->End() ) + count++; + } + if( count > 0 ) m_findZone.samplesCache.counts.push_back_no_space_check( SymList { v.first, 0, count } ); + } + } + + Vector data; + data.reserve( m_findZone.samplesCache.counts.size() ); + for( auto it: m_findZone.samplesCache.counts ) data.push_back_no_space_check( it ); + DrawSamplesStatistics( data, m_findZone.samplesCache.timeRange, AccumulationMode::SelfOnly ); + + ImGui::TreePop(); + } + ImGui::Separator(); + ImGui::TextUnformatted( "Found zones:" ); ImGui::SameLine(); DrawHelpMarker( "Left click to highlight entry." ); @@ -10856,12 +10953,13 @@ void View::DrawFindZone() group->time += timespan; group->zones.push_back_non_empty( ev.Zone() ); - if (lastTid != ev.Thread()) { + if( lastTid != ev.Thread() ) + { lastTid = ev.Thread(); threadZones = &m_findZone.samplesCache.threads[lastTid]; threadZones->reserve( 1024 ); } - threadZones->push_back_non_empty(ev.Zone()); + threadZones->push_back_non_empty( ev.Zone() ); m_findZone.samplesCache.scheduleUpdate = true; } m_findZone.processed = zptr - zones.data(); @@ -11081,97 +11179,6 @@ void View::DrawFindZone() } } - if( ImGui::TreeNodeEx( "Samples", ImGuiTreeNodeFlags_None ) ) - { - { - ImGui::Checkbox( ICON_FA_STOPWATCH " Show time", &m_statSampleTime ); - 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_SITEMAP " Inlines", &m_statSeparateInlines ); - ImGui::SameLine(); - ImGui::Spacing(); - ImGui::SameLine(); - ImGui::Checkbox( ICON_FA_AT " Address", &m_statShowAddress ); - ImGui::SameLine(); - ImGui::Spacing(); - ImGui::SameLine(); - if( ImGui::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel )) - { - m_findZone.samplesCache.scheduleUpdate = true; - } - } - - if (m_findZone.samplesCache.scheduleUpdate && !m_findZone.scheduleResetMatch) { - m_findZone.samplesCache.scheduleUpdate = false; - - m_findZone.samplesCache.timeRange = 0; - for (auto& t: m_findZone.samplesCache.threads) { - pdqsort_branchless( t.second.begin(), t.second.end(), []( const auto& lhs, const auto& rhs ) { return (*lhs).Start() < (*rhs).Start(); } ); - int64_t prevEnd = 0; - for (const auto& it : t.second) - { - int64_t start = (*it).Start(); - int64_t end = (*it).End(); - if (start < prevEnd) start = prevEnd; - if (start < end) { - prevEnd = end; - m_findZone.samplesCache.timeRange += end - start; - } - } - } - - const auto& symMap = m_worker.GetSymbolMap(); - m_findZone.samplesCache.counts.clear(); - m_findZone.samplesCache.counts.reserve( symMap.size() ); - - for( auto& v : symMap ) - { - bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ); - 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() ) - { - pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ); - } - } - } - if (!pass) continue; - - auto samples = m_worker.GetSamplesForSymbol( v.first ); - if( !samples ) continue; - - uint32_t count = 0; - for (auto it: *samples) { - const auto time = it.time.Val(); - const auto& zones = m_findZone.samplesCache.threads[it.thread]; - auto z = std::lower_bound( zones.begin(), zones.end(), time, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); - if( z == zones.end() ) continue; - if (z != zones.begin()) --z; - if (time >= (*z)->Start() && time < (*z)->End()) - count++; - } - if (count > 0) - m_findZone.samplesCache.counts.push_back_no_space_check( SymList { v.first, 0, count } ); - } - } - - Vector data; - data.reserve(m_findZone.samplesCache.counts.size()); - for (auto it: m_findZone.samplesCache.counts) data.push_back_no_space_check(it); - DrawSamplesStatistics(data, m_findZone.samplesCache.timeRange, AccumulationMode::SelfOnly); - - ImGui::TreePop(); - } - ImGui::EndChild(); } #endif From 41130d2a694baf108e6f61828aff41a289cfd06f Mon Sep 17 00:00:00 2001 From: xavier Date: Sun, 5 Sep 2021 11:04:45 +0200 Subject: [PATCH 6/9] Avoid useless work when there aren't any samples --- server/TracyView.cpp | 35 ++++++++++++++++++++++++++++------- server/TracyView.hpp | 1 + 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index 42e50812..43dd081e 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -10699,7 +10699,8 @@ void View::DrawFindZone() SmallCheckbox( "Show zone time in frames", &m_findZone.showZoneInFrames ); ImGui::Separator(); - if( ImGui::TreeNodeEx( "Samples", ImGuiTreeNodeFlags_None ) ) + const bool hasSamples = m_worker.AreCallstackSamplesReady() && m_worker.GetCallstackSampleCount() > 0; + if( hasSamples && ImGui::TreeNodeEx( "Samples", ImGuiTreeNodeFlags_None ) ) { { ImGui::Checkbox( ICON_FA_STOPWATCH " Show time", &m_statSampleTime ); @@ -10723,6 +10724,12 @@ void View::DrawFindZone() m_findZone.samplesCache.scheduleUpdate = true; } } + + if( !m_findZone.samplesCache.needZonesPerThread ) + { + m_findZone.samplesCache.needZonesPerThread = true; + m_findZone.scheduleResetMatch = true; + } if( m_findZone.samplesCache.scheduleUpdate && !m_findZone.scheduleResetMatch ) { @@ -10793,6 +10800,16 @@ void View::DrawFindZone() ImGui::TreePop(); } + else + { + if( m_findZone.samplesCache.needZonesPerThread ) + { + m_findZone.samplesCache.needZonesPerThread = false; + m_findZone.samplesCache.scheduleUpdate = false; + m_findZone.samplesCache.counts = Vector(); + m_findZone.samplesCache.threads = unordered_flat_map> >(); + } + } ImGui::Separator(); ImGui::TextUnformatted( "Found zones:" ); @@ -10953,14 +10970,18 @@ void View::DrawFindZone() group->time += timespan; group->zones.push_back_non_empty( ev.Zone() ); - if( lastTid != ev.Thread() ) + + if( m_findZone.samplesCache.needZonesPerThread ) { - lastTid = ev.Thread(); - threadZones = &m_findZone.samplesCache.threads[lastTid]; - threadZones->reserve( 1024 ); + if( lastTid != ev.Thread() ) + { + lastTid = ev.Thread(); + threadZones = &m_findZone.samplesCache.threads[lastTid]; + threadZones->reserve( 1024 ); + } + threadZones->push_back_non_empty( ev.Zone() ); + m_findZone.samplesCache.scheduleUpdate = true; } - threadZones->push_back_non_empty( ev.Zone() ); - m_findZone.samplesCache.scheduleUpdate = true; } m_findZone.processed = zptr - zones.data(); diff --git a/server/TracyView.hpp b/server/TracyView.hpp index 97af5fba..c0dff780 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -567,6 +567,7 @@ private: Vector counts; int64_t timeRange = 0; bool scheduleUpdate = false; + bool needZonesPerThread = false; } samplesCache; void Reset() From 63acfe72e754b81a9e5a48cae03ecd7667ce3a46 Mon Sep 17 00:00:00 2001 From: xavier Date: Mon, 13 Sep 2021 21:40:02 +0200 Subject: [PATCH 7/9] Apply group filters to the samples statistics in the "find zone" window reduce memory by storing the thread ids next to the zones intead of making zone lists per thread. speed-up by reading the zones in linear order rather than bisecting the whole list for each sample. --- server/TracyView.cpp | 160 +++++++++++++++++++++++++++---------------- server/TracyView.hpp | 11 ++- 2 files changed, 105 insertions(+), 66 deletions(-) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index 43dd081e..bd525247 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -10721,42 +10721,41 @@ void View::DrawFindZone() ImGui::SameLine(); if( ImGui::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel )) { - m_findZone.samplesCache.scheduleUpdate = true; + m_findZone.samples.scheduleUpdate = true; } } - if( !m_findZone.samplesCache.needZonesPerThread ) + if( !m_findZone.samples.enabled ) { - m_findZone.samplesCache.needZonesPerThread = true; + m_findZone.samples.enabled = true; + m_findZone.samples.scheduleUpdate = true; m_findZone.scheduleResetMatch = true; } - if( m_findZone.samplesCache.scheduleUpdate && !m_findZone.scheduleResetMatch ) + if( m_findZone.samples.enabled && m_findZone.samples.scheduleUpdate && !m_findZone.scheduleResetMatch ) { - m_findZone.samplesCache.scheduleUpdate = false; - - m_findZone.samplesCache.timeRange = 0; - for( auto& t: m_findZone.samplesCache.threads ) - { - pdqsort_branchless( t.second.begin(), t.second.end(), []( const auto& lhs, const auto& rhs ) { return (*lhs).Start() < (*rhs).Start(); } ); - - int64_t prevEnd = 0; - for( const auto& it : t.second ) - { - int64_t start = (*it).Start(); - int64_t end = (*it).End(); - if( start < prevEnd ) start = prevEnd; - if( start < end ) - { - prevEnd = end; - m_findZone.samplesCache.timeRange += end - start; - } - } - } + m_findZone.samples.scheduleUpdate = false; const auto& symMap = m_worker.GetSymbolMap(); - m_findZone.samplesCache.counts.clear(); - m_findZone.samplesCache.counts.reserve( symMap.size() ); + m_findZone.samples.counts.clear(); + m_findZone.samples.counts.reserve( symMap.size() ); + + struct GroupRange { + const FindZone::Group* group; + Vector>::const_iterator begin; + Vector>::const_iterator end; + }; + Vector selectedGroups; + selectedGroups.reserve( m_findZone.groups.size() ); + for( auto it = m_findZone.groups.begin(); it != m_findZone.groups.end(); ++it ) + { + assert( it->second.zones.size() == it->second.zonesTids.size() ); + if( ( m_findZone.selGroup == m_findZone.Unselected || it->first == m_findZone.selGroup ) + && !it->second.zones.empty() ) + { + selectedGroups.push_back_no_space_check( GroupRange{&it->second} ); + } + } for( auto& v : symMap ) { @@ -10777,37 +10776,81 @@ void View::DrawFindZone() auto samples = m_worker.GetSamplesForSymbol( v.first ); if( !samples ) continue; + if( samples->empty() ) continue; - uint32_t count = 0; - for( auto it: *samples ) + auto samplesBegin = samples->begin(); + auto samplesEnd = samples->end(); + if( m_findZone.range.active ) { - const auto time = it.time.Val(); - const auto& zones = m_findZone.samplesCache.threads[it.thread]; - auto z = std::lower_bound( zones.begin(), zones.end(), time, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); - if( z == zones.end() ) continue; - if( z != zones.begin() ) --z; - if( time >= (*z)->Start() && time < (*z)->End() ) - count++; + const auto rangeMin = m_findZone.range.min; + const auto rangeMax = m_findZone.range.max; + samplesBegin = std::lower_bound( samplesBegin, samplesEnd, rangeMin, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } ); + if( samplesBegin != samplesEnd ) + { + samplesEnd = std::lower_bound( samplesBegin, samplesEnd, rangeMax, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } ); + } } - if( count > 0 ) m_findZone.samplesCache.counts.push_back_no_space_check( SymList { v.first, 0, count } ); + if( samplesBegin == samplesEnd ) continue; + + bool empty = true; + const auto firstTime = samplesBegin->time.Val(); + const auto lastTime = samplesEnd->time.Val(); + for( auto& g: selectedGroups ) + { + const auto& zones = g.group->zones; + auto begin = std::lower_bound( zones.begin(), zones.end(), firstTime, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); + auto end = std::upper_bound( begin, zones.end(), lastTime, [] ( const auto& l, const auto& r ) { return l <= r->Start(); } ); + g.begin = begin; + g.end = end; + empty = empty && (begin == end); + } + if (empty) continue; + + uint32_t count = 0; + for( auto it = samplesBegin; it != samplesEnd; ++it ) + { + const auto time = it->time.Val(); + bool pass = false; + for( auto& g: selectedGroups ) + { + while( g.begin != g.end && time > (*g.begin)->End() ) ++g.begin; + if( g.begin == g.end ) continue; + if( time < (*g.begin)->Start() ) continue; + + const auto& tids = g.group->zonesTids; + const auto firstZone = g.group->zones.begin(); + for (auto z = g.begin; z != g.end && (*z)->Start() <= time; ++z) + { + auto zoneIndex = z - firstZone; + if( (*z)->End() > time && it->thread == tids[zoneIndex] ) + { + pass = true; + break; + } + } + } + if( pass ) count ++; + } + if( count > 0 ) m_findZone.samples.counts.push_back_no_space_check( SymList { v.first, 0, count } ); } } Vector data; - data.reserve( m_findZone.samplesCache.counts.size() ); - for( auto it: m_findZone.samplesCache.counts ) data.push_back_no_space_check( it ); - DrawSamplesStatistics( data, m_findZone.samplesCache.timeRange, AccumulationMode::SelfOnly ); + data.reserve( m_findZone.samples.counts.size() ); + for( auto it: m_findZone.samples.counts ) data.push_back_no_space_check( it ); + int64_t timeRange = ( m_findZone.selGroup != m_findZone.Unselected ) ? m_findZone.selTotal : m_findZone.total; + DrawSamplesStatistics( data, timeRange, AccumulationMode::SelfOnly ); ImGui::TreePop(); } else { - if( m_findZone.samplesCache.needZonesPerThread ) + if( m_findZone.samples.enabled ) { - m_findZone.samplesCache.needZonesPerThread = false; - m_findZone.samplesCache.scheduleUpdate = false; - m_findZone.samplesCache.counts = Vector(); - m_findZone.samplesCache.threads = unordered_flat_map> >(); + m_findZone.samples.enabled = false; + m_findZone.samples.scheduleUpdate = false; + m_findZone.samples.counts = Vector(); + for( auto& it: m_findZone.groups ) it.second.zonesTids.clear(); } } ImGui::Separator(); @@ -10866,9 +10909,8 @@ void View::DrawFindZone() const auto highlightActive = m_findZone.highlight.active; const auto limitRange = m_findZone.range.active; FindZone::Group* group = nullptr; - uint64_t lastGid = std::numeric_limits::max() - 1; - Vector>* threadZones = nullptr; - uint16_t lastTid = std::numeric_limits::max(); + const uint64_t invalidGid = std::numeric_limits::max() - 1; + uint64_t lastGid = invalidGid; auto zptr = zones.data() + m_findZone.processed; const auto zend = zones.data() + zones.size(); while( zptr < zend ) @@ -10964,27 +11006,25 @@ void View::DrawFindZone() { it = m_findZone.groups.emplace( gid, FindZone::Group { m_findZone.groupId++ } ).first; it->second.zones.reserve( 1024 ); + if( m_findZone.samples.enabled ) + it->second.zonesTids.reserve( 1024 ); } group = &it->second; } group->time += timespan; group->zones.push_back_non_empty( ev.Zone() ); - - - if( m_findZone.samplesCache.needZonesPerThread ) - { - if( lastTid != ev.Thread() ) - { - lastTid = ev.Thread(); - threadZones = &m_findZone.samplesCache.threads[lastTid]; - threadZones->reserve( 1024 ); - } - threadZones->push_back_non_empty( ev.Zone() ); - m_findZone.samplesCache.scheduleUpdate = true; - } + if( m_findZone.samples.enabled ) + group->zonesTids.push_back_non_empty( ev.Thread() ); } m_findZone.processed = zptr - zones.data(); + const bool groupsUpdated = lastGid != invalidGid; + if( m_findZone.samples.enabled && groupsUpdated ) + { + m_findZone.samples.scheduleUpdate = true; + } + + Vector groups; groups.reserve_and_use( m_findZone.groups.size() ); int idx = 0; diff --git a/server/TracyView.hpp b/server/TracyView.hpp index c0dff780..3ea8dba8 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -516,6 +516,7 @@ private: { uint16_t id; Vector> zones; + Vector zonesTids; int64_t time = 0; }; @@ -563,12 +564,10 @@ private: } binCache; struct { - unordered_flat_map> > threads; Vector counts; - int64_t timeRange = 0; bool scheduleUpdate = false; - bool needZonesPerThread = false; - } samplesCache; + bool enabled = false; + } samples; void Reset() { @@ -595,8 +594,6 @@ private: { ResetSelection(); groups.clear(); - samplesCache.threads.clear(); - samplesCache.counts.clear(); processed = 0; groupId = 0; selCs = 0; @@ -613,6 +610,8 @@ private: selTotal = 0; selTime = 0; binCache.numBins = -1; + samples.counts.clear(); + samples.scheduleUpdate = true; } void ShowZone( int16_t srcloc, const char* name ) From 61670e30aa2725249cef0f68e01e78ae705f68bf Mon Sep 17 00:00:00 2001 From: xavier Date: Mon, 13 Sep 2021 22:09:40 +0200 Subject: [PATCH 8/9] Update samples statistics continuously in the "find zone" window --- server/TracyView.cpp | 202 +++++++++++++++++++++---------------------- server/TracyView.hpp | 2 +- 2 files changed, 100 insertions(+), 104 deletions(-) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index bd525247..ea3cf934 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -10732,109 +10732,6 @@ void View::DrawFindZone() m_findZone.scheduleResetMatch = true; } - if( m_findZone.samples.enabled && m_findZone.samples.scheduleUpdate && !m_findZone.scheduleResetMatch ) - { - m_findZone.samples.scheduleUpdate = false; - - const auto& symMap = m_worker.GetSymbolMap(); - m_findZone.samples.counts.clear(); - m_findZone.samples.counts.reserve( symMap.size() ); - - struct GroupRange { - const FindZone::Group* group; - Vector>::const_iterator begin; - Vector>::const_iterator end; - }; - Vector selectedGroups; - selectedGroups.reserve( m_findZone.groups.size() ); - for( auto it = m_findZone.groups.begin(); it != m_findZone.groups.end(); ++it ) - { - assert( it->second.zones.size() == it->second.zonesTids.size() ); - if( ( m_findZone.selGroup == m_findZone.Unselected || it->first == m_findZone.selGroup ) - && !it->second.zones.empty() ) - { - selectedGroups.push_back_no_space_check( GroupRange{&it->second} ); - } - } - - for( auto& v : symMap ) - { - bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ); - 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() ) - { - pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ); - } - } - } - if( !pass ) continue; - - auto samples = m_worker.GetSamplesForSymbol( v.first ); - if( !samples ) continue; - if( samples->empty() ) continue; - - auto samplesBegin = samples->begin(); - auto samplesEnd = samples->end(); - if( m_findZone.range.active ) - { - const auto rangeMin = m_findZone.range.min; - const auto rangeMax = m_findZone.range.max; - samplesBegin = std::lower_bound( samplesBegin, samplesEnd, rangeMin, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } ); - if( samplesBegin != samplesEnd ) - { - samplesEnd = std::lower_bound( samplesBegin, samplesEnd, rangeMax, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } ); - } - } - if( samplesBegin == samplesEnd ) continue; - - bool empty = true; - const auto firstTime = samplesBegin->time.Val(); - const auto lastTime = samplesEnd->time.Val(); - for( auto& g: selectedGroups ) - { - const auto& zones = g.group->zones; - auto begin = std::lower_bound( zones.begin(), zones.end(), firstTime, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); - auto end = std::upper_bound( begin, zones.end(), lastTime, [] ( const auto& l, const auto& r ) { return l <= r->Start(); } ); - g.begin = begin; - g.end = end; - empty = empty && (begin == end); - } - if (empty) continue; - - uint32_t count = 0; - for( auto it = samplesBegin; it != samplesEnd; ++it ) - { - const auto time = it->time.Val(); - bool pass = false; - for( auto& g: selectedGroups ) - { - while( g.begin != g.end && time > (*g.begin)->End() ) ++g.begin; - if( g.begin == g.end ) continue; - if( time < (*g.begin)->Start() ) continue; - - const auto& tids = g.group->zonesTids; - const auto firstZone = g.group->zones.begin(); - for (auto z = g.begin; z != g.end && (*z)->Start() <= time; ++z) - { - auto zoneIndex = z - firstZone; - if( (*z)->End() > time && it->thread == tids[zoneIndex] ) - { - pass = true; - break; - } - } - } - if( pass ) count ++; - } - if( count > 0 ) m_findZone.samples.counts.push_back_no_space_check( SymList { v.first, 0, count } ); - } - } - Vector data; data.reserve( m_findZone.samples.counts.size() ); for( auto it: m_findZone.samples.counts ) data.push_back_no_space_check( it ); @@ -11240,6 +11137,105 @@ void View::DrawFindZone() } } + if( m_findZone.samples.enabled && m_findZone.samples.scheduleUpdate && !m_findZone.scheduleResetMatch ) + { + m_findZone.samples.scheduleUpdate = false; + + const auto& symMap = m_worker.GetSymbolMap(); + m_findZone.samples.counts.clear(); + m_findZone.samples.counts.reserve( symMap.size() ); + + struct GroupRange { + const FindZone::Group* group; + Vector>::const_iterator begin; + Vector>::const_iterator end; + }; + Vector selectedGroups; + selectedGroups.reserve( m_findZone.groups.size() ); + for( auto it = m_findZone.groups.begin(); it != m_findZone.groups.end(); ++it ) + { + assert( it->second.zones.size() == it->second.zonesTids.size() ); + if( ( m_findZone.selGroup == m_findZone.Unselected || it->first == m_findZone.selGroup ) + && !it->second.zones.empty() ) + { + selectedGroups.push_back_no_space_check( GroupRange{&it->second} ); + } + } + + for( auto& v : symMap ) + { + bool pass = ( m_statShowKernel || ( v.first >> 63 ) == 0 ); + 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() ) + { + pass = ( m_statShowKernel || ( parentAddr >> 63 ) == 0 ); + } + } + } + if( !pass ) continue; + + auto samples = m_worker.GetSamplesForSymbol( v.first ); + if( !samples ) continue; + + auto samplesBegin = samples->begin(); + auto samplesEnd = samples->end(); + if( m_findZone.range.active ) + { + const auto rangeMin = m_findZone.range.min; + const auto rangeMax = m_findZone.range.max; + samplesBegin = std::lower_bound( samplesBegin, samplesEnd, rangeMin, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } ); + samplesEnd = std::lower_bound( samplesBegin, samplesEnd, rangeMax, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } ); + } + if( samplesBegin == samplesEnd ) continue; + + bool empty = true; + const auto firstTime = samplesBegin->time.Val(); + const auto lastTime = samplesEnd->time.Val(); + for( auto& g: selectedGroups ) + { + const auto& zones = g.group->zones; + auto begin = std::lower_bound( zones.begin(), zones.end(), firstTime, [] ( const auto& l, const auto& r ) { return l->Start() < r; } ); + auto end = std::upper_bound( begin, zones.end(), lastTime, [] ( const auto& l, const auto& r ) { return l <= r->Start(); } ); + g.begin = begin; + g.end = end; + empty = empty && (begin == end); + } + if (empty) continue; + + uint32_t count = 0; + for( auto it = samplesBegin; it != samplesEnd; ++it ) + { + const auto time = it->time.Val(); + bool pass = false; + for( auto& g: selectedGroups ) + { + while( g.begin != g.end && time > (*g.begin)->End() ) ++g.begin; + if( g.begin == g.end ) continue; + if( time < (*g.begin)->Start() ) continue; + + const auto& tids = g.group->zonesTids; + const auto firstZone = g.group->zones.begin(); + for (auto z = g.begin; z != g.end && (*z)->Start() <= time; ++z) + { + auto zoneIndex = z - firstZone; + if( (*z)->End() > time && it->thread == tids[zoneIndex] ) + { + pass = true; + break; + } + } + } + if( pass ) count ++; + } + if( count > 0 ) m_findZone.samples.counts.push_back_no_space_check( SymList { v.first, 0, count } ); + } + } + ImGui::EndChild(); } #endif diff --git a/server/TracyView.hpp b/server/TracyView.hpp index 3ea8dba8..20eeda4a 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -576,6 +576,7 @@ private: selMatch = 0; selGroup = Unselected; highlight.active = false; + samples.counts.clear(); } void ResetMatch() @@ -610,7 +611,6 @@ private: selTotal = 0; selTime = 0; binCache.numBins = -1; - samples.counts.clear(); samples.scheduleUpdate = true; } From f37ef1affd9b3c15d9ab63fc3b6fbf06514aa41c Mon Sep 17 00:00:00 2001 From: xavier Date: Tue, 14 Sep 2021 10:33:37 +0200 Subject: [PATCH 9/9] Display the samples after the groups in the "find zone" window to make it clear they are filtered by selected group. --- server/TracyView.cpp | 106 +++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/server/TracyView.cpp b/server/TracyView.cpp index ea3cf934..6ae3a96d 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -10699,59 +10699,6 @@ void View::DrawFindZone() SmallCheckbox( "Show zone time in frames", &m_findZone.showZoneInFrames ); ImGui::Separator(); - const bool hasSamples = m_worker.AreCallstackSamplesReady() && m_worker.GetCallstackSampleCount() > 0; - if( hasSamples && ImGui::TreeNodeEx( "Samples", ImGuiTreeNodeFlags_None ) ) - { - { - ImGui::Checkbox( ICON_FA_STOPWATCH " Show time", &m_statSampleTime ); - 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_SITEMAP " Inlines", &m_statSeparateInlines ); - ImGui::SameLine(); - ImGui::Spacing(); - ImGui::SameLine(); - ImGui::Checkbox( ICON_FA_AT " Address", &m_statShowAddress ); - ImGui::SameLine(); - ImGui::Spacing(); - ImGui::SameLine(); - if( ImGui::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel )) - { - m_findZone.samples.scheduleUpdate = true; - } - } - - if( !m_findZone.samples.enabled ) - { - m_findZone.samples.enabled = true; - m_findZone.samples.scheduleUpdate = true; - m_findZone.scheduleResetMatch = true; - } - - Vector data; - data.reserve( m_findZone.samples.counts.size() ); - for( auto it: m_findZone.samples.counts ) data.push_back_no_space_check( it ); - int64_t timeRange = ( m_findZone.selGroup != m_findZone.Unselected ) ? m_findZone.selTotal : m_findZone.total; - DrawSamplesStatistics( data, timeRange, AccumulationMode::SelfOnly ); - - ImGui::TreePop(); - } - else - { - if( m_findZone.samples.enabled ) - { - m_findZone.samples.enabled = false; - m_findZone.samples.scheduleUpdate = false; - m_findZone.samples.counts = Vector(); - for( auto& it: m_findZone.groups ) it.second.zonesTids.clear(); - } - } - ImGui::Separator(); - ImGui::TextUnformatted( "Found zones:" ); ImGui::SameLine(); DrawHelpMarker( "Left click to highlight entry." ); @@ -11236,6 +11183,59 @@ void View::DrawFindZone() } } + ImGui::Separator(); + const bool hasSamples = m_worker.AreCallstackSamplesReady() && m_worker.GetCallstackSampleCount() > 0; + if( hasSamples && ImGui::TreeNodeEx( "Samples", ImGuiTreeNodeFlags_None ) ) + { + { + ImGui::Checkbox( ICON_FA_STOPWATCH " Show time", &m_statSampleTime ); + 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_SITEMAP " Inlines", &m_statSeparateInlines ); + ImGui::SameLine(); + ImGui::Spacing(); + ImGui::SameLine(); + ImGui::Checkbox( ICON_FA_AT " Address", &m_statShowAddress ); + ImGui::SameLine(); + ImGui::Spacing(); + ImGui::SameLine(); + if( ImGui::Checkbox( ICON_FA_HAT_WIZARD " Include kernel", &m_statShowKernel )) + { + m_findZone.samples.scheduleUpdate = true; + } + } + + if( !m_findZone.samples.enabled ) + { + m_findZone.samples.enabled = true; + m_findZone.samples.scheduleUpdate = true; + m_findZone.scheduleResetMatch = true; + } + + Vector data; + data.reserve( m_findZone.samples.counts.size() ); + for( auto it: m_findZone.samples.counts ) data.push_back_no_space_check( it ); + int64_t timeRange = ( m_findZone.selGroup != m_findZone.Unselected ) ? m_findZone.selTotal : m_findZone.total; + DrawSamplesStatistics( data, timeRange, AccumulationMode::SelfOnly ); + + ImGui::TreePop(); + } + else + { + if( m_findZone.samples.enabled ) + { + m_findZone.samples.enabled = false; + m_findZone.samples.scheduleUpdate = false; + m_findZone.samples.counts = Vector(); + for( auto& it: m_findZone.groups ) it.second.zonesTids.clear(); + } + } + ImGui::EndChild(); } #endif