Files
tracy/extra/mcp/eval_guide.md
Alan Tse bee6ac566e docs(mcp): drop dangling tracy://catalog reference
eval_guide.md referenced a tracy://catalog resource that was never
registered (only tracy://prompt and tracy://eval-guide exist), so an
agent following the guide would try to read a nonexistent resource.
Remove the references; the worked snippets the catalog described are
already inlined under "Common query patterns".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016EvfzHvUsDBSAwEzTfLTtA
2026-06-19 15:51:51 -07:00

75 lines
3.2 KiB
Markdown

# Tracy MCP eval guide
This document covers the bindings-layer detail that the analysis
guidance (`tracy://prompt`) does not.
## ctx
`ctx` is a `TracyServerBindings.Worker` — the same object Tracy Assist's
C++ tools query through `Worker::Get*`. The pybind methods are the canonical
data surface. Common entry points:
- Zones: `get_all_zone_stats()` (every callsite, large), `get_root_zone_stats()`
(top-level zones only, useful for "where is the program spending time"),
`get_zone_stats(srcloc_id)`, `get_child_zone_stats(srcloc_id)` (subtract for
self-time), `get_zone_durations(name)`, `get_zone_count()`,
`get_all_zone_source_locations()`
- GPU zones: `get_all_gpu_zone_stats()`, `get_gpu_zone_durations(...)`,
`get_gpu_contexts()`
- Frames: `get_frame_count()`, `get_frame_times()`, `get_frame_times_named(name)`,
`get_frame_boundaries()`, `get_zones_in_frame(...)`
- Threads: `get_threads()`, `get_thread_name(tid)`, `get_thread_context_switches(tid)`
- Messages / plots / locks / memory / callstacks: `get_messages()`, `get_plots()`,
`get_locks()`, `get_memory_events()`, `get_callstack_frames(...)`
- Sections: `get_sections()` — timed code sections from
`TracySectionEnter`/`TracySectionLeave` instrumentation. Returns a list of
`{start, end, text}` dicts (start/end in ns).
- Capture metadata: `get_capture_name()`, `get_capture_program()`,
`get_first_time()`, `get_last_time()`, `get_resolution()`, `get_host_info()`
Run `print([m for m in dir(ctx) if not m.startswith('_')])` for the full list.
## Units and conventions
- All time values returned by Worker methods are **nanoseconds** (int).
`get_first_time()` / `get_last_time()` bound the capture timeline.
- `ZoneStats` fields: `count`, `total`, `min`, `max`, `avg`, `sum_sq`. `total`
is the inclusive aggregate; use `get_child_zone_stats(srcloc_id)` to subtract
child time when you need self-time.
- `get_all_zone_stats()` returns `dict[str, ZoneStats]` keyed by an opaque label
of the form `'name (addr)[arch] <srcloc_id>'`. The trailing `<id>` is the
source-location ID — the int accepted by `get_zone_stats(int)`,
`get_zone_durations_by_id`, and friends. Parse it with a regex if you need
to join across calls.
- Source-location IDs from `get_all_zone_source_locations()` are the join key
between zone-name lookups and per-callsite queries.
## Common query patterns
Small Python snippets for the queries you'll reach for most often:
```python
# top 10 hottest zones by total time
top = sorted(ctx.get_all_zone_stats().items(),
key=lambda kv: kv[1].total, reverse=True)[:10]
for k, v in top:
print(f"{v.total/1e6:.2f}ms count={v.count} {k}")
# primary frame set timing
times = ctx.get_frame_times() # ns per frame
print(f"frames={len(times)} avg={sum(times)/len(times)/1e6:.2f}ms "
f"p99={sorted(times)[int(len(times)*0.99)]/1e6:.2f}ms")
# stats for a named zone — find the srcloc id, then drill in
import re
matches = [k for k in ctx.get_all_zone_stats() if k.startswith("MyFunc ")]
sid = int(re.search(r"<(\d+)>$", matches[0]).group(1))
stats = ctx.get_zone_stats(sid)
```
## Async mode
For long-running queries pass `async_mode=True` to `eval`; it returns
`{task_id, status: "running"}`. Poll with the `task` tool
(`action="poll", task_id=...`).