Add context switch tooltips.

This commit is contained in:
Bartosz Taudul 2019-08-13 15:10:44 +02:00
parent f285e0f5cc
commit 71a5cffc13
2 changed files with 178 additions and 4 deletions

View File

@ -1888,7 +1888,7 @@ void View::DrawZones()
auto ctxSwitch = m_worker.GetContextSwitchData( v->id ); auto ctxSwitch = m_worker.GetContextSwitchData( v->id );
if( ctxSwitch ) if( ctxSwitch )
{ {
DrawContextSwitches( ctxSwitch, pxns, int64_t( nspx ), wpos, offset ); DrawContextSwitches( ctxSwitch, hover, pxns, int64_t( nspx ), wpos, offset );
offset += round( ostep * 0.75f ); offset += round( ostep * 0.75f );
} }
} }
@ -2200,7 +2200,108 @@ void View::DrawZones()
} }
} }
void View::DrawContextSwitches( const ContextSwitch* ctx, double pxns, int64_t nspx, const ImVec2& wpos, int offset ) static const char* DecodeContextSwitchReasonCode( uint8_t reason )
{
switch( reason )
{
case 0: return "Executive";
case 1: return "FreePage";
case 2: return "PageIn";
case 3: return "PoolAllocation";
case 4: return "DelayExecution";
case 5: return "Suspended";
case 6: return "UserRequest";
case 7: return "WrExecutive";
case 8: return "WrFreePage";
case 9: return "WrPageIn";
case 10: return "WrPoolAllocation";
case 11: return "WrDelayExecution";
case 12: return "WrSuspended";
case 13: return "WrUserRequest";
case 14: return "WrEventPair";
case 15: return "WrQueue";
case 16: return "WrLpcReceive";
case 17: return "WrLpcReply";
case 18: return "WrVirtualMemory";
case 19: return "WrPageOut";
case 20: return "WrRendezvous";
case 21: return "WrKeyedEvent";
case 22: return "WrTerminated";
case 23: return "WrProcessInSwap";
case 24: return "WrCpuRateControl";
case 25: return "WrCalloutStack";
case 26: return "WrKernel";
case 27: return "WrResource";
case 28: return "WrPushLock";
case 29: return "WrMutex";
case 30: return "WrQuantumEnd";
case 31: return "WrDispatchInt";
case 32: return "WrPreempted";
case 33: return "WrYieldExecution";
case 34: return "WrFastMutex";
case 35: return "WrGuardedMutex";
case 36: return "WrRundown";
case 37: return "MaximumWaitReason";
default: return "unknown";
}
}
static const char* DecodeContextSwitchReason( uint8_t reason )
{
switch( reason )
{
case 0: return "(Thread is waiting for the scheduler)";
case 1: return "(Thread is waiting for a free virtual memory page)";
case 2: return "(Thread is waiting for a virtual memory page to arrive in memory)";
case 4: return "(Thread execution is delayed)";
case 5: return "(Thread execution is suspended)";
case 6: return "(Thread is waiting on object - WaitForSingleObject, etc.)";
case 7: return "(Thread is waiting for the scheduler)";
case 8: return "(Thread is waiting for a free virtual memory page)";
case 9: return "(Thread is waiting for a virtual memory page to arrive in memory)";
case 11: return "(Thread execution is delayed)";
case 12: return "(Thread execution is suspended)";
case 13: return "(Thread is waiting for window messages)";
case 15: return "(Thread is waiting on KQUEUE)";
case 24: return "(CPU rate limiting)";
case 34: return "(Waiting for a Fast Mutex)";
default: return "";
}
}
static const char* DecodeContextSwitchStateCode( uint8_t state )
{
switch( state )
{
case 0: return "Initialized";
case 1: return "Ready";
case 2: return "Running";
case 3: return "Standby";
case 4: return "Terminated";
case 5: return "Waiting";
case 6: return "Transition";
case 7: return "DeferredReady";
default: return "unknown";
}
}
static const char* DecodeContextSwitchState( uint8_t state )
{
switch( state )
{
case 0: return "(Thread has been initialized, but has not yet started)";
case 1: return "(Thread is waiting to use a processor because no processor is free. The thread is prepared to run on the next available processor)";
case 2: return "(Thread is currently using a processor)";
case 3: return "(Thread is about to use a processor)";
case 4: return "(Thread has finished executing and has exited)";
case 5: return "(Thread is not ready to use the processor because it is waiting for a peripheral operation to complete or a resource to become free)";
case 6: return "(Thread is waiting for a resource, other than the processor, before it can execute)";
case 7: return "(Thread has beed selected to run on a specific processor but have not yet beed scheduled)";
default: return "";
}
}
void View::DrawContextSwitches( const ContextSwitch* ctx, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset )
{ {
auto& vec = ctx->v; auto& vec = ctx->v;
auto it = std::lower_bound( vec.begin(), vec.end(), std::max<int64_t>( 0, m_zvStart ), [] ( const auto& l, const auto& r ) { return (uint64_t)l.end < (uint64_t)r; } ); auto it = std::lower_bound( vec.begin(), vec.end(), std::max<int64_t>( 0, m_zvStart ), [] ( const auto& l, const auto& r ) { return (uint64_t)l.end < (uint64_t)r; } );
@ -2223,10 +2324,44 @@ void View::DrawContextSwitches( const ContextSwitch* ctx, double pxns, int64_t n
auto& ev = *it; auto& ev = *it;
if( pit != citend ) if( pit != citend )
{ {
const bool migration = pit->cpu != ev.cpu;
const auto px0 = std::max( { ( pit->end - m_zvStart ) * pxns, -10.0, minpx } ); const auto px0 = std::max( { ( pit->end - m_zvStart ) * pxns, -10.0, minpx } );
const auto px1 = std::min( ( ev.start - m_zvStart ) * pxns, w + 10.0 ); const auto px1 = std::min( ( ev.start - m_zvStart ) * pxns, w + 10.0 );
const auto color = pit->cpu != ev.cpu ? 0xFFEE7711 : 0xFF2222AA; const auto color = migration ? 0xFFEE7711 : 0xFF2222AA;
draw->AddLine( wpos + ImVec2( px0, round( offset + ty * 0.5 ) - 0.5 ), wpos + ImVec2( px1, round( offset + ty * 0.5 ) - 0.5 ), color, 2 ); draw->AddLine( wpos + ImVec2( px0, round( offset + ty * 0.5 ) - 0.5 ), wpos + ImVec2( px1, round( offset + ty * 0.5 ) - 0.5 ), color, 2 );
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + ty ) ) )
{
ImGui::BeginTooltip();
TextFocused( "Thread is", migration ? "migrating CPUs" : "waiting" );
TextFocused( "Waiting time:", TimeToString( ev.start - pit->end ) );
if( migration )
{
TextFocused( "CPU:", RealToString( pit->cpu, true ) );
ImGui::SameLine();
#ifdef TRACY_EXTENDED_FONT
TextFocused( ICON_FA_LONG_ARROW_ALT_RIGHT, RealToString( ev.cpu, true ) );
#else
TextFocused( "->", RealToString( ev.cpu, true ) );
#endif
}
else
{
TextFocused( "CPU:", RealToString( ev.cpu, true ) );
}
TextFocused( "Wait reason:", DecodeContextSwitchReasonCode( ContextSwitchData::Reason( *pit ) ) );
ImGui::SameLine();
TextDisabledUnformatted( DecodeContextSwitchReason( ContextSwitchData::Reason( *pit ) ) );
TextFocused( "Wait state:", DecodeContextSwitchStateCode( ContextSwitchData::State( *pit ) ) );
ImGui::SameLine();
TextDisabledUnformatted( DecodeContextSwitchState( ContextSwitchData::State( *pit ) ) );
ImGui::EndTooltip();
if( ImGui::IsMouseClicked( 2 ) )
{
ZoomToRange( pit->end, ev.start );
}
}
} }
const auto end = ev.end >= 0 ? ev.end : m_worker.GetLastTime(); const auto end = ev.end >= 0 ? ev.end : m_worker.GetLastTime();
@ -2256,10 +2391,36 @@ void View::DrawContextSwitches( const ContextSwitch* ctx, double pxns, int64_t n
if( num == 1 ) if( num == 1 )
{ {
draw->AddLine( wpos + ImVec2( px0, round( offset + ty * 0.5 ) - 0.5 ), wpos + ImVec2( minpx, round( offset + ty * 0.5 ) - 0.5 ), 0xFF22DD22, 2 ); draw->AddLine( wpos + ImVec2( px0, round( offset + ty * 0.5 ) - 0.5 ), wpos + ImVec2( minpx, round( offset + ty * 0.5 ) - 0.5 ), 0xFF22DD22, 2 );
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( minpx, offset + ty ) ) )
{
ImGui::BeginTooltip();
TextFocused( "Thread is", "running" );
TextFocused( "Activity time:", TimeToString( end - ev.start ) );
TextFocused( "CPU:", RealToString( ev.cpu, true ) );
ImGui::EndTooltip();
if( ImGui::IsMouseClicked( 2 ) )
{
ZoomToRange( ev.start, rend );
}
}
} }
else else
{ {
DrawZigZag( draw, wpos + ImVec2( 0, offset + round( ty/2 ) ), px0, minpx, ty/4, 0xFF888888, 1.5 ); DrawZigZag( draw, wpos + ImVec2( 0, offset + round( ty/2 ) ), px0, minpx, ty/4, 0xFF888888, 1.5 );
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( minpx, offset + ty ) ) )
{
ImGui::BeginTooltip();
TextFocused( "Thread is", "chaning activity multiple times" );
TextFocused( "Number of running regions:", RealToString( num, true ) );
TextFocused( "Time:", TimeToString( rend - ev.start ) );
ImGui::EndTooltip();
if( ImGui::IsMouseClicked( 2 ) )
{
ZoomToRange( ev.start, rend );
}
}
} }
pit = it-1; pit = it-1;
} }
@ -2268,6 +2429,19 @@ void View::DrawContextSwitches( const ContextSwitch* ctx, double pxns, int64_t n
const auto px0 = std::max( { ( ev.start - m_zvStart ) * pxns, -10.0, minpx } ); const auto px0 = std::max( { ( ev.start - m_zvStart ) * pxns, -10.0, minpx } );
const auto px1 = std::min( ( end - m_zvStart ) * pxns, w + 10.0 ); const auto px1 = std::min( ( end - m_zvStart ) * pxns, w + 10.0 );
draw->AddLine( wpos + ImVec2( px0, round( offset + ty * 0.5 ) - 0.5 ), wpos + ImVec2( px1, round( offset + ty * 0.5 ) - 0.5 ), 0xFF22DD22, 2 ); draw->AddLine( wpos + ImVec2( px0, round( offset + ty * 0.5 ) - 0.5 ), wpos + ImVec2( px1, round( offset + ty * 0.5 ) - 0.5 ), 0xFF22DD22, 2 );
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + ty ) ) )
{
ImGui::BeginTooltip();
TextFocused( "Thread is", "running" );
TextFocused( "Activity time:", TimeToString( end - ev.start ) );
TextFocused( "CPU:", RealToString( ev.cpu, true ) );
ImGui::EndTooltip();
if( ImGui::IsMouseClicked( 2 ) )
{
ZoomToRange( ev.start, end );
}
}
pit = it; pit = it;
++it; ++it;
} }

View File

@ -108,7 +108,7 @@ private:
bool DrawZoneFramesHeader(); bool DrawZoneFramesHeader();
bool DrawZoneFrames( const FrameData& frames ); bool DrawZoneFrames( const FrameData& frames );
void DrawZones(); void DrawZones();
void DrawContextSwitches( const ContextSwitch* ctx, double pxns, int64_t nspx, const ImVec2& wpos, int offset ); void DrawContextSwitches( const ContextSwitch* ctx, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset );
int DispatchZoneLevel( const Vector<ZoneEvent*>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax ); int DispatchZoneLevel( const Vector<ZoneEvent*>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax );
int DrawZoneLevel( const Vector<ZoneEvent*>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax ); int DrawZoneLevel( const Vector<ZoneEvent*>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax );
int SkipZoneLevel( const Vector<ZoneEvent*>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax ); int SkipZoneLevel( const Vector<ZoneEvent*>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax );