mirror of
https://github.com/wolfpld/tracy.git
synced 2024-11-10 02:31:48 +00:00
Also extract timeline CPU data.
This commit is contained in:
parent
c6b6cb47da
commit
10205f90b4
@ -43,6 +43,14 @@ private:
|
||||
bool m_active;
|
||||
};
|
||||
|
||||
static tracy_force_inline uint32_t DarkenColor( uint32_t color )
|
||||
{
|
||||
return 0xFF000000 |
|
||||
( ( ( ( color & 0x00FF0000 ) >> 16 ) * 2 / 3 ) << 16 ) |
|
||||
( ( ( ( color & 0x0000FF00 ) >> 8 ) * 2 / 3 ) << 8 ) |
|
||||
( ( ( ( color & 0x000000FF ) ) * 2 / 3 ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1494,14 +1494,6 @@ void View::DrawZoneFramesHeader()
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t DarkenColor( uint32_t color )
|
||||
{
|
||||
return 0xFF000000 |
|
||||
( ( ( ( color & 0x00FF0000 ) >> 16 ) * 2 / 3 ) << 16 ) |
|
||||
( ( ( ( color & 0x0000FF00 ) >> 8 ) * 2 / 3 ) << 8 ) |
|
||||
( ( ( ( color & 0x000000FF ) ) * 2 / 3 ) );
|
||||
}
|
||||
|
||||
static uint32_t MixGhostColor( uint32_t c0, uint32_t c1 )
|
||||
{
|
||||
return 0xFF000000 |
|
||||
@ -4514,448 +4506,6 @@ int View::DrawLocks( uint64_t tid, bool hover, double pxns, const ImVec2& wpos,
|
||||
return cnt;
|
||||
}
|
||||
|
||||
int View::DrawCpuData( int offset, double pxns, const ImVec2& wpos, bool hover, float yMin, float yMax )
|
||||
{
|
||||
auto cpuData = m_worker.GetCpuData();
|
||||
const auto cpuCnt = m_worker.GetCpuDataCpuCount();
|
||||
if( cpuCnt == 0 ) return offset;
|
||||
|
||||
const auto w = ImGui::GetContentRegionAvail().x - 1;
|
||||
const auto ty = ImGui::GetTextLineHeight();
|
||||
const auto ostep = ty + 1;
|
||||
const auto nspxdbl = 1.0 / pxns;
|
||||
const auto nspx = int64_t( nspxdbl );
|
||||
auto draw = ImGui::GetWindowDrawList();
|
||||
const auto to = 9.f;
|
||||
const auto th = ( ty - to ) * sqrt( 3 ) * 0.5;
|
||||
const auto dpos = wpos + ImVec2( 0.5f, 0.5f );
|
||||
|
||||
static int cpuDataVisStub;
|
||||
auto& vis = Vis( &cpuDataVisStub );
|
||||
bool& showFull = vis.showFull;
|
||||
|
||||
const auto yPos = AdjustThreadPosition( vis, wpos.y, offset );
|
||||
const auto oldOffset = offset;
|
||||
ImGui::PushClipRect( wpos, wpos + ImVec2( w, offset + vis.height ), true );
|
||||
if( yPos + ty >= yMin && yPos <= yMax )
|
||||
{
|
||||
if( showFull )
|
||||
{
|
||||
draw->AddTriangleFilled( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( ty - to/2, offset + to/2 ), wpos + ImVec2( ty * 0.5, offset + to/2 + th ), 0xFFDD88DD );
|
||||
}
|
||||
else
|
||||
{
|
||||
draw->AddTriangle( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( to/2, offset + ty - to/2 ), wpos + ImVec2( to/2 + th, offset + ty * 0.5 ), 0xFF6E446E, 2.0f );
|
||||
}
|
||||
|
||||
float txtx = ImGui::CalcTextSize( "CPU data" ).x;
|
||||
DrawTextContrast( draw, wpos + ImVec2( ty, offset ), showFull ? 0xFFDD88DD : 0xFF6E446E, "CPU data" );
|
||||
DrawLine( draw, dpos + ImVec2( 0, offset + ty - 1 ), dpos + ImVec2( w, offset + ty - 1 ), 0x66DD88DD );
|
||||
|
||||
if( hover && IsMouseClicked( 0 ) && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, offset ), wpos + ImVec2( ty + txtx, offset + ty ) ) )
|
||||
{
|
||||
showFull = !showFull;
|
||||
}
|
||||
}
|
||||
offset += ostep;
|
||||
|
||||
if( showFull )
|
||||
{
|
||||
#ifdef TRACY_NO_STATISTICS
|
||||
if( m_vd.drawCpuUsageGraph )
|
||||
#else
|
||||
if( m_vd.drawCpuUsageGraph && m_worker.IsCpuUsageReady() )
|
||||
#endif
|
||||
{
|
||||
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 )
|
||||
{
|
||||
float base;
|
||||
if( usage->first != 0 )
|
||||
{
|
||||
base = dpos.y + offset + ( 1.f - usage->first * 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 )
|
||||
{
|
||||
int usageTotal = usage->first + usage->second;
|
||||
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 )
|
||||
{
|
||||
const auto mt = m_vd.zvStart + ( ImGui::GetIO().MousePos.x - wpos.x ) * nspxdbl;
|
||||
ImGui::Separator();
|
||||
for( int i=0; i<cpuCnt; i++ )
|
||||
{
|
||||
if( !cpuData[i].cs.empty() )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
auto tt = m_worker.GetThreadTopology( i );
|
||||
if( tt )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
offset += cpuUsageHeight + 3;
|
||||
}
|
||||
|
||||
ImGui::PushFont( m_smallFont );
|
||||
const auto sty = round( ImGui::GetTextLineHeight() );
|
||||
const auto sstep = sty + 1;
|
||||
|
||||
const auto origOffset = offset;
|
||||
for( int i=0; i<cpuCnt; i++ )
|
||||
{
|
||||
if( !cpuData[i].cs.empty() )
|
||||
{
|
||||
if( wpos.y + offset + sty >= yMin && wpos.y + offset <= yMax )
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( 0, offset+sty ), dpos + ImVec2( w, offset+sty ), 0x22DD88DD );
|
||||
|
||||
auto& cs = cpuData[i].cs;
|
||||
auto tt = m_worker.GetThreadTopology( i );
|
||||
|
||||
auto it = std::lower_bound( cs.begin(), cs.end(), std::max<int64_t>( 0, m_vd.zvStart ), [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } );
|
||||
if( it != cs.end() )
|
||||
{
|
||||
auto eit = std::lower_bound( it, cs.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.Start() < r; } );
|
||||
while( it < eit )
|
||||
{
|
||||
const auto start = it->Start();
|
||||
const auto end = it->End();
|
||||
const auto zsz = std::max( ( end - start ) * pxns, pxns * 0.5 );
|
||||
if( zsz < MinVisSize )
|
||||
{
|
||||
const auto MinVisNs = MinVisSize * nspx;
|
||||
int num = 0;
|
||||
const auto px0 = ( start - m_vd.zvStart ) * pxns;
|
||||
auto px1ns = end - m_vd.zvStart;
|
||||
auto rend = end;
|
||||
auto nextTime = end + MinVisNs;
|
||||
for(;;)
|
||||
{
|
||||
const auto prevIt = it;
|
||||
it = std::lower_bound( it, eit, nextTime, [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } );
|
||||
if( it == prevIt ) ++it;
|
||||
num += std::distance( prevIt, it );
|
||||
if( it == eit ) break;
|
||||
const auto nend = it->IsEndValid() ? it->End() : m_worker.GetLastTime();
|
||||
const auto nsnext = nend - m_vd.zvStart;
|
||||
if( nsnext - px1ns >= MinVisNs * 2 ) break;
|
||||
px1ns = nsnext;
|
||||
rend = nend;
|
||||
nextTime = nend + nspx;
|
||||
}
|
||||
const auto px1 = px1ns * pxns;
|
||||
DrawZigZag( draw, wpos + ImVec2( 0, offset + sty/2 ), std::max( px0, -10.0 ), std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), sty/4, 0xFF888888 );
|
||||
|
||||
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset-1 ), wpos + ImVec2( std::max( px1, px0+MinVisSize ), offset + sty ) ) )
|
||||
{
|
||||
ImGui::PopFont();
|
||||
ImGui::BeginTooltip();
|
||||
TextFocused( "CPU:", RealToString( i ) );
|
||||
if( tt )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
TextFocused( "Context switch regions:", RealToString( num ) );
|
||||
ImGui::Separator();
|
||||
TextFocused( "Start time:", TimeToString( start ) );
|
||||
TextFocused( "End time:", TimeToString( rend ) );
|
||||
TextFocused( "Activity time:", TimeToString( rend - start ) );
|
||||
ImGui::EndTooltip();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
|
||||
if( IsMouseClicked( 2 ) )
|
||||
{
|
||||
ZoomToRange( start, rend );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto thread = m_worker.DecompressThreadExternal( it->Thread() );
|
||||
bool local, untracked;
|
||||
const char* txt;
|
||||
auto label = GetThreadContextData( thread, local, untracked, txt );
|
||||
const auto pr0 = ( start - m_vd.zvStart ) * pxns;
|
||||
const auto pr1 = ( end - m_vd.zvStart ) * pxns;
|
||||
const auto px0 = std::max( pr0, -10.0 );
|
||||
const auto px1 = std::max( { std::min( pr1, double( w + 10 ) ), px0 + pxns * 0.5, px0 + MinVisSize } );
|
||||
|
||||
uint32_t color;
|
||||
if( m_vd.dynamicColors != 0 )
|
||||
{
|
||||
color = local ? GetThreadColor( thread, 0 ) : ( untracked ? 0xFF663333 : 0xFF444444 );
|
||||
}
|
||||
else
|
||||
{
|
||||
color = local ? 0xFF334488 : ( untracked ? 0xFF663333 : 0xFF444444 );
|
||||
}
|
||||
|
||||
draw->AddRectFilled( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + sty ), color );
|
||||
if( m_drawThreadHighlight == thread )
|
||||
{
|
||||
draw->AddRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + sty ), 0xFFFFFFFF );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto accentColor = HighlightColor( color );
|
||||
const auto darkColor = DarkenColor( color );
|
||||
DrawLine( draw, dpos + ImVec2( px0, offset + sty ), dpos + ImVec2( px0, offset ), dpos + ImVec2( px1-1, offset ), accentColor, 1.f );
|
||||
DrawLine( draw, dpos + ImVec2( px0, offset + sty ), dpos + ImVec2( px1-1, offset + sty ), dpos + ImVec2( px1-1, offset ), darkColor, 1.f );
|
||||
}
|
||||
|
||||
auto tsz = ImGui::CalcTextSize( label );
|
||||
if( tsz.x < zsz )
|
||||
{
|
||||
const auto x = ( start - m_vd.zvStart ) * pxns + ( ( end - start ) * pxns - tsz.x ) / 2;
|
||||
if( x < 0 || x > w - tsz.x )
|
||||
{
|
||||
ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
|
||||
DrawTextContrast( draw, wpos + ImVec2( std::max( std::max( 0., px0 ), std::min( double( w - tsz.x ), x ) ), offset-1 ), local ? 0xFFFFFFFF : 0xAAFFFFFF, label );
|
||||
ImGui::PopClipRect();
|
||||
}
|
||||
else if( start == end )
|
||||
{
|
||||
DrawTextContrast( draw, wpos + ImVec2( px0 + ( px1 - px0 - tsz.x ) * 0.5, offset-1 ), local ? 0xFFFFFFFF : 0xAAFFFFFF, label );
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawTextContrast( draw, wpos + ImVec2( x, offset-1 ), local ? 0xFFFFFFFF : 0xAAFFFFFF, label );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
|
||||
DrawTextContrast( draw, wpos + ImVec2( ( start - m_vd.zvStart ) * pxns, offset-1 ), local ? 0xFFFFFFFF : 0xAAFFFFFF, label );
|
||||
ImGui::PopClipRect();
|
||||
}
|
||||
|
||||
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset-1 ), wpos + ImVec2( px1, offset + sty ) ) )
|
||||
{
|
||||
m_drawThreadHighlight = thread;
|
||||
ImGui::PopFont();
|
||||
ImGui::BeginTooltip();
|
||||
TextFocused( "CPU:", RealToString( i ) );
|
||||
if( tt )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
if( local )
|
||||
{
|
||||
TextFocused( "Program:", m_worker.GetCaptureProgram().c_str() );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "(profiled program)" );
|
||||
SmallColorBox( GetThreadColor( thread, 0 ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Thread:", m_worker.GetThreadName( thread ) );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "(%s)", RealToString( thread ) );
|
||||
m_drawThreadMigrations = thread;
|
||||
m_cpuDataThread = thread;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( untracked )
|
||||
{
|
||||
TextFocused( "Program:", m_worker.GetCaptureProgram().c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
TextFocused( "Program:", txt );
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if( untracked )
|
||||
{
|
||||
TextDisabledUnformatted( "(untracked thread in profiled program)" );
|
||||
}
|
||||
else
|
||||
{
|
||||
TextDisabledUnformatted( "(external)" );
|
||||
}
|
||||
TextFocused( "Thread:", m_worker.GetExternalName( thread ).second );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "(%s)", RealToString( thread ) );
|
||||
}
|
||||
ImGui::Separator();
|
||||
TextFocused( "Start time:", TimeToStringExact( start ) );
|
||||
TextFocused( "End time:", TimeToStringExact( end ) );
|
||||
TextFocused( "Activity time:", TimeToString( end - start ) );
|
||||
ImGui::EndTooltip();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
|
||||
if( IsMouseClicked( 2 ) )
|
||||
{
|
||||
ZoomToRange( start, end );
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char buf[64];
|
||||
if( tt )
|
||||
{
|
||||
sprintf( buf, "[%i:%i] CPU %i", tt->package, tt->core, i );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( buf, "CPU %i", i );
|
||||
}
|
||||
const auto txtx = ImGui::CalcTextSize( buf ).x;
|
||||
DrawTextContrast( draw, wpos + ImVec2( ty, offset-1 ), 0xFFDD88DD, buf );
|
||||
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, offset-1 ), wpos + ImVec2( sty + txtx, offset + sty ) ) )
|
||||
{
|
||||
ImGui::PopFont();
|
||||
ImGui::BeginTooltip();
|
||||
TextFocused( "CPU:", RealToString( i ) );
|
||||
if( tt )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
TextFocused( "Context switch regions:", RealToString( cs.size() ) );
|
||||
ImGui::EndTooltip();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
}
|
||||
}
|
||||
offset += sstep;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_drawThreadMigrations != 0 )
|
||||
{
|
||||
auto ctxSwitch = m_worker.GetContextSwitchData( m_drawThreadMigrations );
|
||||
if( ctxSwitch )
|
||||
{
|
||||
const auto color = HighlightColor( GetThreadColor( m_drawThreadMigrations, -8 ) );
|
||||
|
||||
auto& v = ctxSwitch->v;
|
||||
auto it = std::lower_bound( v.begin(), v.end(), m_vd.zvStart, [] ( const auto& l, const auto& r ) { return l.End() < r; } );
|
||||
if( it != v.begin() ) --it;
|
||||
auto end = std::lower_bound( it, v.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.Start() < r; } );
|
||||
if( end == v.end() ) --end;
|
||||
|
||||
while( it < end )
|
||||
{
|
||||
const auto t0 = it->End();
|
||||
const auto cpu0 = it->Cpu();
|
||||
|
||||
++it;
|
||||
|
||||
const auto t1 = it->Start();
|
||||
const auto cpu1 = it->Cpu();
|
||||
|
||||
const auto px0 = ( t0 - m_vd.zvStart ) * pxns;
|
||||
const auto px1 = ( t1 - m_vd.zvStart ) * pxns;
|
||||
|
||||
if( t1 - t0 < 2 * nspx )
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( px0, origOffset + sty * 0.5f + cpu0 * sstep ), dpos + ImVec2( px1, origOffset + sty * 0.5f + cpu1 * sstep ), color );
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( px0, origOffset + sty * 0.5f + cpu0 * sstep ), dpos + ImVec2( px1, origOffset + sty * 0.5f + cpu1 * sstep ), 0xFF000000, 4.f );
|
||||
DrawLine( draw, dpos + ImVec2( px0, origOffset + sty * 0.5f + cpu0 * sstep ), dpos + ImVec2( px1, origOffset + sty * 0.5f + cpu1 * sstep ), color, 2.f );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
offset += ostep * 0.2f;
|
||||
AdjustThreadHeight( vis, oldOffset, offset );
|
||||
ImGui::PopClipRect();
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void View::DrawHistogramMinMaxLabel( ImDrawList* draw, int64_t tmin, int64_t tmax, ImVec2 wpos, float w, float ty )
|
||||
{
|
||||
const auto dpos = wpos + ImVec2( 0.5f, 0.5f );
|
||||
|
@ -1,9 +1,455 @@
|
||||
#include "TracyColor.hpp"
|
||||
#include "TracyMouse.hpp"
|
||||
#include "TracyPrint.hpp"
|
||||
#include "TracyView.hpp"
|
||||
|
||||
namespace tracy
|
||||
{
|
||||
|
||||
enum { MinVisSize = 3 };
|
||||
|
||||
int View::DrawCpuData( int offset, double pxns, const ImVec2& wpos, bool hover, float yMin, float yMax )
|
||||
{
|
||||
auto cpuData = m_worker.GetCpuData();
|
||||
const auto cpuCnt = m_worker.GetCpuDataCpuCount();
|
||||
if( cpuCnt == 0 ) return offset;
|
||||
|
||||
const auto w = ImGui::GetContentRegionAvail().x - 1;
|
||||
const auto ty = ImGui::GetTextLineHeight();
|
||||
const auto ostep = ty + 1;
|
||||
const auto nspxdbl = 1.0 / pxns;
|
||||
const auto nspx = int64_t( nspxdbl );
|
||||
auto draw = ImGui::GetWindowDrawList();
|
||||
const auto to = 9.f;
|
||||
const auto th = ( ty - to ) * sqrt( 3 ) * 0.5;
|
||||
const auto dpos = wpos + ImVec2( 0.5f, 0.5f );
|
||||
|
||||
static int cpuDataVisStub;
|
||||
auto& vis = Vis( &cpuDataVisStub );
|
||||
bool& showFull = vis.showFull;
|
||||
|
||||
const auto yPos = AdjustThreadPosition( vis, wpos.y, offset );
|
||||
const auto oldOffset = offset;
|
||||
ImGui::PushClipRect( wpos, wpos + ImVec2( w, offset + vis.height ), true );
|
||||
if( yPos + ty >= yMin && yPos <= yMax )
|
||||
{
|
||||
if( showFull )
|
||||
{
|
||||
draw->AddTriangleFilled( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( ty - to/2, offset + to/2 ), wpos + ImVec2( ty * 0.5, offset + to/2 + th ), 0xFFDD88DD );
|
||||
}
|
||||
else
|
||||
{
|
||||
draw->AddTriangle( wpos + ImVec2( to/2, offset + to/2 ), wpos + ImVec2( to/2, offset + ty - to/2 ), wpos + ImVec2( to/2 + th, offset + ty * 0.5 ), 0xFF6E446E, 2.0f );
|
||||
}
|
||||
|
||||
float txtx = ImGui::CalcTextSize( "CPU data" ).x;
|
||||
DrawTextContrast( draw, wpos + ImVec2( ty, offset ), showFull ? 0xFFDD88DD : 0xFF6E446E, "CPU data" );
|
||||
DrawLine( draw, dpos + ImVec2( 0, offset + ty - 1 ), dpos + ImVec2( w, offset + ty - 1 ), 0x66DD88DD );
|
||||
|
||||
if( hover && IsMouseClicked( 0 ) && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, offset ), wpos + ImVec2( ty + txtx, offset + ty ) ) )
|
||||
{
|
||||
showFull = !showFull;
|
||||
}
|
||||
}
|
||||
offset += ostep;
|
||||
|
||||
if( showFull )
|
||||
{
|
||||
#ifdef TRACY_NO_STATISTICS
|
||||
if( m_vd.drawCpuUsageGraph )
|
||||
#else
|
||||
if( m_vd.drawCpuUsageGraph && m_worker.IsCpuUsageReady() )
|
||||
#endif
|
||||
{
|
||||
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 )
|
||||
{
|
||||
float base;
|
||||
if( usage->first != 0 )
|
||||
{
|
||||
base = dpos.y + offset + ( 1.f - usage->first * 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 )
|
||||
{
|
||||
int usageTotal = usage->first + usage->second;
|
||||
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 )
|
||||
{
|
||||
const auto mt = m_vd.zvStart + ( ImGui::GetIO().MousePos.x - wpos.x ) * nspxdbl;
|
||||
ImGui::Separator();
|
||||
for( int i=0; i<cpuCnt; i++ )
|
||||
{
|
||||
if( !cpuData[i].cs.empty() )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
auto tt = m_worker.GetThreadTopology( i );
|
||||
if( tt )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
offset += cpuUsageHeight + 3;
|
||||
}
|
||||
|
||||
ImGui::PushFont( m_smallFont );
|
||||
const auto sty = round( ImGui::GetTextLineHeight() );
|
||||
const auto sstep = sty + 1;
|
||||
|
||||
const auto origOffset = offset;
|
||||
for( int i=0; i<cpuCnt; i++ )
|
||||
{
|
||||
if( !cpuData[i].cs.empty() )
|
||||
{
|
||||
if( wpos.y + offset + sty >= yMin && wpos.y + offset <= yMax )
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( 0, offset+sty ), dpos + ImVec2( w, offset+sty ), 0x22DD88DD );
|
||||
|
||||
auto& cs = cpuData[i].cs;
|
||||
auto tt = m_worker.GetThreadTopology( i );
|
||||
|
||||
auto it = std::lower_bound( cs.begin(), cs.end(), std::max<int64_t>( 0, m_vd.zvStart ), [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } );
|
||||
if( it != cs.end() )
|
||||
{
|
||||
auto eit = std::lower_bound( it, cs.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.Start() < r; } );
|
||||
while( it < eit )
|
||||
{
|
||||
const auto start = it->Start();
|
||||
const auto end = it->End();
|
||||
const auto zsz = std::max( ( end - start ) * pxns, pxns * 0.5 );
|
||||
if( zsz < MinVisSize )
|
||||
{
|
||||
const auto MinVisNs = MinVisSize * nspx;
|
||||
int num = 0;
|
||||
const auto px0 = ( start - m_vd.zvStart ) * pxns;
|
||||
auto px1ns = end - m_vd.zvStart;
|
||||
auto rend = end;
|
||||
auto nextTime = end + MinVisNs;
|
||||
for(;;)
|
||||
{
|
||||
const auto prevIt = it;
|
||||
it = std::lower_bound( it, eit, nextTime, [] ( const auto& l, const auto& r ) { return (uint64_t)l.End() < (uint64_t)r; } );
|
||||
if( it == prevIt ) ++it;
|
||||
num += std::distance( prevIt, it );
|
||||
if( it == eit ) break;
|
||||
const auto nend = it->IsEndValid() ? it->End() : m_worker.GetLastTime();
|
||||
const auto nsnext = nend - m_vd.zvStart;
|
||||
if( nsnext - px1ns >= MinVisNs * 2 ) break;
|
||||
px1ns = nsnext;
|
||||
rend = nend;
|
||||
nextTime = nend + nspx;
|
||||
}
|
||||
const auto px1 = px1ns * pxns;
|
||||
DrawZigZag( draw, wpos + ImVec2( 0, offset + sty/2 ), std::max( px0, -10.0 ), std::min( std::max( px1, px0+MinVisSize ), double( w + 10 ) ), sty/4, 0xFF888888 );
|
||||
|
||||
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset-1 ), wpos + ImVec2( std::max( px1, px0+MinVisSize ), offset + sty ) ) )
|
||||
{
|
||||
ImGui::PopFont();
|
||||
ImGui::BeginTooltip();
|
||||
TextFocused( "CPU:", RealToString( i ) );
|
||||
if( tt )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
TextFocused( "Context switch regions:", RealToString( num ) );
|
||||
ImGui::Separator();
|
||||
TextFocused( "Start time:", TimeToString( start ) );
|
||||
TextFocused( "End time:", TimeToString( rend ) );
|
||||
TextFocused( "Activity time:", TimeToString( rend - start ) );
|
||||
ImGui::EndTooltip();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
|
||||
if( IsMouseClicked( 2 ) )
|
||||
{
|
||||
ZoomToRange( start, rend );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto thread = m_worker.DecompressThreadExternal( it->Thread() );
|
||||
bool local, untracked;
|
||||
const char* txt;
|
||||
auto label = GetThreadContextData( thread, local, untracked, txt );
|
||||
const auto pr0 = ( start - m_vd.zvStart ) * pxns;
|
||||
const auto pr1 = ( end - m_vd.zvStart ) * pxns;
|
||||
const auto px0 = std::max( pr0, -10.0 );
|
||||
const auto px1 = std::max( { std::min( pr1, double( w + 10 ) ), px0 + pxns * 0.5, px0 + MinVisSize } );
|
||||
|
||||
uint32_t color;
|
||||
if( m_vd.dynamicColors != 0 )
|
||||
{
|
||||
color = local ? GetThreadColor( thread, 0 ) : ( untracked ? 0xFF663333 : 0xFF444444 );
|
||||
}
|
||||
else
|
||||
{
|
||||
color = local ? 0xFF334488 : ( untracked ? 0xFF663333 : 0xFF444444 );
|
||||
}
|
||||
|
||||
draw->AddRectFilled( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + sty ), color );
|
||||
if( m_drawThreadHighlight == thread )
|
||||
{
|
||||
draw->AddRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + sty ), 0xFFFFFFFF );
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto accentColor = HighlightColor( color );
|
||||
const auto darkColor = DarkenColor( color );
|
||||
DrawLine( draw, dpos + ImVec2( px0, offset + sty ), dpos + ImVec2( px0, offset ), dpos + ImVec2( px1-1, offset ), accentColor, 1.f );
|
||||
DrawLine( draw, dpos + ImVec2( px0, offset + sty ), dpos + ImVec2( px1-1, offset + sty ), dpos + ImVec2( px1-1, offset ), darkColor, 1.f );
|
||||
}
|
||||
|
||||
auto tsz = ImGui::CalcTextSize( label );
|
||||
if( tsz.x < zsz )
|
||||
{
|
||||
const auto x = ( start - m_vd.zvStart ) * pxns + ( ( end - start ) * pxns - tsz.x ) / 2;
|
||||
if( x < 0 || x > w - tsz.x )
|
||||
{
|
||||
ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
|
||||
DrawTextContrast( draw, wpos + ImVec2( std::max( std::max( 0., px0 ), std::min( double( w - tsz.x ), x ) ), offset-1 ), local ? 0xFFFFFFFF : 0xAAFFFFFF, label );
|
||||
ImGui::PopClipRect();
|
||||
}
|
||||
else if( start == end )
|
||||
{
|
||||
DrawTextContrast( draw, wpos + ImVec2( px0 + ( px1 - px0 - tsz.x ) * 0.5, offset-1 ), local ? 0xFFFFFFFF : 0xAAFFFFFF, label );
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawTextContrast( draw, wpos + ImVec2( x, offset-1 ), local ? 0xFFFFFFFF : 0xAAFFFFFF, label );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushClipRect( wpos + ImVec2( px0, offset ), wpos + ImVec2( px1, offset + tsz.y * 2 ), true );
|
||||
DrawTextContrast( draw, wpos + ImVec2( ( start - m_vd.zvStart ) * pxns, offset-1 ), local ? 0xFFFFFFFF : 0xAAFFFFFF, label );
|
||||
ImGui::PopClipRect();
|
||||
}
|
||||
|
||||
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( px0, offset-1 ), wpos + ImVec2( px1, offset + sty ) ) )
|
||||
{
|
||||
m_drawThreadHighlight = thread;
|
||||
ImGui::PopFont();
|
||||
ImGui::BeginTooltip();
|
||||
TextFocused( "CPU:", RealToString( i ) );
|
||||
if( tt )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
if( local )
|
||||
{
|
||||
TextFocused( "Program:", m_worker.GetCaptureProgram().c_str() );
|
||||
ImGui::SameLine();
|
||||
TextDisabledUnformatted( "(profiled program)" );
|
||||
SmallColorBox( GetThreadColor( thread, 0 ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Thread:", m_worker.GetThreadName( thread ) );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "(%s)", RealToString( thread ) );
|
||||
m_drawThreadMigrations = thread;
|
||||
m_cpuDataThread = thread;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( untracked )
|
||||
{
|
||||
TextFocused( "Program:", m_worker.GetCaptureProgram().c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
TextFocused( "Program:", txt );
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if( untracked )
|
||||
{
|
||||
TextDisabledUnformatted( "(untracked thread in profiled program)" );
|
||||
}
|
||||
else
|
||||
{
|
||||
TextDisabledUnformatted( "(external)" );
|
||||
}
|
||||
TextFocused( "Thread:", m_worker.GetExternalName( thread ).second );
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled( "(%s)", RealToString( thread ) );
|
||||
}
|
||||
ImGui::Separator();
|
||||
TextFocused( "Start time:", TimeToStringExact( start ) );
|
||||
TextFocused( "End time:", TimeToStringExact( end ) );
|
||||
TextFocused( "Activity time:", TimeToString( end - start ) );
|
||||
ImGui::EndTooltip();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
|
||||
if( IsMouseClicked( 2 ) )
|
||||
{
|
||||
ZoomToRange( start, end );
|
||||
}
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char buf[64];
|
||||
if( tt )
|
||||
{
|
||||
sprintf( buf, "[%i:%i] CPU %i", tt->package, tt->core, i );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf( buf, "CPU %i", i );
|
||||
}
|
||||
const auto txtx = ImGui::CalcTextSize( buf ).x;
|
||||
DrawTextContrast( draw, wpos + ImVec2( ty, offset-1 ), 0xFFDD88DD, buf );
|
||||
if( hover && ImGui::IsMouseHoveringRect( wpos + ImVec2( 0, offset-1 ), wpos + ImVec2( sty + txtx, offset + sty ) ) )
|
||||
{
|
||||
ImGui::PopFont();
|
||||
ImGui::BeginTooltip();
|
||||
TextFocused( "CPU:", RealToString( i ) );
|
||||
if( tt )
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Package:", RealToString( tt->package ) );
|
||||
ImGui::SameLine();
|
||||
TextFocused( "Core:", RealToString( tt->core ) );
|
||||
}
|
||||
TextFocused( "Context switch regions:", RealToString( cs.size() ) );
|
||||
ImGui::EndTooltip();
|
||||
ImGui::PushFont( m_smallFont );
|
||||
}
|
||||
}
|
||||
offset += sstep;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_drawThreadMigrations != 0 )
|
||||
{
|
||||
auto ctxSwitch = m_worker.GetContextSwitchData( m_drawThreadMigrations );
|
||||
if( ctxSwitch )
|
||||
{
|
||||
const auto color = HighlightColor( GetThreadColor( m_drawThreadMigrations, -8 ) );
|
||||
|
||||
auto& v = ctxSwitch->v;
|
||||
auto it = std::lower_bound( v.begin(), v.end(), m_vd.zvStart, [] ( const auto& l, const auto& r ) { return l.End() < r; } );
|
||||
if( it != v.begin() ) --it;
|
||||
auto end = std::lower_bound( it, v.end(), m_vd.zvEnd, [] ( const auto& l, const auto& r ) { return l.Start() < r; } );
|
||||
if( end == v.end() ) --end;
|
||||
|
||||
while( it < end )
|
||||
{
|
||||
const auto t0 = it->End();
|
||||
const auto cpu0 = it->Cpu();
|
||||
|
||||
++it;
|
||||
|
||||
const auto t1 = it->Start();
|
||||
const auto cpu1 = it->Cpu();
|
||||
|
||||
const auto px0 = ( t0 - m_vd.zvStart ) * pxns;
|
||||
const auto px1 = ( t1 - m_vd.zvStart ) * pxns;
|
||||
|
||||
if( t1 - t0 < 2 * nspx )
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( px0, origOffset + sty * 0.5f + cpu0 * sstep ), dpos + ImVec2( px1, origOffset + sty * 0.5f + cpu1 * sstep ), color );
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawLine( draw, dpos + ImVec2( px0, origOffset + sty * 0.5f + cpu0 * sstep ), dpos + ImVec2( px1, origOffset + sty * 0.5f + cpu1 * sstep ), 0xFF000000, 4.f );
|
||||
DrawLine( draw, dpos + ImVec2( px0, origOffset + sty * 0.5f + cpu0 * sstep ), dpos + ImVec2( px1, origOffset + sty * 0.5f + cpu1 * sstep ), color, 2.f );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
offset += ostep * 0.2f;
|
||||
AdjustThreadHeight( vis, oldOffset, offset );
|
||||
ImGui::PopClipRect();
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void View::DrawCpuDataWindow()
|
||||
{
|
||||
const auto scale = GetScale();
|
||||
|
Loading…
Reference in New Issue
Block a user