Skip to content

[AMD] [AGENTX] dsv4-fp4-mi355x-vllm-agentic: DEP tuning + LMCache refresh (MTP variant) - #2381

Open
seungrokj wants to merge 29 commits into
mainfrom
amd/agentx_dsv4_vllm_mtp_0728
Open

[AMD] [AGENTX] dsv4-fp4-mi355x-vllm-agentic: DEP tuning + LMCache refresh (MTP variant)#2381
seungrokj wants to merge 29 commits into
mainfrom
amd/agentx_dsv4_vllm_mtp_0728

Conversation

@seungrokj

Copy link
Copy Markdown
Collaborator

Summary

Adds an MTP (multi-token-prediction) variant of the DeepSeek-V4-Pro FP4 MI355X vLLM agentic recipe.

benchmarks/single_node/agentic/dsv4_fp4_mi355x_vllm_mtp.sh (new)

  • Derived from dsv4_fp4_mi355x_vllm.sh, adds --speculative-config with method=mtp, num_speculative_tokens=3.
  • Throughput runs pin synthetic MTP acceptance to the dsv4-pro golden AL (synthetic_acceptance_length=2.49); EVAL_ONLY accuracy runs use real target verification (synthetic acceptance bypasses verification and zeroes the eval score).
  • Carries the shared fixes from the non-MTP recipe: EVAL_FRAMEWORK=lm-eval; per-DP-rank --max-num-seqs (2*CONC/TP under DP-attn); DEP8 --max-num-batched-tokens = MNBT*2 (16384, avoids the rocBLASLt/TensileLite segfault at M=65536); GPU_MEM_UTIL=0.85 (MI355X ~32 GiB/GPU carveout → 0.95 OOMs at init); lmcache v0.5.2, chunk-size 1024, undivided CPU pool.

configs/amd-master.yaml

  • New dsv4-fp4-mi355x-vllm-agentic-mtp entry; active arm TP8/DPA GPU-resident (kv-offloading: none) conc 48 (other arms commented for later sweeps).

Test plan

  • Full-sweep CI green for dsv4-fp4-mi355x-vllm-agentic-mtp
  • Server reaches ready with --speculative-config MTP (no init OOM at 0.85)
  • EVAL_ONLY path uses real verification (non-zero lm-eval score)

🤖 Generated with Claude Code

New MTP agentic recipe for DeepSeek-V4-Pro FP4 on MI355X vLLM, derived from the
non-MTP recipe with --speculative-config method=mtp num_speculative_tokens=3.
Throughput runs pin synthetic MTP acceptance to the dsv4-pro golden AL; EVAL_ONLY
uses real target verification (synthetic acceptance corrupts the eval score).
Carries the shared fixes: EVAL_FRAMEWORK=lm-eval, per-DP-rank max-num-seqs,
DEP8 max-num-batched-tokens MNBT*2, GPU_MEM_UTIL=0.85, lmcache v0.5.2.

amd-master.yaml: add dsv4-fp4-mi355x-vllm-agentic-mtp entry (TP8/DPA GPU-resident
conc 48; other arms commented for later sweeps).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the contribution! Please reach out to respective companies' CODEOWNER to fill in the latest PR_REVIEW_CHECKLIST.md before pinging core maintainer on Slack for review. In order for the signoff PR check bot to trigger, you must follow the PR_REVIEW_CHECKLIST.md template correctly, including the phrase As a PR reviewer and CODEOWNER, I have reviewed this and have.

For PR verification, add the full-sweep-fail-fast label (strongly recommended) to this PR — the benchmark sweep only runs on labeled PRs. Use full-sweep-enabled only if you need matrix jobs to keep running past a failure.

PR authors are responsible for ensuring that after merging, all GitHub Action jobs fully pass. A lot of the time, failures are just flakes and simply re-running the failed jobs will fix it. See GitHub's docs on re-running failed jobs


感谢你的贡献!请联系相应公司的 CODEOWNER 填写最新的 PR_REVIEW_CHECKLIST.md,然后再在 Slack 上联系核心维护者进行审阅。为了触发 signoff PR 检查机器人,你必须正确遵循 PR_REVIEW_CHECKLIST.md 模板,包括保留英文语句 As a PR reviewer and CODEOWNER, I have reviewed this and have

如需进行 PR 验证,请为此 PR 添加 full-sweep-fail-fast 标签(强烈推荐)— 基准测试 sweep 仅在带有标签的 PR 上运行。仅当需要矩阵任务在失败后继续运行时才使用 full-sweep-enabled

PR 作者有责任确保合并后所有 GitHub Action 任务完全通过。 很多时候失败只是偶发抖动(flake),重新运行失败的任务即可解决。参见 GitHub 关于重新运行失败任务的文档

…2381

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@seungrokj seungrokj changed the title [AMD] [AGENTX] Add dsv4-fp4-mi355x-vllm-agentic-mtp (MTP variant) [AMD] [AGENTX] dsv4-fp4-mi355x-vllm-agentic: DEP tuning + LMCache refresh (MTP variant) Jul 28, 2026
@seungrokj seungrokj added AMD full-sweep-fail-fast evals-only Suppress throughput and run only eval jobs; combine with all-evals to expand selection agentx AgentX benchmarks, recipes, and infrastructure labels Jul 28, 2026
Comment on lines +413 to +421
# MTP: cudagraph capture sizes are in TOKENS. With num_speculative_tokens=N,
# every uniform decode batch of S seqs verifies S*(1+N) tokens, so capture the
# explicit multiples (1+N), 2*(1+N), ..., MAX_NUM_SEQS*(1+N) -- one graph per
# decode batch of 1..MAX_NUM_SEQS seqs. vLLM rounds configured sizes up to
# multiples of (1+N) and dedups (adjust_cudagraph_sizes_for_spec_decode), so a
# plain 1..MAX_NUM_SEQS list would collapse to coverage of only
# MAX_NUM_SEQS/(1+N) seqs and drop the largest decode batches to eager.
NUM_SPEC_TOKENS=3
TOKENS_PER_SEQ=$((1 + NUM_SPEC_TOKENS))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 TOKENS_PER_SEQ is computed at line 421 (with a comment explaining that explicit cudagraph_capture_sizes of num_seqs*TOKENS_PER_SEQ must be passed for each num_seqs in 1..MAX_NUM_SEQS to avoid vLLM's adjust_cudagraph_sizes_for_spec_decode dropping the largest decode batches to eager) but is never actually applied — the --compilation-config on line 462 has no cudagraph_capture_sizes key. This is an incomplete port of the sibling dsv4_fp4_b300_vllm_mtp.sh recipe, which builds and embeds this list via a loop; at the only active arm (conc=48), the largest decode batches will silently fall back to eager execution, undercutting the MTP throughput this benchmark is meant to measure.

Extended reasoning...

What the bug is: Lines 413-419 of dsv4_fp4_mi355x_vllm_mtp.sh contain a comment — copied verbatim from benchmarks/single_node/agentic/dsv4_fp4_b300_vllm_mtp.sh — explaining that with MTP speculative decoding, cudagraph capture sizes must be specified in tokens, not sequences: since every uniform decode batch of S sequences verifies S*(1+N) tokens (where N = num_speculative_tokens), the recipe needs to pass explicit capture sizes 1*(1+N), 2*(1+N), ..., MAX_NUM_SEQS*(1+N) via --compilation-config's cudagraph_capture_sizes field. Otherwise vLLM's adjust_cudagraph_sizes_for_spec_decode rounds/dedups the default capture-size list to multiples of (1+N), which collapses coverage and drops the largest decode batches to eager execution.

Line 421 computes TOKENS_PER_SEQ=$((1 + NUM_SPEC_TOKENS)) in preparation for this — but that's the last time the variable is referenced anywhere in the file. The actual --compilation-config passed to vllm serve on line 462 is just the plain '{"mode":3,"cudagraph_mode":"FULL_DECODE_ONLY"}', with no cudagraph_capture_sizes key at all.

Code path / proof: Compare directly against the sibling recipe this was derived from, benchmarks/single_node/agentic/dsv4_fp4_b300_vllm_mtp.sh (lines ~254-279 in that file): it carries the identical explanatory comment, computes the identical TOKENS_PER_SEQ = 1 + NUM_SPEC_TOKENS, and then actually uses it — a for ((num_seqs=1; num_seqs<=MAX_NUM_SEQS; num_seqs++)) loop builds a CUDA_GRAPH_CAPTURE_SIZES string of num_seqs*TOKENS_PER_SEQ values, which is embedded into COMPILATION_CONFIG's cudagraph_capture_sizes field and passed to vllm serve. The MI355X MTP script under review copied the comment and the TOKENS_PER_SEQ line but dropped both the loop and the resulting compilation-config field — a clear incomplete copy-paste. A grep -n "TOKENS_PER_SEQ\|compilation-config" over the file confirms only two hits: the dead assignment at line 421 and the plain config at line 462, with no cudagraph_capture_sizes anywhere.

Concretely, for the only active arm in configs/amd-master.yaml (dp-attn: true, TP8, conc-list: [48]), MAX_NUM_SEQS = 2*48/8 = 12 per DP rank, and TOKENS_PER_SEQ = 1 + 3 = 4. The comment's own stated intent is to capture token-sizes 4, 8, 12, ..., 48 (one graph per decode batch of 1..12 sequences). Without explicit sizes, vLLM's adjust_cudagraph_sizes_for_spec_decode instead rounds/dedups its own default size list to multiples of 4, which per the comment's own logic collapses coverage and drops the largest decode batches to eager execution — silently degrading exactly the throughput this MTP recipe exists to measure.

Why nothing else catches this: There's no functional/type check that would fail — TOKENS_PER_SEQ is just an unused shell variable (a shellcheck SC2034 case), and the server will start and serve requests fine with the plain compilation-config; it just does so less efficiently for the largest decode batches, which won't surface as a CI failure, only as suppressed throughput numbers in benchmark output.

Fix: Port the loop from dsv4_fp4_b300_vllm_mtp.sh — build a CUDA_GRAPH_CAPTURE_SIZES array/string over num_seqs in 1..MAX_NUM_SEQS multiplying by TOKENS_PER_SEQ, and embed it as a cudagraph_capture_sizes key in the --compilation-config JSON passed to vllm serve on line 462.

Severity: I'm marking this normal rather than nit. While it won't crash the server or fail CI, the entire purpose of this new recipe is to measure MTP throughput, and this omission causes the benchmark to systematically under-measure that throughput at its one active concurrency by falling back to eager execution for the largest decode batches — a real, silent measurement defect in the recipe's core deliverable, not a cosmetic issue.

Comment on lines +227 to +247
LMCACHE_PID=""

cleanup_lmcache_server() {
if [[ -n "$LMCACHE_PID" ]] && kill -0 "$LMCACHE_PID" 2>/dev/null; then
kill "$LMCACHE_PID" 2>/dev/null || true
wait "$LMCACHE_PID" 2>/dev/null || true
fi
}

trap cleanup_lmcache_server EXIT

cleanup_agentic_services() {
local exit_code=$?
trap - EXIT INT TERM
set +e
stop_background_process_tree "$ROUTER_PID" "vLLM router"
stop_background_process_tree "$SERVER_PID" "vLLM server" 60
stop_background_process_tree "$MOONCAKE_MASTER_PID" "Mooncake master"
exit "$exit_code"
}
trap cleanup_agentic_services EXIT

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The lmcache-backend branch registers 'trap cleanup_lmcache_server EXIT' (line 236) to reap the standalone LMCache MP server, but it is immediately overwritten by 'trap cleanup_agentic_services EXIT' (line 247) — bash EXIT traps don't stack, so only the latter runs and LMCACHE_PID is never killed, leaking the process (and its DRAM pool + ports 5555/8080) on every exit. This is dormant today since the only active amd-master.yaml arm uses kv-offloading:none, but will trigger the moment a commented-out lmcache arm is enabled; fix by folding LMCACHE_PID teardown into cleanup_agentic_services. Note the identical bug already exists in the sibling dsv4_fp4_mi355x_vllm.sh this file was derived from.

Extended reasoning...

The bug: In the lmcache KV_OFFLOAD_BACKEND branch, line 236 registers trap cleanup_lmcache_server EXIT to kill the standalone LMCache MP server (LMCACHE_PID) on exit. Eleven lines later, line 247 registers trap cleanup_agentic_services EXIT. Bash traps do not stack per signal — only the most recently registered handler for a given signal fires. So cleanup_lmcache_server becomes dead code from the moment it's overwritten, and only cleanup_agentic_services ever runs on exit.

Why the surviving handler doesn't cover it: cleanup_agentic_services calls stop_background_process_tree on ROUTER_PID, SERVER_PID, and MOONCAKE_MASTER_PID only. LMCACHE_PID is never referenced inside it. The LMCache MP server is started later ("${LMCACHE_CMD[@]}" ... & LMCACHE_PID=$!) as a direct child of the script, not a descendant of any of the three tracked process trees, so none of the existing cleanup calls can reap it either directly or transitively.

Trigger path: Any run with KV_OFFLOAD_BACKEND=lmcache hits this on every exit path — normal completion, INT (routes to exit 130), and TERM (routes to exit 143) all funnel through the single surviving EXIT trap. cleanup_agentic_services runs, disables all traps (trap - EXIT INT TERM), stops the three tracked processes, and exits — leaving the LMCache server process running as an orphan.

Step-by-step proof:

  1. Script enters the lmcache) case arm, defines cleanup_lmcache_server, and runs trap cleanup_lmcache_server EXIT (line 236). At this point, EXIT → cleanup_lmcache_server.
  2. Immediately after, the script defines cleanup_agentic_services and runs trap cleanup_agentic_services EXIT (line 247). Bash's trap table now maps EXIT → cleanup_agentic_services only; the line-236 registration is gone with no way to recover it (traps replace, they don't compose).
  3. Later (line ~350) the script launches "${LMCACHE_CMD[@]}" > "$LMCACHE_LOG" 2>&1 & and captures LMCACHE_PID=$!.
  4. Script eventually exits (success, or via the INT/TERM handlers calling exit). The EXIT trap fires cleanup_agentic_services, which does trap - EXIT INT TERM, stops router/server/mooncake-master, and calls exit "$exit_code".
  5. cleanup_lmcache_server never executes; LMCACHE_PID was never signaled. The LMCache server process, holding its large CPU KV pool and bound to ports 5555/8080, survives the script's exit as an orphan.

Impact: On a shared/reused node, the orphaned LMCache server continues holding host DRAM (the recipe sizes this pool from TOTAL_CPU_DRAM_GB, intended to be a large fraction of ~2.7 TiB) and keeps ports 5555/8080 bound, which would block or corrupt a subsequent lmcache run on the same node (port-bind failure or unexpected interaction with a stale server).

Why it doesn't fail this PR today: The sole active search-space arm for dsv4-fp4-mi355x-vllm-agentic-mtp in configs/amd-master.yaml is kv-offloading: none — every lmcache arm is commented out. So the lmcache) case branch, and this trap-overwrite bug, cannot execute in the current config. It's genuinely dormant, but it is new code introduced by this PR and copied verbatim from the pre-existing bug in the sibling benchmarks/single_node/agentic/dsv4_fp4_mi355x_vllm.sh.

Fix: Fold LMCACHE_PID teardown into cleanup_agentic_services (e.g. add a stop_background_process_tree "$LMCACHE_PID" "LMCache server" call, guarded by the variable being set) and drop the now-redundant standalone cleanup_lmcache_server/first trap ... EXIT registration, so there is exactly one EXIT handler that tears down every backgrounded process.

Comment thread configs/amd-master.yaml Outdated
Comment on lines +1548 to +1555
agentic-coding:
- dram-utilization: 0.80
search-space:
#- { tp: 8, ep: 1, dp-attn: false, kv-offloading: none, conc-list: [1, 4, 8, 16, 32, 40, 48] }
#- { tp: 8, ep: 1, dp-attn: true, kv-offloading: none, conc-list: [64, 72], router: { name: vllm-router, version: "0.1.14" } }
#- { tp: 8, ep: 1, dp-attn: false, kv-offloading: dram, kv-offload-backend: { name: lmcache, version: "9229067cec0b3a63bb8a39368d101db7ac0bc3c1" }, conc-list: [32, 40, 48] }
#- { tp: 8, ep: 1, dp-attn: true, kv-offloading: dram, kv-offload-backend: { name: lmcache, version: "v0.5.2" }, conc-list: [76] }
- { tp: 8, ep: 1, dp-attn: true, kv-offloading: none, conc-list: [48] }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The active dp-attn:true search-space row (line 1555) is missing the router: { name: vllm-router, version: "0.1.14" } field that every other dp-attn agentic row in this file carries (including this entry's own commented-out equivalent on line 1552). The launch script hardcodes USE_VLLM_ROUTER=true and deploys vllm-router 0.1.14 whenever DP_ATTENTION=true, so the router really is running — but since generate_sweep_configs.py only pulls router metadata from this YAML field, the published result for this run will be missing router attribution.

Extended reasoning...

The new dsv4-fp4-mi355x-vllm-agentic-mtp entry's only active search-space row (configs/amd-master.yaml:1555, { tp: 8, ep: 1, dp-attn: true, kv-offloading: none, conc-list: [48] }) omits the router field. This is inconsistent with every other dp-attn: true agentic row in the file, including:

  • The sibling non-MTP entry dsv4-fp4-mi355x-vllm-agentic's equivalent dp-attn: true row (line 1531), which carries router: { name: vllm-router, version: "0.1.14" }.
  • This entry's own commented-out dp-attn: true row (line 1552), which also carries the same router field — strong evidence the field was dropped when the commented row was copied into the active one, rather than omitted intentionally.

The code path that makes this matter: utils/matrix_logic/generate_sweep_configs.py's component_metadata() (lines 194-201) resolves router metadata via benchmark.get('router', config.get('router')) — i.e. only from the top-level recipe entry or the per-row router field in the YAML. The MTP entry has neither a top-level router: key nor a router field on its active row, so component_metadata() returns no router info. That flows into ROUTER_METADATA (benchmark-tmpl.yml:173), which process_result.py (lines 77-79) only writes into the published result's router key when present.

Meanwhile, the new launch script benchmarks/single_node/agentic/dsv4_fp4_mi355x_vllm_mtp.sh sets USE_VLLM_ROUTER=true and runs agentic_pip_install --quiet "vllm-router==$VLLM_ROUTER_VERSION" (VLLM_ROUTER_VERSION=0.1.14) purely based on DP_ATTENTION=true, independent of the YAML router field. So the run genuinely deploys vllm-router 0.1.14 as a component of the serving stack, but the published benchmark result for this arm will have no router key at all, unlike every sibling dp-attn agentic result.

Concrete walkthrough:

  1. Sweep config generation reads the active row { tp: 8, ep: 1, dp-attn: true, kv-offloading: none, conc-list: [48] } — no router key present, and the dsv4-fp4-mi355x-vllm-agentic-mtp entry has no benchmark-level router: either.
  2. component_metadata() computes ROUTER = benchmark.get('router', config.get('router'))None for this row.
  3. ROUTER_METADATA env var is left unset for the job.
  4. The launch script independently sees DP_ATTENTION=true and sets USE_VLLM_ROUTER=true, installs and starts vllm-router==0.1.14, and actually routes traffic through it.
  5. process_result.py checks get_optional_component_metadata('ROUTER_METADATA'), finds nothing, and omits router from the published result JSON.
  6. Result: dashboards/analysis for this arm silently lack router attribution that every other dp-attn agentic arm (including the sibling non-MTP entry) records, even though the underlying infra is identical.

Fix: add router: { name: vllm-router, version: "0.1.14" } to the active row at line 1555, matching the commented-out row directly above it and the sibling non-MTP entry.

Impact assessment: this is metadata/attribution-only — the router field is Optional throughout validation.py, nothing crashes, the run itself is unaffected, and benchmark numbers (throughput/latency) are computed independent of this field. It does not block the sweep or change measured performance, so this is a real but low-severity oversight worth a one-line fix before merge.

Override the per-DP-rank sizing for the MTP recipe; use 2*CONC unconditionally
for better throughput.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

1 similar comment
@github-actions

Copy link
Copy Markdown
Contributor

…tp + vllm-router

Add spec-decoding: mtp to all search-space arms so the launcher's SPEC_SUFFIX
routes to dsv4_fp4_mi355x_vllm_mtp.sh (without it, SPEC_DECODING is none and the
non-MTP script runs); add the vllm-router 0.1.14 to the active DP-attention arm.
Fix a missing closing brace on the active-arm flow mapping.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

…k max-num-seqs

Restore MAX_NUM_SEQS=2*CONC/TP under DP-attention (2*CONC in pure-TP). At 2*CONC
(=96) the MTP cudagraph capture list grew to 512 sizes and the activation budget
left only 23.36 GiB for KV cache -- below the 24.06 GiB needed for one max-len
request, so engine init failed in _check_enough_kv_cache_memory. Per-rank sizing
shrinks the capture/activation footprint so KV cache fits.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

seungrokj and others added 2 commits July 29, 2026 10:35
…86 for MTP KV headroom

At 0.85 the ~23.9 GiB KV budget falls below the 24.06 GiB one 1M-context
request needs once the MTP draft layer's per-token KV is counted, so engine
init dies on the tighter eval-only relaunch. 0.86 adds ~2.6 GiB (nearly all
to KV) while staying ~8 GiB under the free-mem hard-fail ceiling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

@seungrokj seungrokj removed the evals-only Suppress throughput and run only eval jobs; combine with all-evals to expand selection label Jul 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

…oad-backend key

Remove the accidentally duplicated kv-offload-backend key on the
vllm-native dram arm.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

… versions, raise GPU_MEM_UTIL to 0.90

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

seungrokj and others added 2 commits July 30, 2026 09:36
…n to 0.60

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ram arm

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

seungrokj and others added 2 commits July 30, 2026 12:04
…5.2 and set DP-attn max-num-seqs to CONC

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

cquil11 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

@seungrokj the AgentX/AIPerf harness has been updated, please merge origin/main into your branch and refresh your submission. Additional tuning may be necessary depending on the config. I apologize for any inconvenience.

This is an automated message.

@github-actions

Copy link
Copy Markdown
Contributor

seungrokj and others added 2 commits July 30, 2026 16:51
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agentx AgentX benchmarks, recipes, and infrastructure AMD full-sweep-enabled

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants