Special mode for callstack grouping in find zone menu.

This commit is contained in:
Bartosz Taudul 2019-02-27 20:37:38 +01:00
parent 851ae9077b
commit 422ed1f452
2 changed files with 206 additions and 112 deletions

View File

@ -5655,11 +5655,11 @@ void View::DrawFindZone()
ImGui::Separator(); ImGui::Separator();
auto& zoneData = m_worker.GetZonesForSourceLocation( m_findZone.match[m_findZone.selMatch] );
if( ImGui::TreeNodeEx( "Histogram", ImGuiTreeNodeFlags_DefaultOpen ) ) if( ImGui::TreeNodeEx( "Histogram", ImGuiTreeNodeFlags_DefaultOpen ) )
{ {
const auto ty = ImGui::GetFontSize(); const auto ty = ImGui::GetFontSize();
auto& zoneData = m_worker.GetZonesForSourceLocation( m_findZone.match[m_findZone.selMatch] );
auto& zones = zoneData.zones; auto& zones = zoneData.zones;
const auto tmin = m_findZone.selfTime ? zoneData.selfMin : zoneData.min; const auto tmin = m_findZone.selfTime ? zoneData.selfMin : zoneData.min;
const auto tmax = m_findZone.selfTime ? zoneData.selfMax : zoneData.max; const auto tmax = m_findZone.selfTime ? zoneData.selfMax : zoneData.max;
@ -6406,137 +6406,139 @@ void View::DrawFindZone()
ImGui::BeginChild( "##zonesScroll", ImVec2( ImGui::GetWindowContentRegionWidth(), std::max( 200.f, ImGui::GetContentRegionAvail().y ) ) ); ImGui::BeginChild( "##zonesScroll", ImVec2( ImGui::GetWindowContentRegionWidth(), std::max( 200.f, ImGui::GetContentRegionAvail().y ) ) );
idx = 0; idx = 0;
for( auto& v : groups ) if( groupBy == FindZone::GroupBy::Callstack )
{ {
const char* hdrString; const auto gsz = groups.size();
switch( groupBy ) if( gsz > 0 )
{ {
case FindZone::GroupBy::Thread: if( m_findZone.selCs > gsz ) m_findZone.selCs = gsz;
hdrString = m_worker.GetThreadString( m_worker.DecompressThread( v->first ) ); const auto group = groups[m_findZone.selCs];
break;
case FindZone::GroupBy::UserText: const bool selHilite = m_findZone.selGroup == group->first;
hdrString = v->first == std::numeric_limits<uint64_t>::max() ? "No user text" : m_worker.GetString( StringIdx( v->first ) ); if( selHilite ) SetButtonHighlightColor();
break; #ifdef TRACY_EXTENDED_FONT
case FindZone::GroupBy::Callstack: if( ImGui::SmallButton( " " ICON_FA_CHECK " " ) )
if( v->first == 0 ) #else
if( ImGui::SmallButton( "Select" ) )
#endif
{ {
hdrString = "No callstack"; m_findZone.selGroup = group->first;
m_findZone.ResetSelection();
} }
else if( selHilite ) ImGui::PopStyleColor( 3 );
ImGui::SameLine();
#ifdef TRACY_EXTENDED_FONT
if( ImGui::SmallButton( " " ICON_FA_CARET_LEFT " " ) )
#else
if( ImGui::SmallButton( " < " ) )
#endif
{ {
auto& callstack = m_worker.GetCallstack( v->first ); m_findZone.selCs = std::max( m_findZone.selCs - 1, 0 );
auto& frameData = *m_worker.GetCallstackFrame( *callstack.begin() );
hdrString = m_worker.GetString( frameData.data[frameData.size-1].name );
} }
break;
default:
hdrString = nullptr;
assert( false );
break;
}
ImGui::PushID( v->first );
const bool expand = ImGui::TreeNodeEx( hdrString, ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ( v->first == m_findZone.selGroup ? ImGuiTreeNodeFlags_Selected : 0 ) );
if( ImGui::IsItemClicked() )
{
m_findZone.selGroup = v->first;
m_findZone.ResetSelection();
}
ImGui::PopID();
ImGui::SameLine();
ImGui::TextColored( ImVec4( 0.5f, 0.5f, 0.5f, 1.0f ), "(%s) %s", RealToString( v->second.zones.size(), true ), TimeToString( v->second.time ) );
if( groupBy == FindZone::GroupBy::Callstack && v->first != 0 )
{
ImGui::SameLine(); ImGui::SameLine();
SmallCallstackButton( "callstack", v->first, idx ); ImGui::Text( "%s / %s", RealToString( m_findZone.selCs + 1, true ), RealToString( gsz, true ) );
}
if( expand )
{
ImGui::Columns( 3, hdrString );
ImGui::Separator();
if( ImGui::SmallButton( "Time from start" ) ) m_findZone.tableSortBy = FindZone::TableSortBy::Starttime;
ImGui::NextColumn();
if( ImGui::SmallButton( "Execution time" ) ) m_findZone.tableSortBy = FindZone::TableSortBy::Runtime;
ImGui::NextColumn();
if( ImGui::SmallButton( "Name" ) ) m_findZone.tableSortBy = FindZone::TableSortBy::Name;
ImGui::SameLine(); ImGui::SameLine();
DrawHelpMarker( "Only displayed if custom zone name is set." ); #ifdef TRACY_EXTENDED_FONT
ImGui::NextColumn(); if( ImGui::SmallButton( " " ICON_FA_CARET_RIGHT " " ) )
ImGui::Separator(); #else
if( ImGui::SmallButton( " > " ) )
Vector<ZoneEvent*>* zonesToIterate = &v->second.zones; #endif
Vector<ZoneEvent*> sortedZones;
if( m_findZone.tableSortBy != FindZone::TableSortBy::Starttime )
{ {
zonesToIterate = &sortedZones; m_findZone.selCs = std::min<int>( m_findZone.selCs + 1, gsz - 1 );
sortedZones.reserve_and_use( v->second.zones.size() ); }
memcpy( sortedZones.data(), v->second.zones.data(), v->second.zones.size() * sizeof( ZoneEvent* ) );
switch( m_findZone.tableSortBy ) ImGui::SameLine();
TextFocused( "Count:", RealToString( group->second.zones.size(), true ) );
ImGui::SameLine();
TextFocused( "Time:", TimeToString( group->second.time ) );
ImGui::SameLine();
ImGui::TextDisabled( "(%.2f%%)", group->second.time * 100.f / zoneData.total );
if( group->first != 0 )
{
ImGui::SameLine();
int fidx = 0;
#ifdef TRACY_EXTENDED_FONT
SmallCallstackButton( " " ICON_FA_ALIGN_JUSTIFY " ", group->first, fidx, false );
#else
SmallCallstackButton( "Call stack", group->first, fidx, false );
#endif
ImGui::Spacing();
ImGui::Indent();
auto& csdata = m_worker.GetCallstack( group->first );
for( auto& entry : csdata )
{ {
case FindZone::TableSortBy::Runtime: ImGui::TextDisabled( "%i.", fidx++ );
if( m_findZone.selfTime ) ImGui::SameLine();
auto frame = m_worker.GetCallstackFrame( entry );
if( !frame )
{ {
pdqsort_branchless( sortedZones.begin(), sortedZones.end(), [this]( const auto& lhs, const auto& rhs ) { ImGui::Text( "0x%" PRIX64, entry );
return m_worker.GetZoneEndDirect( *lhs ) - lhs->start - this->GetZoneChildTimeFast( *lhs ) >
m_worker.GetZoneEndDirect( *rhs ) - rhs->start - this->GetZoneChildTimeFast( *rhs );
} );
} }
else else
{ {
pdqsort_branchless( sortedZones.begin(), sortedZones.end(), [this]( const auto& lhs, const auto& rhs ) { ImGui::TextUnformatted( m_worker.GetString( frame->data[frame->size-1].name ) );
return m_worker.GetZoneEndDirect( *lhs ) - lhs->start > m_worker.GetZoneEndDirect( *rhs ) - rhs->start;
} );
} }
break;
case FindZone::TableSortBy::Name:
pdqsort_branchless( sortedZones.begin(), sortedZones.end(), [this]( const auto& lhs, const auto& rhs ) {
if( lhs->name.active != rhs->name.active ) return lhs->name.active > rhs->name.active;
return strcmp( m_worker.GetString( lhs->name ), m_worker.GetString( rhs->name ) ) < 0;
} );
break;
default:
assert( false );
break;
} }
ImGui::Unindent();
} }
else
for( auto& ev : *zonesToIterate )
{ {
const auto end = m_worker.GetZoneEndDirect( *ev ); ImGui::Text( "No call stack" );
auto timespan = end - ev->start; }
if( m_findZone.selfTime ) timespan -= GetZoneChildTimeFast( *ev );
ImGui::Spacing();
ImGui::PushID( ev ); if( ImGui::TreeNodeEx( "Zone list" ) )
if( ImGui::Selectable( TimeToString( ev->start - m_worker.GetTimeBegin() ), m_zoneInfoWindow == ev, ImGuiSelectableFlags_SpanAllColumns ) ) {
{ DrawZoneList( group->second.zones );
ShowZoneInfo( *ev ); }
} }
if( ImGui::IsItemHovered() ) }
{ else
m_zoneHighlight = ev; {
if( ImGui::IsMouseClicked( 2 ) ) for( auto& v : groups )
{ {
ZoomToZone( *ev ); const char* hdrString;
} switch( groupBy )
ZoneTooltip( *ev ); {
} case FindZone::GroupBy::Thread:
hdrString = m_worker.GetThreadString( m_worker.DecompressThread( v->first ) );
ImGui::NextColumn(); break;
ImGui::TextUnformatted( TimeToString( timespan ) ); case FindZone::GroupBy::UserText:
ImGui::NextColumn(); hdrString = v->first == std::numeric_limits<uint64_t>::max() ? "No user text" : m_worker.GetString( StringIdx( v->first ) );
if( ev->name.active ) break;
{ case FindZone::GroupBy::Callstack:
ImGui::TextUnformatted( m_worker.GetString( ev->name ) ); if( v->first == 0 )
} {
ImGui::NextColumn(); hdrString = "No callstack";
}
ImGui::PopID(); else
{
auto& callstack = m_worker.GetCallstack( v->first );
auto& frameData = *m_worker.GetCallstackFrame( *callstack.begin() );
hdrString = m_worker.GetString( frameData.data[frameData.size-1].name );
}
break;
default:
hdrString = nullptr;
assert( false );
break;
}
ImGui::PushID( v->first );
const bool expand = ImGui::TreeNodeEx( hdrString, ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ( v->first == m_findZone.selGroup ? ImGuiTreeNodeFlags_Selected : 0 ) );
if( ImGui::IsItemClicked() )
{
m_findZone.selGroup = v->first;
m_findZone.ResetSelection();
}
ImGui::PopID();
ImGui::SameLine();
ImGui::TextColored( ImVec4( 0.5f, 0.5f, 0.5f, 1.0f ), "(%s) %s", RealToString( v->second.zones.size(), true ), TimeToString( v->second.time ) );
if( expand )
{
DrawZoneList( v->second.zones );
} }
ImGui::Columns( 1 );
ImGui::Separator();
ImGui::TreePop();
} }
} }
ImGui::EndChild(); ImGui::EndChild();
@ -6551,6 +6553,95 @@ void View::DrawFindZone()
ImGui::End(); ImGui::End();
} }
void View::DrawZoneList( const Vector<ZoneEvent*>& zones )
{
ImGui::Columns( 3 );
ImGui::Separator();
if( ImGui::SmallButton( "Time from start" ) ) m_findZone.tableSortBy = FindZone::TableSortBy::Starttime;
ImGui::NextColumn();
if( ImGui::SmallButton( "Execution time" ) ) m_findZone.tableSortBy = FindZone::TableSortBy::Runtime;
ImGui::NextColumn();
if( ImGui::SmallButton( "Name" ) ) m_findZone.tableSortBy = FindZone::TableSortBy::Name;
ImGui::SameLine();
DrawHelpMarker( "Only displayed if custom zone name is set." );
ImGui::NextColumn();
ImGui::Separator();
const Vector<ZoneEvent*>* zonesToIterate = &zones;
Vector<ZoneEvent*> sortedZones;
if( m_findZone.tableSortBy != FindZone::TableSortBy::Starttime )
{
zonesToIterate = &sortedZones;
sortedZones.reserve_and_use( zones.size() );
memcpy( sortedZones.data(), zones.data(), zones.size() * sizeof( ZoneEvent* ) );
switch( m_findZone.tableSortBy )
{
case FindZone::TableSortBy::Runtime:
if( m_findZone.selfTime )
{
pdqsort_branchless( sortedZones.begin(), sortedZones.end(), [this]( const auto& lhs, const auto& rhs ) {
return m_worker.GetZoneEndDirect( *lhs ) - lhs->start - this->GetZoneChildTimeFast( *lhs ) >
m_worker.GetZoneEndDirect( *rhs ) - rhs->start - this->GetZoneChildTimeFast( *rhs );
} );
}
else
{
pdqsort_branchless( sortedZones.begin(), sortedZones.end(), [this]( const auto& lhs, const auto& rhs ) {
return m_worker.GetZoneEndDirect( *lhs ) - lhs->start > m_worker.GetZoneEndDirect( *rhs ) - rhs->start;
} );
}
break;
case FindZone::TableSortBy::Name:
pdqsort_branchless( sortedZones.begin(), sortedZones.end(), [this]( const auto& lhs, const auto& rhs ) {
if( lhs->name.active != rhs->name.active ) return lhs->name.active > rhs->name.active;
return strcmp( m_worker.GetString( lhs->name ), m_worker.GetString( rhs->name ) ) < 0;
} );
break;
default:
assert( false );
break;
}
}
for( auto& ev : *zonesToIterate )
{
const auto end = m_worker.GetZoneEndDirect( *ev );
auto timespan = end - ev->start;
if( m_findZone.selfTime ) timespan -= GetZoneChildTimeFast( *ev );
ImGui::PushID( ev );
if( ImGui::Selectable( TimeToString( ev->start - m_worker.GetTimeBegin() ), m_zoneInfoWindow == ev, ImGuiSelectableFlags_SpanAllColumns ) )
{
ShowZoneInfo( *ev );
}
if( ImGui::IsItemHovered() )
{
m_zoneHighlight = ev;
if( ImGui::IsMouseClicked( 2 ) )
{
ZoomToZone( *ev );
}
ZoneTooltip( *ev );
}
ImGui::NextColumn();
ImGui::TextUnformatted( TimeToString( timespan ) );
ImGui::NextColumn();
if( ev->name.active )
{
ImGui::TextUnformatted( m_worker.GetString( ev->name ) );
}
ImGui::NextColumn();
ImGui::PopID();
}
ImGui::Columns( 1 );
ImGui::Separator();
ImGui::TreePop();
}
void View::DrawCompare() void View::DrawCompare()
{ {
ImGui::Begin( "Compare traces", &m_compare.show ); ImGui::Begin( "Compare traces", &m_compare.show );

View File

@ -131,6 +131,7 @@ private:
std::vector<CallstackFrameTree> GetCallstackFrameTreeBottomUp( const MemData& mem ) const; std::vector<CallstackFrameTree> GetCallstackFrameTreeBottomUp( const MemData& mem ) const;
std::vector<CallstackFrameTree> GetCallstackFrameTreeTopDown( const MemData& mem ) const; std::vector<CallstackFrameTree> GetCallstackFrameTreeTopDown( const MemData& mem ) const;
void DrawFrameTreeLevel( std::vector<CallstackFrameTree>& tree, int& idx ); void DrawFrameTreeLevel( std::vector<CallstackFrameTree>& tree, int& idx );
void DrawZoneList( const Vector<ZoneEvent*>& zones );
void DrawInfoWindow(); void DrawInfoWindow();
void DrawZoneInfoWindow(); void DrawZoneInfoWindow();
@ -333,6 +334,7 @@ private:
bool drawAvgMed = true; bool drawAvgMed = true;
bool drawSelAvgMed = true; bool drawSelAvgMed = true;
bool scheduleResetMatch = false; bool scheduleResetMatch = false;
int selCs = 0;
void Reset() void Reset()
{ {
@ -358,6 +360,7 @@ private:
ResetSelection(); ResetSelection();
groups.clear(); groups.clear();
processed = 0; processed = 0;
selCs = 0;
} }
void ResetSelection() void ResetSelection()