feat(benchmark): add agentperf benchmark type for trajectory replay - #353
Conversation
Adds an 'agentperf' benchmark runner that drives the agentperf-client trajectory-replay load generator against an srt-slurm-launched server. This is a different client from the InferenceX AgentX harness (NVIDIA#342): agentperf-client is a standalone uv-managed project with a Rust streaming core, invoked as agentperf/run.py, producing per-phase trajectory outputs plus a per-request requests.jsonl. The bench script is a faithful translation of the standalone disagg-harness invocation it was ported from, so results stay comparable: - isolated job-scoped runtime under /tmp (HOME/CARGO_HOME/RUSTUP_HOME/ UV_PROJECT_ENVIRONMENT), read-only-mount friendly - pinned toolchain preflight (rust via rustup archive, uv via pip), uv sync --frozen + maturin rustcore build, tokenizer cache warm - trajectory/user-assignments datasets staged from shared storage to node-local /tmp before measurement, with config paths rewritten - self-validating READY marker (arch + client commit) and an atomic build lock for relocated runtimes The workload definition lives in the client's own config YAML (benchmark.agentperf_config); srtctl injects endpoint, model and concurrency via CLI overrides. rollup.py normalizes per-phase stats into benchmark-rollup.json. Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #353 +/- ##
=======================================
Coverage ? 72.09%
=======================================
Files ? 96
Lines ? 13064
Branches ? 0
=======================================
Hits ? 9418
Misses ? 3646
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Adds scripts/agentperf/port_harness_run.py: a host-side tool that ports a standalone disagg-harness AgentPerf run directory to an srt-slurm recipe + client workload YAML, with a provenance report (every generated field -> source artifact) and a TODO list for the few things it cannot infer (dataset originals, gpu_type, cross-user path reachability). Encodes the translations learned porting the DSV4 c1010 baseline: DYN_KV_BLOCK_SIZE -> DYN_TRTLLM_KV_BLOCK_SIZE, DYN_UCX_TLS -> UCX_TLS, /lustre -> /scratch rewrites, harness-managed env drops, frontend flag reconstruction (without the worker-only --dyn-*-parser flags), taskset -> numa_cpu_bind detection, settle-time recovery from output stems. Verified against the real c1010 run dir: generated recipe matches the hand-validated parity recipe on 176/184 fields (all remaining diffs benign and TODO-flagged) and the workload YAML on 19/19 fields. Signed-off-by: Yuewei Na <nv-yna@users.noreply.github.com>
Parity evidence: script-harness vs srt-slurm orchestration (DSV4 c1010, GB300)The parity gate this PR was drafted against is now closed. The same c1010 configuration (DeepSeek-V4-Pro, 5 prefill workers dep4 + 1 decode worker dep32 across 13 GB300 nodes, dynamo frontend co-located with etcd and prefill_0, agentperf-client pinned at the same tree) was run under srt-slurm orchestration (oci-aga job 592210, recipe
Verdict: no systematic difference from the orchestration translation. The primary metric (server-reported output throughput) lands −0.41% from the reference, well inside the ~1–2% run-to-run band observed between the reference campaign's own single-run variants. TTFT medians agree within ~2%; the p99 tail is noisy across runs and domains in the reference data and the srt-slurm run's tail falls at the favorable edge of the observed band. Notes for reproducers:
🤖 Generated with Claude Code |
What
Adds an
agentperfbenchmark type that lets srt-slurm orchestrate the agentperf-client trajectory-replay load generator (deterministic agentic workload, Rust streaming core, per-phase*__traj*.{jsonl,txt,json}outputs + per-requestrequests.jsonl).This is a different client from the InferenceX AgentX harness in #342 — the two are complementary benchmark types.
Launching an AgentPerf load: client-side steps
Step 0 (optional) — port an existing script-harness run automatically
If you already have a run directory from the standalone disagg-harness (a
bm_agentperf_*/.../c<N>/dir), you don't need to reverse-engineer it by hand — this PR ships a porter:python3 src/srtctl/benchmarks/scripts/agentperf/port_harness_run.py \ /path/to/old/.../c1010 \ --out my-recipe.yaml --workload-out my-workload.yaml \ --dataset-root /scratch/.../datasets # where the original trajectory/assignments liveYou don't need to know how the old harness worked. The script reads the artifacts every harness run leaves behind — the job parameter file (container image, model, concurrency), the engine configs (copied verbatim into the recipe), the client launch script (which pinned agentperf-client checkout was used), the client's own startup banner in
client.log(all workload knobs: phase timeout, settling time, worker/token limits, routing flags, seed), and thesrunlaunch lines injob.log(worker/frontend environment and the node topology) — and emits a ready-to-edit srt-slurm recipe plus the client workload YAML.It also applies the translations that are easy to get wrong when porting by hand: environment variables that only the old harness understood are renamed to the ones dynamo actually reads (e.g. the KV block size, which would otherwise silently fall back to a wrong default), variables that srt-slurm or the container manage are dropped,
/lustrepaths are rewritten for clusters where containers only mount/scratch, CPU pinning is auto-detected from the old worker logs, and frontend flags that would crash the frontend are excluded.Everything it generates is traceable: it prints a provenance report (each field → the artifact it came from) and a TODO list of the few things it cannot infer — chiefly where the original datasets live (the logs only show staged copies;
--dataset-rootlets it search), your cluster'sgpu_type, and whether paths owned by other users are readable from your compute containers. Review the TODOs, then continue at Step 4.Verified: ported the DSV4 c1010 GB300 baseline run and compared against a hand-validated parity recipe — 176/184 recipe fields and 19/19 workload fields identical, every remaining diff benign and TODO-flagged.
Step 1 — mount a pinned agentperf-client checkout
The client is not vendored. Put a checkout at a pinned commit somewhere container-visible and mount it:
Step 2 — write the workload YAML
This is the client's own config (
benchmark.agentperf_config). It carries what the client CLI can't set:settling_time_seconds,user_spawn_rate, stop criteria, dataset paths. Three rules:base_url/model/concurrencies— the client validates the YAML before merging CLI overrides; srtctl then overrides all three at run time.phase_timeout_seconds ≥ (max concurrency − 1)/user_spawn_rate + settling_time_seconds + min_measurement_seconds, computed for the concurrency the recipe injects.Step 3 — recipe benchmark section
Step 4 — validate and submit
srtctl dry-run -f recipe.yaml # shows mounts/env so you can verify before burning nodes srtctl apply -f recipe.yamlStep 5 — what happens and where results land
On first run the bench step preflights an isolated client runtime under
/tmp/agentperf-<jobid>(pinned Rust + uv,uv sync --frozen, maturinrustcorebuild, tokenizer cache) and stages the trajectory/assignments datasets to node-local/tmp— needs network egress from the benchmark node, adds ~5–10 min before the first phase. Results land in the run's log dir:agentperf/*__traj*.{txt,jsonl,json}(per-phase summary + per-request metrics),agentperf/requests.jsonl,agentperf/phase_manifest.jsonl, and a normalizedbenchmark-rollup.json.Implementation notes
src/srtctl/benchmarks/agentperf.py— runner: validatesagentperf_client_dir/agentperf_config/ concurrencies, injects endpoint + served model + concurrency via the client's CLI overrides.scripts/agentperf/bench.sh— a faithful translation of the standalone disagg-harness client invocation (same isolated /tmp runtime layout, pinned rust/uv toolchain preflight,uv sync --frozen+ maturin rustcore build, node-local dataset staging). READY marker is self-validating (arch + client commit) with an atomic build lock for relocated runtimes.scripts/agentperf/port_harness_run.py— the Step-0 porter (host-side tool; provenance report + TODOs).scripts/agentperf/rollup.py— normalizes per-phase stats intobenchmark-rollup.json.BenchmarkConfigfields (agentperf_client_dir,agentperf_config).config-reference.mdtypes table + full section. Tests: runner + porter suites;make check: 1480 passed.Draft until parity is proven
This PR is the first half of a two-step deliverable: the same DSV4 c1010 configuration (5p1d, dep4/dep32, GB300) is being run under srt-slurm orchestration and compared against the script-harness reference numbers (server-reported output throughput, TTFT percentiles). Marking ready once the parity evidence is attached.
🤖 Generated with Claude Code