mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-25 23:44:35 +00:00
Preprocess CPU usage.
Things of note: Worker::GetCpuUsage() functionality was moved to TimelineItemCpuData::PreprocessCpuUsage().
This commit is contained in:
parent
dcf27f4989
commit
5eebc5d7cf
@ -56,6 +56,13 @@ struct MessagesDraw
|
||||
uint32_t num;
|
||||
};
|
||||
|
||||
|
||||
struct CpuUsageDraw
|
||||
{
|
||||
int own;
|
||||
int other;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -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<num; i++ )
|
||||
{
|
||||
const auto time = int64_t( vStart + nspx * i );
|
||||
if( time > 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<cpuDataCount; i++ )
|
||||
{
|
||||
auto& cs = cpuData[i].cs;
|
||||
if( !cs.empty() )
|
||||
{
|
||||
auto itBegin = cs.begin();
|
||||
auto ptr = m_cpuDraw.data();
|
||||
for( size_t i=0; i<num; i++ )
|
||||
{
|
||||
const auto time = int64_t( vStart + nspx * i );
|
||||
if( time > 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<CpuUsageDraw> m_cpuDraw;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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<MessagesDraw>& 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<CpuUsageDraw>&, int& offset );
|
||||
|
||||
bool m_showRanges = false;
|
||||
Range m_statRange;
|
||||
@ -841,8 +842,6 @@ private:
|
||||
int64_t time;
|
||||
} m_sendQueueWarning;
|
||||
|
||||
std::vector<std::pair<int, int>> m_cpuUsageBuf;
|
||||
|
||||
bool m_attnProtoMismatch = false;
|
||||
bool m_attnNotAvailable = false;
|
||||
bool m_attnDropped = false;
|
||||
|
@ -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<CpuUsageDraw>& 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; i<cpuCnt; i++ )
|
||||
const auto& usage = cpuDraw[ImGui::GetIO().MousePos.x - wpos.x];
|
||||
TextFocused( "Cores used by profiled program:", RealToString( usage.own ) );
|
||||
ImGui::SameLine();
|
||||
char buf[64];
|
||||
PrintStringPercent( buf, usage.own * cpuCntRev * 100 );
|
||||
TextDisabledUnformatted( buf );
|
||||
TextFocused( "Cores used by other programs:", RealToString( usage.other ) );
|
||||
ImGui::SameLine();
|
||||
PrintStringPercent( buf, usage.other * cpuCntRev * 100 );
|
||||
TextDisabledUnformatted( buf );
|
||||
TextFocused( "Number of cores:", RealToString( cpuCnt ) );
|
||||
if( usage.own + usage.other != 0 )
|
||||
{
|
||||
if( !cpuData[i].cs.empty() )
|
||||
const auto mt = m_vd.zvStart + ( ImGui::GetIO().MousePos.x - wpos.x ) * nspxdbl;
|
||||
ImGui::Separator();
|
||||
for( int i=0; i<cpuCnt; i++ )
|
||||
{
|
||||
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 )
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -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<std::pair<int, int>>& 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<num; i++ )
|
||||
{
|
||||
const auto time = int64_t( t0 + tstep * i );
|
||||
if( time < 0 || time > 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.cpuDataCount; i++ )
|
||||
{
|
||||
auto& cs = m_data.cpuData[i].cs;
|
||||
if( !cs.empty() )
|
||||
{
|
||||
auto itBegin = cs.begin();
|
||||
auto ptr = out.data();
|
||||
for( size_t i=0; i<num; i++ )
|
||||
{
|
||||
const auto time = int64_t( t0 + tstep * i );
|
||||
if( time > 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 );
|
||||
|
@ -512,7 +512,6 @@ public:
|
||||
int GetCpuDataCpuCount() const { return m_data.cpuDataCount; }
|
||||
uint64_t GetPidFromTid( uint64_t tid ) const;
|
||||
const unordered_flat_map<uint64_t, CpuThreadData>& GetCpuThreadData() const { return m_data.cpuThreadData; }
|
||||
void GetCpuUsage( int64_t t0, double tstep, size_t num, std::vector<std::pair<int, int>>& out );
|
||||
const unordered_flat_map<const char*, MemoryBlock, charutil::Hasher, charutil::Comparator>& 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<ContextSwitchUsage>& GetCpuUsage() const { return m_data.ctxUsage; }
|
||||
|
||||
const unordered_flat_map<uint64_t, SymbolStats>& GetSymbolStats() const { return m_data.symbolStats; }
|
||||
const SymbolStats* GetSymbolStats( uint64_t symAddr ) const;
|
||||
|
Loading…
Reference in New Issue
Block a user