Allow limiting wait stacks to certain threads.

This commit is contained in:
Bartosz Taudul 2021-11-13 18:20:06 +01:00
parent 265a39e7c9
commit 94d4272c9c
No known key found for this signature in database
GPG Key ID: B7FE2008B7575DF3
2 changed files with 127 additions and 44 deletions

View File

@ -16320,68 +16320,140 @@ void View::DrawRangeEntry( Range& range, const char* label, uint32_t color, cons
void View::DrawWaitStacks() void View::DrawWaitStacks()
{ {
ImGui::SetNextWindowSize( ImVec2( 1400, 500 ), ImGuiCond_FirstUseEver ); ImGui::SetNextWindowSize( ImVec2( 1400, 500 ), ImGuiCond_FirstUseEver );
ImGui::Begin( "Wait stacks", &m_showWaitStacks, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse ); ImGui::Begin( "Wait stacks", &m_showWaitStacks );
#ifdef TRACY_NO_STATISTICS #ifdef TRACY_NO_STATISTICS
ImGui::TextWrapped( "Rebuild without the TRACY_NO_STATISTICS macro to enable wait stacks." ); ImGui::TextWrapped( "Rebuild without the TRACY_NO_STATISTICS macro to enable wait stacks." );
#else #else
uint64_t totalCount = 0;
unordered_flat_map<uint32_t, uint64_t> stacks; unordered_flat_map<uint32_t, uint64_t> stacks;
auto& td = m_worker.GetThreadData(); for( auto& t : m_threadOrder )
for( auto& t : td )
{ {
for( auto& sd : t->ctxSwitchSamples ) if( WaitStackThread( t->id ) )
{ {
auto cs = sd.callstack.Val(); totalCount += t->ctxSwitchSamples.size();
auto it = stacks.find( cs ); for( auto& sd : t->ctxSwitchSamples )
if( it == stacks.end() )
{ {
stacks.emplace( cs, 1 ); auto cs = sd.callstack.Val();
} auto it = stacks.find( cs );
else if( it == stacks.end() )
{ {
it->second++; stacks.emplace( cs, 1 );
}
else
{
it->second++;
}
} }
} }
} }
const auto totalSamples = m_worker.GetContextSwitchSampleCount(); TextFocused( "Total wait stacks:", RealToString( m_worker.GetContextSwitchSampleCount() ) );
TextFocused( "Total wait stacks:", RealToString( totalSamples ) );
ImGui::SameLine(); ImGui::SameLine();
ImGui::Spacing(); ImGui::Spacing();
ImGui::SameLine(); ImGui::SameLine();
TextDisabledUnformatted( "Wait stack:" ); TextFocused( "Selected:", RealToString( totalCount ) );
bool threadsChanged = false;
auto expand = ImGui::TreeNode( ICON_FA_RANDOM " Visible threads:" );
ImGui::SameLine(); ImGui::SameLine();
if( ImGui::SmallButton( " " ICON_FA_CARET_LEFT " " ) ) ImGui::TextDisabled( "(%zu)", m_threadOrder.size() );
if( expand )
{ {
m_waitStack = std::max( m_waitStack - 1, 0 ); auto& crash = m_worker.GetCrashEvent();
ImGui::SameLine();
if( ImGui::SmallButton( "Select all" ) )
{
for( const auto& t : m_threadOrder )
{
WaitStackThread( t->id ) = true;
}
threadsChanged = true;
}
ImGui::SameLine();
if( ImGui::SmallButton( "Unselect all" ) )
{
for( const auto& t : m_threadOrder )
{
WaitStackThread( t->id ) = false;
}
threadsChanged = true;
}
int idx = 0;
for( const auto& t : m_threadOrder )
{
if( t->ctxSwitchSamples.empty() ) continue;
ImGui::PushID( idx++ );
const auto threadColor = GetThreadColor( t->id, 0 );
SmallColorBox( threadColor );
ImGui::SameLine();
if( SmallCheckbox( m_worker.GetThreadName( t->id ), &WaitStackThread( t->id ) ) )
{
threadsChanged = true;
}
ImGui::PopID();
ImGui::SameLine();
ImGui::TextDisabled( "(%s)", RealToString( t->ctxSwitchSamples.size() ) );
if( crash.thread == t->id )
{
ImGui::SameLine();
TextColoredUnformatted( ImVec4( 1.f, 0.2f, 0.2f, 1.f ), ICON_FA_SKULL " Crashed" );
}
if( t->isFiber )
{
ImGui::SameLine();
TextColoredUnformatted( ImVec4( 0.2f, 0.6f, 0.2f, 1.f ), "Fiber" );
}
}
ImGui::TreePop();
} }
ImGui::SameLine(); if( threadsChanged ) m_waitStack = 0;
ImGui::Text( "%s / %s", RealToString( m_waitStack + 1 ), RealToString( stacks.size() ) );
if( ImGui::IsItemClicked() ) ImGui::OpenPopup( "WaitStacksPopup" );
ImGui::SameLine();
if( ImGui::SmallButton( " " ICON_FA_CARET_RIGHT " " ) )
{
m_waitStack = std::min<int>( m_waitStack + 1, stacks.size() - 1 );
}
if( ImGui::BeginPopup( "WaitStacksPopup" ) )
{
int sel = m_waitStack + 1;
ImGui::SetNextItemWidth( 120 );
const bool clicked = ImGui::InputInt( "##waitStack", &sel, 1, 100, ImGuiInputTextFlags_EnterReturnsTrue );
if( clicked ) m_waitStack = std::min( std::max( sel, 1 ), int( stacks.size() ) ) - 1;
ImGui::EndPopup();
}
Vector<decltype(stacks.begin())> data;
data.reserve( stacks.size() );
for( auto it = stacks.begin(); it != stacks.end(); ++it ) data.push_back( it );
pdqsort_branchless( data.begin(), data.end(), []( const auto& l, const auto& r ) { return l->second > r->second; } );
ImGui::SameLine();
TextFocused( "Counts:", RealToString( data[m_waitStack]->second ) );
ImGui::SameLine();
char buf[64];
PrintStringPercent( buf, 100. * data[m_waitStack]->second / totalSamples );
TextDisabledUnformatted( buf );
ImGui::Separator(); ImGui::Separator();
DrawCallstackTable( data[m_waitStack]->first, false ); if( stacks.empty() )
{
ImGui::TextUnformatted( "No wait stacks to display." );
}
else
{
TextDisabledUnformatted( "Wait stack:" );
ImGui::SameLine();
if( ImGui::SmallButton( " " ICON_FA_CARET_LEFT " " ) )
{
m_waitStack = std::max( m_waitStack - 1, 0 );
}
ImGui::SameLine();
ImGui::Text( "%s / %s", RealToString( m_waitStack + 1 ), RealToString( stacks.size() ) );
if( ImGui::IsItemClicked() ) ImGui::OpenPopup( "WaitStacksPopup" );
ImGui::SameLine();
if( ImGui::SmallButton( " " ICON_FA_CARET_RIGHT " " ) )
{
m_waitStack = std::min<int>( m_waitStack + 1, stacks.size() - 1 );
}
if( ImGui::BeginPopup( "WaitStacksPopup" ) )
{
int sel = m_waitStack + 1;
ImGui::SetNextItemWidth( 120 );
const bool clicked = ImGui::InputInt( "##waitStack", &sel, 1, 100, ImGuiInputTextFlags_EnterReturnsTrue );
if( clicked ) m_waitStack = std::min( std::max( sel, 1 ), int( stacks.size() ) ) - 1;
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
Vector<decltype(stacks.begin())> data;
data.reserve( stacks.size() );
for( auto it = stacks.begin(); it != stacks.end(); ++it ) data.push_back( it );
pdqsort_branchless( data.begin(), data.end(), []( const auto& l, const auto& r ) { return l->second > r->second; } );
TextFocused( "Counts:", RealToString( data[m_waitStack]->second ) );
ImGui::SameLine();
char buf[64];
PrintStringPercent( buf, 100. * data[m_waitStack]->second / totalCount );
TextDisabledUnformatted( buf );
ImGui::Separator();
DrawCallstackTable( data[m_waitStack]->first, false );
}
#endif #endif
ImGui::End(); ImGui::End();
} }

View File

@ -313,6 +313,7 @@ private:
unordered_flat_map<const void*, VisData> m_visData; unordered_flat_map<const void*, VisData> m_visData;
unordered_flat_map<uint64_t, bool> m_visibleMsgThread; unordered_flat_map<uint64_t, bool> m_visibleMsgThread;
unordered_flat_map<uint64_t, bool> m_waitStackThread;
unordered_flat_map<const void*, int> m_gpuDrift; unordered_flat_map<const void*, int> m_gpuDrift;
unordered_flat_map<const PlotData*, PlotView> m_plotView; unordered_flat_map<const PlotData*, PlotView> m_plotView;
Vector<const ThreadData*> m_threadOrder; Vector<const ThreadData*> m_threadOrder;
@ -338,6 +339,16 @@ private:
return it->second; return it->second;
} }
tracy_force_inline bool& WaitStackThread( uint64_t thread )
{
auto it = m_waitStackThread.find( thread );
if( it == m_waitStackThread.end() )
{
it = m_waitStackThread.emplace( thread, true ).first;
}
return it->second;
}
tracy_force_inline int& GpuDrift( const void* ptr ) tracy_force_inline int& GpuDrift( const void* ptr )
{ {
auto it = m_gpuDrift.find( ptr ); auto it = m_gpuDrift.find( ptr );