diff --git a/server/TracyTimelineDraw.hpp b/server/TracyTimelineDraw.hpp index 24fd90e0..688c67b6 100644 --- a/server/TracyTimelineDraw.hpp +++ b/server/TracyTimelineDraw.hpp @@ -56,6 +56,13 @@ struct MessagesDraw uint32_t num; }; + +struct CpuUsageDraw +{ + int own; + int other; +}; + } #endif diff --git a/server/TracyTimelineItemCpuData.cpp b/server/TracyTimelineItemCpuData.cpp index 7ce37f2b..62cdc4cf 100644 --- a/server/TracyTimelineItemCpuData.cpp +++ b/server/TracyTimelineItemCpuData.cpp @@ -10,7 +10,7 @@ namespace tracy { TimelineItemCpuData::TimelineItemCpuData( View& view, Worker& worker, void* key ) - : TimelineItem( view, worker, key, false ) + : TimelineItem( view, worker, key, true ) { } @@ -41,7 +41,118 @@ int64_t TimelineItemCpuData::RangeEnd() const bool TimelineItemCpuData::DrawContents( const TimelineContext& ctx, int& offset ) { - return m_view.DrawCpuData( ctx, offset ); + m_view.DrawCpuData( ctx, m_cpuDraw, offset ); + return true; +} + +void TimelineItemCpuData::DrawFinished() +{ + m_cpuDraw.clear(); +} + +void TimelineItemCpuData::Preprocess( const TimelineContext& ctx, TaskDispatch& td, bool visible ) +{ + assert( m_cpuDraw.empty() ); + + if( !visible ) return; + +#ifdef TRACY_NO_STATISTICS + if( m_view.GetViewData().drawCpuUsageGraph ) +#else + if( m_view.GetViewData().drawCpuUsageGraph && m_worker.IsCpuUsageReady() ) +#endif + { + td.Queue( [this, &ctx] { + PreprocessCpuUsage( ctx ); + } ); + } +} + +void TimelineItemCpuData::PreprocessCpuUsage( const TimelineContext& ctx ) +{ + const auto vStart = ctx.vStart; + const auto nspx = ctx.nspx; + const auto w = ctx.w; + const auto num = size_t( w ); + + if( vStart > m_worker.GetLastTime() || int64_t( vStart + nspx * num ) < 0 ) return; + + const auto lastTime = m_worker.GetLastTime(); + +#ifndef TRACY_NO_STATISTICS + auto& ctxUsage = m_worker.GetCpuUsage(); + if( !ctxUsage.empty() ) + { + auto itBegin = ctxUsage.begin(); + for( size_t i=0; i lastTime ) return; + if( time < 0 ) + { + m_cpuDraw.emplace_back( CpuUsageDraw { 0, 0 } ); + } + else + { + const auto test = ( time << 16 ) | 0xFFFF; + auto it = std::upper_bound( itBegin, ctxUsage.end(), test, [] ( const auto& l, const auto& r ) { return l < r._time_other_own; } ); + if( it == ctxUsage.end() ) return; + if( it == ctxUsage.begin() ) + { + m_cpuDraw.emplace_back( CpuUsageDraw { 0, 0 } ); + } + else + { + --it; + m_cpuDraw.emplace_back( CpuUsageDraw { it->Own(), it->Other() } ); + } + itBegin = it; + } + } + } + else +#endif + { + m_cpuDraw.resize( num ); + memset( m_cpuDraw.data(), 0, sizeof( CpuUsageDraw ) * num ); + + const auto pid = m_worker.GetPid(); + const auto cpuDataCount = m_worker.GetCpuDataCpuCount(); + const auto cpuData = m_worker.GetCpuData(); + + for( int i=0; i lastTime ) break; + if( time >= 0 ) + { + auto it = std::lower_bound( itBegin, cs.end(), time, [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } ); + if( it == cs.end() ) break; + if( it->IsEndValid() && it->Start() <= time ) + { + if( m_worker.GetPidFromTid( m_worker.DecompressThreadExternal( it->Thread() ) ) == pid ) + { + ptr->own++; + } + else + { + ptr->other++; + } + } + itBegin = it; + } + ptr++; + } + } + } + } } } diff --git a/server/TracyTimelineItemCpuData.hpp b/server/TracyTimelineItemCpuData.hpp index 85e42606..6110a236 100644 --- a/server/TracyTimelineItemCpuData.hpp +++ b/server/TracyTimelineItemCpuData.hpp @@ -3,6 +3,7 @@ #include "TracyEvent.hpp" #include "TracyTimelineItem.hpp" +#include "TracyTimelineDraw.hpp" namespace tracy { @@ -25,8 +26,16 @@ protected: int64_t RangeEnd() const override; bool DrawContents( const TimelineContext& ctx, int& offset ) override; + void DrawFinished() override; bool IsEmpty() const override; + + void Preprocess( const TimelineContext& ctx, TaskDispatch& td, bool visible ) override; + +private: + void PreprocessCpuUsage( const TimelineContext& ctx ); + + std::vector m_cpuDraw; }; } diff --git a/server/TracyView.hpp b/server/TracyView.hpp index dd0e9480..3895354c 100644 --- a/server/TracyView.hpp +++ b/server/TracyView.hpp @@ -45,6 +45,7 @@ struct TimelineDraw; struct ContextSwitchDraw; struct SamplesDraw; struct MessagesDraw; +struct CpuUsageDraw; class View { @@ -131,7 +132,7 @@ public: void DrawThreadMessagesList( const TimelineContext& ctx, const std::vector& drawList, int offset, uint64_t tid ); void DrawThreadOverlays( const ThreadData& thread, const ImVec2& ul, const ImVec2& dr ); bool DrawGpu( const TimelineContext& ctx, const GpuCtxData& gpu, int& offset ); - bool DrawCpuData( const TimelineContext& ctx, int& offset ); + bool DrawCpuData( const TimelineContext& ctx, const std::vector&, int& offset ); bool m_showRanges = false; Range m_statRange; @@ -841,8 +842,6 @@ private: int64_t time; } m_sendQueueWarning; - std::vector> m_cpuUsageBuf; - bool m_attnProtoMismatch = false; bool m_attnNotAvailable = false; bool m_attnDropped = false; diff --git a/server/TracyView_CpuData.cpp b/server/TracyView_CpuData.cpp index f1709f51..569b4105 100644 --- a/server/TracyView_CpuData.cpp +++ b/server/TracyView_CpuData.cpp @@ -4,6 +4,7 @@ #include "TracyImGui.hpp" #include "TracyMouse.hpp" #include "TracyPrint.hpp" +#include "TracyTimelineDraw.hpp" #include "TracyTimelineItem.hpp" #include "TracyTimelineContext.hpp" #include "TracyView.hpp" @@ -13,7 +14,7 @@ namespace tracy constexpr float MinVisSize = 3; -bool View::DrawCpuData( const TimelineContext& ctx, int& offset ) +bool View::DrawCpuData( const TimelineContext& ctx, const std::vector& cpuDraw, int& offset ) { auto cpuData = m_worker.GetCpuData(); const auto cpuCnt = m_worker.GetCpuDataCpuCount(); @@ -32,106 +33,106 @@ bool View::DrawCpuData( const TimelineContext& ctx, int& offset ) auto draw = ImGui::GetWindowDrawList(); -#ifdef TRACY_NO_STATISTICS - if( m_vd.drawCpuUsageGraph ) -#else - if( m_vd.drawCpuUsageGraph && m_worker.IsCpuUsageReady() ) -#endif + if( m_vd.drawCpuUsageGraph && !cpuDraw.empty() ) { const auto cpuUsageHeight = floor( 30.f * GetScale() ); if( wpos.y + offset + cpuUsageHeight + 3 >= yMin && wpos.y + offset <= yMax ) { - const auto iw = (size_t)w; - m_worker.GetCpuUsage( m_vd.zvStart, nspxdbl, iw, m_cpuUsageBuf ); - const float cpuCntRev = 1.f / cpuCnt; - float pos = 0; - auto usage = m_cpuUsageBuf.begin(); - while( pos < w ) + int pos = 0; + for( auto& v : cpuDraw ) { float base; - if( usage->first != 0 ) + if( v.own != 0 ) { - base = dpos.y + offset + ( 1.f - usage->first * cpuCntRev ) * cpuUsageHeight; + base = dpos.y + offset + ( 1.f - v.own * cpuCntRev ) * cpuUsageHeight; DrawLine( draw, ImVec2( dpos.x + pos, dpos.y + offset + cpuUsageHeight ), ImVec2( dpos.x + pos, base ), 0xFF55BB55 ); } else { base = dpos.y + offset + cpuUsageHeight; } - if( usage->second != 0 ) + if( v.other != 0 ) { - int usageTotal = usage->first + usage->second; + int usageTotal = v.own + v.other; DrawLine( draw, ImVec2( dpos.x + pos, base ), ImVec2( dpos.x + pos, dpos.y + offset + ( 1.f - usageTotal * cpuCntRev ) * cpuUsageHeight ), 0xFF666666 ); } pos++; - usage++; } DrawLine( draw, dpos + ImVec2( 0, offset+cpuUsageHeight+2 ), dpos + ImVec2( w, offset+cpuUsageHeight+2 ), 0x22DD88DD ); if( hover && ImGui::IsMouseHoveringRect( ImVec2( wpos.x, wpos.y + offset ), ImVec2( wpos.x + w, wpos.y + offset + cpuUsageHeight ), true ) ) { - const auto& usage = m_cpuUsageBuf[ImGui::GetIO().MousePos.x - wpos.x]; ImGui::BeginTooltip(); - TextFocused( "Cores used by profiled program:", RealToString( usage.first ) ); - ImGui::SameLine(); - char buf[64]; - PrintStringPercent( buf, usage.first * cpuCntRev * 100 ); - TextDisabledUnformatted( buf ); - TextFocused( "Cores used by other programs:", RealToString( usage.second ) ); - ImGui::SameLine(); - PrintStringPercent( buf, usage.second * cpuCntRev * 100 ); - TextDisabledUnformatted( buf ); - TextFocused( "Number of cores:", RealToString( cpuCnt ) ); - if( usage.first + usage.second != 0 ) + if( cpuDraw.size() > ( ImGui::GetIO().MousePos.x - wpos.x ) ) { - const auto mt = m_vd.zvStart + ( ImGui::GetIO().MousePos.x - wpos.x ) * nspxdbl; - ImGui::Separator(); - for( int i=0; iStart() <= mt && it->End() >= mt ) + if( !cpuData[i].cs.empty() ) { - auto tt = m_worker.GetThreadTopology( i ); - if( tt ) + auto& cs = cpuData[i].cs; + auto it = std::lower_bound( cs.begin(), cs.end(), mt, [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } ); + if( it != cs.end() && it->Start() <= mt && it->End() >= mt ) { - ImGui::TextDisabled( "[%i:%i] CPU %i:", tt->package, tt->core, i ); - } - else - { - ImGui::TextDisabled( "CPU %i:", i ); - } - ImGui::SameLine(); - const auto thread = m_worker.DecompressThreadExternal( it->Thread() ); - bool local, untracked; - const char* txt; - auto label = GetThreadContextData( thread, local, untracked, txt ); - if( local || untracked ) - { - uint32_t color; - if( m_vd.dynamicColors != 0 ) + auto tt = m_worker.GetThreadTopology( i ); + if( tt ) { - color = local ? GetThreadColor( thread, 0 ) : ( untracked ? 0xFF663333 : 0xFF444444 ); + ImGui::TextDisabled( "[%i:%i] CPU %i:", tt->package, tt->core, i ); } else { - color = local ? 0xFF334488 : ( untracked ? 0xFF663333 : 0xFF444444 ); + ImGui::TextDisabled( "CPU %i:", i ); } - TextColoredUnformatted( HighlightColor<75>( color ), label ); ImGui::SameLine(); - ImGui::TextDisabled( "(%s)", RealToString( thread ) ); - } - else - { - TextDisabledUnformatted( label ); + const auto thread = m_worker.DecompressThreadExternal( it->Thread() ); + bool local, untracked; + const char* txt; + auto label = GetThreadContextData( thread, local, untracked, txt ); + if( local || untracked ) + { + uint32_t color; + if( m_vd.dynamicColors != 0 ) + { + color = local ? GetThreadColor( thread, 0 ) : ( untracked ? 0xFF663333 : 0xFF444444 ); + } + else + { + color = local ? 0xFF334488 : ( untracked ? 0xFF663333 : 0xFF444444 ); + } + TextColoredUnformatted( HighlightColor<75>( color ), label ); + ImGui::SameLine(); + ImGui::TextDisabled( "(%s)", RealToString( thread ) ); + } + else + { + TextDisabledUnformatted( label ); + } } } } } } + else + { + TextFocused( "Cores used by profiled program:", "0" ); + TextFocused( "Cores used by other programs:", "0" ); + TextFocused( "Number of cores:", RealToString( cpuCnt ) ); + } ImGui::EndTooltip(); } } diff --git a/server/TracyWorker.cpp b/server/TracyWorker.cpp index 8cd4cd69..b4a97d8b 100644 --- a/server/TracyWorker.cpp +++ b/server/TracyWorker.cpp @@ -2052,88 +2052,6 @@ uint64_t Worker::GetPidFromTid( uint64_t tid ) const return it->second; } -void Worker::GetCpuUsage( int64_t t0, double tstep, size_t num, std::vector>& out ) -{ - if( out.size() < num ) out.resize( num ); - - if( t0 > m_data.lastTime || int64_t( t0 + tstep * num ) < 0 ) - { - memset( out.data(), 0, sizeof( int ) * 2 * num ); - return; - } - -#ifndef TRACY_NO_STATISTICS - if( !m_data.ctxUsage.empty() ) - { - auto ptr = out.data(); - auto itBegin = m_data.ctxUsage.begin(); - for( size_t i=0; i m_data.lastTime ) - { - ptr->first = 0; - ptr->second = 0; - } - else - { - const auto test = ( time << 16 ) | 0xFFFF; - auto it = std::upper_bound( itBegin, m_data.ctxUsage.end(), test, [] ( const auto& l, const auto& r ) { return l < r._time_other_own; } ); - if( it == m_data.ctxUsage.begin() || it == m_data.ctxUsage.end() ) - { - ptr->first = 0; - ptr->second = 0; - } - else - { - --it; - ptr->first = it->Own(); - ptr->second = it->Other(); - } - itBegin = it; - } - ptr++; - } - } - else -#endif - { - memset( out.data(), 0, sizeof( int ) * 2 * num ); - for( int i=0; i m_data.lastTime ) break; - if( time >= 0 ) - { - auto it = std::lower_bound( itBegin, cs.end(), time, [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } ); - if( it == cs.end() ) break; - if( it->IsEndValid() && it->Start() <= time ) - { - if( GetPidFromTid( DecompressThreadExternal( it->Thread() ) ) == m_pid ) - { - ptr->first++; - } - else - { - ptr->second++; - } - } - itBegin = it; - } - ptr++; - } - } - } - } -} - const ContextSwitch* const Worker::GetContextSwitchDataImpl( uint64_t thread ) { auto it = m_data.ctxSwitch.find( thread ); diff --git a/server/TracyWorker.hpp b/server/TracyWorker.hpp index aff34a8d..61cc8ab3 100644 --- a/server/TracyWorker.hpp +++ b/server/TracyWorker.hpp @@ -512,7 +512,6 @@ public: int GetCpuDataCpuCount() const { return m_data.cpuDataCount; } uint64_t GetPidFromTid( uint64_t tid ) const; const unordered_flat_map& GetCpuThreadData() const { return m_data.cpuThreadData; } - void GetCpuUsage( int64_t t0, double tstep, size_t num, std::vector>& out ); const unordered_flat_map& GetSourceFileCache() const { return m_data.sourceFileCache; } uint64_t GetSourceFileCacheCount() const { return m_data.sourceFileCache.size(); } uint64_t GetSourceFileCacheSize() const; @@ -606,6 +605,7 @@ public: bool AreSourceLocationZonesReady() const { return m_data.sourceLocationZonesReady; } bool AreGpuSourceLocationZonesReady() const { return m_data.gpuSourceLocationZonesReady; } bool IsCpuUsageReady() const { return m_data.ctxUsageReady; } + const Vector& GetCpuUsage() const { return m_data.ctxUsage; } const unordered_flat_map& GetSymbolStats() const { return m_data.symbolStats; } const SymbolStats* GetSymbolStats( uint64_t symAddr ) const;