From 66d3c2a4721c5331c45119616c08757de4da2d4a Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Sun, 19 Mar 2023 18:22:23 +0100 Subject: [PATCH] Draw CPU zones using a precalculated list. --- server/TracyTimelineItemThread.cpp | 2 +- server/TracyView.hpp | 14 +- server/TracyView_ZoneTimeline.cpp | 685 ++++++++++------------------- 3 files changed, 233 insertions(+), 468 deletions(-) diff --git a/server/TracyTimelineItemThread.cpp b/server/TracyTimelineItemThread.cpp index 8ac043fb..17508cdc 100644 --- a/server/TracyTimelineItemThread.cpp +++ b/server/TracyTimelineItemThread.cpp @@ -258,7 +258,7 @@ void TimelineItemThread::HeaderExtraContents( const TimelineContext& ctx, int of bool TimelineItemThread::DrawContents( const TimelineContext& ctx, int& offset ) { - const auto res = m_view.DrawThread( ctx, *m_thread, offset, m_ghost ); + const auto res = m_view.DrawThread( ctx, *m_thread, m_draw, offset, m_depth ); if( !res ) { auto& crash = m_worker.GetCrashEvent(); diff --git a/server/TracyView.hpp b/server/TracyView.hpp index 747a2950..8c0a3ff1 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -41,6 +41,7 @@ struct MemoryPage; class FileRead; class SourceView; struct TimelineContext; +struct TimelineDraw; class View { @@ -121,7 +122,7 @@ public: void HighlightThread( uint64_t thread ); void ZoomToRange( int64_t start, int64_t end, bool pause = true ); bool DrawPlot( const TimelineContext& ctx, PlotData& plot, int& offset ); - bool DrawThread( const TimelineContext& ctx, const ThreadData& thread, int& offset, bool ghostMode ); + bool DrawThread( const TimelineContext& ctx, const ThreadData& thread, const std::vector& draw, int& offset, int depth ); void DrawThreadMessages( const TimelineContext& ctx, const ThreadData& thread, int offset ); void DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const ImVec2& dr ); bool DrawGpu( const TimelineContext& ctx, const GpuCtxData& gpu, int& offset ); @@ -206,16 +207,7 @@ private: void DrawTimeline(); void DrawContextSwitches( const ContextSwitch* ctx, const Vector& sampleData, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int endOffset, bool isFiber ); void DrawSamples( const Vector& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset ); -#ifndef TRACY_NO_STATISTICS - int DispatchGhostLevel( const Vector& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax, uint64_t tid ); - int DrawGhostLevel( const Vector& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax, uint64_t tid ); - int SkipGhostLevel( const Vector& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax, uint64_t tid ); -#endif - int DispatchZoneLevel( const Vector>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax, uint64_t tid ); - template - int DrawZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax, uint64_t tid ); - template - int SkipZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, float yMin, float yMax, uint64_t tid ); + void DrawZoneList( const TimelineContext& ctx, const std::vector& drawList, int offset, uint64_t tid ); int DispatchGpuZoneLevel( const Vector>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift ); template int DrawGpuZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int offset, int depth, uint64_t thread, float yMin, float yMax, int64_t begin, int drift ); diff --git a/server/TracyView_ZoneTimeline.cpp b/server/TracyView_ZoneTimeline.cpp index c3098843..31905ebd 100644 --- a/server/TracyView_ZoneTimeline.cpp +++ b/server/TracyView_ZoneTimeline.cpp @@ -5,6 +5,7 @@ #include "TracyMouse.hpp" #include "TracyPrint.hpp" #include "TracyTimelineContext.hpp" +#include "TracyTimelineDraw.hpp" #include "TracyView.hpp" namespace tracy @@ -22,7 +23,7 @@ static tracy_force_inline uint32_t MixGhostColor( uint32_t c0, uint32_t c1 ) ( ( ( ( ( c0 & 0x000000FF ) ) + 3 * ( ( c1 & 0x000000FF ) ) ) >> 2 ) ); } -bool View::DrawThread( const TimelineContext& ctx, const ThreadData& thread, int& offset, bool ghostMode ) +bool View::DrawThread( const TimelineContext& ctx, const ThreadData& thread, const std::vector& draw, int& offset, int depth ) { const auto& wpos = ctx.wpos; const auto ty = ctx.ty; @@ -38,7 +39,6 @@ bool View::DrawThread( const TimelineContext& ctx, const ThreadData& thread, int const auto sstep = sty + 1; ImGui::PopFont(); - int depth = 0; const auto sampleOffset = offset; const auto hasSamples = m_vd.drawSamples && !thread.samples.empty(); const auto hasCtxSwitch = m_vd.drawContextSwitches && m_worker.GetContextSwitchData( thread.id ); @@ -61,15 +61,10 @@ bool View::DrawThread( const TimelineContext& ctx, const ThreadData& thread, int offset += round( ostep * 0.75f ); } -#ifndef TRACY_NO_STATISTICS - if( m_worker.AreGhostZonesReady() && ( ghostMode || ( m_vd.ghostZones && thread.timeline.empty() ) ) ) + const auto yPos = wpos.y + offset; + if( !draw.empty() && yPos <= yMax && yPos + ostep * depth >= yMin ) { - depth = DispatchGhostLevel( thread.ghostZones, hover, pxns, int64_t( nspx ), wpos, offset, 0, yMin, yMax, thread.id ); - } - else -#endif - { - depth = DispatchZoneLevel( thread.timeline, hover, pxns, int64_t( nspx ), wpos, offset, 0, yMin, yMax, thread.id ); + DrawZoneList( ctx, draw, offset, thread.id ); } offset += ostep * depth; @@ -236,71 +231,226 @@ void View::DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const } } -#ifndef TRACY_NO_STATISTICS -int View::DispatchGhostLevel( const Vector& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, float yMin, float yMax, uint64_t tid ) +void View::DrawZoneList( const TimelineContext& ctx, const std::vector& drawList, int _offset, uint64_t tid ) { - const auto ty = ImGui::GetTextLineHeight(); - const auto ostep = ty + 1; - const auto offset = _offset + ostep * depth; - - const auto yPos = wpos.y + offset; - // Inline frames have to be taken into account, hence the multiply by 64 (arbitrary limit for inline frames in client) - if( yPos + 64 * ostep >= yMin && yPos <= yMax ) - { - return DrawGhostLevel( vec, hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - } - else - { - return SkipGhostLevel( vec, hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - } -} - -int View::DrawGhostLevel( const Vector& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, float yMin, float yMax, uint64_t tid ) -{ - auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart - 2 * MinVisSize * nspx ), [] ( const auto& l, const auto& r ) { return l.end.Val() < r; } ); - if( it == vec.end() ) return depth; - - const auto zitend = std::lower_bound( it, vec.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.start.Val() < r; } ); - if( it == zitend ) return depth; - if( (zitend-1)->end.Val() < m_vd.zvStart ) return depth; - - const auto w = ImGui::GetContentRegionAvail().x - 1; - const auto ty = ImGui::GetTextLineHeight(); - const auto ostep = ty + 1; - const auto offset = _offset + ostep * depth; auto draw = ImGui::GetWindowDrawList(); + const auto w = ctx.w; + const auto& wpos = ctx.wpos; const auto dpos = wpos + ImVec2( 0.5f, 0.5f ); + const auto ty = ctx.ty; + const auto ostep = ty + 1; + const auto yMin = ctx.yMin; + const auto yMax = ctx.yMax; + const auto pxns = ctx.pxns; + const auto hover = ctx.hover; + const auto vStart = ctx.vStart; + const auto dsz = m_worker.GetDelay() * pxns; + const auto rsz = m_worker.GetResolution() * pxns; - depth++; - int maxdepth = depth; + const auto ty025 = round( ty * 0.25f ); + const auto ty05 = round( ty * 0.5f ); + const auto ty075 = round( ty * 0.75f ); - while( it < zitend ) + for( auto& v : drawList ) { - auto& ev = *it; - const auto end = ev.end.Val(); - const auto zsz = std::max( ( end - ev.start.Val() ) * pxns, pxns * 0.5 ); - if( zsz < MinVisSize ) + const auto offset = _offset + ostep * v.depth; + const auto yPos = wpos.y + offset; + if( yPos > yMax || yPos + ostep < yMin ) continue; + + switch( v.type ) { - const auto MinVisNs = MinVisSize * nspx; - const auto color = m_vd.dynamicColors == 2 ? 0xFF666666 : MixGhostColor( GetThreadColor( tid, depth ), 0x665555 ); - const auto px0 = ( ev.start.Val() - m_vd.zvStart ) * pxns; - auto px1ns = ev.end.Val() - m_vd.zvStart; - auto rend = end; - auto nextTime = end + MinVisNs; - for(;;) + case TimelineDrawType::Folded: + { + auto& ev = *(const ZoneEvent*)v.ev.get(); + const auto color = m_vd.dynamicColors == 2 ? 0xFF666666 : GetThreadColor( tid, v.depth ); + const auto rend = v.rend.Val(); + const auto px0 = ( ev.Start() - vStart ) * pxns; + const auto px1 = ( rend - vStart ) * pxns; + draw->AddRectFilled( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty ), color ); + DrawZigZag( draw, wpos + ImVec2( 0, offset + ty/2 ), std::max( px0, -10.0 ), std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), ty/4, DarkenColor( color ) ); + if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty + 1 ) ) ) { - const auto prevIt = it; - it = std::lower_bound( it, zitend, nextTime, [] ( const auto& l, const auto& r ) { return l.end.Val() < r; } ); - if( it == prevIt ) ++it; - if( it == zitend ) break; - const auto nend = it->end.Val(); - const auto nsnext = nend - m_vd.zvStart; - if( nsnext - px1ns >= MinVisNs * 2 ) break; - px1ns = nsnext; - rend = nend; - nextTime = nend + nspx; + if( IsMouseClickReleased( 1 ) ) m_setRangePopup = RangeSlim { ev.Start(), rend, true }; + if( v.num > 1 ) + { + ImGui::BeginTooltip(); + TextFocused( "Zones too small to display:", RealToString( v.num ) ); + ImGui::Separator(); + TextFocused( "Execution time:", TimeToString( rend - ev.Start() ) ); + ImGui::EndTooltip(); + + if( IsMouseClicked( 2 ) && rend - ev.Start() > 0 ) + { + ZoomToRange( ev.Start(), rend ); + } + } + else + { + ZoneTooltip( ev ); + + if( IsMouseClicked( 2 ) && rend - ev.Start() > 0 ) + { + ZoomToZone( ev ); + } + if( IsMouseClicked( 0 ) ) + { + if( ImGui::GetIO().KeyCtrl ) + { + auto& srcloc = m_worker.GetSourceLocation( ev.SrcLoc() ); + m_findZone.ShowZone( ev.SrcLoc(), m_worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function ) ); + } + else + { + ShowZoneInfo( ev ); + } + } + + m_zoneSrcLocHighlight = ev.SrcLoc(); + m_zoneHover = &ev; + } } - const auto px1 = px1ns * pxns; + const auto tmp = RealToString( v.num ); + const auto tsz = ImGui::CalcTextSize( tmp ); + if( tsz.x < px1 - px0 ) + { + const auto x = px0 + ( px1 - px0 - tsz.x ) / 2; + DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFF4488DD, tmp ); + } + break; + } + case TimelineDrawType::Zone: + { + auto& ev = *(const ZoneEvent*)v.ev.get(); + const auto end = m_worker.GetZoneEnd( ev ); + const auto zsz = std::max( ( end - ev.Start() ) * pxns, pxns * 0.5 ); + const auto zoneColor = GetZoneColorData( ev, tid, v.depth ); + const char* zoneName = m_worker.GetZoneName( ev ); + + auto tsz = ImGui::CalcTextSize( zoneName ); + if( m_shortenName == ShortenName::Always || ( ( m_shortenName == ShortenName::NoSpace || m_shortenName == ShortenName::NoSpaceAndNormalize ) && tsz.x > zsz ) ) + { + zoneName = ShortenZoneName( m_shortenName, zoneName, tsz, zsz ); + } + + const auto pr0 = ( ev.Start() - m_vd.zvStart ) * pxns; + const auto pr1 = ( end - m_vd.zvStart ) * pxns; + const auto px0 = std::max( pr0, -10.0 ); + const auto px1 = std::max( { std::min( pr1, double( w + 10 ) ), px0 + pxns * 0.5, px0 + MinVisSize } ); + draw->AddRectFilled( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), zoneColor.color ); + if( zoneColor.highlight ) + { + if( zoneColor.thickness > 1.f ) + { + draw->AddRect( wpos + ImVec2( px0 + 1, offset + 1 ), wpos + ImVec2( px1 - 1, offset + tsz.y - 1 ), zoneColor.accentColor, 0.f, -1, zoneColor.thickness ); + } + else + { + draw->AddRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), zoneColor.accentColor, 0.f, -1, zoneColor.thickness ); + } + } + else + { + const auto darkColor = DarkenColor( zoneColor.color ); + DrawLine( draw, dpos + ImVec2( px0, offset + tsz.y ), dpos + ImVec2( px0, offset ), dpos + ImVec2( px1-1, offset ), zoneColor.accentColor, zoneColor.thickness ); + DrawLine( draw, dpos + ImVec2( px0, offset + tsz.y ), dpos + ImVec2( px1-1, offset + tsz.y ), dpos + ImVec2( px1-1, offset ), darkColor, zoneColor.thickness ); + } + if( dsz > MinVisSize ) + { + const auto diff = dsz - MinVisSize; + uint32_t color; + if( diff < 1 ) + { + color = ( uint32_t( diff * 0x88 ) << 24 ) | 0x2222DD; + } + else + { + color = 0x882222DD; + } + + draw->AddRectFilled( wpos + ImVec2( pr0, offset ), wpos + ImVec2( std::min( pr0+dsz, pr1 ), offset + tsz.y ), color ); + draw->AddRectFilled( wpos + ImVec2( pr1, offset ), wpos + ImVec2( pr1+dsz, offset + tsz.y ), color ); + } + if( rsz > MinVisSize ) + { + const auto diff = rsz - MinVisSize; + uint32_t color; + if( diff < 1 ) + { + color = ( uint32_t( diff * 0xAA ) << 24 ) | 0xFFFFFF; + } + else + { + color = 0xAAFFFFFF; + } + + DrawLine( draw, dpos + ImVec2( pr0 + rsz, offset + ty05 ), dpos + ImVec2( pr0 - rsz, offset + ty05 ), color ); + DrawLine( draw, dpos + ImVec2( pr0 + rsz, offset + ty025 ), dpos + ImVec2( pr0 + rsz, offset + ty075 ), color ); + DrawLine( draw, dpos + ImVec2( pr0 - rsz, offset + ty025 ), dpos + ImVec2( pr0 - rsz, offset + ty075 ), color ); + + DrawLine( draw, dpos + ImVec2( pr1 + rsz, offset + ty05 ), dpos + ImVec2( pr1 - rsz, offset + ty05 ), color ); + DrawLine( draw, dpos + ImVec2( pr1 + rsz, offset + ty025 ), dpos + ImVec2( pr1 + rsz, offset + ty075 ), color ); + DrawLine( draw, dpos + ImVec2( pr1 - rsz, offset + ty025 ), dpos + ImVec2( pr1 - rsz, offset + ty075 ), color ); + } + if( tsz.x < zsz ) + { + const auto x = ( ev.Start() - m_vd.zvStart ) * pxns + ( ( end - ev.Start() ) * pxns - tsz.x ) / 2; + if( x < 0 || x > w - tsz.x ) + { + ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true ); + DrawTextContrast( draw, wpos + ImVec2( std::max( std::max( 0., px0 ), std::min( double( w - tsz.x ), x ) ), offset ), 0xFFFFFFFF, zoneName ); + ImGui::PopClipRect(); + } + else if( ev.Start() == ev.End() ) + { + DrawTextContrast( draw, wpos + ImVec2( px0 + ( px1 - px0 - tsz.x ) * 0.5, offset ), 0xFFFFFFFF, zoneName ); + } + else + { + DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFFFFFFFF, zoneName ); + } + } + else + { + ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true ); + DrawTextContrast( draw, wpos + ImVec2( std::max( int64_t( 0 ), ev.Start() - m_vd.zvStart ) * pxns, offset ), 0xFFFFFFFF, zoneName ); + ImGui::PopClipRect(); + } + + if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y + 1 ) ) ) + { + ZoneTooltip( ev ); + if( IsMouseClickReleased( 1 ) ) m_setRangePopup = RangeSlim { ev.Start(), m_worker.GetZoneEnd( ev ), true }; + + if( !m_zoomAnim.active && IsMouseClicked( 2 ) ) + { + ZoomToZone( ev ); + } + if( IsMouseClicked( 0 ) ) + { + if( ImGui::GetIO().KeyCtrl ) + { + auto& srcloc = m_worker.GetSourceLocation( ev.SrcLoc() ); + m_findZone.ShowZone( ev.SrcLoc(), m_worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function ) ); + } + else + { + ShowZoneInfo( ev ); + } + } + + m_zoneSrcLocHighlight = ev.SrcLoc(); + m_zoneHover = &ev; + } + break; + } +#ifndef TRACY_NO_STATISTICS + case TimelineDrawType::GhostFolded: + { + auto& ev = *(const GhostZone*)v.ev.get(); + const auto color = m_vd.dynamicColors == 2 ? 0xFF666666 : MixGhostColor( GetThreadColor( tid, v.depth ), 0x665555 ); + const auto rend = v.rend.Val(); + const auto px0 = ( ev.start.Val() - m_vd.zvStart ) * pxns; + const auto px1 = ( rend - ev.end.Val() ) * pxns; draw->AddRectFilled( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty ), color ); DrawZigZag( draw, wpos + ImVec2( 0, offset + ty/2 ), std::max( px0, -10.0 ), std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), ty/4, DarkenColor( color ) ); if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty + 1 ) ) ) @@ -317,9 +467,14 @@ int View::DrawGhostLevel( const Vector& vec, bool hover, double pxns, ZoomToRange( ev.start.Val(), rend ); } } + break; } - else + case TimelineDrawType::Ghost: { + auto& ev = *(const GhostZone*)v.ev.get(); + const auto end = ev.end.Val(); + const auto zsz = std::max( ( end - ev.start.Val() ) * pxns, pxns * 0.5 ); + const auto& ghostKey = m_worker.GetGhostFrame( ev.frame ); const auto frame = m_worker.GetCallstackFrame( ghostKey.frame ); @@ -329,16 +484,16 @@ int View::DrawGhostLevel( const Vector& vec, bool hover, double pxns, if( frame ) { const auto& sym = frame->data[ghostKey.inlineFrame]; - color = GetHsvColor( sym.name.Idx(), depth ); + color = GetHsvColor( sym.name.Idx(), v.depth ); } else { - color = GetHsvColor( ghostKey.frame.data, depth ); + color = GetHsvColor( ghostKey.frame.data, v.depth ); } } else { - color = MixGhostColor( GetThreadColor( tid, depth ), 0x665555 ); + color = MixGhostColor( GetThreadColor( tid, v.depth ), 0x665555 ); } const auto pr0 = ( ev.start.Val() - m_vd.zvStart ) * pxns; @@ -520,396 +675,14 @@ int View::DrawGhostLevel( const Vector& vec, bool hover, double pxns, } } } - - if( ev.child >= 0 ) - { - const auto d = DispatchGhostLevel( m_worker.GetGhostChildren( ev.child ), hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - if( d > maxdepth ) maxdepth = d; - } - ++it; + break; } - } - - return maxdepth; -} - -int View::SkipGhostLevel( const Vector& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, float yMin, float yMax, uint64_t tid ) -{ - auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart - 2 * MinVisSize * nspx ), [] ( const auto& l, const auto& r ) { return l.end.Val() < r; } ); - if( it == vec.end() ) return depth; - - const auto zitend = std::lower_bound( it, vec.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.start.Val() < r; } ); - if( it == zitend ) return depth; - if( (zitend-1)->end.Val() < m_vd.zvStart ) return depth; - - depth++; - int maxdepth = depth; - - while( it < zitend ) - { - auto& ev = *it; - const auto end = ev.end.Val(); - const auto zsz = std::max( ( end - ev.start.Val() ) * pxns, pxns * 0.5 ); - if( zsz < MinVisSize ) - { - const auto MinVisNs = MinVisSize * nspx; - auto px1ns = ev.end.Val() - m_vd.zvStart; - auto nextTime = end + MinVisNs; - for(;;) - { - const auto prevIt = it; - it = std::lower_bound( it, zitend, nextTime, [] ( const auto& l, const auto& r ) { return l.end.Val() < r; } ); - if( it == prevIt ) ++it; - if( it == zitend ) break; - const auto nend = it->end.Val(); - const auto nsnext = nend - m_vd.zvStart; - if( nsnext - px1ns >= MinVisNs * 2 ) break; - px1ns = nsnext; - nextTime = nend + nspx; - } - } - else - { - if( ev.child >= 0 ) - { - const auto d = DispatchGhostLevel( m_worker.GetGhostChildren( ev.child ), hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - if( d > maxdepth ) maxdepth = d; - } - ++it; - } - } - - return maxdepth; -} #endif - -int View::DispatchZoneLevel( const Vector>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, float yMin, float yMax, uint64_t tid ) -{ - const auto ty = ImGui::GetTextLineHeight(); - const auto ostep = ty + 1; - const auto offset = _offset + ostep * depth; - - const auto yPos = wpos.y + offset; - if( yPos + ostep >= yMin && yPos <= yMax ) - { - if( vec.is_magic() ) - { - return DrawZoneLevel>( *(Vector*)( &vec ), hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - } - else - { - return DrawZoneLevel>( vec, hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - } - } - else - { - if( vec.is_magic() ) - { - return SkipZoneLevel>( *(Vector*)( &vec ), hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - } - else - { - return SkipZoneLevel>( vec, hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); + default: + assert( false ); + break; } } } -template -int View::DrawZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, float yMin, float yMax, uint64_t tid ) -{ - const auto delay = m_worker.GetDelay(); - const auto resolution = m_worker.GetResolution(); - // cast to uint64_t, so that unended zones (end = -1) are still drawn - auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart - std::max( delay, 2 * MinVisSize * nspx ) ), [] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)a(l).End() < (uint64_t)r; } ); - if( it == vec.end() ) return depth; - - const auto zitend = std::lower_bound( it, vec.end(), m_vd.zvEnd + resolution, [] ( const auto& l, const auto& r ) { Adapter a; return a(l).Start() < r; } ); - if( it == zitend ) return depth; - Adapter a; - if( !a(*it).IsEndValid() && m_worker.GetZoneEnd( a(*it) ) < m_vd.zvStart ) return depth; - if( m_worker.GetZoneEnd( a(*(zitend-1)) ) < m_vd.zvStart ) return depth; - - const auto w = ImGui::GetContentRegionAvail().x - 1; - const auto ty = ImGui::GetTextLineHeight(); - const auto ostep = ty + 1; - const auto offset = _offset + ostep * depth; - auto draw = ImGui::GetWindowDrawList(); - const auto dsz = delay * pxns; - const auto rsz = resolution * pxns; - const auto dpos = wpos + ImVec2( 0.5f, 0.5f ); - - const auto ty025 = round( ty * 0.25f ); - const auto ty05 = round( ty * 0.5f ); - const auto ty075 = round( ty * 0.75f ); - - depth++; - int maxdepth = depth; - - while( it < zitend ) - { - auto& ev = a(*it); - const auto end = m_worker.GetZoneEnd( ev ); - const auto zsz = std::max( ( end - ev.Start() ) * pxns, pxns * 0.5 ); - if( zsz < MinVisSize ) - { - const auto MinVisNs = MinVisSize * nspx; - const auto color = m_vd.dynamicColors == 2 ? 0xFF666666 : GetThreadColor( tid, depth ); - int num = 0; - const auto px0 = ( ev.Start() - m_vd.zvStart ) * pxns; - auto px1ns = end - m_vd.zvStart; - auto rend = end; - auto nextTime = end + MinVisNs; - for(;;) - { - const auto prevIt = it; - it = std::lower_bound( it, zitend, nextTime, [] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)a(l).End() < (uint64_t)r; } ); - if( it == prevIt ) ++it; - num += std::distance( prevIt, it ); - if( it == zitend ) break; - const auto nend = m_worker.GetZoneEnd( a(*it) ); - const auto nsnext = nend - m_vd.zvStart; - if( nsnext - px1ns >= MinVisNs * 2 ) break; - px1ns = nsnext; - rend = nend; - nextTime = nend + nspx; - } - const auto px1 = px1ns * pxns; - draw->AddRectFilled( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty ), color ); - DrawZigZag( draw, wpos + ImVec2( 0, offset + ty/2 ), std::max( px0, -10.0 ), std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), ty/4, DarkenColor( color ) ); - if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( std::max( px0, -10.0 ), offset ), wpos + ImVec2( std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), offset + ty + 1 ) ) ) - { - if( IsMouseClickReleased( 1 ) ) m_setRangePopup = RangeSlim { ev.Start(), rend, true }; - if( num > 1 ) - { - ImGui::BeginTooltip(); - TextFocused( "Zones too small to display:", RealToString( num ) ); - ImGui::Separator(); - TextFocused( "Execution time:", TimeToString( rend - ev.Start() ) ); - ImGui::EndTooltip(); - - if( IsMouseClicked( 2 ) && rend - ev.Start() > 0 ) - { - ZoomToRange( ev.Start(), rend ); - } - } - else - { - ZoneTooltip( ev ); - - if( IsMouseClicked( 2 ) && rend - ev.Start() > 0 ) - { - ZoomToZone( ev ); - } - if( IsMouseClicked( 0 ) ) - { - if( ImGui::GetIO().KeyCtrl ) - { - auto& srcloc = m_worker.GetSourceLocation( ev.SrcLoc() ); - m_findZone.ShowZone( ev.SrcLoc(), m_worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function ) ); - } - else - { - ShowZoneInfo( ev ); - } - } - - m_zoneSrcLocHighlight = ev.SrcLoc(); - m_zoneHover = &ev; - } - } - const auto tmp = RealToString( num ); - const auto tsz = ImGui::CalcTextSize( tmp ); - if( tsz.x < px1 - px0 ) - { - const auto x = px0 + ( px1 - px0 - tsz.x ) / 2; - DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFF4488DD, tmp ); - } - } - else - { - const auto zoneColor = GetZoneColorData( ev, tid, depth ); - const char* zoneName = m_worker.GetZoneName( ev ); - - if( ev.HasChildren() ) - { - const auto d = DispatchZoneLevel( m_worker.GetZoneChildren( ev.Child() ), hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - if( d > maxdepth ) maxdepth = d; - } - - auto tsz = ImGui::CalcTextSize( zoneName ); - if( m_shortenName == ShortenName::Always || ( ( m_shortenName == ShortenName::NoSpace || m_shortenName == ShortenName::NoSpaceAndNormalize ) && tsz.x > zsz ) ) - { - zoneName = ShortenZoneName( m_shortenName, zoneName, tsz, zsz ); - } - - const auto pr0 = ( ev.Start() - m_vd.zvStart ) * pxns; - const auto pr1 = ( end - m_vd.zvStart ) * pxns; - const auto px0 = std::max( pr0, -10.0 ); - const auto px1 = std::max( { std::min( pr1, double( w + 10 ) ), px0 + pxns * 0.5, px0 + MinVisSize } ); - draw->AddRectFilled( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), zoneColor.color ); - if( zoneColor.highlight ) - { - if( zoneColor.thickness > 1.f ) - { - draw->AddRect( wpos + ImVec2( px0 + 1, offset + 1 ), wpos + ImVec2( px1 - 1, offset + tsz.y - 1 ), zoneColor.accentColor, 0.f, -1, zoneColor.thickness ); - } - else - { - draw->AddRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y ), zoneColor.accentColor, 0.f, -1, zoneColor.thickness ); - } - } - else - { - const auto darkColor = DarkenColor( zoneColor.color ); - DrawLine( draw, dpos + ImVec2( px0, offset + tsz.y ), dpos + ImVec2( px0, offset ), dpos + ImVec2( px1-1, offset ), zoneColor.accentColor, zoneColor.thickness ); - DrawLine( draw, dpos + ImVec2( px0, offset + tsz.y ), dpos + ImVec2( px1-1, offset + tsz.y ), dpos + ImVec2( px1-1, offset ), darkColor, zoneColor.thickness ); - } - if( dsz > MinVisSize ) - { - const auto diff = dsz - MinVisSize; - uint32_t color; - if( diff < 1 ) - { - color = ( uint32_t( diff * 0x88 ) << 24 ) | 0x2222DD; - } - else - { - color = 0x882222DD; - } - - draw->AddRectFilled( wpos + ImVec2( pr0, offset ), wpos + ImVec2( std::min( pr0+dsz, pr1 ), offset + tsz.y ), color ); - draw->AddRectFilled( wpos + ImVec2( pr1, offset ), wpos + ImVec2( pr1+dsz, offset + tsz.y ), color ); - } - if( rsz > MinVisSize ) - { - const auto diff = rsz - MinVisSize; - uint32_t color; - if( diff < 1 ) - { - color = ( uint32_t( diff * 0xAA ) << 24 ) | 0xFFFFFF; - } - else - { - color = 0xAAFFFFFF; - } - - DrawLine( draw, dpos + ImVec2( pr0 + rsz, offset + ty05 ), dpos + ImVec2( pr0 - rsz, offset + ty05 ), color ); - DrawLine( draw, dpos + ImVec2( pr0 + rsz, offset + ty025 ), dpos + ImVec2( pr0 + rsz, offset + ty075 ), color ); - DrawLine( draw, dpos + ImVec2( pr0 - rsz, offset + ty025 ), dpos + ImVec2( pr0 - rsz, offset + ty075 ), color ); - - DrawLine( draw, dpos + ImVec2( pr1 + rsz, offset + ty05 ), dpos + ImVec2( pr1 - rsz, offset + ty05 ), color ); - DrawLine( draw, dpos + ImVec2( pr1 + rsz, offset + ty025 ), dpos + ImVec2( pr1 + rsz, offset + ty075 ), color ); - DrawLine( draw, dpos + ImVec2( pr1 - rsz, offset + ty025 ), dpos + ImVec2( pr1 - rsz, offset + ty075 ), color ); - } - if( tsz.x < zsz ) - { - const auto x = ( ev.Start() - m_vd.zvStart ) * pxns + ( ( end - ev.Start() ) * pxns - tsz.x ) / 2; - if( x < 0 || x > w - tsz.x ) - { - ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true ); - DrawTextContrast( draw, wpos + ImVec2( std::max( std::max( 0., px0 ), std::min( double( w - tsz.x ), x ) ), offset ), 0xFFFFFFFF, zoneName ); - ImGui::PopClipRect(); - } - else if( ev.Start() == ev.End() ) - { - DrawTextContrast( draw, wpos + ImVec2( px0 + ( px1 - px0 - tsz.x ) * 0.5, offset ), 0xFFFFFFFF, zoneName ); - } - else - { - DrawTextContrast( draw, wpos + ImVec2( x, offset ), 0xFFFFFFFF, zoneName ); - } - } - else - { - ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true ); - DrawTextContrast( draw, wpos + ImVec2( std::max( int64_t( 0 ), ev.Start() - m_vd.zvStart ) * pxns, offset ), 0xFFFFFFFF, zoneName ); - ImGui::PopClipRect(); - } - - if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y + 1 ) ) ) - { - ZoneTooltip( ev ); - if( IsMouseClickReleased( 1 ) ) m_setRangePopup = RangeSlim { ev.Start(), m_worker.GetZoneEnd( ev ), true }; - - if( !m_zoomAnim.active && IsMouseClicked( 2 ) ) - { - ZoomToZone( ev ); - } - if( IsMouseClicked( 0 ) ) - { - if( ImGui::GetIO().KeyCtrl ) - { - auto& srcloc = m_worker.GetSourceLocation( ev.SrcLoc() ); - m_findZone.ShowZone( ev.SrcLoc(), m_worker.GetString( srcloc.name.active ? srcloc.name : srcloc.function ) ); - } - else - { - ShowZoneInfo( ev ); - } - } - - m_zoneSrcLocHighlight = ev.SrcLoc(); - m_zoneHover = &ev; - } - - ++it; - } - } - return maxdepth; -} - -template -int View::SkipZoneLevel( const V& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, float yMin, float yMax, uint64_t tid ) -{ - const auto delay = m_worker.GetDelay(); - const auto resolution = m_worker.GetResolution(); - // cast to uint64_t, so that unended zones (end = -1) are still drawn - auto it = std::lower_bound( vec.begin(), vec.end(), std::max( 0, m_vd.zvStart - std::max( delay, 2 * MinVisSize * nspx ) ), [] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)a(l).End() < (uint64_t)r; } ); - if( it == vec.end() ) return depth; - - Adapter a; - - const auto zitend = std::lower_bound( it, vec.end(), m_vd.zvEnd + resolution, [] ( const auto& l, const auto& r ) { Adapter a; return a(l).Start() < r; } ); - if( it == zitend ) return depth; - if( m_worker.GetZoneEnd( a(*(zitend-1)) ) < m_vd.zvStart ) return depth; - - depth++; - int maxdepth = depth; - - while( it < zitend ) - { - auto& ev = a(*it); - const auto end = m_worker.GetZoneEnd( ev ); - const auto zsz = std::max( ( end - ev.Start() ) * pxns, pxns * 0.5 ); - if( zsz < MinVisSize ) - { - const auto MinVisNs = MinVisSize * nspx; - auto px1ns = end - m_vd.zvStart; - auto nextTime = end + MinVisNs; - for(;;) - { - const auto prevIt = it; - it = std::lower_bound( it, zitend, nextTime, [] ( const auto& l, const auto& r ) { Adapter a; return (uint64_t)a(l).End() < (uint64_t)r; } ); - if( it == prevIt ) ++it; - if( it == zitend ) break; - const auto nend = m_worker.GetZoneEnd( a(*it) ); - const auto nsnext = nend - m_vd.zvStart; - if( nsnext - px1ns >= MinVisNs * 2 ) break; - px1ns = nsnext; - nextTime = nend + nspx; - } - } - else - { - if( ev.HasChildren() ) - { - const auto d = DispatchZoneLevel( m_worker.GetZoneChildren( ev.Child() ), hover, pxns, nspx, wpos, _offset, depth, yMin, yMax, tid ); - if( d > maxdepth ) maxdepth = d; - } - ++it; - } - } - return maxdepth; -} - }