feat(mcp): get zone stats for a single thread

get_all_zone_stats mixes every thread, so the main-thread cost of a
zone could not be separated from worker threads. get_thread_zone_stats
returns the same per-name stats for the zones recorded on one thread,
and its per-thread sums match get_all_zone_stats exactly.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L3DnWkXakGRgz9C8BaLM47
This commit is contained in:
Alan Tse
2026-10-27 10:04:47 -07:00
co-authored by Claude Sonnet 5.5
parent 0ea62d9551
commit bbb4eebc61
3 changed files with 76 additions and 0 deletions
+36
View File
@@ -323,6 +323,42 @@ PYBIND11_MODULE( TracyServerBindings, m )
return result;
} ) )
.def( "get_thread_zone_stats", locked( +[]( const Worker& w, uint64_t threadId ) {
// Same shape and name handling as get_all_zone_stats(), counting only zones recorded on one thread
py::dict result;
#ifndef TRACY_NO_STATISTICS
std::unordered_map<std::string, int16_t> chosen;
for( const auto& kv : w.GetSourceLocationZones() )
{
if( kv.second.zones.size() == 0 ) continue;
chosen[w.GetZoneName( w.GetSourceLocation( kv.first ) )] = kv.first;
}
for( const auto& kv : w.GetSourceLocationZones() )
{
const std::string name = w.GetZoneName( w.GetSourceLocation( kv.first ) );
const auto it = chosen.find( name );
if( it == chosen.end() || it->second != kv.first ) continue;
int64_t min = INT64_MAX, max = INT64_MIN, total = 0;
double sumSq = 0;
size_t count = 0;
for( const auto& ztd : kv.second.zones )
{
if( w.DecompressThread( ztd.Thread() ) != threadId ) continue;
const auto* z = ztd.Zone();
if( !z || !z->IsEndValid() ) continue;
const int64_t dur = z->End() - z->Start();
total += dur;
sumSq += (double)dur * dur;
count++;
if( dur < min ) min = dur;
if( dur > max ) max = dur;
}
if( count ) result[name.c_str()] = ZoneStats{ min, max, total, sumSq, count, (double)total / count };
}
#endif
return result;
} ), "thread_id"_a )
// --- Per-occurrence zone data (for temporal correlation / distribution) ---
.def( "get_zone_durations", locked( +[]( const Worker& w, const std::string& name, size_t maxSamples ) {
// Accumulates across ALL srclocs with this name (same name can appear at multiple srclocs)