diff --git a/profiler/src/profiler/TracyTimelineItemThread.cpp b/profiler/src/profiler/TracyTimelineItemThread.cpp index 72c1412a..dfd2c3bd 100644 --- a/profiler/src/profiler/TracyTimelineItemThread.cpp +++ b/profiler/src/profiler/TracyTimelineItemThread.cpp @@ -44,6 +44,7 @@ uint32_t TimelineItemThread::HeaderColor() const auto& crash = m_worker.GetCrashEvent(); if( crash.thread == m_thread->id ) return 0xFF2222FF; if( m_thread->isFiber ) return 0xFF88FF88; + if( m_thread->isFlatView ) return 0xFFFFCC88; // light blue (ABGR) return 0xFFFFFFFF; } @@ -52,6 +53,7 @@ uint32_t TimelineItemThread::HeaderColorInactive() const auto& crash = m_worker.GetCrashEvent(); if( crash.thread == m_thread->id ) return 0xFF111188; if( m_thread->isFiber ) return 0xFF448844; + if( m_thread->isFlatView ) return 0xFF886644; // darker light blue return 0xFF888888; } @@ -235,6 +237,8 @@ void TimelineItemThread::HeaderTooltip( const char* label ) const void TimelineItemThread::HeaderExtraContents( const TimelineContext& ctx, int offset, float labelWidth ) { + if( m_thread->isFlatView ) return; + m_view.DrawThreadMessagesList( ctx, m_msgDraw, offset, m_thread->id ); const bool hasGhostZones = m_worker.AreGhostZonesReady() && !m_thread->ghostZones.empty(); @@ -275,6 +279,16 @@ void TimelineItemThread::DrawOverlay( const ImVec2& ul, const ImVec2& dr ) void TimelineItemThread::DrawExtraPopupItems() { + if( m_thread->isFlatView ) + { + if( ImGui::MenuItem( ICON_FA_TRASH_CAN " Destroy flatten view" ) ) + { + m_view.QueueDestroyFlattenViewByTid( m_thread->id ); + ImGui::CloseCurrentPopup(); + } + return; + } + if( m_view.GetSelectThread() == m_thread->id ) { if( ImGui::MenuItem( ICON_FA_TIMELINE " Unselect in CPU timeline" ) ) @@ -493,7 +507,7 @@ int TimelineItemThread::PreprocessZoneLevel( const TimelineContext& ctx, const V if( hasChildren ) childrenInherited = DarkenColorSlightly( color ); } } - if( hasChildren ) + if( hasChildren && !m_thread->isFlatView ) { const auto d = PreprocessZoneLevel( ctx, m_worker.GetZoneChildren( ev.Child() ), depth + 1, visible, childrenInherited ); if( d > maxdepth ) maxdepth = d; diff --git a/profiler/src/profiler/TracyView.cpp b/profiler/src/profiler/TracyView.cpp index 12269225..c47d59ab 100644 --- a/profiler/src/profiler/TracyView.cpp +++ b/profiler/src/profiler/TracyView.cpp @@ -1235,9 +1235,17 @@ bool View::DrawImpl() { AddAnnotation( s, e ); } + if( m_seqFlattenPopupSeqId != 0 ) + { + if( ImGui::Selectable( ICON_FA_DIAGRAM_PROJECT " Flatten sequence timeline" ) ) + { + MakeFlattenView( m_seqFlattenPopupSeqId ); + } + } ImGui::EndPopup(); } m_setRangePopupOpen = ImGui::IsPopupOpen( "SetZoneRange" ); + if( !m_setRangePopupOpen ) m_seqFlattenPopupSeqId = 0; if( m_zoomAnim.active ) { diff --git a/profiler/src/profiler/TracyView.hpp b/profiler/src/profiler/TracyView.hpp index e92f42b2..74307f30 100644 --- a/profiler/src/profiler/TracyView.hpp +++ b/profiler/src/profiler/TracyView.hpp @@ -171,6 +171,7 @@ public: } void HighlightThread( uint64_t thread ); + void QueueDestroyFlattenViewByTid( uint64_t tid ); void SelectThread( uint64_t thread ); uint64_t GetSelectThread() const { return m_selectedThread; } void ZoomToRange( int64_t start, int64_t end, bool pause = true ); @@ -280,8 +281,10 @@ private: void DrawTimelineFrames( const FrameData& frames ); void DrawTimeline(); void DrawSampleList( const TimelineContext& ctx, const std::vector& drawList, const Vector& vec, int offset, uint64_t tid ); - void DrawZoneList( const TimelineContext& ctx, const std::vector& drawList, int offset, uint64_t tid, int maxDepth, double margin ); + void DrawZoneList( const TimelineContext& ctx, const std::vector& drawList, int offset, uint64_t tid, int maxDepth, double margin, bool isFlatView ); void DrawSeqArrows( double pxns, const ImVec2& wpos ); + void MakeFlattenView( uint64_t seqId ); + void DestroyFlattenView( uint64_t seqId ); void DrawThreadCropper( const int depth, const uint64_t tid, const float xPos, const float yPos, const float ostep, const float cropperWidth, const bool hasCtxSwitches ); void DrawContextSwitchList( const TimelineContext& ctx, const std::vector& drawList, const Vector& ctxSwitch, int offset, int endOffset, bool isFiber ); 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 ); @@ -538,6 +541,16 @@ private: }; std::vector m_seqArrowDraw; unordered_flat_map m_seqZoneYPos; + + struct FlattenView + { + std::unique_ptr td; + uint64_t seqId; + }; + std::vector m_flattenViews; + std::vector m_flattenViewDestroyQueue; + uint32_t m_nextFlattenTid = 1; + uint64_t m_seqFlattenPopupSeqId = 0; int m_frameHover = -1; bool m_messagesScrollBottom; diff --git a/profiler/src/profiler/TracyView_Timeline.cpp b/profiler/src/profiler/TracyView_Timeline.cpp index f8342d33..44de5548 100644 --- a/profiler/src/profiler/TracyView_Timeline.cpp +++ b/profiler/src/profiler/TracyView_Timeline.cpp @@ -261,6 +261,12 @@ void View::DrawTimeline() m_zoneHover2.Decay( nullptr ); m_seqArrowDraw.clear(); m_seqZoneYPos.clear(); + + for( auto seqId : m_flattenViewDestroyQueue ) + { + DestroyFlattenView( seqId ); + } + m_flattenViewDestroyQueue.clear(); m_findZone.range.StartFrame(); m_statRange.StartFrame(); m_flameRange.StartFrame(); @@ -398,6 +404,10 @@ void View::DrawTimeline() } m_threadReinsert.clear(); } + for( const auto& fv : m_flattenViews ) + { + m_tc.AddItem( fv.td.get() ); + } for( const auto& v : m_threadOrder ) { m_tc.AddItem( v ); diff --git a/profiler/src/profiler/TracyView_ZoneTimeline.cpp b/profiler/src/profiler/TracyView_ZoneTimeline.cpp index c5e1c9a7..b4138990 100644 --- a/profiler/src/profiler/TracyView_ZoneTimeline.cpp +++ b/profiler/src/profiler/TracyView_ZoneTimeline.cpp @@ -76,7 +76,7 @@ void View::DrawThread( const TimelineContext& ctx, const ThreadData& thread, con if( !draw.empty() && yPos <= yMax && yPos + ostep * croppedDepth >= yMin ) { // Only apply margin when croppingActive to avoid text moving around when mouse is getting close to the cropper widget - DrawZoneList( ctx, draw, offset, thread.id, croppedDepth, croppingActive ? cropperAdditionalMargin + GetScale() /* Ensure text has a bit of space for text */ : 0.f ); + DrawZoneList( ctx, draw, offset, thread.id, croppedDepth, croppingActive ? cropperAdditionalMargin + GetScale() /* Ensure text has a bit of space for text */ : 0.f, thread.isFlatView != 0 ); } offset += ostep * croppedDepth; @@ -230,7 +230,7 @@ void View::DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const } -void View::DrawZoneList( const TimelineContext& ctx, const std::vector& drawList, int _offset, uint64_t tid, int maxDepth, double margin ) +void View::DrawZoneList( const TimelineContext& ctx, const std::vector& drawList, int _offset, uint64_t tid, int maxDepth, double margin, bool isFlatView ) { auto draw = ImGui::GetWindowDrawList(); const auto w = ctx.w; @@ -356,12 +356,23 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vectorsecond.seqId ); + if( sit != seqMap.end() && seqIt->second.continuationIdx < sit->second->continuations.size() ) + { + colorTid = sit->second->continuations[seqIt->second.continuationIdx].tid; + } + } + const auto zoneColor = GetZoneColorData( ev, colorTid, v.depth, v.inheritedColor ); const char* zoneName = m_worker.GetZoneName( ev ); auto tsz = ImGui::CalcTextSize( zoneName ); @@ -395,7 +406,11 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vectorsecond.seqId : 0; + } if( !m_zoomAnim.active && IsMouseClicked( 2 ) ) { @@ -417,7 +432,7 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vectorsecond.seqId ); @@ -438,6 +453,7 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vectorsecond->continuations.empty() ) return; + const auto& conts = sit->second->continuations; + + const uint64_t synthTid = ( uint64_t(2) << 32 ) | m_nextFlattenTid++; + + auto td = std::make_unique(); + td->id = synthTid; + td->count = 0; + td->nextZoneId = 0; + td->kernelSampleCnt = 0; + td->isFiber = 0; + td->isFlatView = 1; + td->fiber = nullptr; + td->stackCount = nullptr; + td->groupHint = 0; +#ifndef TRACY_NO_STATISTICS + td->ghostIdx = 0; +#endif + + for( const auto& c : conts ) + { + td->timeline.push_back( c.zone ); + } + + char name[128]; + const auto* firstZone = (const ZoneEvent*)conts[0].zone; + const char* zName = m_worker.GetZoneName( *firstZone ); + std::snprintf( name, sizeof( name ), "flat: %s", zName ? zName : "?" ); + m_worker.RegisterFlattenThreadName( synthTid, name, strlen( name ) ); + + m_flattenViews.push_back( FlattenView{ std::move( td ), seqId } ); +} + +void View::DestroyFlattenView( uint64_t seqId ) +{ + for( auto it = m_flattenViews.begin(); it != m_flattenViews.end(); ++it ) + { + if( it->seqId == seqId ) + { + m_worker.UnregisterFlattenThreadName( it->td->id ); + m_flattenViews.erase( it ); + return; + } + } +} + +void View::QueueDestroyFlattenViewByTid( uint64_t tid ) +{ + for( const auto& fv : m_flattenViews ) + { + if( fv.td->id == tid ) + { + m_flattenViewDestroyQueue.push_back( fv.seqId ); + return; + } + } +} + void View::DrawSeqArrows( double pxns, const ImVec2& wpos ) { if( m_seqArrowDraw.empty() ) return; diff --git a/server/TracyEvent.hpp b/server/TracyEvent.hpp index 35b1bd52..69879bd3 100644 --- a/server/TracyEvent.hpp +++ b/server/TracyEvent.hpp @@ -706,6 +706,7 @@ struct ThreadData Vector ctxSwitchSamples; uint64_t kernelSampleCnt; uint8_t isFiber; + uint8_t isFlatView = 0; ThreadData* fiber; uint8_t* stackCount; int32_t groupHint; diff --git a/server/TracyWorker.cpp b/server/TracyWorker.cpp index ce043b0b..cf30aa08 100644 --- a/server/TracyWorker.cpp +++ b/server/TracyWorker.cpp @@ -3695,6 +3695,18 @@ void Worker::CheckFiberName( uint64_t id, uint64_t tid ) if( m_sock.IsValid() ) Query( ServerQueryFiberName, id ); } +void Worker::RegisterFlattenThreadName( uint64_t tid, const char* name, size_t sz ) +{ + if( m_data.threadNames.find( tid ) != m_data.threadNames.end() ) return; + const auto sl = StoreString( name, sz ); + m_data.threadNames.emplace( tid, sl.ptr ); +} + +void Worker::UnregisterFlattenThreadName( uint64_t tid ) +{ + m_data.threadNames.erase( tid ); +} + void Worker::CheckExternalName( uint64_t id ) { if( m_data.externalNames.find( id ) != m_data.externalNames.end() ) return; diff --git a/server/TracyWorker.hpp b/server/TracyWorker.hpp index 9cfbfb54..bfe2ddd8 100644 --- a/server/TracyWorker.hpp +++ b/server/TracyWorker.hpp @@ -614,6 +614,8 @@ public: const char* GetString( const StringRef& ref ) const; const char* GetString( const StringIdx& idx ) const; const char* GetThreadName( uint64_t id ) const; + void RegisterFlattenThreadName( uint64_t tid, const char* name, size_t sz ); + void UnregisterFlattenThreadName( uint64_t tid ); bool IsThreadLocal( uint64_t id ) { return IsThreadLocal( id, m_data.threadDataLast ); } bool IsThreadLocal( uint64_t id, ThreadCache& cache ); bool IsThreadFiber( uint64_t id );