mirror of
https://github.com/wolfpld/tracy.git
synced 2026-10-23 01:00:54 +00:00
feat(mcp): expose background-load readiness
Smoke-testing the lock fix against a real 143M-zone capture surfaced a second concurrent-mutation source: file loads spawn a background thread that finishes populating zone/symbol statistics after Worker construction returns, so get_all_zone_stats() et al. could silently come back empty or partial with no way to tell "not built yet" from "genuinely empty". Adds is_background_done (a relaxed atomic, same as is_connected, so no locked() wrapper needed) and surfaces it as background_done in list_instances, with load_capture's docstring pointing callers at it.
This commit is contained in:
@@ -385,6 +385,11 @@ async def list_instances() -> list[dict]:
|
||||
kicks in at the `TRACY_MCP_MAX_INSTANCES` cap (LRU, connected live
|
||||
instances are never evicted) or after a disconnected live instance sits
|
||||
idle past `TRACY_MCP_DISCONNECTED_TTL_S`.
|
||||
|
||||
`background_done: false` means a just-loaded capture is still building
|
||||
zone/symbol statistics on a background thread — `get_all_zone_stats`
|
||||
and similar stats-based `eval` queries can return empty or partial
|
||||
results until this flips to true.
|
||||
"""
|
||||
now = time.time()
|
||||
return [
|
||||
@@ -394,6 +399,7 @@ async def list_instances() -> list[dict]:
|
||||
"mtime": inst.mtime,
|
||||
"live": inst.path is None,
|
||||
"connected": inst.worker.is_connected() if inst.path is None and inst.worker else None,
|
||||
"background_done": inst.worker.is_background_done() if inst.worker else None,
|
||||
"idle_seconds": now - inst.last_used,
|
||||
}
|
||||
for name, inst in instances.items()
|
||||
@@ -523,6 +529,12 @@ async def load_capture(path: str, alias: str | None = None) -> str:
|
||||
|
||||
If you don't already have a path, call `list_captures` first — it lists
|
||||
.tracy files in the TRACY_CAPTURES_DIR environment directory.
|
||||
|
||||
Loading returns before zone/symbol statistics finish building — a
|
||||
background thread populates them after the file itself is read. Check
|
||||
`background_done` in `list_instances` (or poll it) before relying on
|
||||
`get_all_zone_stats` and similar stats-based `eval` queries; they can
|
||||
return empty or partial results until it's true.
|
||||
"""
|
||||
if not tracy_server:
|
||||
return "Error: Tracy Server bindings not found."
|
||||
|
||||
@@ -230,14 +230,21 @@ PYBIND11_MODULE( TracyServerBindings, m )
|
||||
|
||||
// --- Sections ---
|
||||
.def( "get_sections", locked( +[]( const Worker& w ) {
|
||||
// GetSections() is keyed by category (multiple named section sets);
|
||||
// flatten across categories, tagging each item with its category name.
|
||||
py::list result;
|
||||
for( auto& s : w.GetSections() )
|
||||
for( const auto& kv : w.GetSections() )
|
||||
{
|
||||
py::dict d;
|
||||
d["start"] = s.start.Val();
|
||||
d["end"] = s.end.Val();
|
||||
d["text"] = std::string( w.GetString( s.text ) );
|
||||
result.append( d );
|
||||
const char* category = w.GetSectionCategoryDescription( kv.first );
|
||||
for( const auto& s : kv.second )
|
||||
{
|
||||
py::dict d;
|
||||
d["category"] = std::string( category );
|
||||
d["start"] = s.start.Val();
|
||||
d["end"] = s.end.Val();
|
||||
d["text"] = std::string( w.GetString( s.text ) );
|
||||
result.append( d );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} ) )
|
||||
@@ -1098,7 +1105,11 @@ PYBIND11_MODULE( TracyServerBindings, m )
|
||||
// --- Connection control ---
|
||||
.def( "is_connected", &Worker::IsConnected )
|
||||
.def( "shutdown", &Worker::Shutdown )
|
||||
.def( "disconnect", &Worker::Disconnect );
|
||||
.def( "disconnect", &Worker::Disconnect )
|
||||
// Plain relaxed atomic like IsConnected() above — no locked()
|
||||
// needed. True once post-load zone/symbol stats have finished
|
||||
// building; get_all_zone_stats() et al. can be empty until then.
|
||||
.def( "is_background_done", &Worker::IsBackgroundDone );
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// FileRead
|
||||
|
||||
Reference in New Issue
Block a user