Repository navigation
feat(compare): score a trace replay against production's record of the same requests - #44
fergusfinn wants to merge 2 commits into
Conversation
…e same requests batchbench-compare-trace-replay joins a manifest's metadata.requests and the agent's request events to the Dynamo trace rows they came from, and reports both sides over a scoring window: failures, first-token, time per output token and end-to-end percentiles, and the share within a latency bound. A production context file splits production by worker set and gives each set's throughput per GPU beside the replay's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDPqeFzGgF3vkuiyimwMxX
There was a problem hiding this comment.
3 issues found across 5 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/batchbench/trace_replay.py">
<violation number="1" location="src/batchbench/trace_replay.py:108">
P2: `within_slo` counts every successful request with missing TPOT as within SLO, even when it has two or more output tokens. Restrict the missing-TPOT exception to requests with fewer than two output tokens.</violation>
<violation number="2" location="src/batchbench/trace_replay.py:123">
P2: A malformed or truncated trace line containing `"request_end"` crashes the comparison before it can report valid rows from the file. Parse the row defensively and skip malformed or non-mapping lines, matching `load_trace_records` behavior.</violation>
<violation number="3" location="src/batchbench/trace_replay.py:225">
P1: The documented replay-events input cannot be produced by `batchbench-agent`: it exposes only `--agent-events-jsonl`, which writes agent lifecycle records without `invocation` or request timings. Add the per-request event output (or consume the existing format) and update the command/docs consistently.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Turn on auto-fix | Re-trigger cubic
| description="Compare a replay of Dynamo request traces with production's record of the same requests.", | ||
| ) | ||
| parser.add_argument("--manifest", required=True, help="the replayed manifest (batchbench-export-plans --dynamo-traces)") | ||
| parser.add_argument("--request-events", required=True, help="the replay's batchbench-agent --request-events-jsonl") |
There was a problem hiding this comment.
P1: The documented replay-events input cannot be produced by batchbench-agent: it exposes only --agent-events-jsonl, which writes agent lifecycle records without invocation or request timings. Add the per-request event output (or consume the existing format) and update the command/docs consistently.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/batchbench/trace_replay.py, line 225:
<comment>The documented replay-events input cannot be produced by `batchbench-agent`: it exposes only `--agent-events-jsonl`, which writes agent lifecycle records without `invocation` or request timings. Add the per-request event output (or consume the existing format) and update the command/docs consistently.</comment>
<file context>
@@ -0,0 +1,272 @@
+ description="Compare a replay of Dynamo request traces with production's record of the same requests.",
+ )
+ parser.add_argument("--manifest", required=True, help="the replayed manifest (batchbench-export-plans --dynamo-traces)")
+ parser.add_argument("--request-events", required=True, help="the replay's batchbench-agent --request-events-jsonl")
+ parser.add_argument("--dynamo-traces", action="append", required=True, metavar="PATH",
+ help="production trace files: a directory, file or glob; repeatable")
</file context>
| for line in _trace_lines(path, stats): | ||
| if f'"{TRACE_EVENT}"' not in line: | ||
| continue | ||
| request = json.loads(line).get("request") or {} |
There was a problem hiding this comment.
P2: A malformed or truncated trace line containing "request_end" crashes the comparison before it can report valid rows from the file. Parse the row defensively and skip malformed or non-mapping lines, matching load_trace_records behavior.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/batchbench/trace_replay.py, line 123:
<comment>A malformed or truncated trace line containing `"request_end"` crashes the comparison before it can report valid rows from the file. Parse the row defensively and skip malformed or non-mapping lines, matching `load_trace_records` behavior.</comment>
<file context>
@@ -0,0 +1,272 @@
+ for line in _trace_lines(path, stats):
+ if f'"{TRACE_EVENT}"' not in line:
+ continue
+ request = json.loads(line).get("request") or {}
+ request_id = request.get("request_id")
+ in_window = model is not None and request.get("model") == model and lo_ms <= (request.get("request_received_ms") or 0) < hi_ms
</file context>
| request = json.loads(line).get("request") or {} | |
| try: | |
| row = json.loads(line) | |
| except ValueError: | |
| continue | |
| if not isinstance(row, Mapping): | |
| continue | |
| request = row.get("request") or {} | |
| if not isinstance(request, Mapping): | |
| continue |
| """Succeeded, first token within the bound, and time per output token within its bound (or under two tokens).""" | ||
|
|
||
| return (timing.ok and timing.ttft_s is not None and timing.ttft_s <= slo_ttft_s | ||
| and (timing.tpot_s is None or timing.tpot_s <= slo_tpot_s)) |
There was a problem hiding this comment.
P2: within_slo counts every successful request with missing TPOT as within SLO, even when it has two or more output tokens. Restrict the missing-TPOT exception to requests with fewer than two output tokens.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/batchbench/trace_replay.py, line 108:
<comment>`within_slo` counts every successful request with missing TPOT as within SLO, even when it has two or more output tokens. Restrict the missing-TPOT exception to requests with fewer than two output tokens.</comment>
<file context>
@@ -0,0 +1,272 @@
+ """Succeeded, first token within the bound, and time per output token within its bound (or under two tokens)."""
+
+ return (timing.ok and timing.ttft_s is not None and timing.ttft_s <= slo_ttft_s
+ and (timing.tpot_s is None or timing.tpot_s <= slo_tpot_s))
+
+
</file context>
|
Virtual Fergus: reviewed, looks right.
|
Trace and prompt-chain records don't say whether a request was streamed, so exported requests went out non-streamed and batchbench-agent recorded no first-token time or time per output token for them. --stream sets stream: true on every request; the comparison docs say to use it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDPqeFzGgF3vkuiyimwMxX
There was a problem hiding this comment.
0 issues found across 3 files (changes from recent commits).
Requires human review: Auto-approval blocked by 3 unresolved issues from previous reviews.
View guided diff | Turn on auto-fix | Re-trigger cubic
|
Virtual Fergus: re-reviewed at 59ab413 ( One wording fix. The |
Adds
batchbench-compare-trace-replay, which scores a replay of Dynamo request traces against production's own record of the same requests.It joins three inputs on each request's source row:
metadata.requests(feat(export): name each trace request's source row in trajectory metadata #42), which names each request's source row;--request-events-jsonl(feat(agent): record per-request timings with --request-events-jsonl #41), which holds the replay's client-side timings;Over a scoring window of source time, it reports for both sides:
A failed replayed request counts against that share.
--replay-gpusadds the replay's throughput per GPU. An optional production context file maps decode worker ids to worker sets and gives each set's GPUs. With it, production's figures are split by set, and with--modeleach set's throughput per GPU over the window is reported beside the replay's.Only requests whose source arrived inside the window count. That lets an export that starts earlier warm the replay's caches before scoring begins.
Stacked on #42.
Checked end to end on a real manifest: a 1/16 session sample of GLM-5.3-Flash, 12 Nov 17:30–19:00, scored over 18:00–19:00.
Tests: 44 pass, 2 skipped (they need the compiled agent).
🤖 Generated with Claude Code
https://claude.ai/code/session_01VDPqeFzGgF3vkuiyimwMxX