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;
+ }
+ }
+}
+
}