From 10dbefefaba899d40c7869b2cb561fb1806d18c7 Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Sat, 2 Jul 2022 13:43:09 +0200 Subject: [PATCH] Extract context switch UI from View. --- profiler/build/win32/Tracy.vcxproj | 1 + profiler/build/win32/Tracy.vcxproj.filters | 3 + server/TracyImGui.cpp | 50 ++++ server/TracyImGui.hpp | 2 + server/TracyView.cpp | 286 --------------------- server/TracyView_ContextSwitch.cpp | 247 ++++++++++++++++++ 6 files changed, 303 insertions(+), 286 deletions(-) create mode 100644 server/TracyImGui.cpp diff --git a/profiler/build/win32/Tracy.vcxproj b/profiler/build/win32/Tracy.vcxproj index c12b9350..812b79f6 100644 --- a/profiler/build/win32/Tracy.vcxproj +++ b/profiler/build/win32/Tracy.vcxproj @@ -121,6 +121,7 @@ + diff --git a/profiler/build/win32/Tracy.vcxproj.filters b/profiler/build/win32/Tracy.vcxproj.filters index 762bf6aa..2362874c 100644 --- a/profiler/build/win32/Tracy.vcxproj.filters +++ b/profiler/build/win32/Tracy.vcxproj.filters @@ -261,6 +261,9 @@ server + + server + diff --git a/server/TracyImGui.cpp b/server/TracyImGui.cpp new file mode 100644 index 00000000..03a22d84 --- /dev/null +++ b/server/TracyImGui.cpp @@ -0,0 +1,50 @@ +#include "TracyImGui.hpp" + +namespace tracy +{ + +void DrawZigZag( ImDrawList* draw, const ImVec2& wpos, double start, double end, double h, uint32_t color, float thickness ) +{ + const auto dpos = wpos + ImVec2( 0.5f, 0.5f ); + + const auto spanSz = end - start; + if( spanSz <= h * 0.5 ) + { + DrawLine( draw, dpos + ImVec2( start, 0 ), wpos + ImVec2( start + spanSz, round( -spanSz ) ), color, thickness ); + return; + } + + const auto h05 = round( h * 0.5 ); + const auto h2 = h*2; + int steps = int( ( end - start ) / h2 ); + + auto path = (ImVec2*)alloca( sizeof( ImVec2 ) * ( 2 * steps + 4 ) ); + auto ptr = path; + + *ptr++ = dpos + ImVec2( start, 0 ); + *ptr++ = dpos + ImVec2( start + h05, -h05 ); + start += h05; + + while( steps-- ) + { + *ptr++ = dpos + ImVec2( start + h, h05 ); + *ptr++ = dpos + ImVec2( start + h2, -h05 ); + start += h2; + } + + if( end - start <= h ) + { + const auto span = end - start; + *ptr++ = dpos + ImVec2( start + span, round( span - h*0.5 ) ); + } + else + { + const auto span = end - start - h; + *ptr++ = dpos + ImVec2( start + h, h05 ); + *ptr++ = dpos + ImVec2( start + h + span, round( h*0.5 - span ) ); + } + + draw->AddPolyline( path, ptr - path, color, 0, thickness ); +} + +} diff --git a/server/TracyImGui.hpp b/server/TracyImGui.hpp index 72479fed..3e92884a 100644 --- a/server/TracyImGui.hpp +++ b/server/TracyImGui.hpp @@ -23,6 +23,8 @@ static inline ImVec2 operator-( const ImVec2& l, const ImVec2& r ) { return ImVe namespace tracy { +void DrawZigZag( ImDrawList* draw, const ImVec2& wpos, double start, double end, double h, uint32_t color, float thickness = 1.f ); + static const ImVec4 SyntaxColors[] = { { 0.7f, 0.7f, 0.7f, 1 }, // default { 0.45f, 0.68f, 0.32f, 1 }, // comment diff --git a/server/TracyView.cpp b/server/TracyView.cpp index ecc411c4..f5eb9492 100644 --- a/server/TracyView.cpp +++ b/server/TracyView.cpp @@ -79,7 +79,6 @@ static inline bool AreOtherWaiting( uint64_t bitlist, uint64_t threadBit ) enum { MinVisSize = 3 }; -enum { MinCtxSize = 4 }; enum { MinFrameSize = 5 }; static View* s_instance = nullptr; @@ -2498,50 +2497,6 @@ static uint32_t MixGhostColor( uint32_t c0, uint32_t c1 ) ( ( ( ( ( c0 & 0x000000FF ) ) + 3 * ( ( c1 & 0x000000FF ) ) ) >> 2 ) ); } -static void DrawZigZag( ImDrawList* draw, const ImVec2& wpos, double start, double end, double h, uint32_t color, float thickness = 1.f ) -{ - const auto dpos = wpos + ImVec2( 0.5f, 0.5f ); - - const auto spanSz = end - start; - if( spanSz <= h * 0.5 ) - { - DrawLine( draw, dpos + ImVec2( start, 0 ), wpos + ImVec2( start + spanSz, round( -spanSz ) ), color, thickness ); - return; - } - - const auto h05 = round( h * 0.5 ); - const auto h2 = h*2; - int steps = int( ( end - start ) / h2 ); - - auto path = (ImVec2*)alloca( sizeof( ImVec2 ) * ( 2 * steps + 4 ) ); - auto ptr = path; - - *ptr++ = dpos + ImVec2( start, 0 ); - *ptr++ = dpos + ImVec2( start + h05, -h05 ); - start += h05; - - while( steps-- ) - { - *ptr++ = dpos + ImVec2( start + h, h05 ); - *ptr++ = dpos + ImVec2( start + h2, -h05 ); - start += h2; - } - - if( end - start <= h ) - { - const auto span = end - start; - *ptr++ = dpos + ImVec2( start + span, round( span - h*0.5 ) ); - } - else - { - const auto span = end - start - h; - *ptr++ = dpos + ImVec2( start + h, h05 ); - *ptr++ = dpos + ImVec2( start + h + span, round( h*0.5 - span ) ); - } - - draw->AddPolyline( path, ptr - path, color, 0, thickness ); -} - static uint32_t GetColorMuted( uint32_t color, bool active ) { if( active ) @@ -3767,247 +3722,6 @@ void View::DrawZones() } } -void View::DrawContextSwitches( const ContextSwitch* ctx, const Vector& sampleData, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int endOffset, bool isFiber ) -{ - const auto lineSize = 2 * GetScale(); - - auto& vec = ctx->v; - auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart ), [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } ); - if( it == vec.end() ) return; - if( it != vec.begin() ) --it; - - auto citend = std::lower_bound( it, vec.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.Start() < r; } ); - if( it == citend ) return; - if( citend != vec.end() ) ++citend; - - const auto w = ImGui::GetContentRegionAvail().x - 1; - const auto ty = round( ImGui::GetTextLineHeight() * 0.75f ); - const auto ty05 = round( ty * 0.5f ); - auto draw = ImGui::GetWindowDrawList(); - const auto dpos = wpos + ImVec2( 0.5f, 0.5f ); - - auto pit = citend; - double minpx = -10.0; - - while( it < citend ) - { - auto& ev = *it; - if( pit != citend ) - { - const bool migration = pit->Cpu() != ev.Cpu(); - const auto px0 = std::max( { ( pit->End() - m_vd.zvStart ) * pxns, -10.0, minpx } ); - const auto pxw = ( ev.WakeupVal() - m_vd.zvStart ) * pxns; - const auto px1 = std::min( ( ev.Start() - m_vd.zvStart ) * pxns, w + 10.0 ); - const auto color = migration ? 0xFFEE7711 : 0xFF2222AA; - if( m_vd.darkenContextSwitches ) - { - draw->AddRectFilled( dpos + ImVec2( px0, offset + ty05 ), dpos + ImVec2( px1, endOffset ), 0x661C2321 ); - } - DrawLine( draw, dpos + ImVec2( px0, offset + ty05 - 0.5f ), dpos + ImVec2( std::min( pxw, w+10.0 ), offset + ty05 - 0.5f ), color, lineSize ); - if( ev.WakeupVal() != ev.Start() ) - { - DrawLine( draw, dpos + ImVec2( std::max( pxw, 10.0 ), offset + ty05 - 0.5f ), dpos + ImVec2( px1, offset + ty05 - 0.5f ), 0xFF2280A0, lineSize ); - } - - if( hover ) - { - bool tooltip = false; - if( ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( pxw, offset + ty ) ) ) - { - ImGui::BeginTooltip(); - if( isFiber ) - { - TextFocused( "Fiber is", "yielding" ); - TextFocused( "Yield time:", TimeToString( ev.Start() - pit->End() ) ); - } - else - { - TextFocused( "Thread is", migration ? "migrating CPUs" : "waiting" ); - TextFocused( "Waiting time:", TimeToString( ev.WakeupVal() - pit->End() ) ); - if( migration ) - { - TextFocused( "CPU:", RealToString( pit->Cpu() ) ); - ImGui::SameLine(); - TextFocused( ICON_FA_LONG_ARROW_ALT_RIGHT, RealToString( ev.Cpu() ) ); - } - else - { - TextFocused( "CPU:", RealToString( ev.Cpu() ) ); - } - if( pit->Reason() != 100 ) - { - TextFocused( "Wait reason:", DecodeContextSwitchReasonCode( pit->Reason() ) ); - ImGui::SameLine(); - ImGui::PushFont( m_smallFont ); - ImGui::AlignTextToFramePadding(); - TextDisabledUnformatted( DecodeContextSwitchReason( pit->Reason() ) ); - ImGui::PopFont(); - } - TextFocused( "Wait state:", DecodeContextSwitchStateCode( pit->State() ) ); - ImGui::SameLine(); - ImGui::PushFont( m_smallFont ); - ImGui::AlignTextToFramePadding(); - TextDisabledUnformatted( DecodeContextSwitchState( pit->State() ) ); - ImGui::PopFont(); - } - tooltip = true; - - if( IsMouseClicked( 2 ) ) - { - ZoomToRange( pit->End(), ev.WakeupVal() ); - } - } - else if( ev.WakeupVal() != ev.Start() && ImGui::IsMouseHoveringRect( wpos + ImVec2( pxw, offset ), wpos + ImVec2( px1, offset + ty ) ) ) - { - assert( !isFiber ); - ImGui::BeginTooltip(); - TextFocused( "Thread is", "waking up" ); - TextFocused( "Scheduling delay:", TimeToString( ev.Start() - ev.WakeupVal() ) ); - TextFocused( "CPU:", RealToString( ev.Cpu() ) ); - if( IsMouseClicked( 2 ) ) - { - ZoomToRange( pit->End(), ev.WakeupVal() ); - } - tooltip = true; - } - if( tooltip ) - { - if( !sampleData.empty() ) - { - auto sdit = std::lower_bound( sampleData.begin(), sampleData.end(), ev.Start(), [] ( const auto& l, const auto& r ) { return l.time.Val() < r; } ); - bool found = sdit != sampleData.end() && sdit->time.Val() == ev.Start(); - if( !found && it != vec.begin() ) - { - auto eit = it; - --eit; - sdit = std::lower_bound( sampleData.begin(), sampleData.end(), eit->End(), [] ( const auto& l, const auto& r ) { return l.time.Val() < r; } ); - found = sdit != sampleData.end() && sdit->time.Val() == eit->End(); - } - if( found ) - { - ImGui::Separator(); - TextDisabledUnformatted( ICON_FA_HOURGLASS_HALF " Wait stack:" ); - CallstackTooltipContents( sdit->callstack.Val() ); - if( ImGui::IsMouseClicked( 0 ) ) - { - m_callstackInfoWindow = sdit->callstack.Val(); - } - } - } - ImGui::EndTooltip(); - } - } - } - - const auto end = ev.IsEndValid() ? ev.End() : m_worker.GetLastTime(); - const auto zsz = std::max( ( end - ev.Start() ) * pxns, pxns * 0.5 ); - if( zsz < MinCtxSize ) - { - const auto MinCtxNs = MinCtxSize * nspx; - int num = 0; - const auto px0 = std::max( ( ev.Start() - m_vd.zvStart ) * pxns, -10.0 ); - auto px1ns = end - m_vd.zvStart; - auto rend = end; - auto nextTime = end + MinCtxNs; - for(;;) - { - const auto prevIt = it; - it = std::lower_bound( it, citend, nextTime, [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } ); - if( it == prevIt ) ++it; - num += std::distance( prevIt, it ); - if( it == citend ) break; - const auto nend = it->IsEndValid() ? it->End() : m_worker.GetLastTime(); - const auto nsnext = nend - m_vd.zvStart; - if( nsnext - px1ns >= MinCtxNs * 2 ) break; - px1ns = nsnext; - rend = nend; - nextTime = nend + nspx; - } - minpx = std::min( std::max( px1ns * pxns, px0+MinCtxSize ), double( w + 10 ) ); - if( num == 1 ) - { - DrawLine( draw, dpos + ImVec2( px0, offset + ty05 - 0.5f ), dpos + ImVec2( minpx, offset + ty05 - 0.5f ), 0xFF22DD22, lineSize ); - if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( minpx, offset + ty + 1 ) ) ) - { - ImGui::BeginTooltip(); - if( isFiber ) - { - const auto tid = m_worker.DecompressThread( ev.Thread() ); - TextFocused( "Fiber is", "running" ); - TextFocused( "Activity time:", TimeToString( end - ev.Start() ) ); - TextFocused( "Thread:", m_worker.GetThreadName( tid ) ); - ImGui::SameLine(); - ImGui::TextDisabled( "(%s)", RealToString( tid ) ); - } - else - { - TextFocused( "Thread is", "running" ); - TextFocused( "Activity time:", TimeToString( end - ev.Start() ) ); - TextFocused( "CPU:", RealToString( ev.Cpu() ) ); - } - ImGui::EndTooltip(); - - if( IsMouseClicked( 2 ) ) - { - ZoomToRange( ev.Start(), rend ); - } - } - } - else - { - DrawZigZag( draw, wpos + ImVec2( 0, offset + ty05 ), px0, minpx, ty/4, 0xFF888888, 1.5 ); - if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( minpx, offset + ty + 1 ) ) ) - { - ImGui::BeginTooltip(); - TextFocused( isFiber ? "Fiber is" : "Thread is", "changing activity multiple times" ); - TextFocused( "Number of running regions:", RealToString( num ) ); - TextFocused( "Time:", TimeToString( rend - ev.Start() ) ); - ImGui::EndTooltip(); - - if( IsMouseClicked( 2 ) ) - { - ZoomToRange( ev.Start(), rend ); - } - } - } - pit = it-1; - } - else - { - const auto px0 = std::max( { ( ev.Start() - m_vd.zvStart ) * pxns, -10.0, minpx } ); - const auto px1 = std::min( ( end - m_vd.zvStart ) * pxns, w + 10.0 ); - DrawLine( draw, dpos + ImVec2( px0, offset + ty05 - 0.5f ), dpos + ImVec2( px1, offset + ty05 - 0.5f ), 0xFF22DD22, lineSize ); - if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + ty + 1 ) ) ) - { - ImGui::BeginTooltip(); - if( isFiber ) - { - const auto tid = m_worker.DecompressThread( ev.Thread() ); - TextFocused( "Fiber is", "running" ); - TextFocused( "Activity time:", TimeToString( end - ev.Start() ) ); - TextFocused( "Thread:", m_worker.GetThreadName( tid ) ); - ImGui::SameLine(); - ImGui::TextDisabled( "(%s)", RealToString( tid ) ); - } - else - { - TextFocused( "Thread is", "running" ); - TextFocused( "Activity time:", TimeToString( end - ev.Start() ) ); - TextFocused( "CPU:", RealToString( ev.Cpu() ) ); - } - ImGui::EndTooltip(); - - if( IsMouseClicked( 2 ) ) - { - ZoomToRange( ev.Start(), end ); - } - } - pit = it; - ++it; - } - } -} - void View::DrawSamples( const Vector& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset ) { auto it = std::lower_bound( vec.begin(), vec.end(), m_vd.zvStart, [] ( const auto& l, const auto& r ) { return l.time.Val() < r; } ); diff --git a/server/TracyView_ContextSwitch.cpp b/server/TracyView_ContextSwitch.cpp index 6840c9fd..ee951b8f 100644 --- a/server/TracyView_ContextSwitch.cpp +++ b/server/TracyView_ContextSwitch.cpp @@ -1,8 +1,14 @@ +#include + +#include "TracyMouse.hpp" +#include "TracyPrint.hpp" #include "TracyView.hpp" namespace tracy { +enum { MinCtxSize = 4 }; + const char* View::DecodeContextSwitchReasonCode( uint8_t reason ) { switch( reason ) @@ -127,4 +133,245 @@ const char* View::DecodeContextSwitchState( uint8_t state ) } } +void View::DrawContextSwitches( const ContextSwitch* ctx, const Vector& sampleData, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int endOffset, bool isFiber ) +{ + const auto lineSize = 2 * GetScale(); + + auto& vec = ctx->v; + auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart ), [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } ); + if( it == vec.end() ) return; + if( it != vec.begin() ) --it; + + auto citend = std::lower_bound( it, vec.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.Start() < r; } ); + if( it == citend ) return; + if( citend != vec.end() ) ++citend; + + const auto w = ImGui::GetContentRegionAvail().x - 1; + const auto ty = round( ImGui::GetTextLineHeight() * 0.75f ); + const auto ty05 = round( ty * 0.5f ); + auto draw = ImGui::GetWindowDrawList(); + const auto dpos = wpos + ImVec2( 0.5f, 0.5f ); + + auto pit = citend; + double minpx = -10.0; + + while( it < citend ) + { + auto& ev = *it; + if( pit != citend ) + { + const bool migration = pit->Cpu() != ev.Cpu(); + const auto px0 = std::max( { ( pit->End() - m_vd.zvStart ) * pxns, -10.0, minpx } ); + const auto pxw = ( ev.WakeupVal() - m_vd.zvStart ) * pxns; + const auto px1 = std::min( ( ev.Start() - m_vd.zvStart ) * pxns, w + 10.0 ); + const auto color = migration ? 0xFFEE7711 : 0xFF2222AA; + if( m_vd.darkenContextSwitches ) + { + draw->AddRectFilled( dpos + ImVec2( px0, offset + ty05 ), dpos + ImVec2( px1, endOffset ), 0x661C2321 ); + } + DrawLine( draw, dpos + ImVec2( px0, offset + ty05 - 0.5f ), dpos + ImVec2( std::min( pxw, w+10.0 ), offset + ty05 - 0.5f ), color, lineSize ); + if( ev.WakeupVal() != ev.Start() ) + { + DrawLine( draw, dpos + ImVec2( std::max( pxw, 10.0 ), offset + ty05 - 0.5f ), dpos + ImVec2( px1, offset + ty05 - 0.5f ), 0xFF2280A0, lineSize ); + } + + if( hover ) + { + bool tooltip = false; + if( ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( pxw, offset + ty ) ) ) + { + ImGui::BeginTooltip(); + if( isFiber ) + { + TextFocused( "Fiber is", "yielding" ); + TextFocused( "Yield time:", TimeToString( ev.Start() - pit->End() ) ); + } + else + { + TextFocused( "Thread is", migration ? "migrating CPUs" : "waiting" ); + TextFocused( "Waiting time:", TimeToString( ev.WakeupVal() - pit->End() ) ); + if( migration ) + { + TextFocused( "CPU:", RealToString( pit->Cpu() ) ); + ImGui::SameLine(); + TextFocused( ICON_FA_LONG_ARROW_ALT_RIGHT, RealToString( ev.Cpu() ) ); + } + else + { + TextFocused( "CPU:", RealToString( ev.Cpu() ) ); + } + if( pit->Reason() != 100 ) + { + TextFocused( "Wait reason:", DecodeContextSwitchReasonCode( pit->Reason() ) ); + ImGui::SameLine(); + ImGui::PushFont( m_smallFont ); + ImGui::AlignTextToFramePadding(); + TextDisabledUnformatted( DecodeContextSwitchReason( pit->Reason() ) ); + ImGui::PopFont(); + } + TextFocused( "Wait state:", DecodeContextSwitchStateCode( pit->State() ) ); + ImGui::SameLine(); + ImGui::PushFont( m_smallFont ); + ImGui::AlignTextToFramePadding(); + TextDisabledUnformatted( DecodeContextSwitchState( pit->State() ) ); + ImGui::PopFont(); + } + tooltip = true; + + if( IsMouseClicked( 2 ) ) + { + ZoomToRange( pit->End(), ev.WakeupVal() ); + } + } + else if( ev.WakeupVal() != ev.Start() && ImGui::IsMouseHoveringRect( wpos + ImVec2( pxw, offset ), wpos + ImVec2( px1, offset + ty ) ) ) + { + assert( !isFiber ); + ImGui::BeginTooltip(); + TextFocused( "Thread is", "waking up" ); + TextFocused( "Scheduling delay:", TimeToString( ev.Start() - ev.WakeupVal() ) ); + TextFocused( "CPU:", RealToString( ev.Cpu() ) ); + if( IsMouseClicked( 2 ) ) + { + ZoomToRange( pit->End(), ev.WakeupVal() ); + } + tooltip = true; + } + if( tooltip ) + { + if( !sampleData.empty() ) + { + auto sdit = std::lower_bound( sampleData.begin(), sampleData.end(), ev.Start(), [] ( const auto& l, const auto& r ) { return l.time.Val() < r; } ); + bool found = sdit != sampleData.end() && sdit->time.Val() == ev.Start(); + if( !found && it != vec.begin() ) + { + auto eit = it; + --eit; + sdit = std::lower_bound( sampleData.begin(), sampleData.end(), eit->End(), [] ( const auto& l, const auto& r ) { return l.time.Val() < r; } ); + found = sdit != sampleData.end() && sdit->time.Val() == eit->End(); + } + if( found ) + { + ImGui::Separator(); + TextDisabledUnformatted( ICON_FA_HOURGLASS_HALF " Wait stack:" ); + CallstackTooltipContents( sdit->callstack.Val() ); + if( ImGui::IsMouseClicked( 0 ) ) + { + m_callstackInfoWindow = sdit->callstack.Val(); + } + } + } + ImGui::EndTooltip(); + } + } + } + + const auto end = ev.IsEndValid() ? ev.End() : m_worker.GetLastTime(); + const auto zsz = std::max( ( end - ev.Start() ) * pxns, pxns * 0.5 ); + if( zsz < MinCtxSize ) + { + const auto MinCtxNs = MinCtxSize * nspx; + int num = 0; + const auto px0 = std::max( ( ev.Start() - m_vd.zvStart ) * pxns, -10.0 ); + auto px1ns = end - m_vd.zvStart; + auto rend = end; + auto nextTime = end + MinCtxNs; + for(;;) + { + const auto prevIt = it; + it = std::lower_bound( it, citend, nextTime, [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } ); + if( it == prevIt ) ++it; + num += std::distance( prevIt, it ); + if( it == citend ) break; + const auto nend = it->IsEndValid() ? it->End() : m_worker.GetLastTime(); + const auto nsnext = nend - m_vd.zvStart; + if( nsnext - px1ns >= MinCtxNs * 2 ) break; + px1ns = nsnext; + rend = nend; + nextTime = nend + nspx; + } + minpx = std::min( std::max( px1ns * pxns, px0+MinCtxSize ), double( w + 10 ) ); + if( num == 1 ) + { + DrawLine( draw, dpos + ImVec2( px0, offset + ty05 - 0.5f ), dpos + ImVec2( minpx, offset + ty05 - 0.5f ), 0xFF22DD22, lineSize ); + if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( minpx, offset + ty + 1 ) ) ) + { + ImGui::BeginTooltip(); + if( isFiber ) + { + const auto tid = m_worker.DecompressThread( ev.Thread() ); + TextFocused( "Fiber is", "running" ); + TextFocused( "Activity time:", TimeToString( end - ev.Start() ) ); + TextFocused( "Thread:", m_worker.GetThreadName( tid ) ); + ImGui::SameLine(); + ImGui::TextDisabled( "(%s)", RealToString( tid ) ); + } + else + { + TextFocused( "Thread is", "running" ); + TextFocused( "Activity time:", TimeToString( end - ev.Start() ) ); + TextFocused( "CPU:", RealToString( ev.Cpu() ) ); + } + ImGui::EndTooltip(); + + if( IsMouseClicked( 2 ) ) + { + ZoomToRange( ev.Start(), rend ); + } + } + } + else + { + DrawZigZag( draw, wpos + ImVec2( 0, offset + ty05 ), px0, minpx, ty/4, 0xFF888888, 1.5 ); + if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( minpx, offset + ty + 1 ) ) ) + { + ImGui::BeginTooltip(); + TextFocused( isFiber ? "Fiber is" : "Thread is", "changing activity multiple times" ); + TextFocused( "Number of running regions:", RealToString( num ) ); + TextFocused( "Time:", TimeToString( rend - ev.Start() ) ); + ImGui::EndTooltip(); + + if( IsMouseClicked( 2 ) ) + { + ZoomToRange( ev.Start(), rend ); + } + } + } + pit = it-1; + } + else + { + const auto px0 = std::max( { ( ev.Start() - m_vd.zvStart ) * pxns, -10.0, minpx } ); + const auto px1 = std::min( ( end - m_vd.zvStart ) * pxns, w + 10.0 ); + DrawLine( draw, dpos + ImVec2( px0, offset + ty05 - 0.5f ), dpos + ImVec2( px1, offset + ty05 - 0.5f ), 0xFF22DD22, lineSize ); + if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + ty + 1 ) ) ) + { + ImGui::BeginTooltip(); + if( isFiber ) + { + const auto tid = m_worker.DecompressThread( ev.Thread() ); + TextFocused( "Fiber is", "running" ); + TextFocused( "Activity time:", TimeToString( end - ev.Start() ) ); + TextFocused( "Thread:", m_worker.GetThreadName( tid ) ); + ImGui::SameLine(); + ImGui::TextDisabled( "(%s)", RealToString( tid ) ); + } + else + { + TextFocused( "Thread is", "running" ); + TextFocused( "Activity time:", TimeToString( end - ev.Start() ) ); + TextFocused( "CPU:", RealToString( ev.Cpu() ) ); + } + ImGui::EndTooltip(); + + if( IsMouseClicked( 2 ) ) + { + ZoomToRange( ev.Start(), end ); + } + } + pit = it; + ++it; + } + } +} + }