adding "flatten view" to sequence points

This commit is contained in:
Marcos Slomp
2026-05-28 11:07:57 -07:00
parent 5c600b06e7
commit 71f21d08fb
8 changed files with 150 additions and 8 deletions

View File

@@ -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;

View File

@@ -1230,9 +1230,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 )
{

View File

@@ -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 );
@@ -279,8 +280,10 @@ private:
void DrawTimelineFrames( const FrameData& frames );
void DrawTimeline();
void DrawSampleList( const TimelineContext& ctx, const std::vector<SamplesDraw>& drawList, const Vector<SampleData>& vec, int offset, uint64_t tid );
void DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineDraw>& drawList, int offset, uint64_t tid, int maxDepth, double margin );
void DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineDraw>& 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<ContextSwitchDraw>& drawList, const Vector<ContextSwitchData>& ctxSwitch, int offset, int endOffset, bool isFiber );
int DispatchGpuZoneLevel( const Vector<short_ptr<GpuEvent>>& 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 );
@@ -537,6 +540,16 @@ private:
};
std::vector<SeqArrowDraw> m_seqArrowDraw;
unordered_flat_map<const ZoneEvent*, float> m_seqZoneYPos;
struct FlattenView
{
std::unique_ptr<ThreadData> td;
uint64_t seqId;
};
std::vector<FlattenView> m_flattenViews;
std::vector<uint64_t> m_flattenViewDestroyQueue;
uint32_t m_nextFlattenTid = 1;
uint64_t m_seqFlattenPopupSeqId = 0;
int m_frameHover = -1;
bool m_messagesScrollBottom;

View File

@@ -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<TimelineItemThread>( fv.td.get() );
}
for( const auto& v : m_threadOrder )
{
m_tc.AddItem<TimelineItemThread>( v );

View File

@@ -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<TimelineDraw>& drawList, int _offset, uint64_t tid, int maxDepth, double margin )
void View::DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineDraw>& 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::vector<TimelineD
const auto& seqRefMap = m_worker.GetZoneSeqRef();
const auto seqIt = seqRefMap.find( &ev );
if( seqIt != seqRefMap.end() )
if( !isFlatView && seqIt != seqRefMap.end() )
{
m_seqZoneYPos[&ev] = wpos.y + offset + ty * 0.5f;
}
const auto zoneColor = GetZoneColorData( ev, tid, v.depth, v.inheritedColor );
// Preserve original-thread coloring when rendered on a flat view.
uint64_t colorTid = tid;
if( isFlatView && seqIt != seqRefMap.end() )
{
const auto& seqMap = m_worker.GetSequences();
auto sit = seqMap.find( seqIt->second.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::vector<TimelineD
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( IsMouseClickReleased( 1 ) )
{
m_setRangePopup = RangeSlim { ev.Start(), m_worker.GetZoneEnd( ev ), true };
m_seqFlattenPopupSeqId = ( !isFlatView && seqIt != seqRefMap.end() ) ? seqIt->second.seqId : 0;
}
if( !m_zoomAnim.active && IsMouseClicked( 2 ) )
{
@@ -417,7 +432,7 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineD
m_zoneSrcLocHighlight = ev.SrcLoc();
m_zoneHover = &ev;
if( seqIt != seqRefMap.end() )
if( !isFlatView && seqIt != seqRefMap.end() )
{
const auto& seqMap = m_worker.GetSequences();
const auto sit = seqMap.find( seqIt->second.seqId );
@@ -438,6 +453,7 @@ void View::DrawZoneList( const TimelineContext& ctx, const std::vector<TimelineD
conts[idx+1].resumeTime, (const ZoneEvent*)conts[idx+1].zone } );
}
}
}
}
break;
@@ -701,6 +717,72 @@ void View::DrawThreadCropper( const int depth, const uint64_t tid, const float x
}
}
void View::MakeFlattenView( uint64_t seqId )
{
for( const auto& fv : m_flattenViews )
{
if( fv.seqId == seqId ) return; // idempotent
}
const auto& seqMap = m_worker.GetSequences();
auto sit = seqMap.find( seqId );
if( sit == seqMap.end() || sit->second->continuations.empty() ) return;
const auto& conts = sit->second->continuations;
const uint64_t synthTid = ( uint64_t(2) << 32 ) | m_nextFlattenTid++;
auto td = std::make_unique<ThreadData>();
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;

View File

@@ -706,6 +706,7 @@ struct ThreadData
Vector<SampleData> ctxSwitchSamples;
uint64_t kernelSampleCnt;
uint8_t isFiber;
uint8_t isFlatView = 0;
ThreadData* fiber;
uint8_t* stackCount;
int32_t groupHint;

View File

@@ -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;

View File

@@ -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 );