mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-10 10:41:50 +00:00
Migrate drawing CPU threads to the new timeline item system.
This commit is contained in:
parent
e3007062fc
commit
ec3dcaeef3
@ -139,6 +139,7 @@
|
|||||||
<ClCompile Include="..\..\..\server\TracyTimelineController.cpp" />
|
<ClCompile Include="..\..\..\server\TracyTimelineController.cpp" />
|
||||||
<ClCompile Include="..\..\..\server\TracyTimelineItem.cpp" />
|
<ClCompile Include="..\..\..\server\TracyTimelineItem.cpp" />
|
||||||
<ClCompile Include="..\..\..\server\TracyTimelineItemPlot.cpp" />
|
<ClCompile Include="..\..\..\server\TracyTimelineItemPlot.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\server\TracyTimelineItemThread.cpp" />
|
||||||
<ClCompile Include="..\..\..\server\TracyUserData.cpp" />
|
<ClCompile Include="..\..\..\server\TracyUserData.cpp" />
|
||||||
<ClCompile Include="..\..\..\server\TracyUtility.cpp" />
|
<ClCompile Include="..\..\..\server\TracyUtility.cpp" />
|
||||||
<ClCompile Include="..\..\..\server\TracyView.cpp" />
|
<ClCompile Include="..\..\..\server\TracyView.cpp" />
|
||||||
@ -277,6 +278,7 @@
|
|||||||
<ClInclude Include="..\..\..\server\TracyTimelineController.hpp" />
|
<ClInclude Include="..\..\..\server\TracyTimelineController.hpp" />
|
||||||
<ClInclude Include="..\..\..\server\TracyTimelineItem.hpp" />
|
<ClInclude Include="..\..\..\server\TracyTimelineItem.hpp" />
|
||||||
<ClInclude Include="..\..\..\server\TracyTimelineItemPlot.hpp" />
|
<ClInclude Include="..\..\..\server\TracyTimelineItemPlot.hpp" />
|
||||||
|
<ClInclude Include="..\..\..\server\TracyTimelineItemThread.hpp" />
|
||||||
<ClInclude Include="..\..\..\server\TracyUserData.hpp" />
|
<ClInclude Include="..\..\..\server\TracyUserData.hpp" />
|
||||||
<ClInclude Include="..\..\..\server\TracyUtility.hpp" />
|
<ClInclude Include="..\..\..\server\TracyUtility.hpp" />
|
||||||
<ClInclude Include="..\..\..\server\TracyVarArray.hpp" />
|
<ClInclude Include="..\..\..\server\TracyVarArray.hpp" />
|
||||||
|
@ -363,6 +363,9 @@
|
|||||||
<ClCompile Include="..\..\..\server\TracyTimelineItem.cpp">
|
<ClCompile Include="..\..\..\server\TracyTimelineItem.cpp">
|
||||||
<Filter>server</Filter>
|
<Filter>server</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\server\TracyTimelineItemThread.cpp">
|
||||||
|
<Filter>server</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\server\TracyEvent.hpp">
|
<ClInclude Include="..\..\..\server\TracyEvent.hpp">
|
||||||
@ -737,6 +740,9 @@
|
|||||||
<ClInclude Include="..\..\..\server\TracyTimelineItemPlot.hpp">
|
<ClInclude Include="..\..\..\server\TracyTimelineItemPlot.hpp">
|
||||||
<Filter>server</Filter>
|
<Filter>server</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\server\TracyTimelineItemThread.hpp">
|
||||||
|
<Filter>server</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Natvis Include="DebugVis.natvis" />
|
<Natvis Include="DebugVis.natvis" />
|
||||||
|
266
server/TracyTimelineItemThread.cpp
Normal file
266
server/TracyTimelineItemThread.cpp
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include "TracyImGui.hpp"
|
||||||
|
#include "TracyMouse.hpp"
|
||||||
|
#include "TracyPrint.hpp"
|
||||||
|
#include "TracyTimelineItemThread.hpp"
|
||||||
|
#include "TracyView.hpp"
|
||||||
|
#include "TracyWorker.hpp"
|
||||||
|
|
||||||
|
namespace tracy
|
||||||
|
{
|
||||||
|
|
||||||
|
TimelineItemThread::TimelineItemThread( View& view, Worker& worker, const ThreadData* thread )
|
||||||
|
: TimelineItem( view, worker )
|
||||||
|
, m_thread( thread )
|
||||||
|
, m_ghost( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimelineItemThread::IsEmpty() const
|
||||||
|
{
|
||||||
|
auto& crash = m_worker.GetCrashEvent();
|
||||||
|
return crash.thread != m_thread->id &&
|
||||||
|
m_thread->timeline.empty() &&
|
||||||
|
m_thread->messages.empty() &&
|
||||||
|
m_thread->ghostZones.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TimelineItemThread::HeaderColor() const
|
||||||
|
{
|
||||||
|
auto& crash = m_worker.GetCrashEvent();
|
||||||
|
if( crash.thread == m_thread->id ) return 0xFF2222FF;
|
||||||
|
if( m_thread->isFiber ) return 0xFF88FF88;
|
||||||
|
return 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TimelineItemThread::HeaderColorInactive() const
|
||||||
|
{
|
||||||
|
auto& crash = m_worker.GetCrashEvent();
|
||||||
|
if( crash.thread == m_thread->id ) return 0xFF111188;
|
||||||
|
if( m_thread->isFiber ) return 0xFF448844;
|
||||||
|
return 0xFF888888;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t TimelineItemThread::HeaderLineColor() const
|
||||||
|
{
|
||||||
|
return 0x33FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* TimelineItemThread::HeaderLabel() const
|
||||||
|
{
|
||||||
|
return m_worker.GetThreadName( m_thread->id );
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t TimelineItemThread::RangeBegin() const
|
||||||
|
{
|
||||||
|
int64_t first = std::numeric_limits<int64_t>::max();
|
||||||
|
const auto ctx = m_worker.GetContextSwitchData( m_thread->id );
|
||||||
|
if( ctx && !ctx->v.empty() )
|
||||||
|
{
|
||||||
|
first = ctx->v.begin()->Start();
|
||||||
|
}
|
||||||
|
if( !m_thread->timeline.empty() )
|
||||||
|
{
|
||||||
|
if( m_thread->timeline.is_magic() )
|
||||||
|
{
|
||||||
|
auto& tl = *((Vector<ZoneEvent>*)&m_thread->timeline);
|
||||||
|
first = std::min( first, tl.front().Start() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
first = std::min( first, m_thread->timeline.front()->Start() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !m_thread->messages.empty() )
|
||||||
|
{
|
||||||
|
first = std::min( first, m_thread->messages.front()->time );
|
||||||
|
}
|
||||||
|
for( const auto& lock : m_worker.GetLockMap() )
|
||||||
|
{
|
||||||
|
const auto& lockmap = *lock.second;
|
||||||
|
if( !lockmap.valid ) continue;
|
||||||
|
auto it = lockmap.threadMap.find( m_thread->id );
|
||||||
|
if( it == lockmap.threadMap.end() ) continue;
|
||||||
|
const auto thread = it->second;
|
||||||
|
auto lptr = lockmap.timeline.data();
|
||||||
|
while( lptr->ptr->thread != thread ) lptr++;
|
||||||
|
if( lptr->ptr->Time() < first ) first = lptr->ptr->Time();
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t TimelineItemThread::RangeEnd() const
|
||||||
|
{
|
||||||
|
int64_t last = -1;
|
||||||
|
const auto ctx = m_worker.GetContextSwitchData( m_thread->id );
|
||||||
|
if( ctx && !ctx->v.empty() )
|
||||||
|
{
|
||||||
|
const auto& back = ctx->v.back();
|
||||||
|
last = back.IsEndValid() ? back.End() : back.Start();
|
||||||
|
}
|
||||||
|
if( !m_thread->timeline.empty() )
|
||||||
|
{
|
||||||
|
if( m_thread->timeline.is_magic() )
|
||||||
|
{
|
||||||
|
auto& tl = *((Vector<ZoneEvent>*)&m_thread->timeline);
|
||||||
|
last = std::max( last, m_worker.GetZoneEnd( tl.back() ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last = std::max( last, m_worker.GetZoneEnd( *m_thread->timeline.back() ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( !m_thread->messages.empty() )
|
||||||
|
{
|
||||||
|
last = std::max( last, m_thread->messages.back()->time );
|
||||||
|
}
|
||||||
|
for( const auto& lock : m_worker.GetLockMap() )
|
||||||
|
{
|
||||||
|
const auto& lockmap = *lock.second;
|
||||||
|
if( !lockmap.valid ) continue;
|
||||||
|
auto it = lockmap.threadMap.find( m_thread->id );
|
||||||
|
if( it == lockmap.threadMap.end() ) continue;
|
||||||
|
const auto thread = it->second;
|
||||||
|
auto eptr = lockmap.timeline.data() + lockmap.timeline.size() - 1;
|
||||||
|
while( eptr->ptr->thread != thread ) eptr--;
|
||||||
|
if( eptr->ptr->Time() > last ) last = eptr->ptr->Time();
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimelineItemThread::HeaderTooltip( const char* label ) const
|
||||||
|
{
|
||||||
|
m_view.HighlightThread( m_thread->id );
|
||||||
|
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
SmallColorBox( GetThreadColor( m_thread->id, 0, m_view.GetViewData().dynamicColors ) );
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted( m_worker.GetThreadName( m_thread->id ) );
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextDisabled( "(%s)", RealToString( m_thread->id ) );
|
||||||
|
auto& crash = m_worker.GetCrashEvent();
|
||||||
|
if( crash.thread == m_thread->id )
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
TextColoredUnformatted( ImVec4( 1.f, 0.2f, 0.2f, 1.f ), ICON_FA_SKULL " Crashed" );
|
||||||
|
}
|
||||||
|
if( m_thread->isFiber )
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
TextColoredUnformatted( ImVec4( 0.2f, 0.6f, 0.2f, 1.f ), "Fiber" );
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ctx = m_worker.GetContextSwitchData( m_thread->id );
|
||||||
|
const auto first = RangeBegin();
|
||||||
|
const auto last = RangeEnd();
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
size_t lockCnt = 0;
|
||||||
|
for( const auto& lock : m_worker.GetLockMap() )
|
||||||
|
{
|
||||||
|
const auto& lockmap = *lock.second;
|
||||||
|
if( !lockmap.valid ) continue;
|
||||||
|
auto it = lockmap.threadMap.find( m_thread->id );
|
||||||
|
if( it == lockmap.threadMap.end() ) continue;
|
||||||
|
lockCnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( last >= 0 )
|
||||||
|
{
|
||||||
|
const auto lifetime = last - first;
|
||||||
|
const auto traceLen = m_worker.GetLastTime();
|
||||||
|
|
||||||
|
TextFocused( "Appeared at", TimeToString( first ) );
|
||||||
|
TextFocused( "Last event at", TimeToString( last ) );
|
||||||
|
TextFocused( "Lifetime:", TimeToString( lifetime ) );
|
||||||
|
ImGui::SameLine();
|
||||||
|
char buf[64];
|
||||||
|
PrintStringPercent( buf, lifetime / double( traceLen ) * 100 );
|
||||||
|
TextDisabledUnformatted( buf );
|
||||||
|
|
||||||
|
if( ctx )
|
||||||
|
{
|
||||||
|
TextFocused( "Time in running state:", TimeToString( ctx->runningTime ) );
|
||||||
|
ImGui::SameLine();
|
||||||
|
PrintStringPercent( buf, ctx->runningTime / double( lifetime ) * 100 );
|
||||||
|
TextDisabledUnformatted( buf );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Separator();
|
||||||
|
if( !m_thread->timeline.empty() )
|
||||||
|
{
|
||||||
|
TextFocused( "Zone count:", RealToString( m_thread->count ) );
|
||||||
|
TextFocused( "Top-level zones:", RealToString( m_thread->timeline.size() ) );
|
||||||
|
}
|
||||||
|
if( !m_thread->messages.empty() )
|
||||||
|
{
|
||||||
|
TextFocused( "Messages:", RealToString( m_thread->messages.size() ) );
|
||||||
|
}
|
||||||
|
if( lockCnt != 0 )
|
||||||
|
{
|
||||||
|
TextFocused( "Locks:", RealToString( lockCnt ) );
|
||||||
|
}
|
||||||
|
if( ctx )
|
||||||
|
{
|
||||||
|
TextFocused( "Running state regions:", RealToString( ctx->v.size() ) );
|
||||||
|
}
|
||||||
|
if( !m_thread->samples.empty() )
|
||||||
|
{
|
||||||
|
TextFocused( "Call stack samples:", RealToString( m_thread->samples.size() ) );
|
||||||
|
if( m_thread->kernelSampleCnt != 0 )
|
||||||
|
{
|
||||||
|
TextFocused( "Kernel samples:", RealToString( m_thread->kernelSampleCnt ) );
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextDisabled( "(%.2f%%)", 100.f * m_thread->kernelSampleCnt / m_thread->samples.size() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimelineItemThread::HeaderExtraContents( int offset, const ImVec2& wpos, float labelWidth, double pxns, bool hover )
|
||||||
|
{
|
||||||
|
m_view.DrawThreadMessages( *m_thread, pxns, offset, wpos, hover );
|
||||||
|
|
||||||
|
#ifndef TRACY_NO_STATISTICS
|
||||||
|
const bool hasGhostZones = m_worker.AreGhostZonesReady() && !m_thread->ghostZones.empty();
|
||||||
|
if( hasGhostZones && !m_thread->timeline.empty() )
|
||||||
|
{
|
||||||
|
auto draw = ImGui::GetWindowDrawList();
|
||||||
|
const auto ty = ImGui::GetTextLineHeight();
|
||||||
|
|
||||||
|
const auto color = m_ghost ? 0xFFAA9999 : 0x88AA7777;
|
||||||
|
draw->AddText( wpos + ImVec2( 1.5f * ty + labelWidth, offset ), color, ICON_FA_GHOST );
|
||||||
|
float ghostSz = ImGui::CalcTextSize( ICON_FA_GHOST ).x;
|
||||||
|
|
||||||
|
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( 1.5f * ty + labelWidth, offset ), wpos + ImVec2( 1.5f * ty + labelWidth + ghostSz, offset + ty ) ) )
|
||||||
|
{
|
||||||
|
if( IsMouseClicked( 0 ) )
|
||||||
|
{
|
||||||
|
m_ghost = !m_ghost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimelineItemThread::DrawContents( double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax )
|
||||||
|
{
|
||||||
|
const auto res = m_view.DrawThread( *m_thread, pxns, offset, wpos, hover, yMin, yMax, m_ghost );
|
||||||
|
if( !res )
|
||||||
|
{
|
||||||
|
auto& crash = m_worker.GetCrashEvent();
|
||||||
|
return crash.thread == m_thread->id;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimelineItemThread::DrawOverlay( const ImVec2& ul, const ImVec2& dr )
|
||||||
|
{
|
||||||
|
m_view.DrawThreadOverlays( *m_thread, ul, dr );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
39
server/TracyTimelineItemThread.hpp
Normal file
39
server/TracyTimelineItemThread.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef __TRACYTIMELINEITEMTHREAD_HPP__
|
||||||
|
#define __TRACYTIMELINEITEMTHREAD_HPP__
|
||||||
|
|
||||||
|
#include "TracyEvent.hpp"
|
||||||
|
#include "TracyTimelineItem.hpp"
|
||||||
|
|
||||||
|
namespace tracy
|
||||||
|
{
|
||||||
|
|
||||||
|
class TimelineItemThread final : public TimelineItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TimelineItemThread( View& view, Worker& worker, const ThreadData* plot );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t HeaderColor() const override;
|
||||||
|
uint32_t HeaderColorInactive() const override;
|
||||||
|
uint32_t HeaderLineColor() const override;
|
||||||
|
const char* HeaderLabel() const override;
|
||||||
|
|
||||||
|
int64_t RangeBegin() const override;
|
||||||
|
int64_t RangeEnd() const override;
|
||||||
|
|
||||||
|
void HeaderTooltip( const char* label ) const override;
|
||||||
|
void HeaderExtraContents( int offset, const ImVec2& wpos, float labelWidth, double pxns, bool hover ) override;
|
||||||
|
|
||||||
|
bool DrawContents( double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax ) override;
|
||||||
|
void DrawOverlay( const ImVec2& ul, const ImVec2& dr ) override;
|
||||||
|
|
||||||
|
bool IsEmpty() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ThreadData* m_thread;
|
||||||
|
bool m_ghost;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -116,6 +116,9 @@ public:
|
|||||||
void HighlightThread( uint64_t thread );
|
void HighlightThread( uint64_t thread );
|
||||||
void ZoomToRange( int64_t start, int64_t end, bool pause = true );
|
void ZoomToRange( int64_t start, int64_t end, bool pause = true );
|
||||||
bool DrawPlot( PlotData& plot, double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax );
|
bool DrawPlot( PlotData& plot, double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax );
|
||||||
|
bool DrawThread( const ThreadData& thread, double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax, bool ghostMode );
|
||||||
|
void DrawThreadMessages( const ThreadData& thread, double pxns, int offset, const ImVec2& wpos, bool hover );
|
||||||
|
void DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const ImVec2& dr );
|
||||||
|
|
||||||
bool m_showRanges = false;
|
bool m_showRanges = false;
|
||||||
Range m_statRange;
|
Range m_statRange;
|
||||||
@ -401,6 +404,7 @@ private:
|
|||||||
const ZoneEvent* m_zoneHighlight;
|
const ZoneEvent* m_zoneHighlight;
|
||||||
DecayValue<int16_t> m_zoneSrcLocHighlight = 0;
|
DecayValue<int16_t> m_zoneSrcLocHighlight = 0;
|
||||||
LockHighlight m_lockHighlight { -1 };
|
LockHighlight m_lockHighlight { -1 };
|
||||||
|
LockHighlight m_nextLockHighlight;
|
||||||
DecayValue<const MessageData*> m_msgHighlight = nullptr;
|
DecayValue<const MessageData*> m_msgHighlight = nullptr;
|
||||||
DecayValue<uint32_t> m_lockHoverHighlight = InvalidId;
|
DecayValue<uint32_t> m_lockHoverHighlight = InvalidId;
|
||||||
DecayValue<const MessageData*> m_msgToFocus = nullptr;
|
DecayValue<const MessageData*> m_msgToFocus = nullptr;
|
||||||
|
@ -586,7 +586,7 @@ void View::DrawOptions()
|
|||||||
{
|
{
|
||||||
for( const auto& t : m_threadOrder )
|
for( const auto& t : m_threadOrder )
|
||||||
{
|
{
|
||||||
m_tc.Vis( t ).visible = true;
|
m_tc.GetItem( t ).SetVisible( true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
@ -594,7 +594,7 @@ void View::DrawOptions()
|
|||||||
{
|
{
|
||||||
for( const auto& t : m_threadOrder )
|
for( const auto& t : m_threadOrder )
|
||||||
{
|
{
|
||||||
m_tc.Vis( t ).visible = false;
|
m_tc.GetItem( t ).SetVisible( false );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,7 +609,7 @@ void View::DrawOptions()
|
|||||||
const auto threadColor = GetThreadColor( t->id, 0 );
|
const auto threadColor = GetThreadColor( t->id, 0 );
|
||||||
SmallColorBox( threadColor );
|
SmallColorBox( threadColor );
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
SmallCheckbox( threadName, &m_tc.Vis( t ).visible );
|
m_tc.GetItem( t ).VisibilityCheckbox();
|
||||||
if( ImGui::BeginDragDropSource( ImGuiDragDropFlags_SourceNoHoldToOpenOthers ) )
|
if( ImGui::BeginDragDropSource( ImGuiDragDropFlags_SourceNoHoldToOpenOthers ) )
|
||||||
{
|
{
|
||||||
ImGui::SetDragDropPayload( "ThreadOrder", &idx, sizeof(int) );
|
ImGui::SetDragDropPayload( "ThreadOrder", &idx, sizeof(int) );
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "TracyPrint.hpp"
|
#include "TracyPrint.hpp"
|
||||||
#include "TracySourceView.hpp"
|
#include "TracySourceView.hpp"
|
||||||
#include "TracyTimelineItemPlot.hpp"
|
#include "TracyTimelineItemPlot.hpp"
|
||||||
|
#include "TracyTimelineItemThread.hpp"
|
||||||
#include "TracyView.hpp"
|
#include "TracyView.hpp"
|
||||||
|
|
||||||
namespace tracy
|
namespace tracy
|
||||||
@ -244,6 +245,7 @@ void View::DrawTimeline()
|
|||||||
m_waitStackRange.StartFrame();
|
m_waitStackRange.StartFrame();
|
||||||
m_memInfo.range.StartFrame();
|
m_memInfo.range.StartFrame();
|
||||||
m_yDelta = 0;
|
m_yDelta = 0;
|
||||||
|
m_nextLockHighlight = { -1 };
|
||||||
|
|
||||||
if( m_vd.zvStart == m_vd.zvEnd ) return;
|
if( m_vd.zvStart == m_vd.zvEnd ) return;
|
||||||
assert( m_vd.zvStart < m_vd.zvEnd );
|
assert( m_vd.zvStart < m_vd.zvEnd );
|
||||||
@ -629,7 +631,8 @@ void View::DrawTimeline()
|
|||||||
{
|
{
|
||||||
offset = DrawCpuData( offset, pxns, wpos, hover, yMin, yMax );
|
offset = DrawCpuData( offset, pxns, wpos, hover, yMin, yMax );
|
||||||
}
|
}
|
||||||
|
if( m_vd.drawZones )
|
||||||
|
{
|
||||||
const auto& threadData = m_worker.GetThreadData();
|
const auto& threadData = m_worker.GetThreadData();
|
||||||
if( threadData.size() != m_threadOrder.size() )
|
if( threadData.size() != m_threadOrder.size() )
|
||||||
{
|
{
|
||||||
@ -639,403 +642,11 @@ void View::DrawTimeline()
|
|||||||
m_threadOrder.push_back( threadData[i] );
|
m_threadOrder.push_back( threadData[i] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& crash = m_worker.GetCrashEvent();
|
|
||||||
LockHighlight nextLockHighlight { -1 };
|
|
||||||
for( const auto& v : m_threadOrder )
|
for( const auto& v : m_threadOrder )
|
||||||
{
|
{
|
||||||
auto& vis = m_tc.Vis( v );
|
m_tc.AddItem<TimelineItemThread>( v );
|
||||||
if( !vis.visible )
|
|
||||||
{
|
|
||||||
vis.height = 0;
|
|
||||||
vis.offset = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bool showFull = vis.showFull;
|
|
||||||
ImGui::PushID( &vis );
|
|
||||||
|
|
||||||
const auto yPos = m_tc.AdjustThreadPosition( vis, wpos.y, offset );
|
|
||||||
const auto oldOffset = offset;
|
|
||||||
ImGui::PushClipRect( wpos, wpos + ImVec2( w, offset + vis.height ), true );
|
|
||||||
|
|
||||||
int depth = 0;
|
|
||||||
offset += ostep;
|
|
||||||
if( showFull )
|
|
||||||
{
|
|
||||||
const auto sampleOffset = offset;
|
|
||||||
const auto hasSamples = m_vd.drawSamples && !v->samples.empty();
|
|
||||||
const auto hasCtxSwitch = m_vd.drawContextSwitches && m_worker.GetContextSwitchData( v->id );
|
|
||||||
|
|
||||||
if( hasSamples )
|
|
||||||
{
|
|
||||||
if( hasCtxSwitch )
|
|
||||||
{
|
|
||||||
offset += round( ostep * 0.5f );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
offset += round( ostep * 0.75f );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ctxOffset = offset;
|
|
||||||
if( hasCtxSwitch ) offset += round( ostep * 0.75f );
|
|
||||||
|
|
||||||
if( m_vd.drawZones )
|
|
||||||
{
|
|
||||||
#ifndef TRACY_NO_STATISTICS
|
|
||||||
if( m_worker.AreGhostZonesReady() && ( vis.ghost || ( m_vd.ghostZones && v->timeline.empty() ) ) )
|
|
||||||
{
|
|
||||||
depth = DispatchGhostLevel( v->ghostZones, hover, pxns, int64_t( nspx ), wpos, offset, 0, yMin, yMax, v->id );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
depth = DispatchZoneLevel( v->timeline, hover, pxns, int64_t( nspx ), wpos, offset, 0, yMin, yMax, v->id );
|
|
||||||
}
|
|
||||||
offset += ostep * depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( hasCtxSwitch )
|
|
||||||
{
|
|
||||||
auto ctxSwitch = m_worker.GetContextSwitchData( v->id );
|
|
||||||
if( ctxSwitch )
|
|
||||||
{
|
|
||||||
DrawContextSwitches( ctxSwitch, v->samples, hover, pxns, int64_t( nspx ), wpos, ctxOffset, offset, v->isFiber );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( hasSamples )
|
|
||||||
{
|
|
||||||
DrawSamples( v->samples, hover, pxns, int64_t( nspx ), wpos, sampleOffset );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( m_vd.drawLocks )
|
|
||||||
{
|
|
||||||
const auto lockDepth = DrawLocks( v->id, hover, pxns, wpos, offset, nextLockHighlight, yMin, yMax );
|
|
||||||
offset += sstep * lockDepth;
|
|
||||||
depth += lockDepth;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
offset += ostep * 0.2f;
|
|
||||||
|
|
||||||
auto msgit = std::lower_bound( v->messages.begin(), v->messages.end(), m_vd.zvStart, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } );
|
|
||||||
auto msgend = std::lower_bound( msgit, v->messages.end(), m_vd.zvEnd+1, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } );
|
|
||||||
|
|
||||||
if( !m_vd.drawEmptyLabels && showFull && depth == 0 && msgit == msgend && crash.thread != v->id )
|
|
||||||
{
|
|
||||||
auto& vis = m_tc.Vis( v );
|
|
||||||
vis.height = 0;
|
|
||||||
vis.offset = 0;
|
|
||||||
offset = oldOffset;
|
|
||||||
}
|
|
||||||
else if( yPos + ostep >= yMin && yPos <= yMax )
|
|
||||||
{
|
|
||||||
DrawLine( draw, dpos + ImVec2( 0, oldOffset + ostep - 1 ), dpos + ImVec2( w, oldOffset + ostep - 1 ), 0x33FFFFFF );
|
|
||||||
|
|
||||||
uint32_t labelColor;
|
|
||||||
if( crash.thread == v->id ) labelColor = showFull ? 0xFF2222FF : 0xFF111188;
|
|
||||||
else if( v->isFiber ) labelColor = showFull ? 0xFF88FF88 : 0xFF448844;
|
|
||||||
else labelColor = showFull ? 0xFFFFFFFF : 0xFF888888;
|
|
||||||
|
|
||||||
if( showFull )
|
|
||||||
{
|
|
||||||
draw->AddTriangleFilled( wpos + ImVec2( to/2, oldOffset + to/2 ), wpos + ImVec2( ty - to/2, oldOffset + to/2 ), wpos + ImVec2( ty * 0.5, oldOffset + to/2 + th ), labelColor );
|
|
||||||
|
|
||||||
while( msgit < msgend )
|
|
||||||
{
|
|
||||||
const auto next = std::upper_bound( msgit, v->messages.end(), (*msgit)->time + MinVisSize * nspx, [] ( const auto& lhs, const auto& rhs ) { return lhs < rhs->time; } );
|
|
||||||
const auto dist = std::distance( msgit, next );
|
|
||||||
|
|
||||||
const auto px = ( (*msgit)->time - m_vd.zvStart ) * pxns;
|
|
||||||
const bool isMsgHovered = hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px - (ty - to) * 0.5 - 1, oldOffset ), wpos + ImVec2( px + (ty - to) * 0.5 + 1, oldOffset + ty ) );
|
|
||||||
|
|
||||||
unsigned int color = 0xFFDDDDDD;
|
|
||||||
float animOff = 0;
|
|
||||||
if( dist > 1 )
|
|
||||||
{
|
|
||||||
if( m_msgHighlight && m_worker.DecompressThread( m_msgHighlight->thread ) == v->id )
|
|
||||||
{
|
|
||||||
const auto hTime = m_msgHighlight->time;
|
|
||||||
if( (*msgit)->time <= hTime && ( next == v->messages.end() || (*next)->time > hTime ) )
|
|
||||||
{
|
|
||||||
color = 0xFF4444FF;
|
|
||||||
if( !isMsgHovered )
|
|
||||||
{
|
|
||||||
animOff = -fabs( sin( s_time * 8 ) ) * th;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
draw->AddTriangleFilled( wpos + ImVec2( px - (ty - to) * 0.5, animOff + oldOffset + to ), wpos + ImVec2( px + (ty - to) * 0.5, animOff + oldOffset + to ), wpos + ImVec2( px, animOff + oldOffset + to + th ), color );
|
|
||||||
draw->AddTriangle( wpos + ImVec2( px - (ty - to) * 0.5, animOff + oldOffset + to ), wpos + ImVec2( px + (ty - to) * 0.5, animOff + oldOffset + to ), wpos + ImVec2( px, animOff + oldOffset + to + th ), color, 2.0f );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( m_msgHighlight == *msgit )
|
|
||||||
{
|
|
||||||
color = 0xFF4444FF;
|
|
||||||
if( !isMsgHovered )
|
|
||||||
{
|
|
||||||
animOff = -fabs( sin( s_time * 8 ) ) * th;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
draw->AddTriangle( wpos + ImVec2( px - (ty - to) * 0.5, animOff + oldOffset + to ), wpos + ImVec2( px + (ty - to) * 0.5, animOff + oldOffset + to ), wpos + ImVec2( px, animOff + oldOffset + to + th ), color, 2.0f );
|
|
||||||
}
|
|
||||||
if( isMsgHovered )
|
|
||||||
{
|
|
||||||
ImGui::BeginTooltip();
|
|
||||||
if( dist > 1 )
|
|
||||||
{
|
|
||||||
ImGui::Text( "%i messages", (int)dist );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TextFocused( "Message at", TimeToStringExact( (*msgit)->time ) );
|
|
||||||
ImGui::PushStyleColor( ImGuiCol_Text, (*msgit)->color );
|
|
||||||
ImGui::TextUnformatted( m_worker.GetString( (*msgit)->ref ) );
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
}
|
|
||||||
ImGui::EndTooltip();
|
|
||||||
m_msgHighlight = *msgit;
|
|
||||||
|
|
||||||
if( IsMouseClicked( 0 ) )
|
|
||||||
{
|
|
||||||
m_showMessages = true;
|
|
||||||
m_msgToFocus = *msgit;
|
|
||||||
}
|
|
||||||
if( IsMouseClicked( 2 ) )
|
|
||||||
{
|
|
||||||
CenterAtTime( (*msgit)->time );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
msgit = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( crash.thread == v->id && crash.time >= m_vd.zvStart && crash.time <= m_vd.zvEnd )
|
|
||||||
{
|
|
||||||
const auto px = ( crash.time - m_vd.zvStart ) * pxns;
|
|
||||||
|
|
||||||
draw->AddTriangleFilled( wpos + ImVec2( px - (ty - to) * 0.25f, oldOffset + to + th * 0.5f ), wpos + ImVec2( px + (ty - to) * 0.25f, oldOffset + to + th * 0.5f ), wpos + ImVec2( px, oldOffset + to + th ), 0xFF2222FF );
|
|
||||||
draw->AddTriangle( wpos + ImVec2( px - (ty - to) * 0.25f, oldOffset + to + th * 0.5f ), wpos + ImVec2( px + (ty - to) * 0.25f, oldOffset + to + th * 0.5f ), wpos + ImVec2( px, oldOffset + to + th ), 0xFF2222FF, 2.0f );
|
|
||||||
|
|
||||||
const auto crashText = ICON_FA_SKULL " crash " ICON_FA_SKULL;
|
|
||||||
auto ctw = ImGui::CalcTextSize( crashText ).x;
|
|
||||||
DrawTextContrast( draw, wpos + ImVec2( px - ctw * 0.5f, oldOffset + to + th * 0.5f - ty ), 0xFF2222FF, crashText );
|
|
||||||
|
|
||||||
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px - (ty - to) * 0.5 - 1, oldOffset ), wpos + ImVec2( px + (ty - to) * 0.5 + 1, oldOffset + ty ) ) )
|
|
||||||
{
|
|
||||||
CrashTooltip();
|
|
||||||
if( IsMouseClicked( 0 ) )
|
|
||||||
{
|
|
||||||
m_showInfo = true;
|
|
||||||
}
|
|
||||||
if( IsMouseClicked( 2 ) )
|
|
||||||
{
|
|
||||||
CenterAtTime( crash.time );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
draw->AddTriangle( wpos + ImVec2( to/2, oldOffset + to/2 ), wpos + ImVec2( to/2, oldOffset + ty - to/2 ), wpos + ImVec2( to/2 + th, oldOffset + ty * 0.5 ), labelColor, 2.0f );
|
|
||||||
}
|
|
||||||
const auto txt = m_worker.GetThreadName( v->id );
|
|
||||||
const auto txtsz = ImGui::CalcTextSize( txt );
|
|
||||||
if( m_gpuThread == v->id )
|
|
||||||
{
|
|
||||||
draw->AddRectFilled( wpos + ImVec2( 0, oldOffset ), wpos + ImVec2( w, offset ), 0x228888DD );
|
|
||||||
draw->AddRect( wpos + ImVec2( 0, oldOffset ), wpos + ImVec2( w, offset ), 0x448888DD );
|
|
||||||
}
|
|
||||||
if( m_gpuInfoWindow && m_gpuInfoWindowThread == v->id )
|
|
||||||
{
|
|
||||||
draw->AddRectFilled( wpos + ImVec2( 0, oldOffset ), wpos + ImVec2( w, offset ), 0x2288DD88 );
|
|
||||||
draw->AddRect( wpos + ImVec2( 0, oldOffset ), wpos + ImVec2( w, offset ), 0x4488DD88 );
|
|
||||||
}
|
|
||||||
if( m_cpuDataThread == v->id )
|
|
||||||
{
|
|
||||||
draw->AddRectFilled( wpos + ImVec2( 0, oldOffset ), wpos + ImVec2( w, offset ), 0x2DFF8888 );
|
|
||||||
draw->AddRect( wpos + ImVec2( 0, oldOffset ), wpos + ImVec2( w, offset ), 0x4DFF8888 );
|
|
||||||
}
|
|
||||||
DrawTextContrast( draw, wpos + ImVec2( ty, oldOffset ), labelColor, txt );
|
|
||||||
|
|
||||||
#ifndef TRACY_NO_STATISTICS
|
|
||||||
const bool hasGhostZones = showFull && m_worker.AreGhostZonesReady() && !v->ghostZones.empty();
|
|
||||||
float ghostSz;
|
|
||||||
if( hasGhostZones && !v->timeline.empty() )
|
|
||||||
{
|
|
||||||
auto& vis = m_tc.Vis( v );
|
|
||||||
const auto color = vis.ghost ? 0xFFAA9999 : 0x88AA7777;
|
|
||||||
draw->AddText( wpos + ImVec2( 1.5f * ty + txtsz.x, oldOffset ), color, ICON_FA_GHOST );
|
|
||||||
ghostSz = ImGui::CalcTextSize( ICON_FA_GHOST ).x;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if( hover )
|
|
||||||
{
|
|
||||||
#ifndef TRACY_NO_STATISTICS
|
|
||||||
if( hasGhostZones && !v->timeline.empty() && ImGui::IsMouseHoveringRect( wpos + ImVec2( 1.5f * ty + txtsz.x, oldOffset ), wpos + ImVec2( 1.5f * ty + txtsz.x + ghostSz, oldOffset + ty ) ) )
|
|
||||||
{
|
|
||||||
if( IsMouseClicked( 0 ) )
|
|
||||||
{
|
|
||||||
auto& vis = m_tc.Vis( v );
|
|
||||||
vis.ghost = !vis.ghost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if( ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, oldOffset ), wpos + ImVec2( ty + txtsz.x, oldOffset + ty ) ) )
|
|
||||||
{
|
|
||||||
m_drawThreadMigrations = v->id;
|
|
||||||
m_drawThreadHighlight = v->id;
|
|
||||||
ImGui::BeginTooltip();
|
|
||||||
SmallColorBox( GetThreadColor( v->id, 0 ) );
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::TextUnformatted( m_worker.GetThreadName( v->id ) );
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::TextDisabled( "(%s)", RealToString( v->id ) );
|
|
||||||
if( crash.thread == v->id )
|
|
||||||
{
|
|
||||||
ImGui::SameLine();
|
|
||||||
TextColoredUnformatted( ImVec4( 1.f, 0.2f, 0.2f, 1.f ), ICON_FA_SKULL " Crashed" );
|
|
||||||
}
|
|
||||||
if( v->isFiber )
|
|
||||||
{
|
|
||||||
ImGui::SameLine();
|
|
||||||
TextColoredUnformatted( ImVec4( 0.2f, 0.6f, 0.2f, 1.f ), "Fiber" );
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto ctx = m_worker.GetContextSwitchData( v->id );
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
int64_t first = std::numeric_limits<int64_t>::max();
|
|
||||||
int64_t last = -1;
|
|
||||||
if( ctx && !ctx->v.empty() )
|
|
||||||
{
|
|
||||||
const auto& back = ctx->v.back();
|
|
||||||
first = ctx->v.begin()->Start();
|
|
||||||
last = back.IsEndValid() ? back.End() : back.Start();
|
|
||||||
}
|
|
||||||
if( !v->timeline.empty() )
|
|
||||||
{
|
|
||||||
if( v->timeline.is_magic() )
|
|
||||||
{
|
|
||||||
auto& tl = *((Vector<ZoneEvent>*)&v->timeline);
|
|
||||||
first = std::min( first, tl.front().Start() );
|
|
||||||
last = std::max( last, m_worker.GetZoneEnd( tl.back() ) );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
first = std::min( first, v->timeline.front()->Start() );
|
|
||||||
last = std::max( last, m_worker.GetZoneEnd( *v->timeline.back() ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( !v->messages.empty() )
|
|
||||||
{
|
|
||||||
first = std::min( first, v->messages.front()->time );
|
|
||||||
last = std::max( last, v->messages.back()->time );
|
|
||||||
}
|
|
||||||
size_t lockCnt = 0;
|
|
||||||
for( const auto& lock : m_worker.GetLockMap() )
|
|
||||||
{
|
|
||||||
const auto& lockmap = *lock.second;
|
|
||||||
if( !lockmap.valid ) continue;
|
|
||||||
auto it = lockmap.threadMap.find( v->id );
|
|
||||||
if( it == lockmap.threadMap.end() ) continue;
|
|
||||||
lockCnt++;
|
|
||||||
const auto thread = it->second;
|
|
||||||
auto lptr = lockmap.timeline.data();
|
|
||||||
auto eptr = lptr + lockmap.timeline.size() - 1;
|
|
||||||
while( lptr->ptr->thread != thread ) lptr++;
|
|
||||||
if( lptr->ptr->Time() < first ) first = lptr->ptr->Time();
|
|
||||||
while( eptr->ptr->thread != thread ) eptr--;
|
|
||||||
if( eptr->ptr->Time() > last ) last = eptr->ptr->Time();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( last >= 0 )
|
|
||||||
{
|
|
||||||
const auto lifetime = last - first;
|
|
||||||
const auto traceLen = m_worker.GetLastTime();
|
|
||||||
|
|
||||||
TextFocused( "Appeared at", TimeToString( first ) );
|
|
||||||
TextFocused( "Last event at", TimeToString( last ) );
|
|
||||||
TextFocused( "Lifetime:", TimeToString( lifetime ) );
|
|
||||||
ImGui::SameLine();
|
|
||||||
char buf[64];
|
|
||||||
PrintStringPercent( buf, lifetime / double( traceLen ) * 100 );
|
|
||||||
TextDisabledUnformatted( buf );
|
|
||||||
|
|
||||||
if( ctx )
|
|
||||||
{
|
|
||||||
TextFocused( "Time in running state:", TimeToString( ctx->runningTime ) );
|
|
||||||
ImGui::SameLine();
|
|
||||||
PrintStringPercent( buf, ctx->runningTime / double( lifetime ) * 100 );
|
|
||||||
TextDisabledUnformatted( buf );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
if( !v->timeline.empty() )
|
|
||||||
{
|
|
||||||
TextFocused( "Zone count:", RealToString( v->count ) );
|
|
||||||
TextFocused( "Top-level zones:", RealToString( v->timeline.size() ) );
|
|
||||||
}
|
|
||||||
if( !v->messages.empty() )
|
|
||||||
{
|
|
||||||
TextFocused( "Messages:", RealToString( v->messages.size() ) );
|
|
||||||
}
|
|
||||||
if( lockCnt != 0 )
|
|
||||||
{
|
|
||||||
TextFocused( "Locks:", RealToString( lockCnt ) );
|
|
||||||
}
|
|
||||||
if( ctx )
|
|
||||||
{
|
|
||||||
TextFocused( "Running state regions:", RealToString( ctx->v.size() ) );
|
|
||||||
}
|
|
||||||
if( !v->samples.empty() )
|
|
||||||
{
|
|
||||||
TextFocused( "Call stack samples:", RealToString( v->samples.size() ) );
|
|
||||||
if( v->kernelSampleCnt != 0 )
|
|
||||||
{
|
|
||||||
TextFocused( "Kernel samples:", RealToString( v->kernelSampleCnt ) );
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::TextDisabled( "(%.2f%%)", 100.f * v->kernelSampleCnt / v->samples.size() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::EndTooltip();
|
|
||||||
|
|
||||||
if( IsMouseClicked( 0 ) )
|
|
||||||
{
|
|
||||||
m_tc.Vis( v ).showFull = !showFull;
|
|
||||||
}
|
|
||||||
if( last >= 0 && IsMouseClicked( 2 ) )
|
|
||||||
{
|
|
||||||
ZoomToRange( first, last );
|
|
||||||
}
|
|
||||||
if( IsMouseClicked( 1 ) )
|
|
||||||
{
|
|
||||||
ImGui::OpenPopup( "menuPopup" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( ImGui::BeginPopup( "menuPopup" ) )
|
|
||||||
{
|
|
||||||
if( ImGui::MenuItem( ICON_FA_EYE_SLASH " Hide" ) )
|
|
||||||
{
|
|
||||||
vis.visible = false;
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_tc.AdjustThreadHeight( m_tc.Vis( v ), oldOffset, offset );
|
|
||||||
ImGui::PopClipRect();
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
|
||||||
m_lockHighlight = nextLockHighlight;
|
|
||||||
|
|
||||||
if( m_vd.drawPlots )
|
if( m_vd.drawPlots )
|
||||||
{
|
{
|
||||||
for( const auto& v : m_worker.GetPlots() )
|
for( const auto& v : m_worker.GetPlots() )
|
||||||
@ -1047,6 +658,8 @@ void View::DrawTimeline()
|
|||||||
m_tc.End( pxns, offset, wpos, hover, yMin, yMax );
|
m_tc.End( pxns, offset, wpos, hover, yMin, yMax );
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
m_lockHighlight = m_nextLockHighlight;
|
||||||
|
|
||||||
for( auto& ann : m_annotations )
|
for( auto& ann : m_annotations )
|
||||||
{
|
{
|
||||||
if( ann->range.min < m_vd.zvEnd && ann->range.max > m_vd.zvStart )
|
if( ann->range.min < m_vd.zvEnd && ann->range.max > m_vd.zvStart )
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
namespace tracy
|
namespace tracy
|
||||||
{
|
{
|
||||||
|
|
||||||
|
extern double s_time;
|
||||||
|
|
||||||
constexpr float MinVisSize = 3;
|
constexpr float MinVisSize = 3;
|
||||||
|
|
||||||
static tracy_force_inline uint32_t MixGhostColor( uint32_t c0, uint32_t c1 )
|
static tracy_force_inline uint32_t MixGhostColor( uint32_t c0, uint32_t c1 )
|
||||||
@ -19,6 +21,209 @@ static tracy_force_inline uint32_t MixGhostColor( uint32_t c0, uint32_t c1 )
|
|||||||
( ( ( ( ( c0 & 0x000000FF ) ) + 3 * ( ( c1 & 0x000000FF ) ) ) >> 2 ) );
|
( ( ( ( ( c0 & 0x000000FF ) ) + 3 * ( ( c1 & 0x000000FF ) ) ) >> 2 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool View::DrawThread( const ThreadData& thread, double pxns, int& offset, const ImVec2& wpos, bool hover, float yMin, float yMax, bool ghostMode )
|
||||||
|
{
|
||||||
|
const auto ty = ImGui::GetTextLineHeight();
|
||||||
|
const auto ostep = ty + 1;
|
||||||
|
const auto nspx = 1.0 / pxns;
|
||||||
|
|
||||||
|
ImGui::PushFont( m_smallFont );
|
||||||
|
const auto sty = ImGui::GetTextLineHeight();
|
||||||
|
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 );
|
||||||
|
|
||||||
|
if( hasSamples )
|
||||||
|
{
|
||||||
|
if( hasCtxSwitch )
|
||||||
|
{
|
||||||
|
offset += round( ostep * 0.5f );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
offset += round( ostep * 0.75f );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ctxOffset = offset;
|
||||||
|
if( hasCtxSwitch )
|
||||||
|
{
|
||||||
|
offset += round( ostep * 0.75f );
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef TRACY_NO_STATISTICS
|
||||||
|
if( m_worker.AreGhostZonesReady() && ( ghostMode || ( m_vd.ghostZones && thread.timeline.empty() ) ) )
|
||||||
|
{
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
offset += ostep * depth;
|
||||||
|
|
||||||
|
if( hasCtxSwitch )
|
||||||
|
{
|
||||||
|
auto ctxSwitch = m_worker.GetContextSwitchData( thread.id );
|
||||||
|
if( ctxSwitch )
|
||||||
|
{
|
||||||
|
DrawContextSwitches( ctxSwitch, thread.samples, hover, pxns, int64_t( nspx ), wpos, ctxOffset, offset, thread.isFiber );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( hasSamples )
|
||||||
|
{
|
||||||
|
DrawSamples( thread.samples, hover, pxns, int64_t( nspx ), wpos, sampleOffset );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_vd.drawLocks )
|
||||||
|
{
|
||||||
|
const auto lockDepth = DrawLocks( thread.id, hover, pxns, wpos, offset, m_nextLockHighlight, yMin, yMax );
|
||||||
|
offset += sstep * lockDepth;
|
||||||
|
depth += lockDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( depth == 0 )
|
||||||
|
{
|
||||||
|
auto msgit = std::lower_bound( thread.messages.begin(), thread.messages.end(), m_vd.zvStart, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } );
|
||||||
|
auto msgend = std::lower_bound( msgit, thread.messages.end(), m_vd.zvEnd+1, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } );
|
||||||
|
return msgit != msgend;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void View::DrawThreadMessages( const ThreadData& thread, double pxns, int offset, const ImVec2& wpos, bool hover )
|
||||||
|
{
|
||||||
|
const auto nspx = 1.0 / pxns;
|
||||||
|
auto draw = ImGui::GetWindowDrawList();
|
||||||
|
const auto ty = ImGui::GetTextLineHeight();
|
||||||
|
const auto to = 9.f * GetScale();
|
||||||
|
const auto th = ( ty - to ) * sqrt( 3 ) * 0.5;
|
||||||
|
|
||||||
|
auto msgit = std::lower_bound( thread.messages.begin(), thread.messages.end(), m_vd.zvStart, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } );
|
||||||
|
auto msgend = std::lower_bound( msgit, thread.messages.end(), m_vd.zvEnd+1, [] ( const auto& lhs, const auto& rhs ) { return lhs->time < rhs; } );
|
||||||
|
|
||||||
|
while( msgit < msgend )
|
||||||
|
{
|
||||||
|
const auto next = std::upper_bound( msgit, thread.messages.end(), (*msgit)->time + MinVisSize * nspx, [] ( const auto& lhs, const auto& rhs ) { return lhs < rhs->time; } );
|
||||||
|
const auto dist = std::distance( msgit, next );
|
||||||
|
|
||||||
|
const auto px = ( (*msgit)->time - m_vd.zvStart ) * pxns;
|
||||||
|
const bool isMsgHovered = hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px - (ty - to) * 0.5 - 1, offset ), wpos + ImVec2( px + (ty - to) * 0.5 + 1, offset + ty ) );
|
||||||
|
|
||||||
|
unsigned int color = 0xFFDDDDDD;
|
||||||
|
float animOff = 0;
|
||||||
|
if( dist > 1 )
|
||||||
|
{
|
||||||
|
if( m_msgHighlight && m_worker.DecompressThread( m_msgHighlight->thread ) == thread.id )
|
||||||
|
{
|
||||||
|
const auto hTime = m_msgHighlight->time;
|
||||||
|
if( (*msgit)->time <= hTime && ( next == thread.messages.end() || (*next)->time > hTime ) )
|
||||||
|
{
|
||||||
|
color = 0xFF4444FF;
|
||||||
|
if( !isMsgHovered )
|
||||||
|
{
|
||||||
|
animOff = -fabs( sin( s_time * 8 ) ) * th;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw->AddTriangleFilled( wpos + ImVec2( px - (ty - to) * 0.5, animOff + offset + to ), wpos + ImVec2( px + (ty - to) * 0.5, animOff + offset + to ), wpos + ImVec2( px, animOff + offset + to + th ), color );
|
||||||
|
draw->AddTriangle( wpos + ImVec2( px - (ty - to) * 0.5, animOff + offset + to ), wpos + ImVec2( px + (ty - to) * 0.5, animOff + offset + to ), wpos + ImVec2( px, animOff + offset + to + th ), color, 2.0f );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( m_msgHighlight == *msgit )
|
||||||
|
{
|
||||||
|
color = 0xFF4444FF;
|
||||||
|
if( !isMsgHovered )
|
||||||
|
{
|
||||||
|
animOff = -fabs( sin( s_time * 8 ) ) * th;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw->AddTriangle( wpos + ImVec2( px - (ty - to) * 0.5, animOff + offset + to ), wpos + ImVec2( px + (ty - to) * 0.5, animOff + offset + to ), wpos + ImVec2( px, animOff + offset + to + th ), color, 2.0f );
|
||||||
|
}
|
||||||
|
if( isMsgHovered )
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
if( dist > 1 )
|
||||||
|
{
|
||||||
|
ImGui::Text( "%i messages", (int)dist );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TextFocused( "Message at", TimeToStringExact( (*msgit)->time ) );
|
||||||
|
ImGui::PushStyleColor( ImGuiCol_Text, (*msgit)->color );
|
||||||
|
ImGui::TextUnformatted( m_worker.GetString( (*msgit)->ref ) );
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
}
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
m_msgHighlight = *msgit;
|
||||||
|
|
||||||
|
if( IsMouseClicked( 0 ) )
|
||||||
|
{
|
||||||
|
m_showMessages = true;
|
||||||
|
m_msgToFocus = *msgit;
|
||||||
|
}
|
||||||
|
if( IsMouseClicked( 2 ) )
|
||||||
|
{
|
||||||
|
CenterAtTime( (*msgit)->time );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
msgit = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& crash = m_worker.GetCrashEvent();
|
||||||
|
if( crash.thread == thread.id && crash.time >= m_vd.zvStart && crash.time <= m_vd.zvEnd )
|
||||||
|
{
|
||||||
|
const auto px = ( crash.time - m_vd.zvStart ) * pxns;
|
||||||
|
|
||||||
|
draw->AddTriangleFilled( wpos + ImVec2( px - (ty - to) * 0.25f, offset + to + th * 0.5f ), wpos + ImVec2( px + (ty - to) * 0.25f, offset + to + th * 0.5f ), wpos + ImVec2( px, offset + to + th ), 0xFF2222FF );
|
||||||
|
draw->AddTriangle( wpos + ImVec2( px - (ty - to) * 0.25f, offset + to + th * 0.5f ), wpos + ImVec2( px + (ty - to) * 0.25f, offset + to + th * 0.5f ), wpos + ImVec2( px, offset + to + th ), 0xFF2222FF, 2.0f );
|
||||||
|
|
||||||
|
const auto crashText = ICON_FA_SKULL " crash " ICON_FA_SKULL;
|
||||||
|
auto ctw = ImGui::CalcTextSize( crashText ).x;
|
||||||
|
DrawTextContrast( draw, wpos + ImVec2( px - ctw * 0.5f, offset + to + th * 0.5f - ty ), 0xFF2222FF, crashText );
|
||||||
|
|
||||||
|
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px - (ty - to) * 0.5 - 1, offset ), wpos + ImVec2( px + (ty - to) * 0.5 + 1, offset + ty ) ) )
|
||||||
|
{
|
||||||
|
CrashTooltip();
|
||||||
|
if( IsMouseClicked( 0 ) )
|
||||||
|
{
|
||||||
|
m_showInfo = true;
|
||||||
|
}
|
||||||
|
if( IsMouseClicked( 2 ) )
|
||||||
|
{
|
||||||
|
CenterAtTime( crash.time );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void View::DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const ImVec2& dr )
|
||||||
|
{
|
||||||
|
auto draw = ImGui::GetWindowDrawList();
|
||||||
|
|
||||||
|
if( m_gpuThread == thread.id )
|
||||||
|
{
|
||||||
|
draw->AddRectFilled( ul, dr, 0x228888DD );
|
||||||
|
draw->AddRect( ul, dr, 0x448888DD );
|
||||||
|
}
|
||||||
|
if( m_gpuInfoWindow && m_gpuInfoWindowThread == thread.id )
|
||||||
|
{
|
||||||
|
draw->AddRectFilled( ul, dr, 0x2288DD88 );
|
||||||
|
draw->AddRect( ul, dr, 0x4488DD88 );
|
||||||
|
}
|
||||||
|
if( m_cpuDataThread == thread.id )
|
||||||
|
{
|
||||||
|
draw->AddRectFilled( ul, dr, 0x2DFF8888 );
|
||||||
|
draw->AddRect( ul, dr, 0x4DFF8888 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef TRACY_NO_STATISTICS
|
#ifndef TRACY_NO_STATISTICS
|
||||||
int View::DispatchGhostLevel( const Vector<GhostZone>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, float yMin, float yMax, uint64_t tid )
|
int View::DispatchGhostLevel( const Vector<GhostZone>& vec, bool hover, double pxns, int64_t nspx, const ImVec2& wpos, int _offset, int depth, float yMin, float yMax, uint64_t tid )
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user