1
0
mirror of https://github.com/wolfpld/tracy synced 2025-01-15 20:08:00 +00:00

Compare commits

...

37 Commits

Author SHA1 Message Date
Bartosz Taudul
4a1142fddf
Merge pull request #201 from nosferalatu/dont_early_out_in_memfree_when_ptr_is_zero
Change ev.ptr nullptr early-out to properly handle nullptrs
2021-04-21 23:44:21 +02:00
David Farrell
be963f184c Change ev.ptr nullptr early-out to happen only when there is not a previous allocation for address 0. Custom memory pools (like custom allocators for Vulkan memory pools) can allocate at address 0, so the previous code would cause the Tracy server to alloc(0), free(0) (but early out), then on the next alloc(0) it would have a MemAllocTwiceFailure (because it skipped the free). 2021-04-21 11:53:55 -07:00
Bartosz Taudul
da9a32fd09
Update manual. 2021-04-20 18:34:08 +02:00
Bartosz Taudul
0bbda5ea11
Pressing Z will temporarily switch child calls. 2021-04-20 18:19:00 +02:00
Bartosz Taudul
e189f596ac
Add no-statistics guards. 2021-04-18 22:59:10 +02:00
Bartosz Taudul
cbf8550a45
Update NEWS. 2021-04-18 22:46:10 +02:00
Bartosz Taudul
d234f4dbe4
Generate child sample data during capture. 2021-04-18 22:44:37 +02:00
Bartosz Taudul
fb872fa088
Add child samples to source view percentages. 2021-04-18 22:23:55 +02:00
Bartosz Taudul
cba72859e9
No parents if only child samples. 2021-04-18 22:00:49 +02:00
Bartosz Taudul
141a4bc0fe
Fix scroll bar display of child-only samples. 2021-04-18 22:00:49 +02:00
Bartosz Taudul
c7da9b1092
Fix rendering of lines with no local samples. 2021-04-18 22:00:49 +02:00
Bartosz Taudul
66ef71cf7b
Gather child IP stats for addresses without samples. 2021-04-18 22:00:49 +02:00
Bartosz Taudul
ef93c69ee9
Make child calls more discoverable. 2021-04-18 22:00:48 +02:00
Bartosz Taudul
2009f63e32
Group time/samples data by local and child. 2021-04-18 20:43:23 +02:00
Bartosz Taudul
a5afa2cb4e
Use correct address for child sample information. 2021-04-18 20:43:23 +02:00
Bartosz Taudul
4970c48c51
Don't shadow variables. 2021-04-18 20:43:23 +02:00
Bartosz Taudul
c859d655ad
Include child calls in asm view percentages. 2021-04-18 20:43:22 +02:00
Bartosz Taudul
50a1faa880
Don't print zero sample counts in tooltips. 2021-04-18 20:16:05 +02:00
Bartosz Taudul
5f97c484f1
Include child samples in symbol view file list. 2021-04-18 19:42:24 +02:00
Bartosz Taudul
046881e32f
Add AddrStat::operator+=( AddrStat ). 2021-04-18 19:40:43 +02:00
Bartosz Taudul
22a8c53e8b
Account for case with no local samples (external only). 2021-04-18 19:21:53 +02:00
Bartosz Taudul
b217e00dd9
Hackfix support for UTF-8 in source files. 2021-04-18 19:14:12 +02:00
Bartosz Taudul
526d0cd22a
Display child time and samples in symbol stats. 2021-04-18 19:10:39 +02:00
Bartosz Taudul
c5eb398319
Gather external IP stats (no range limit case). 2021-04-18 19:04:29 +02:00
Bartosz Taudul
8db9bcf7f8
Disable child calls checkbox while processing data. 2021-04-18 18:27:39 +02:00
Bartosz Taudul
0d8ee47231
Store instruction pointer stats as AddrStat. 2021-04-18 16:16:47 +02:00
Bartosz Taudul
3845c392fa
Cosmetics. 2021-04-18 15:52:42 +02:00
Bartosz Taudul
55efa64b3f
Do not copy instruction pointer maps. 2021-04-18 15:51:50 +02:00
Bartosz Taudul
32e3c0ebb1
Display child sample counts in info window. 2021-04-18 15:06:54 +02:00
Bartosz Taudul
34b80ac52f
Add child samples count getters. 2021-04-18 15:03:42 +02:00
Bartosz Taudul
2f6adf3641
Add child calls UI. 2021-04-18 15:00:19 +02:00
Bartosz Taudul
ffe8aebfbd
Extend address stats to include child samples. 2021-04-18 15:00:19 +02:00
Bartosz Taudul
df462f109d
Reconstruct child sample data. 2021-04-18 15:00:19 +02:00
Bartosz Taudul
4dc6222ba1
Add child samples data structure. 2021-04-18 14:42:35 +02:00
Bartosz Taudul
fa8c99fd74
Fix missing limit range checkbox in source view.
This could happen if range was limited in such a way, that no sample was
within the region.
2021-04-18 14:42:35 +02:00
Bartosz Taudul
0476e851ff
Force inline LZ4_NbCommonBytes(). 2021-04-18 14:42:35 +02:00
Bartosz Taudul
aee39d3fcd
Disable collapsing of connection window. 2021-04-18 14:42:31 +02:00
9 changed files with 484 additions and 117 deletions

1
NEWS
View File

@ -12,6 +12,7 @@ v0.x.x (xxxx-xx-xx)
- Updated Zen 3 and added Tiger Lake microarchitectural data.
- Manually disconnecting from the server will no longer display erroneous
warning message.
- Added ability to display sample time spent in child function calls.
v0.7.7 (2021-04-01)

View File

@ -512,7 +512,7 @@ LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const si
/*-************************************
* Common functions
**************************************/
static unsigned LZ4_NbCommonBytes (reg_t val)
LZ4_FORCE_INLINE unsigned LZ4_NbCommonBytes (reg_t val)
{
assert(val != 0);
if (LZ4_isLittleEndian()) {

View File

@ -3244,6 +3244,8 @@ An assembly instruction may be associated with only a single source line, but a
If automated call stack sampling (see chapter~\ref{sampling}) was performed, additional profiling information will be available. The first column of source and assembly views will contain percentage counts of collected instruction pointer samples for each displayed line, both in numerical and graphical bar form. This information can be used to determine which line of the function takes the most time. The displayed percentage values are heat map color coded, with the lowest values mapped to dark red, and the highest values mapped to bright yellow. The color code will appear next to the percentage value, and on the scroll bar, so that 'hot' places in code can be identified at a glance.
By default samples are displayed only from within the selected symbol, in isolation. In some cases you may however want to include samples from functions that were called. To do so, enable the \emph{\faSignOut*{}~Child calls} option, which may also be temporarily toggled by pressing the \keys{Z} key. Make sure to familiarize yourself with section~\ref{readingcallstacks} to be able to properly read the results.
Instruction timings can be viewed as a group. To begin constructing such group, click the \LMB{}~left mouse button on the percentage value. Additional instructions can be added using the \keys{\ctrl}~key, while holding the \keys{\shift}~key will allow selection of a range. To cancel the selection, click the \RMB{}~right mouse button on a percentage value. Group statistics can be seen at the bottom of the pane.
Clicking the \MMB{}~middle mouse button on the percentage value of an assembly instruction will display entry call stacks of the selected sample (see chapter~\ref{sampleparents}). This functionality is only available for instructions that have collected sampling data, and only in the assembly view, as the source code may be inlined multiple times, which would result in ambiguous location data. Note that number of entry call stacks is displayed in a tooltip, for a quick reference.

View File

@ -124,7 +124,7 @@ std::vector<Tokenizer::Token> Tokenizer::Tokenize( const char* begin, const char
}
else
{
while( begin != end && isspace( *begin ) ) begin++;
while( begin != end && isspace( (uint8_t)*begin ) ) begin++;
if( first && begin < end && *begin == '#' )
{
if( *(end-1) == '\\' ) m_isInPreprocessor = true;

View File

@ -88,6 +88,7 @@ SourceView::SourceView( ImFont* font, GetWindowCallback gwcb )
, m_asmShowSourceLocation( true )
, m_calcInlineStats( true )
, m_atnt( false )
, m_childCalls( false )
, m_showJumps( true )
, m_cpuArch( CpuArchUnknown )
, m_showLatency( false )
@ -863,6 +864,7 @@ void SourceView::RenderSimpleSourceView()
const auto lx = ts * maxLine + ty + round( ts*0.4f );
draw->AddLine( wpos + ImVec2( lx, 0 ), wpos + ImVec2( lx, wh ), 0x08FFFFFF );
const AddrStat zero = {};
if( m_targetLine != 0 )
{
int lineNum = 1;
@ -873,7 +875,7 @@ void SourceView::RenderSimpleSourceView()
m_targetLine = 0;
ImGui::SetScrollHereY();
}
RenderLine( line, lineNum++, 0, 0, 0, nullptr );
RenderLine( line, lineNum++, zero, zero, zero, nullptr );
}
const auto win = ImGui::GetCurrentWindowRead();
m_srcWidth = win->DC.CursorMaxPos.x - win->DC.CursorStartPos.x;
@ -886,7 +888,7 @@ void SourceView::RenderSimpleSourceView()
{
for( auto i=clipper.DisplayStart; i<clipper.DisplayEnd; i++ )
{
RenderLine( lines[i], i+1, 0, 0, 0, nullptr );
RenderLine( lines[i], i+1, zero, zero, zero, nullptr );
}
}
}
@ -1092,12 +1094,13 @@ void SourceView::RenderSymbolView( const Worker& worker, View& view )
TextFocused( ICON_FA_WEIGHT_HANGING " Code size:", MemSizeToString( m_codeLen ) );
}
uint32_t iptotalSrc = 0, iptotalAsm = 0;
uint32_t ipmaxSrc = 0, ipmaxAsm = 0;
unordered_flat_map<uint64_t, uint32_t> ipcountSrc, ipcountAsm;
AddrStat iptotalSrc = {}, iptotalAsm = {};
AddrStat ipmaxSrc = {}, ipmaxAsm = {};
unordered_flat_map<uint64_t, AddrStat> ipcountSrc, ipcountAsm;
if( m_calcInlineStats )
{
GatherIpStats( m_symAddr, iptotalSrc, iptotalAsm, ipcountSrc, ipcountAsm, ipmaxSrc, ipmaxAsm, worker, limitView, view );
GatherAdditionalIpStats( m_symAddr, iptotalSrc, iptotalAsm, ipcountSrc, ipcountAsm, ipmaxSrc, ipmaxAsm, worker, limitView, view );
}
else
{
@ -1112,18 +1115,78 @@ void SourceView::RenderSymbolView( const Worker& worker, View& view )
iptr++;
}
}
GatherAdditionalIpStats( m_symAddr, iptotalSrc, iptotalAsm, ipcountSrc, ipcountAsm, ipmaxSrc, ipmaxAsm, worker, limitView, view );
iptotalSrc = iptotalAsm;
}
if( iptotalAsm > 0 )
const auto slzReady = worker.AreSourceLocationZonesReady();
if( ( iptotalAsm.local + iptotalAsm.ext ) > 0 || ( view.m_statRange.active && worker.GetSamplesForSymbol( m_baseAddr ) ) )
{
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
TextFocused( ICON_FA_STOPWATCH " Time:", TimeToString( iptotalAsm * worker.GetSamplingPeriod() ) );
if( !slzReady )
{
ImGui::PushItemFlag( ImGuiItemFlags_Disabled, true );
ImGui::PushStyleVar( ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f );
m_childCalls = false;
}
else if( ImGui::IsKeyDown( 'Z' ) )
{
m_childCalls = !m_childCalls;
}
SmallCheckbox( ICON_FA_SIGN_OUT_ALT " Child calls", &m_childCalls );
if( !slzReady )
{
ImGui::PopStyleVar();
ImGui::PopItemFlag();
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
ImGui::TextUnformatted( "Please wait, processing data..." );
ImGui::EndTooltip();
}
}
else
{
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
ImGui::TextUnformatted( "Press Z key to temporarily reverse selection." );
ImGui::EndTooltip();
}
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
TextFocused( ICON_FA_EYE_DROPPER " Samples:", RealToString( iptotalAsm ) );
if( m_childCalls )
{
TextFocused( ICON_FA_STOPWATCH " Time:", TimeToString( ( iptotalAsm.local + iptotalAsm.ext ) * worker.GetSamplingPeriod() ) );
}
else
{
TextFocused( ICON_FA_STOPWATCH " Time:", TimeToString( iptotalAsm.local * worker.GetSamplingPeriod() ) );
}
if( iptotalAsm.ext )
{
ImGui::SameLine();
ImGui::TextDisabled( "(%c%s)", m_childCalls ? '-' : '+', TimeToString( iptotalAsm.ext * worker.GetSamplingPeriod() ) );
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
if( m_childCalls )
{
TextFocused( ICON_FA_EYE_DROPPER " Samples:", RealToString( iptotalAsm.local + iptotalAsm.ext ) );
}
else
{
TextFocused( ICON_FA_EYE_DROPPER " Samples:", RealToString( iptotalAsm.local ) );
}
if( iptotalAsm.ext )
{
ImGui::SameLine();
ImGui::Text( "(%c%s)", m_childCalls ? '-' : '+', RealToString( iptotalAsm.ext ) );
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
@ -1139,7 +1202,7 @@ void SourceView::RenderSymbolView( const Worker& worker, View& view )
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
ImGui::TextUnformatted( "Waiting for background tasks to finish" );
ImGui::TextUnformatted( "Please wait, processing data..." );
ImGui::EndTooltip();
}
}
@ -1188,6 +1251,8 @@ void SourceView::RenderSymbolView( const Worker& worker, View& view )
break;
}
if( slzReady && ImGui::IsKeyDown( 'Z' ) ) m_childCalls = !m_childCalls;
if( jumpOut != 0 )
{
auto sym = worker.GetSymbolData( jumpOut );
@ -1230,10 +1295,9 @@ static uint32_t GetHotnessColor( uint32_t ipSum, uint32_t maxIpCount )
{
return 0xFFFFFFFF;
}
}
void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<uint64_t, uint32_t> ipcount, unordered_flat_map<uint64_t, uint32_t> ipcountAsm, uint32_t ipmax, const Worker& worker, const View& view )
void SourceView::RenderSymbolSourceView( const AddrStat& iptotal, const unordered_flat_map<uint64_t, AddrStat>& ipcount, const unordered_flat_map<uint64_t, AddrStat>& ipcountAsm, const AddrStat& ipmax, const Worker& worker, const View& view )
{
if( m_sourceFiles.empty() )
{
@ -1315,15 +1379,15 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
}
else
{
uint32_t totalSamples = 0;
unordered_flat_map<uint32_t, uint32_t> fileCounts;
AddrStat totalSamples = {};
unordered_flat_map<uint32_t, AddrStat> fileCounts;
for( auto& v : m_asm )
{
uint32_t srcline;
const auto srcidx = worker.GetLocationForAddress( v.addr, srcline );
if( srcline != 0 )
{
uint32_t cnt = 0;
AddrStat cnt = {};
auto ait = ipcountAsm.find( v.addr );
if( ait != ipcountAsm.end() ) cnt = ait->second;
@ -1332,19 +1396,27 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
{
fileCounts.emplace( srcidx.Idx(), cnt );
}
else if( cnt != 0 )
else
{
fit->second += cnt;
}
totalSamples += cnt;
}
}
std::vector<std::pair<uint32_t, uint32_t>> fileCountsVec;
std::vector<std::pair<uint32_t, AddrStat>> fileCountsVec;
fileCountsVec.reserve( fileCounts.size() );
for( auto& v : fileCounts ) fileCountsVec.emplace_back( v.first, v.second );
pdqsort_branchless( fileCountsVec.begin(), fileCountsVec.end(), [&worker] (const auto& l, const auto& r ) { return l.second == r.second ? strcmp( worker.GetString( l.first ), worker.GetString( r.first ) ) < 0 : l.second > r.second; } );
if( m_childCalls )
{
pdqsort_branchless( fileCountsVec.begin(), fileCountsVec.end(), [&worker] (const auto& l, const auto& r ) { return ( l.second.local + l.second.ext == r.second.local + r.second.ext ) ? strcmp( worker.GetString( l.first ), worker.GetString( r.first ) ) < 0 : ( l.second.local + l.second.ext > r.second.local + r.second.ext ); } );
}
else
{
pdqsort_branchless( fileCountsVec.begin(), fileCountsVec.end(), [&worker] (const auto& l, const auto& r ) { return l.second.local == r.second.local ? strcmp( worker.GetString( l.first ), worker.GetString( r.first ) ) < 0 : l.second.local > r.second.local; } );
}
if( totalSamples != 0 )
const auto hasSamples = totalSamples.local + totalSamples.ext != 0;
if( hasSamples )
{
ImGui::Columns( 2 );
static bool widthSet = false;
@ -1359,21 +1431,48 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
}
for( auto& v : fileCountsVec )
{
if( totalSamples != 0 )
if( hasSamples )
{
auto fit = fileCounts.find( v.first );
assert( fit != fileCounts.end() );
if( fit->second != 0 )
if( fit->second.local + fit->second.ext != 0 )
{
ImGui::TextUnformatted( TimeToString( fit->second * worker.GetSamplingPeriod() ) );
ImGui::SameLine();
ImGui::TextDisabled( "(%.2f%%)", 100.f * fit->second / totalSamples );
if( m_childCalls )
{
ImGui::TextUnformatted( TimeToString( ( fit->second.local + fit->second.ext ) * worker.GetSamplingPeriod() ) );
}
else
{
ImGui::TextUnformatted( TimeToString( fit->second.local * worker.GetSamplingPeriod() ) );
}
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
TextFocused( "Sample count:", RealToString( fit->second ) );
if( fit->second.local )
{
TextFocused( "Local time:", TimeToString( fit->second.local * worker.GetSamplingPeriod() ) );
TextFocused( "Local samples:", RealToString( fit->second.local ) );
}
if( fit->second.ext )
{
TextFocused( "Child time:", TimeToString( fit->second.ext * worker.GetSamplingPeriod() ) );
TextFocused( "Child samples:", RealToString( fit->second.ext ) );
}
ImGui::EndTooltip();
}
ImGui::SameLine();
if( m_childCalls )
{
ImGui::TextDisabled( "(%.2f%%)", 100.f * ( fit->second.local + fit->second.ext ) / ( totalSamples.local + totalSamples.ext ) );
}
else if( totalSamples.local != 0 )
{
ImGui::TextDisabled( "(%.2f%%)", 100.f * fit->second.local / totalSamples.local );
}
else
{
ImGui::TextDisabled( "(%.2f%%)", 0 );
}
}
ImGui::NextColumn();
}
@ -1405,9 +1504,9 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
{
TextDisabledUnformatted( fstr );
}
if( totalSamples != 0 ) ImGui::NextColumn();
if( hasSamples ) ImGui::NextColumn();
}
if( totalSamples != 0 ) ImGui::EndColumns();
if( hasSamples ) ImGui::EndColumns();
}
ImGui::EndCombo();
}
@ -1429,7 +1528,7 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
const auto tmp = RealToString( lineCount );
const auto maxLine = strlen( tmp );
auto lx = ts * maxLine + ty + round( ts*0.4f );
if( iptotal != 0 ) lx += ts * 7 + ty;
if( iptotal.local + iptotal.ext != 0 ) lx += ts * 7 + ty;
if( !m_asm.empty() )
{
const auto tmp = RealToString( m_asm.size() );
@ -1438,6 +1537,7 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
}
draw->AddLine( wpos + ImVec2( lx, 0 ), wpos + ImVec2( lx, wh ), 0x08FFFFFF );
const AddrStat zero = {};
m_selectedAddressesHover.clear();
if( m_targetLine != 0 )
{
@ -1449,7 +1549,7 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
m_targetLine = 0;
ImGui::SetScrollHereY();
}
RenderLine( line, lineNum++, 0, iptotal, ipmax, &worker );
RenderLine( line, lineNum++, zero, iptotal, ipmax, &worker );
}
const auto win = ImGui::GetCurrentWindowRead();
m_srcWidth = win->DC.CursorMaxPos.x - win->DC.CursorStartPos.x;
@ -1460,11 +1560,11 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
clipper.Begin( (int)lines.size() );
while( clipper.Step() )
{
if( iptotal == 0 )
if( iptotal.local + iptotal.ext == 0 )
{
for( auto i=clipper.DisplayStart; i<clipper.DisplayEnd; i++ )
{
RenderLine( lines[i], i+1, 0, 0, 0, &worker );
RenderLine( lines[i], i+1, zero, zero, zero, &worker );
}
}
else
@ -1472,7 +1572,7 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
for( auto i=clipper.DisplayStart; i<clipper.DisplayEnd; i++ )
{
auto it = ipcount.find( i+1 );
const auto ipcnt = it == ipcount.end() ? 0 : it->second;
const auto ipcnt = it == ipcount.end() ? zero : it->second;
RenderLine( lines[i], i+1, ipcnt, iptotal, ipmax, &worker );
}
}
@ -1496,7 +1596,7 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
draw->AddLine( ImVec2( rect.Min.x, ly ), ImVec2( rect.Max.x, ly ), 0x88888888, 3 );
}
std::vector<std::pair<uint64_t, uint32_t>> ipData;
std::vector<std::pair<uint64_t, AddrStat>> ipData;
ipData.reserve( ipcount.size() );
for( auto& v : ipcount ) ipData.emplace_back( v.first, v.second );
for( uint32_t lineNum = 1; lineNum <= lines.size(); lineNum++ )
@ -1510,7 +1610,7 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
{
if( addr >= m_baseAddr && addr < m_baseAddr + m_codeLen )
{
ipData.emplace_back( lineNum, 0 );
ipData.emplace_back( lineNum, AddrStat {} );
break;
}
}
@ -1527,15 +1627,23 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
while( it != ipData.end() )
{
const auto firstLine = it->first;
uint32_t ipSum = 0;
AddrStat ipSum = {};
while( it != ipData.end() && it->first <= firstLine + step )
{
ipSum += it->second;
++it;
}
const auto ly = round( rect.Min.y + float( firstLine ) / lines.size() * rect.GetHeight() );
const uint32_t color = ipSum == 0 ? 0x22FFFFFF : GetHotnessColor( ipSum, ipmax );
draw->AddRectFilled( ImVec2( x14, ly ), ImVec2( x34, ly+3 ), color );
if( m_childCalls )
{
const auto color = ( ipSum.local + ipSum.ext == 0 ) ? 0x22FFFFFF : GetHotnessColor( ipSum.local + ipSum.ext, ipmax.local + ipmax.ext );
draw->AddRectFilled( ImVec2( x14, ly ), ImVec2( x34, ly+3 ), color );
}
else
{
const auto color = ipSum.local == 0 ? 0x22FFFFFF : GetHotnessColor( ipSum.local, ipmax.local );
draw->AddRectFilled( ImVec2( x14, ly ), ImVec2( x34, ly+3 ), color );
}
}
ImGui::PopClipRect();
@ -1546,7 +1654,7 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
if( !m_srcSampleSelect.empty() )
{
uint32_t count = 0;
AddrStat count = {};
uint32_t numLines = 0;
for( auto& idx : m_srcSampleSelect )
{
@ -1566,17 +1674,43 @@ void SourceView::RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<ui
}
ImGui::SameLine();
char buf[16];
auto end = PrintFloat( buf, buf+16, 100.f * count / iptotal, 2 );
char* end;
if( m_childCalls )
{
end = PrintFloat( buf, buf+16, 100.f * ( count.local + count.ext ) / ( iptotal.local + iptotal.ext ), 2 );
}
else if( iptotal.local != 0 )
{
end = PrintFloat( buf, buf+16, 100.f * count.local / iptotal.local, 2 );
}
else
{
end = PrintFloat( buf, buf+16, 0.f, 2 );
}
memcpy( end, "%", 2 );
TextFocused( "Selected:", buf );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
TextFocused( "Time:", TimeToString( count * worker.GetSamplingPeriod() ) );
if( m_childCalls )
{
TextFocused( "Time:", TimeToString( ( count.local + count.ext ) * worker.GetSamplingPeriod() ) );
}
else
{
TextFocused( "Time:", TimeToString( count.local * worker.GetSamplingPeriod() ) );
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
TextFocused( "Sample count:", RealToString( count ) );
if( m_childCalls )
{
TextFocused( "Sample count:", RealToString( count.local + count.ext ) );
}
else
{
TextFocused( "Sample count:", RealToString( count.local ) );
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
@ -1632,7 +1766,7 @@ static int PrintHexBytes( char* buf, const uint8_t* bytes, size_t len, CpuArchit
}
}
uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<uint64_t, uint32_t> ipcount, uint32_t ipmax, const Worker& worker, View& view )
uint64_t SourceView::RenderSymbolAsmView( const AddrStat& iptotal, const unordered_flat_map<uint64_t, AddrStat>& ipcount, const AddrStat& ipmax, const Worker& worker, View& view )
{
if( m_disasmFail >= 0 )
{
@ -1775,6 +1909,7 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
uint64_t selJumpTarget;
uint64_t jumpOut = 0;
const AddrStat zero = {};
if( m_targetAddr != 0 )
{
for( auto& line : m_asm )
@ -1784,7 +1919,7 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
m_targetAddr = 0;
ImGui::SetScrollHereY();
}
RenderAsmLine( line, 0, iptotal, ipmax, worker, jumpOut, maxAddrLen, view );
RenderAsmLine( line, zero, iptotal, ipmax, worker, jumpOut, maxAddrLen, view );
}
const auto win = ImGui::GetCurrentWindowRead();
m_asmWidth = win->DC.CursorMaxPos.x - win->DC.CursorStartPos.x;
@ -1800,11 +1935,11 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
const auto wpos = ImGui::GetCursorScreenPos();
static std::vector<uint64_t> insList;
insList.clear();
if( iptotal == 0 )
if( iptotal.local + iptotal.ext == 0 )
{
for( auto i=clipper.DisplayStart; i<clipper.DisplayEnd; i++ )
{
RenderAsmLine( m_asm[i], 0, 0, 0, worker, jumpOut, maxAddrLen, view );
RenderAsmLine( m_asm[i], zero, zero, zero, worker, jumpOut, maxAddrLen, view );
insList.emplace_back( m_asm[i].addr );
}
}
@ -1814,7 +1949,7 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
{
auto& line = m_asm[i];
auto it = ipcount.find( line.addr );
const auto ipcnt = it == ipcount.end() ? 0 : it->second;
const auto ipcnt = it == ipcount.end() ? zero : it->second;
RenderAsmLine( line, ipcnt, iptotal, ipmax, worker, jumpOut, maxAddrLen, view );
insList.emplace_back( line.addr );
}
@ -1825,7 +1960,7 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
const auto ts = ImGui::CalcTextSize( " " );
const auto th2 = floor( ts.y / 2 );
const auto th4 = floor( ts.y / 4 );
const auto xoff = ( iptotal == 0 ? 0 : ( 7 * ts.x + ts.y ) ) + (3+maxAddrLen) * ts.x + ( ( m_asmShowSourceLocation && !m_sourceFiles.empty() ) ? 36 * ts.x : 0 ) + ( m_asmBytes ? m_maxAsmBytes*3 * ts.x : 0 );
const auto xoff = ( ( iptotal.local + iptotal.ext ) == 0 ? 0 : ( 7 * ts.x + ts.y ) ) + (3+maxAddrLen) * ts.x + ( ( m_asmShowSourceLocation && !m_sourceFiles.empty() ) ? 36 * ts.x : 0 ) + ( m_asmBytes ? m_maxAsmBytes*3 * ts.x : 0 );
const auto minAddr = m_asm[clipper.DisplayStart].addr;
const auto maxAddr = m_asm[clipper.DisplayEnd-1].addr;
const auto mjl = m_maxJumpLevel;
@ -2008,7 +2143,7 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
}
uint32_t selJumpLineStart, selJumpLineEnd, selJumpLineTarget;
std::vector<std::pair<uint64_t, uint32_t>> ipData;
std::vector<std::pair<uint64_t, AddrStat>> ipData;
ipData.reserve( ipcount.size() );
if( selJumpStart == 0 )
{
@ -2042,15 +2177,23 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
while( it != ipData.end() )
{
const auto firstLine = it->first;
uint32_t ipSum = 0;
AddrStat ipSum = {};
while( it != ipData.end() && it->first <= firstLine + step )
{
ipSum += it->second;
++it;
}
const auto ly = round( rect.Min.y + float( firstLine ) / m_asm.size() * rect.GetHeight() );
const uint32_t color = GetHotnessColor( ipSum, ipmax );
draw->AddRectFilled( ImVec2( x40, ly ), ImVec2( x60, ly+3 ), color );
if( m_childCalls )
{
const auto color = GetHotnessColor( ipSum.local + ipSum.ext, ipmax.local + ipmax.ext );
draw->AddRectFilled( ImVec2( x40, ly ), ImVec2( x60, ly+3 ), color );
}
else if( ipmax.local != 0 )
{
const auto color = GetHotnessColor( ipSum.local, ipmax.local );
draw->AddRectFilled( ImVec2( x40, ly ), ImVec2( x60, ly+3 ), color );
}
}
if( selJumpStart != 0 )
@ -2106,7 +2249,7 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
if( !m_asmSampleSelect.empty() )
{
uint32_t count = 0;
AddrStat count = {};
uint32_t numLines = 0;
for( auto& idx : m_asmSampleSelect )
{
@ -2126,17 +2269,43 @@ uint64_t SourceView::RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<u
}
ImGui::SameLine();
char buf[16];
auto end = PrintFloat( buf, buf+16, 100.f * count / iptotal, 2 );
char* end;
if( m_childCalls )
{
end = PrintFloat( buf, buf+16, 100.f * ( count.local + count.ext ) / ( iptotal.local + iptotal.ext ), 2 );
}
else if( iptotal.local != 0 )
{
end = PrintFloat( buf, buf+16, 100.f * count.local / iptotal.local, 2 );
}
else
{
end = PrintFloat( buf, buf+16, 0.f, 2 );
}
memcpy( end, "%", 2 );
TextFocused( "Selected:", buf );
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
TextFocused( "Time:", TimeToString( count * worker.GetSamplingPeriod() ) );
if( m_childCalls )
{
TextFocused( "Time:", TimeToString( ( count.local + count.ext ) * worker.GetSamplingPeriod() ) );
}
else
{
TextFocused( "Time:", TimeToString( count.local * worker.GetSamplingPeriod() ) );
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
TextFocused( "Sample count:", RealToString( count ) );
if( m_childCalls )
{
TextFocused( "Sample count:", RealToString( count.local + count.ext ) );
}
else
{
TextFocused( "Sample count:", RealToString( count.local ) );
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
@ -2172,7 +2341,7 @@ static bool PrintPercentage( float val, uint32_t col = 0xFFFFFFFF )
return ImGui::IsWindowHovered() && ImGui::IsMouseHoveringRect( wpos, wpos + ImVec2( stw * 7, ty ) );
}
void SourceView::RenderLine( const Tokenizer::Line& line, int lineNum, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker* worker )
void SourceView::RenderLine( const Tokenizer::Line& line, int lineNum, const AddrStat& ipcnt, const AddrStat& iptotal, const AddrStat& ipmax, const Worker* worker )
{
const auto ty = ImGui::GetFontSize();
auto draw = ImGui::GetWindowDrawList();
@ -2188,9 +2357,9 @@ void SourceView::RenderLine( const Tokenizer::Line& line, int lineNum, uint32_t
}
bool mouseHandled = false;
if( iptotal != 0 )
if( iptotal.local + iptotal.ext != 0 )
{
if( ipcnt == 0 )
if( ( m_childCalls && ipcnt.local + ipcnt.ext == 0 ) || ( !m_childCalls && ipcnt.local == 0 ) )
{
const auto ts = ImGui::CalcTextSize( " " );
ImGui::ItemSize( ImVec2( 7 * ts.x, ts.y ) );
@ -2198,12 +2367,29 @@ void SourceView::RenderLine( const Tokenizer::Line& line, int lineNum, uint32_t
else
{
auto sit = m_srcSampleSelect.find( lineNum );
if( PrintPercentage( 100.f * ipcnt / iptotal, sit == m_srcSampleSelect.end() ? 0xFFFFFFFF : 0xFF8888FF ) )
bool hover;
if( m_childCalls )
{
hover = PrintPercentage( 100.f * ( ipcnt.local + ipcnt.ext ) / ( iptotal.local + iptotal.ext ), sit == m_srcSampleSelect.end() ? 0xFFFFFFFF : 0xFF8888FF );
}
else
{
hover = PrintPercentage( 100.f * ipcnt.local / iptotal.local, sit == m_srcSampleSelect.end() ? 0xFFFFFFFF : 0xFF8888FF );
}
if( hover )
{
if( m_font ) ImGui::PopFont();
ImGui::BeginTooltip();
if( worker ) TextFocused( "Time:", TimeToString( ipcnt * worker->GetSamplingPeriod() ) );
TextFocused( "Sample count:", RealToString( ipcnt ) );
if( ipcnt.local )
{
if( worker ) TextFocused( "Local time:", TimeToString( ipcnt.local * worker->GetSamplingPeriod() ) );
TextFocused( "Local samples:", RealToString( ipcnt.local ) );
}
if( ipcnt.ext )
{
if( worker ) TextFocused( "Child time:", TimeToString( ipcnt.ext * worker->GetSamplingPeriod() ) );
TextFocused( "Child samples:", RealToString( ipcnt.ext ) );
}
ImGui::EndTooltip();
if( m_font ) ImGui::PushFont( m_font );
@ -2263,7 +2449,14 @@ void SourceView::RenderLine( const Tokenizer::Line& line, int lineNum, uint32_t
m_srcGroupSelect = -1;
}
}
draw->AddLine( wpos + ImVec2( 0, 1 ), wpos + ImVec2( 0, ty-2 ), GetHotnessColor( ipcnt, ipmax ) );
if( m_childCalls )
{
draw->AddLine( wpos + ImVec2( 0, 1 ), wpos + ImVec2( 0, ty-2 ), GetHotnessColor( ipcnt.local + ipcnt.ext, ipmax.local + ipmax.ext ) );
}
else
{
draw->AddLine( wpos + ImVec2( 0, 1 ), wpos + ImVec2( 0, ty-2 ), GetHotnessColor( ipcnt.local, ipmax.local ) );
}
}
ImGui::SameLine( 0, ty );
}
@ -2349,7 +2542,7 @@ void SourceView::RenderLine( const Tokenizer::Line& line, int lineNum, uint32_t
draw->AddLine( wpos + ImVec2( 0, ty+2 ), wpos + ImVec2( w, ty+2 ), 0x08FFFFFF );
}
void SourceView::RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker& worker, uint64_t& jumpOut, int maxAddrLen, View& view )
void SourceView::RenderAsmLine( AsmLine& line, const AddrStat& ipcnt, const AddrStat& iptotal, const AddrStat& ipmax, const Worker& worker, uint64_t& jumpOut, int maxAddrLen, View& view )
{
const auto ty = ImGui::GetFontSize();
auto draw = ImGui::GetWindowDrawList();
@ -2370,9 +2563,9 @@ void SourceView::RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal,
const auto asmIdx = &line - m_asm.data();
if( iptotal != 0 )
if( iptotal.local + iptotal.ext != 0 )
{
if( ipcnt == 0 )
if( ( m_childCalls && ipcnt.local + ipcnt.ext == 0 ) || ( !m_childCalls && ipcnt.local == 0 ) )
{
const auto ts = ImGui::CalcTextSize( " " );
ImGui::ItemSize( ImVec2( 7 * ts.x, ts.y ) );
@ -2381,7 +2574,16 @@ void SourceView::RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal,
{
const auto idx = &line - m_asm.data();
auto sit = m_asmSampleSelect.find( idx );
if( PrintPercentage( 100.f * ipcnt / iptotal, sit == m_asmSampleSelect.end() ? 0xFFFFFFFF : 0xFF8888FF ) )
bool hover;
if( m_childCalls )
{
hover = PrintPercentage( 100.f * ( ipcnt.local + ipcnt.ext ) / ( iptotal.local + iptotal.ext ), sit == m_asmSampleSelect.end() ? 0xFFFFFFFF : 0xFF8888FF );
}
else
{
hover = PrintPercentage( 100.f * ipcnt.local / iptotal.local, sit == m_asmSampleSelect.end() ? 0xFFFFFFFF : 0xFF8888FF );
}
if( hover )
{
uint64_t symAddrParents = m_baseAddr;
auto inlineList = worker.GetInlineSymbolList( m_baseAddr, m_codeLen );
@ -2403,17 +2605,27 @@ void SourceView::RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal,
inlineList++;
}
}
const auto& stats = *worker.GetSymbolStats( symAddrParents );
assert( !stats.parents.empty() );
if( m_font ) ImGui::PopFont();
ImGui::BeginTooltip();
TextFocused( "Time:", TimeToString( ipcnt * worker.GetSamplingPeriod() ) );
TextFocused( "Sample count:", RealToString( ipcnt ) );
ImGui::Separator();
TextFocused( "Entry call stacks:", RealToString( stats.parents.size() ) );
ImGui::SameLine();
TextDisabledUnformatted( "(middle click to view)" );
if( ipcnt.local )
{
TextFocused( "Local time:", TimeToString( ipcnt.local * worker.GetSamplingPeriod() ) );
TextFocused( "Local samples:", RealToString( ipcnt.local ) );
}
if( ipcnt.ext )
{
TextFocused( "Child time:", TimeToString( ipcnt.ext * worker.GetSamplingPeriod() ) );
TextFocused( "Child samples:", RealToString( ipcnt.ext ) );
}
const auto& stats = *worker.GetSymbolStats( symAddrParents );
if( !stats.parents.empty() )
{
ImGui::Separator();
TextFocused( "Entry call stacks:", RealToString( stats.parents.size() ) );
ImGui::SameLine();
TextDisabledUnformatted( "(middle click to view)" );
}
ImGui::EndTooltip();
if( m_font ) ImGui::PushFont( m_font );
@ -2470,12 +2682,19 @@ void SourceView::RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal,
m_asmSampleSelect.clear();
m_asmGroupSelect = -1;
}
else if( ImGui::IsMouseClicked( 2 ) )
else if( !stats.parents.empty() && ImGui::IsMouseClicked( 2 ) )
{
view.ShowSampleParents( symAddrParents );
}
}
draw->AddLine( wpos + ImVec2( 0, 1 ), wpos + ImVec2( 0, ty-2 ), GetHotnessColor( ipcnt, ipmax ) );
if( m_childCalls )
{
draw->AddLine( wpos + ImVec2( 0, 1 ), wpos + ImVec2( 0, ty-2 ), GetHotnessColor( ipcnt.local + ipcnt.ext, ipmax.local + ipmax.ext ) );
}
else
{
draw->AddLine( wpos + ImVec2( 0, 1 ), wpos + ImVec2( 0, ty-2 ), GetHotnessColor( ipcnt.local, ipmax.local ) );
}
}
ImGui::SameLine( 0, ty );
}
@ -2662,7 +2881,7 @@ void SourceView::RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal,
const auto th4 = floor( ts.y / 4 );
const auto& mjl = m_maxJumpLevel;
const auto col = GetHsvColor( line.jumpAddr, 6 );
const auto xoff = ( iptotal == 0 ? 0 : ( 7 * ts.x + ts.y ) ) + (3+maxAddrLen) * ts.x + ( ( m_asmShowSourceLocation && !m_sourceFiles.empty() ) ? 36 * ts.x : 0 ) + ( m_asmBytes ? m_maxAsmBytes*3 * ts.x : 0 );
const auto xoff = ( ( iptotal.local + iptotal.ext == 0 ) ? 0 : ( 7 * ts.x + ts.y ) ) + (3+maxAddrLen) * ts.x + ( ( m_asmShowSourceLocation && !m_sourceFiles.empty() ) ? 36 * ts.x : 0 ) + ( m_asmBytes ? m_maxAsmBytes*3 * ts.x : 0 );
draw->AddLine( wpos + ImVec2( xoff + JumpSeparation * mjl + th2, th2 ), wpos + ImVec2( xoff + JumpSeparation * mjl + th2 + JumpArrow / 2, th2 ), col );
draw->AddLine( wpos + ImVec2( xoff + JumpSeparation * mjl + th2, th2 ), wpos + ImVec2( xoff + JumpSeparation * mjl + th2 + th4, th2 - th4 ), col );
@ -3145,17 +3364,18 @@ void SourceView::SelectAsmLinesHover( uint32_t file, uint32_t line, const Worker
}
}
void SourceView::GatherIpStats( uint64_t addr, uint32_t& iptotalSrc, uint32_t& iptotalAsm, unordered_flat_map<uint64_t, uint32_t>& ipcountSrc, unordered_flat_map<uint64_t, uint32_t>& ipcountAsm, uint32_t& ipmaxSrc, uint32_t& ipmaxAsm, const Worker& worker, bool limitView, const View& view )
void SourceView::GatherIpStats( uint64_t baseAddr, AddrStat& iptotalSrc, AddrStat& iptotalAsm, unordered_flat_map<uint64_t, AddrStat>& ipcountSrc, unordered_flat_map<uint64_t, AddrStat>& ipcountAsm, AddrStat& ipmaxSrc, AddrStat& ipmaxAsm, const Worker& worker, bool limitView, const View& view )
{
const auto slzReady = worker.AreSourceLocationZonesReady();
auto filename = m_source.filename();
if( limitView )
{
auto vec = worker.GetSamplesForSymbol( addr );
auto vec = worker.GetSamplesForSymbol( baseAddr );
if( !vec ) return;
auto it = std::lower_bound( vec->begin(), vec->end(), view.m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
if( it == vec->end() ) return;
auto end = std::lower_bound( it, vec->end(), view.m_statRange.max, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
iptotalAsm += end - it;
iptotalAsm.local += end - it;
while( it != end )
{
if( filename )
@ -3172,16 +3392,16 @@ void SourceView::GatherIpStats( uint64_t addr, uint32_t& iptotalSrc, uint32_t& i
auto sit = ipcountSrc.find( line );
if( sit == ipcountSrc.end() )
{
ipcountSrc.emplace( line, 1 );
if( ipmaxSrc < 1 ) ipmaxSrc = 1;
ipcountSrc.emplace( line, AddrStat { 1, 0 } );
if( ipmaxSrc.local < 1 ) ipmaxSrc.local = 1;
}
else
{
const auto sum = sit->second + 1;
sit->second = sum;
if( ipmaxSrc < sum ) ipmaxSrc = sum;
const auto sum = sit->second.local + 1;
sit->second.local = sum;
if( ipmaxSrc.local < sum ) ipmaxSrc.local = sum;
}
iptotalSrc++;
iptotalSrc.local++;
}
}
}
@ -3191,14 +3411,14 @@ void SourceView::GatherIpStats( uint64_t addr, uint32_t& iptotalSrc, uint32_t& i
auto sit = ipcountAsm.find( addr );
if( sit == ipcountAsm.end() )
{
ipcountAsm.emplace( addr, 1 );
if( ipmaxAsm < 1 ) ipmaxAsm = 1;
ipcountAsm.emplace( addr, AddrStat{ 1, 0 } );
if( ipmaxAsm.local < 1 ) ipmaxAsm.local = 1;
}
else
{
const auto sum = sit->second + 1;
sit->second = sum;
if( ipmaxAsm < sum ) ipmaxAsm = sum;
const auto sum = sit->second.local + 1;
sit->second.local = sum;
if( ipmaxAsm.local < sum ) ipmaxAsm.local = sum;
}
++it;
@ -3206,10 +3426,20 @@ void SourceView::GatherIpStats( uint64_t addr, uint32_t& iptotalSrc, uint32_t& i
}
else
{
auto ipmap = worker.GetSymbolInstructionPointers( addr );
auto ipmap = worker.GetSymbolInstructionPointers( baseAddr );
if( !ipmap ) return;
for( auto& ip : *ipmap )
{
auto addr = worker.GetCanonicalPointer( ip.first );
assert( ipcountAsm.find( addr ) == ipcountAsm.end() );
auto cp = slzReady ? worker.GetChildSamples( addr ) : nullptr;
const uint32_t ccnt = cp ? (uint32_t)cp->size() : 0;
ipcountAsm.emplace( addr, AddrStat { ip.second, ccnt } );
iptotalAsm.local += ip.second;
iptotalAsm.ext += ccnt;
if( ipmaxAsm.local < ip.second ) ipmaxAsm.local = ip.second;
if( ipmaxAsm.ext < ccnt ) ipmaxAsm.ext = ccnt;
if( filename )
{
auto frame = worker.GetCallstackFrame( ip.first );
@ -3224,35 +3454,89 @@ void SourceView::GatherIpStats( uint64_t addr, uint32_t& iptotalSrc, uint32_t& i
auto it = ipcountSrc.find( line );
if( it == ipcountSrc.end() )
{
ipcountSrc.emplace( line, ip.second );
if( ipmaxSrc < ip.second ) ipmaxSrc = ip.second;
ipcountSrc.emplace( line, AddrStat{ ip.second, ccnt } );
if( ipmaxSrc.local < ip.second ) ipmaxSrc.local = ip.second;
if( ipmaxSrc.ext < ccnt ) ipmaxSrc.ext = ccnt;
}
else
{
const auto sum = it->second + ip.second;
it->second = sum;
if( ipmaxSrc < sum ) ipmaxSrc = sum;
const auto sum = it->second.local + ip.second;
const auto csum = it->second.ext + ccnt;
it->second.local = sum;
it->second.ext = csum;
if( ipmaxSrc.local < sum ) ipmaxSrc.local = sum;
if( ipmaxSrc.ext < csum ) ipmaxSrc.ext = csum;
}
iptotalSrc += ip.second;
iptotalSrc.local += ip.second;
iptotalSrc.ext += ccnt;
}
}
}
}
auto addr = worker.GetCanonicalPointer( ip.first );
assert( ipcountAsm.find( addr ) == ipcountAsm.end() );
ipcountAsm.emplace( addr, ip.second );
iptotalAsm += ip.second;
if( ipmaxAsm < ip.second ) ipmaxAsm = ip.second;
}
}
}
uint32_t SourceView::CountAsmIpStats( uint64_t addr, const Worker& worker, bool limitView, const View& view )
void SourceView::GatherAdditionalIpStats( uint64_t baseAddr, AddrStat& iptotalSrc, AddrStat& iptotalAsm, unordered_flat_map<uint64_t, AddrStat>& ipcountSrc, unordered_flat_map<uint64_t, AddrStat>& ipcountAsm, AddrStat& ipmaxSrc, AddrStat& ipmaxAsm, const Worker& worker, bool limitView, const View& view )
{
if( !worker.AreSourceLocationZonesReady() ) return;
auto filename = m_source.filename();
if( limitView )
{
}
else
{
auto sym = worker.GetSymbolData( baseAddr );
if( sym )
{
for( uint64_t ip = baseAddr; ip < baseAddr + sym->size.Val(); ip++ )
{
if( ipcountAsm.find( ip ) != ipcountAsm.end() ) continue;
auto cp = worker.GetChildSamples( ip );
if( !cp ) continue;
const auto ccnt = (uint32_t)cp->size();
ipcountAsm.emplace( ip, AddrStat { 0, ccnt } );
iptotalAsm.ext += ccnt;
if( ipmaxAsm.ext < ccnt ) ipmaxAsm.ext = ccnt;
if( filename )
{
auto frame = worker.GetCallstackFrame( worker.PackPointer( ip ) );
if( frame )
{
auto ffn = worker.GetString( frame->data[0].file );
if( strcmp( ffn, filename ) == 0 )
{
const auto line = frame->data[0].line;
if( line != 0 )
{
auto it = ipcountSrc.find( line );
if( it == ipcountSrc.end() )
{
ipcountSrc.emplace( line, AddrStat{ 0, ccnt } );
if( ipmaxSrc.ext < ccnt ) ipmaxSrc.ext = ccnt;
}
else
{
const auto csum = it->second.ext + ccnt;
it->second.ext = csum;
if( ipmaxSrc.ext < csum ) ipmaxSrc.ext = csum;
}
iptotalSrc.ext += ccnt;
}
}
}
}
}
}
}
}
uint32_t SourceView::CountAsmIpStats( uint64_t baseAddr, const Worker& worker, bool limitView, const View& view )
{
if( limitView )
{
auto vec = worker.GetSamplesForSymbol( addr );
auto vec = worker.GetSamplesForSymbol( baseAddr );
if( !vec ) return 0;
auto it = std::lower_bound( vec->begin(), vec->end(), view.m_statRange.min, [] ( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs; } );
if( it == vec->end() ) return 0;
@ -3262,7 +3546,7 @@ uint32_t SourceView::CountAsmIpStats( uint64_t addr, const Worker& worker, bool
else
{
uint32_t cnt = 0;
auto ipmap = worker.GetSymbolInstructionPointers( addr );
auto ipmap = worker.GetSymbolInstructionPointers( baseAddr );
if( !ipmap ) return 0;
for( auto& ip : *ipmap ) cnt += ip.second;
return cnt;

View File

@ -100,6 +100,19 @@ private:
DisplayMixed
};
struct AddrStat
{
uint32_t local;
uint32_t ext;
AddrStat& operator+=( const AddrStat& other )
{
local += other.local;
ext += other.ext;
return *this;
}
};
public:
using GetWindowCallback = void*(*)();
@ -123,18 +136,19 @@ private:
void RenderSimpleSourceView();
void RenderSymbolView( const Worker& worker, View& view );
void RenderSymbolSourceView( uint32_t iptotal, unordered_flat_map<uint64_t, uint32_t> ipcount, unordered_flat_map<uint64_t, uint32_t> ipcountAsm, uint32_t ipmax, const Worker& worker, const View& view );
uint64_t RenderSymbolAsmView( uint32_t iptotal, unordered_flat_map<uint64_t, uint32_t> ipcount, uint32_t ipmax, const Worker& worker, View& view );
void RenderSymbolSourceView( const AddrStat& iptotal, const unordered_flat_map<uint64_t, AddrStat>& ipcount, const unordered_flat_map<uint64_t, AddrStat>& ipcountAsm, const AddrStat& ipmax, const Worker& worker, const View& view );
uint64_t RenderSymbolAsmView( const AddrStat& iptotal, const unordered_flat_map<uint64_t, AddrStat>& ipcount, const AddrStat& ipmax, const Worker& worker, View& view );
void RenderLine( const Tokenizer::Line& line, int lineNum, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker* worker );
void RenderAsmLine( AsmLine& line, uint32_t ipcnt, uint32_t iptotal, uint32_t ipmax, const Worker& worker, uint64_t& jumpOut, int maxAddrLen, View& view );
void RenderLine( const Tokenizer::Line& line, int lineNum, const AddrStat& ipcnt, const AddrStat& iptotal, const AddrStat& ipmax, const Worker* worker );
void RenderAsmLine( AsmLine& line, const AddrStat& ipcnt, const AddrStat& iptotal, const AddrStat& ipmax, const Worker& worker, uint64_t& jumpOut, int maxAddrLen, View& view );
void SelectLine( uint32_t line, const Worker* worker, bool changeAsmLine = true, uint64_t targetAddr = 0 );
void SelectAsmLines( uint32_t file, uint32_t line, const Worker& worker, bool changeAsmLine = true, uint64_t targetAddr = 0 );
void SelectAsmLinesHover( uint32_t file, uint32_t line, const Worker& worker );
void GatherIpStats( uint64_t addr, uint32_t& iptotalSrc, uint32_t& iptotalAsm, unordered_flat_map<uint64_t, uint32_t>& ipcountSrc, unordered_flat_map<uint64_t, uint32_t>& ipcountAsm, uint32_t& ipmaxSrc, uint32_t& ipmaxAsm, const Worker& worker, bool limitView, const View& view );
uint32_t CountAsmIpStats( uint64_t addr, const Worker& worker, bool limitView, const View& view );
void GatherIpStats( uint64_t baseAddr, AddrStat& iptotalSrc, AddrStat& iptotalAsm, unordered_flat_map<uint64_t, AddrStat>& ipcountSrc, unordered_flat_map<uint64_t, AddrStat>& ipcountAsm, AddrStat& ipmaxSrc, AddrStat& ipmaxAsm, const Worker& worker, bool limitView, const View& view );
void GatherAdditionalIpStats( uint64_t baseAddr, AddrStat& iptotalSrc, AddrStat& iptotalAsm, unordered_flat_map<uint64_t, AddrStat>& ipcountSrc, unordered_flat_map<uint64_t, AddrStat>& ipcountAsm, AddrStat& ipmaxSrc, AddrStat& ipmaxAsm, const Worker& worker, bool limitView, const View& view );
uint32_t CountAsmIpStats( uint64_t baseAddr, const Worker& worker, bool limitView, const View& view );
void SelectMicroArchitecture( const char* moniker );
@ -169,6 +183,7 @@ private:
uint8_t m_maxAsmBytes;
bool m_atnt;
uint64_t m_jumpPopupAddr;
bool m_childCalls;
SourceContents m_source;
SourceContents m_sourceTooltip;

View File

@ -618,7 +618,7 @@ bool View::DrawImpl()
bool keepOpen = true;
char tmp[2048];
sprintf( tmp, "%s###Connection", m_worker.GetAddr().c_str() );
ImGui::Begin( tmp, &keepOpen, ImGuiWindowFlags_AlwaysAutoResize );
ImGui::Begin( tmp, &keepOpen, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse );
TextCentered( ICON_FA_WIFI );
ImGui::TextUnformatted( "Waiting for connection..." );
DrawWaitingDots( s_time );
@ -13801,6 +13801,15 @@ void View::DrawInfo()
}
TextFocused( "Call stack samples:", RealToString( m_worker.GetCallstackSampleCount() ) );
TextFocused( "Ghost zones:", RealToString( m_worker.GetGhostZonesCount() ) );
#ifndef TRACY_NO_STATISTICS
TextFocused( "Child sample symbols:", RealToString( m_worker.GetChildSamplesCountSyms() ) );
if( ImGui::IsItemHovered() )
{
ImGui::BeginTooltip();
TextFocused( "Child samples:", RealToString( m_worker.GetChildSamplesCountFull() ) );
ImGui::EndTooltip();
}
#endif
TextFocused( "Frame images:", RealToString( ficnt ) );
if( ficnt != 0 && ImGui::IsItemHovered() )
{

View File

@ -1830,12 +1830,29 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks )
it->second.push_back_non_empty( SampleDataRange { time, ip } );
}
}
for( uint16_t i=1; i<callstack.size(); i++ )
{
auto addr = GetCanonicalPointer( callstack[i] );
auto it = m_data.childSamples.find( addr );
if( it == m_data.childSamples.end() )
{
m_data.childSamples.emplace( addr, Vector<Int48>( time ) );
}
else
{
it->second.push_back_non_empty( time );
}
}
}
}
for( auto& v : m_data.symbolSamples )
{
pdqsort_branchless( v.second.begin(), v.second.end(), []( const auto& lhs, const auto& rhs ) { return lhs.time.Val() < rhs.time.Val(); } );
}
for( auto& v : m_data.childSamples )
{
pdqsort_branchless( v.second.begin(), v.second.end(), []( const auto& lhs, const auto& rhs ) { return lhs.Val() < rhs.Val(); } );
}
std::lock_guard<std::mutex> lock( m_data.lock );
m_data.symbolSamplesReady = true;
} ) );
@ -1983,6 +2000,18 @@ uint64_t Worker::GetContextSwitchPerCpuCount() const
return cnt;
}
#ifndef TRACY_NO_STATISTICS
uint64_t Worker::GetChildSamplesCountFull() const
{
uint64_t cnt = 0;
for( auto& v : m_data.childSamples )
{
cnt += v.second.size();
}
return cnt;
}
#endif
uint64_t Worker::GetPidFromTid( uint64_t tid ) const
{
auto it = m_data.tidToPid.find( tid );
@ -2196,6 +2225,14 @@ const Vector<SampleDataRange>* Worker::GetSamplesForSymbol( uint64_t symAddr ) c
if( it == m_data.symbolSamples.end() ) return nullptr;
return &it->second;
}
const Vector<Int48>* Worker::GetChildSamples( uint64_t addr ) const
{
assert( m_data.symbolSamplesReady );
auto it = m_data.childSamples.find( addr );
if( it == m_data.childSamples.end() ) return nullptr;
return &it->second;
}
#endif
const SymbolData* Worker::GetSymbolData( uint64_t sym ) const
@ -5565,11 +5602,11 @@ MemEvent* Worker::ProcessMemFreeImpl( uint64_t memname, MemData& memdata, const
const auto refTime = m_refTimeSerial + ev.time;
m_refTimeSerial = refTime;
if( ev.ptr == 0 ) return nullptr;
auto it = memdata.active.find( ev.ptr );
if( it == memdata.active.end() )
{
if( ev.ptr == 0 ) return nullptr;
if( !m_ignoreMemFreeFaults )
{
CheckThreadString( ev.thread );
@ -5793,6 +5830,19 @@ void Worker::ProcessCallstackSample( const QueueCallstackSample& ev )
}
}
}
for( uint16_t i=1; i<cs.size(); i++ )
{
auto addr = GetCanonicalPointer( cs[i] );
auto it = m_data.childSamples.find( addr );
if( it == m_data.childSamples.end() )
{
m_data.childSamples.emplace( addr, Vector<Int48>( sd.time ) );
}
else
{
it->second.push_back_non_empty( sd.time );
}
}
const auto framesKnown = UpdateSampleStatistics( m_pendingCallstackId, 1, true );
assert( td->samples.size() > td->ghostIdx );

View File

@ -294,6 +294,7 @@ private:
unordered_flat_map<uint64_t, unordered_flat_map<CallstackFrameId, uint32_t, CallstackFrameIdHash, CallstackFrameIdCompare>> instructionPointersMap;
unordered_flat_map<uint64_t, Vector<SampleDataRange>> symbolSamples;
unordered_flat_map<CallstackFrameId, Vector<SampleDataRange>, CallstackFrameIdHash, CallstackFrameIdCompare> pendingSymbolSamples;
unordered_flat_map<uint64_t, Vector<Int48>> childSamples;
bool newFramesWereReceived = false;
bool callstackSamplesReady = false;
bool ghostZonesReady = false;
@ -444,6 +445,10 @@ public:
uint64_t GetGhostZonesCount() const { return m_data.ghostCnt; }
uint32_t GetFrameImageCount() const { return (uint32_t)m_data.frameImage.size(); }
uint64_t GetStringsCount() const { return m_data.strings.size() + m_data.stringData.size(); }
#ifndef TRACY_NO_STATISTICS
uint64_t GetChildSamplesCountSyms() const { return m_data.childSamples.size(); }
uint64_t GetChildSamplesCountFull() const;
#endif
uint64_t GetFrameOffset() const { return m_data.frameOffset; }
const FrameData* GetFramesBase() const { return m_data.framesBase; }
const Vector<FrameData*>& GetFrames() const { return m_data.frames.Data(); }
@ -497,6 +502,7 @@ public:
const VarArray<CallstackFrameId>& GetParentCallstack( uint32_t idx ) const { return *m_data.parentCallstackPayload[idx]; }
const CallstackFrameData* GetParentCallstackFrame( const CallstackFrameId& ptr ) const;
const Vector<SampleDataRange>* GetSamplesForSymbol( uint64_t symAddr ) const;
const Vector<Int48>* GetChildSamples( uint64_t addr ) const;
#endif
const CrashEvent& GetCrashEvent() const { return m_data.crashEvent; }