diff options
author | Bartosz Taudul <wolf@nereid.pl> | 2022-09-04 00:28:54 +0300 |
---|---|---|
committer | Bartosz Taudul <wolf@nereid.pl> | 2022-09-04 00:28:54 +0300 |
commit | ec3dcaeef38f0ec909e93626d4ff6dea0213be58 (patch) | |
tree | 29b1a6aa394b53bc93110e7c7b1d236c9ec2818f /server/TracyTimelineItemThread.cpp | |
parent | e3007062fcfe81ac3c121bcea7bc6ed87e5eb299 (diff) |
Migrate drawing CPU threads to the new timeline item system.
Diffstat (limited to 'server/TracyTimelineItemThread.cpp')
-rw-r--r-- | server/TracyTimelineItemThread.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/server/TracyTimelineItemThread.cpp b/server/TracyTimelineItemThread.cpp new file mode 100644 index 00000000..7b515107 --- /dev/null +++ b/server/TracyTimelineItemThread.cpp @@ -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 ); +} + +} |