Skip to content

Commit bb00055

Browse files
ichbinblauchunfangamdChuanLi1101simondanielssonclaude
authored
[AMD] vLLM Kimi MXFP4 & MiniMax M2.5 FP8 disaggregated prefill-decode for MI355X (#1569)
* [AMD] Add vLLM disaggregated prefill-decode benchmark for MI355X Add multi-node vLLM PD disaggregation recipe using Nixl/RIXL KV transfer and vllm-router, mirroring the existing SGLang disagg recipe structure. - New benchmark config: dsr1-fp8-mi355x-vllm-disagg (1P2D, TP8) - New utils: vllm_disagg_utils/ (job.slurm, server.sh, submit.sh, etc.) - Runner: extend launch_mi355x-amds.sh for vllm-disagg framework * [AMD] Refactor vLLM disagg recipe: models.yaml, UCX cleanup, QoS support Extract hardcoded model configurations from server.sh bash maps and job.slurm VALID_MODELS into a declarative models.yaml, mirroring the SGLang disagg recipe pattern. Adding a new model now requires no script changes. Also: - Consolidate UCX transport vars in job.slurm Docker env; remove duplicated setup_ucx_env() from server.sh - Extract RDMA workarounds (ionic /31 route fix, Nixl UCX patch) into setup_rdma_env() helper - Lower UCX_LOG_LEVEL from info to warn - Add nicctl mount and QoS/DSCP auto-detection to env.sh - Remove stale host libionic bind-mounts (driver now built into image) * [AMD] Update vLLM disagg recipe for v0.17.1 NixlConnector API Adapt server.sh to vLLM v0.17.1 breaking changes: - Use simplified kv-transfer-config (side channel via env vars instead of kv_ip/kv_port, add kv_load_failure_policy) - Remove deprecated --disable-log-requests (disabled by default in v0.17) - Route NIXL side channel through RDMA IP for correct fabric path - Fix RIXL ucx_error_handling_mode patch for updated _api.py layout * [AMD] Make vLLM disagg recipe CI-compatible (mia1 cluster) bench.sh: replace `vllm bench serve` (log-only output) with the shared run_benchmark_serving helper from benchmark_lib.sh, matching the SGLang disagg pattern. This produces the .json result files that the multinode CI workflow expects (benchmark-multinode-tmpl.yml → process_result.py). server.sh: make the Nixl ucx_error_handling_mode=none runtime patch conditional on Pensando ionic RDMA devices (IBDEVICES=*ionic*). On the mia1 cluster (ConnectX/mlx5, IBDEVICES=rdma*), UCX handles error mode natively and the patch is skipped. Model-path resolution and IBDEVICES/UCX/QoS auto-detection were verified to already work on mia1 — no changes needed. Tested locally (Job 2802, 1P+2D, ISL/OSL=1024): conc 8 → 507 tok/s conc 32 → 1778 tok/s conc 16 → 1004 tok/s conc 64 → 2480 tok/s All four .json result files produced; 100% external prefix cache hit rate. * [AMD] Co-locate vLLM disagg router with prefill on NODE_RANK=0 Move the vllm-router from a dedicated proxy node onto the first prefill node, mirroring SGLang's co-location pattern. This reduces the node count from xP + yD + 1 to xP + yD (e.g., 3 nodes instead of 4 for 1P+2D). - server.sh: NODE_RANK=0 now runs both vllm serve (prefill, port 2584) and vllm-router (port 30000); barrier waits on all nodes - submit.sh / job.slurm: NUM_NODES = PREFILL_NODES + DECODE_NODES - bench.sh: ROUTER_PORT default updated to 30000 Local 1P+2D benchmark (ISL/OSL=1024, DeepSeek-R1 FP8, MI355X): - Throughput: +1.6% to +8.4% across concurrency 8-64 - Mean TTFT: -22% to -63% (prefill is local to router) - TPOT/ITL: unchanged (within noise) - 25% fewer nodes, no performance regression * [AMD] Use public vLLM base image with runtime dependency install Replace the custom Docker image (vllm_disagg_pd:latest) with the public vllm/vllm-openai-rocm:v0.17.1 base image. Missing components (UCX, RIXL, etcd, libionic1, vllm-router) are now installed at container start via setup_deps.sh, which is sourced by server.sh. This eliminates the need to build, host, and maintain a custom image — CI nodes can pull directly from Docker Hub. Changes: - Add setup_deps.sh: idempotent installer for UCX (ROCm fork), RIXL, etcd, libionic1 (Pensando ionic), and vllm-router (NODE_RANK=0 only). Build steps run in subshells to avoid CWD pollution. - server.sh: source setup_deps.sh before any other logic - job.slurm: add --entrypoint "" to override the base image's vllm CLI entrypoint, allowing bash -lc to work correctly - env.sh: update comment (paths now set by setup_deps.sh, not image ENV) - amd-master.yaml: image changed to vllm/vllm-openai-rocm:v0.17.1 Tested locally (Job 2807, 3 nodes, ISL/OSL=1024): Setup overhead: ~2.5 min per node (all components built from source) Benchmark completed successfully across concurrency 8/16/32/64 * [AMD] Enable Expert Parallelism with MoRI all-to-all on vLLM disagg decode Enable MoRI-based Expert Parallelism (--enable-expert-parallel --all2all-backend mori) on decode workers for DeepSeek-R1-0528, while keeping TP=8 to preserve KV cache transfer compatibility with the prefill node via NixlConnector. This matches SGLang's approach of TP=8 + EP within the TP group. KV Transfer: RIXL/NixlConnector (unchanged) MoE All-to-All: NCCL (default) -> MoRI-EP (--all2all-backend mori) Changes: - models.yaml: Add --enable-expert-parallel --all2all-backend mori to decode_flags; increase engine ready timeout to 1200s - setup_deps.sh: Add MoRI install and vLLM v0.17.1 patches for MoRI-EP + FP8 compatibility (AITER assertion, defer_input_quant) - server.sh: Support decode_env from models.yaml for decode-specific environment overrides - dsr1_fp8_mi355x_vllm-disagg.sh: Pass NODELIST to submit.sh for Slurm node constraints * [AMD] Switch vLLM disagg KV transfer to MoRI-IO with protocol-aware proxy Replace NixlConnector with MoRIIOConnector for KV cache transfer and replace the Rust-based vllm-router with a MoRI-IO-aware Python proxy that handles both HTTP routing and ZMQ-based RDMA endpoint discovery. The key architectural change is that the proxy enriches each request's kv_transfer_params with remote RDMA endpoint info (handshake_port, notify_port, host, port) before dispatching, enabling concurrent prefill+decode in WRITE mode — something vllm-router could not do because it only understands HTTP, not the MoRI-IO registration protocol. Changes: - Add moriio_proxy.py: MoRI-IO-aware proxy with ZMQ service discovery, request enrichment, and /health endpoint (adapted from vLLM upstream moriio_toy_proxy_server.py) - server.sh: switch --kv-transfer-config from NixlConnector to MoRIIOConnector with kv_connector_extra_config (proxy_ip, proxy_ping_port, http_port); launch proxy before prefill on NODE_RANK=0; set VLLM_DISABLE_REQUEST_ID_RANDOMIZATION=1 as workaround for v0.17.1 completion-ID mismatch (upstream fix: vllm-project/vllm#34907) - setup_deps.sh: replace vllm-router/Rust install with lightweight Python deps (quart, aiohttp, msgpack, pyzmq) for the proxy Benchmark (Job 2853 vs 2818 NixlConnector baseline, ISL/OSL=1024): TTFT median: -37% to -55% across C8–C64 (e.g. 384→241ms @C64) TTFT p99: -63% at C64 (6622→2469ms) Throughput: +8% at C64 (2634→2844 tok/s) TPOT: unchanged (~22ms @C64) * [AMD] BUG fix: RANDOM_RANGE_RATIO never reaches bench.sh Signed-off-by: Theresa Shan <theresa.shan@amd.com> * Bug fix: 1. With DRY_RUN=1, node 0 skipped starting proxy/prefill but still ran the first barrier; 2. kill and kill run only when DRY_RUN=0 Signed-off-by: Theresa Shan <theresa.shan@amd.com> * [AMD] Fix vLLM disagg hang: READ mode support + safety timeouts Enable READ-mode KV transfer (decode-initiated RDMA reads) with a critical scheduler assertion fix, and add safety timeouts to prevent indefinite hangs during RDMA transfers. Changes: - setup_deps.sh: Add patches — save_kv_layer/start_load_kv handshake timeouts (30s), RDMA transfer timeout (120s), deferred write task expiry (60s), write worker error handling, and scheduler assertion fix for READ-mode intermediate request states - moriio_proxy.py: Add stream idle timeout (PROXY_STREAM_IDLE_TIMEOUT) to abort stalled decode streams, and proper response.release() - submit.sh, job.slurm: Plumb PROXY_STREAM_IDLE_TIMEOUT and VLLM_MORIIO_CONNECTOR_READ_MODE env vars into Docker containers Validated: 1k/1k full sweep (C8–C512), 100% success rate at all concurrency levels, peak 8500 output tok/s at C512. * Adapt vLLM disagg recipe for 9N mia1 cluster (mlx5 NICs) Port the vLLM disaggregated serving pipeline from the 4N cluster (Pensando ionic NICs) to the 9N mia1 cluster (mlx5/rdma NICs). Key changes: - Fix C512 deadlock: apply ucx_error_handling_mode=none universally instead of only for ionic NICs. Under high concurrency, UCX's default UCP_ERR_HANDLING_MODE_PEER prevents RIXL RDMA READ retries from recovering after ibv_post_send queue exhaustion, causing prefill KV cache saturation and pipeline deadlock. - Force-reinstall MoRI from b645fc8 to fix PCI topology assertion failure on nodes with Broadcom PEX890xx PCIe switches. - Auto-detect Docker privilege (sudo vs non-sudo) for cross-cluster portability. - Add SLURM_EXCLUDE_NODES support to skip nodes with broken Docker sockets. - Increase VLLM_ENGINE_READY_TIMEOUT_S to 3600 to accommodate longer setup times (RIXL/MoRI source builds over NFS). * [AMD] Fix vLLM disagg sweep hang: KV cache leak + benchmark client hardening Server-side: RIXL can lose `finished_sending` notifications under high concurrency with ibv_post_send failures, permanently leaking prefill KV blocks. Over multiple benchmark rounds (sweep), leaked blocks accumulate and saturate the prefill KV cache, deadlocking C512. - Fix finished_sending handler to unconditionally free KV blocks (the conditional status check had no recovery path, causing leaks) - Add idle KV block reaper: detects engine idle >5s with finished requests still holding blocks, then force-frees them - Add 10s cooldown between benchmark rounds for reaper activation Client-side: SSE streaming loop did not break on the [DONE] sentinel, causing the benchmark client to hang when the proxy held connections open after request completion. - Break SSE loop on [DONE] in completions and chat completions - Share a single aiohttp.ClientSession across all requests (connection pooling via TCPConnector instead of per-request session creation) - Add asyncio.wait_for timeout around asyncio.gather with proper task cancellation and partial result collection - Reduce AIOHTTP_TIMEOUT from 6h to 30min Verified: sweep 1K/1K C128→C256→C512 all pass (Job 6222, 9N cluster). * [AMD] Fix vLLM disagg Slurm job never terminating after benchmark completion Background processes (proxy, prefill, decode, etcd) were started via `cmd 2>&1 | tee logfile &`, causing bash $! to capture the PID of tee rather than the actual process. `kill $pid` only killed tee, leaving the real process running. The proxy kept port 30000 open, so decode nodes' `sync.py wait` never detected shutdown and the Slurm job hung forever. Additionally, etcd's stderr was not redirected, holding the Docker container's main pipe open and preventing container exit even after server.sh completed. Changes: - Redirect all background processes to log files instead of piping through tee, so $! captures the correct PID (matches SGLang pattern) - Redirect etcd launcher's stderr to prevent pipe leak - Add pkill fallback cleanup for proxy, vllm, and etcd processes - Increase barrier grace period to handle node setup time variance - Increase container creation barrier timeout from 300s to 600s * [AMD] Enable MoRI-IO READ mode by default for vLLM disagg * [AMD] Fix CI checkout failure caused by root-owned __pycache__ files Fix per-node Docker privilege detection in vLLM disagg job.slurm * [AMD] Fix CI checkout EACCES by redirecting Python bytecache off NFS Docker containers run as root, so __pycache__/*.pyc files created during benchmark_serving.py import end up root-owned on the NFS workspace. The CI runner cannot delete them, breaking checkout. Set PYTHONPYCACHEPREFIX=/tmp/pycache in the Docker env so bytecache stays inside the container. Remove the previous server.sh find-and- delete workaround since the root cause is now addressed. * [AMD] Fix KV reaper deadlock on high-ISL disagg workloads The idle KV block reaper only fired when both running=0 AND waiting=0. Under 8K ISL at C64+, leaked blocks filled the prefill KV cache while new requests queued in WAITING state — the non-empty wait queue prevented the reaper from ever triggering, causing a permanent hang. Remove the waiting-queue check so the reaper fires whenever no requests are actively running, which is precisely when leaked blocks can be safely reclaimed. Verified with 8K/1K sweep (C32–C512) completing without hangs. * [AMD] Enable reading PREFILL_TP,PREFILL_EP,PREFILL_DP_ATTN,DECODE_TP,DECODE_EP,DECODE_DP_ATTN from amd-master.yaml config. Signed-off-by: Theresa Shan <theresa.shan@amd.com> * [AMD] Upgrade vLLM disagg image from v0.17.1 to v0.18.0 Bump vllm/vllm-openai-rocm to v0.18.0 for the dsr1-fp8-mi355x-vllm-disagg config. Changes required by the new image: - setup_deps.sh: drop aiohttp/pyzmq installs (now pre-installed in v0.18.0); move install_mori_proxy_deps before patches and run on all nodes so msgpack is available when patch scripts import MoRI-IO connector modules - moriio_proxy.py: populate transfer_id in kv_transfer_params dicts (new required field in v0.18.0's moriio_connector.update_state_after_alloc) - MoRI PCI topology bug persists in v0.18.0; rebuild from b645fc8 retained Tested: 1K1K C8,16,32,64,128,256 on mia1 3-node (1P+2D) CONC512 is ongoing but it seems good so far * [AMD] Add Kimi-K2.5-MXFP4 disagg inference config (1P2D) Enable vLLM disagg serving for amd/Kimi-K2.5-MXFP4 on MI355X with a 1P2D node topology (TP=8, decode EP=8). Changes: - amd-master.yaml: add kimik2.5-fp4-mi355x-vllm-disagg config with three seq-len scenarios (1K1K, 8K1K), READ mode enabled - models.yaml: add Kimi-K2.5-MXFP4 server flags (PIECEWISE cudagraph, --gpu-memory-utilization 0.90, --mm-encoder-tp-mode data) - bench.sh: add --trust-remote-code for models with custom code - setup_deps.sh: install amd-quark for MXFP4 quantization support - Add kimik2.5_fp4_mi355x_vllm-disagg.sh entry script Verified with full 1K/1K sweep (CONC 8–512) on SA4N and mia1 9N cluster; all concurrency levels completed without hang. * feat: add MiniMax M2.5 PD disaggregation recipe (1P2D, MoRI-EP + MoRI-IO) Cherry-picked from ChuanLi1101/InferenceMAX:chuali/minimax-m25-vllm-disagg (commit 72a0002). Resolved conflict in models.yaml to keep both Kimi-K2.5-MXFP4 and MiniMax-M2.5 entries. Add multi-node vLLM PD disaggregation support for MiniMax-M2.5 (FP8), following the DeepSeek R1 disagg recipe pattern. Includes: - models.yaml: MiniMax-M2.5 config with TP8 prefill / TP8+EP8+MoRI decode - Entry script: minimaxm25_fp8_mi355x_vllm-disagg.sh - amd-master.yaml: e2e test entry for 1P2D on MI355X (1k1k, 8k1k, 1k8k) MiniMax M2.5 (230B, 256 experts, top-8 sigmoid routing, GQA) uses the same disagg infrastructure as DSR1. Unlike DeepSeek MLA models, M2.5 uses standard GQA attention so AITER paged attention is fully supported and no block-size/cudagraph workarounds are needed. Co-authored-by: ChuanLi1101 <Chuan.Li2@amd.com> Co-authored-by: Claude Made-with: Cursor * feat: add Dockerfile and runtime patch for MiniMax M2.5 WideEP + MoRI Cherry-picked from ChuanLi1101/InferenceMAX:chuali/minimax-m25-vllm-disagg (commit bb6bd0e). Adapted for v0.18.0 base: kept vllm/vllm-openai-rocm:v0.18.0 image (runtime patch via setup_deps.sh is sufficient; custom Docker image available in docker/minimax-m25-disagg/ if needed). Two deployment options for getting vLLM minimax_m2.py changes into the container: Option A -- Custom Docker image (docker/minimax-m25-disagg/): Builds from the public vLLM ROCm image and pre-installs UCX, etcd, RIXL, and patched minimax_m2.py with WideEP + MoRI + EPLB support baked in. Option B -- Runtime patch (setup_deps.sh): patch_minimax_m2_wideep_mori() copies patched minimax_m2.py from the mounted InferenceX repo into the container's vLLM installation at startup. Co-authored-by: ChuanLi1101 <Chuan.Li2@amd.com> Co-authored-by: Claude Made-with: Cursor * Fix: rename minimaxm25 to minimaxm2.5 for CI naming consistency Align MiniMax M2.5 disagg naming with existing single-node configs (minimaxm2.5_fp8_mi355x.sh, minimaxm2.5_fp8_mi300x.sh, etc.). - amd-master.yaml: minimaxm25 -> minimaxm2.5 in config key + model-prefix - Rename entry script: minimaxm25_fp8_mi355x_vllm-disagg.sh -> minimaxm2.5_fp8_mi355x_vllm-disagg.sh - Dockerfile: update COPY path to match renamed script * Optimize: add --gpu-memory-utilization 0.95 and --block-size 32 to MiniMax M2.5 disagg Align MiniMax M2.5 disagg serve parameters with the proven single-node config (minimaxm2.5_fp8_mi355x.sh). MiniMax M2.5 uses GQA (not MLA), so block-size 32 is optimal (vs block-size 1 for DeepSeek/Kimi MLA). The extra 5% GPU memory (0.95 vs default 0.9) increases KV cache capacity for high-concurrency sweeps (C256/C512). * Fix: MiniMax M2.5 disagg — require EP=8 for prefill, fix ROCm gate dtype MiniMax M2.5 has expert intermediate_size=1536; with TP=8 and no EP the sharded dimension (192) is not divisible by FP8 block_n=128, crashing the prefill node. Set prefill EP=8 (matching decode and single-node) and add --enable-expert-parallel --all2all-backend mori to prefill_flags. Fix GateLinear to use out_dtype=torch.float32 instead of params_dtype=torch.float32 so the GEMM runs in bf16 (ROCm compatible) and only the output is cast to fp32 for routing precision. Remove the 1K/8K benchmark scenario (not needed). * Remove unused docker/minimax-m25-disagg/ directory The Dockerfile, build.sh, and duplicate minimax_m2.py patch were never used by the CI pipeline or local tests. * remove vllm disagg for dpsr1 and dpv3 Signed-off-by: Theresa Shan <theresa.shan@amd.com> * consolidate amd_utils for sglang and vllm Signed-off-by: Theresa Shan <theresa.shan@amd.com> * use vLLM router as default router for vllm disagg Signed-off-by: Theresa Shan <theresa.shan@amd.com> * fix bugs Signed-off-by: Chun Fang <chun.fang@amd.com> * [AMD] Bump to nightly vllm and vllm-router images (#1208) --------- Signed-off-by: Simon Danielsson <pedaniel@amd.com> * update vllm image and vllm router image * update the interface prefix for tw cluster Signed-off-by: Theresa Shan <theresa.shan@amd.com> * add deps for ib device auto-detection Signed-off-by: Shan Theresa <theresa.shan@amd.com> * update vllm image Signed-off-by: Theresa Shan <theresa.shan@amd.com> * fix indentation and add missing finally block in async_request_openai_chat_completions Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix tw-eth interface detection pattern in env.sh Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix vllm-disagg config schema: use scenarios.fixed-seq-len Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix vllm-disagg routing to multi_node benchmark subdir Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix result collection to use FRAMEWORK as log directory prefix The inline collect_latest_results.py hardcoded "sglang" as the log directory prefix, causing "No logs directory found" for vllm-disagg runs where bench.sh creates directories named vllm-disagg_isl_X_osl_Y. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * suppress tokenizer warnings and debug output in bench.sh Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix vllm-disagg deadlock: stop router after rank 0 container exits The vllm-router runs as a separate container on node 0. After node 0's main container finishes the benchmark and exits, decode nodes remain stuck waiting for the router port to close. The router cleanup in job.slurm can't run until srun completes, but srun can't complete because decode nodes are blocked — deadlock. Fix: skip exec on rank 0 for vllm-disagg so the srun bash script continues after docker exits and can stop the router container, allowing decode nodes to detect the port closure and exit. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * reduce vllm-disagg concurrency sweep to single point for faster iteration Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * preserve slurm logs on failure and print stderr inline The EXIT trap deleted benchmark_logs/ before saving artifacts, making it impossible to debug container startup failures. Now the trap always copies slurm .out/.err to the artifact directory and prints the last 100 lines of .err inline in the CI output. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * enable set -x around docker privilege detection for CI debugging Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix docker detection: test on compute node, not batch host The batch host has docker socket permissions but the compute nodes do not, causing "permission denied" on all srun tasks. Move the detection after SELECTED_NODES is known and probe via srun. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix docker detection: per-node probe since group membership varies Export DOCKER_CMD_DETECT as a shell snippet that each srun participant evaluates locally, instead of testing a single node and assuming all nodes have the same docker socket permissions. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * add vllm-disagg changelog entries and update kimi conc-list - Add perf-changelog entries for kimik2.5-fp4-mi355x-vllm-disagg and minimaxm2.5-fp8-mi355x-vllm-disagg to trigger CI benchmarks - Update kimi 1k1k conc-list from [8] to [16] - Comment out kimi 8k1k config until eval pipeline is wired up Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * switch vllm-disagg to 8k1k config to trigger multi-node eval Comment out 1k1k config and enable 8k1k with conc-list [16] so mark_eval_entries picks it up for the eval pipeline. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * add multi-node eval feature Signed-off-by: Theresa Shan <theresa.shan@amd.com> * remove start_etcd.sh Signed-off-by: Theresa Shan <theresa.shan@amd.com> * change decode to 1, easier for testing Signed-off-by: Theresa Shan <theresa.shan@amd.com> * add --served-model-name to vllm serve commands and wire up eval Set --served-model-name on all prefill/decode vllm serve commands so the model name matches what run_lm_eval sends in API requests. Also add eval pipeline support (health check, run_eval, artifact staging) mirroring server_sglang.sh. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix model name consistency between vllm serve and bench client bench.sh now uses MODEL_NAME for vllm-disagg to match --served-model-name, and MODEL_PATH for sglang to match its default. Simplified SERVED_MODEL to use MODEL_NAME directly since MODEL env var is not available inside the container. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * add token patch to bench for vllm Signed-off-by: Theresa Shan <theresa.shan@amd.com> * add --tokenizer passthrough to run_benchmark_serving benchmark_lib.sh rejected unknown flags — add --tokenizer support so vllm-disagg bench can resolve the tokenizer from the local model path instead of attempting an HF download with the short model name. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * update vllm image for kimi2.5 and Minimax disagg. Signed-off-by: Shan Theresa <theresa.shan@amd.com> * Update setup_deps.sh * Update amd-master.yaml restore the kimi k2.5 settings * update req rate for vllm. Signed-off-by: Theresa Shan <theresa.shan@amd.com> * make the sglang env consistent with upstream Signed-off-by: Theresa Shan <theresa.shan@amd.com> * node blacklist Signed-off-by: Theresa Shan <theresa.shan@amd.com> * fix: remove faulty minimax patch Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: remove unneeded commented-out code from setup_deps.sh Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: bump to latest nightly vllm image on minimax Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: temporarily mount /coredumps Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * tmp: add bette r debugging capabilities Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: disable custom all-reduce for minimax Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: minimax segfault by avoiding M=8K fmoe kernel shape Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * revert: fix: temporarily mount /coredumps Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * feat: add VLLM_ROCM_SHUFFLE_KV_CACHE_LAYOUT=1 as in single node example Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> * fix: use FRAMEWORK arg in collect_latest_results.py to match vllm-disagg log dirs Signed-off-by: Theresa Shan <theresa.shan@amd.com> * remove unused vllm_disagg_utils directory No external references to this folder exist in the codebase. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * revert: restore backend_request_func.py to match main Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * revert: restore benchmark_serving.py to match main Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * revert: fully restore benchmark_serving.py to match main Restores import order and failure-rate check block. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * revert: fully restore backend_request_func.py to match main Restores _resolve helper and tokenizer fix logic. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * add pr-link to vllm-disagg changelog entries Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix: sync env.sh with upstream main - Fix IBDEVICES detection log: move info message inside success branch, exit 1 on failure instead of silently propagating empty strings - Add missing SGLANG_USE_AITER=1 - Set SGLANG_ENABLE_OVERLAP_PLAN_STREAM=0 to match upstream Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix: restore SGLANG_MORI_COMBINE_DTYPE in server launch commands The refactored server_sglang.sh dropped the per-role COMBINE_DTYPE mapping that the old server.sh had. SGLang reads SGLANG_MORI_COMBINE_DTYPE internally, so map it from MORI_COMBINE_DTYPE_PREFILL (fp8_direct_cast) on prefill and MORI_COMBINE_DTYPE_DECODE (fp8) on decode. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * refactor: move static vLLM env vars to env.sh, remove dead etcd code Move VLLM_USE_V1, VLLM_SERVER_DEV_MODE, VLLM_DISABLE_REQUEST_ID_RANDOMIZATION to env.sh alongside other engine-specific config. Remove commented-out etcd setup block that is no longer used. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix: pass IS_MULTINODE into Docker container The refactored DOCKER_ENV_COMMON array dropped -e IS_MULTINODE that the old job.slurm had. Without it, eval metadata tagging inside the container sees an empty value. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix: improve vllm-disagg changelog descriptions Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> * fix: restore DP+EP override blocks and trailing newline in server_sglang.sh Add BENCH_MAX_CONC_VALUE extraction and the two DP+EP override blocks that the refactor from server.sh dropped. These adjust max-running-requests, dispatch tokens, and MOE input tokens when both DP and EP are enabled. Also add trailing newline for POSIX compliance. server_sglang.sh now matches upstream server.sh exactly. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> --------- Signed-off-by: Theresa Shan <theresa.shan@amd.com> Signed-off-by: Chun Fang <chun.fang@amd.com> Signed-off-by: Simon Danielsson <pedaniel@amd.com> Signed-off-by: Shan Theresa <theresa.shan@amd.com> Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> Co-authored-by: Chun Fang <chun.fang@amd.com> Co-authored-by: ChuanLi1101 <Chuan.Li2@amd.com> Co-authored-by: Simon Danielsson <70206058+simondanielsson@users.noreply.github.com> Co-authored-by: Claude Opus 4 <noreply@anthropic.com> Co-authored-by: simondanielsson <simon.danielsson99@hotmail.com>
1 parent c5ff8da commit bb00055

18 files changed

Lines changed: 2984 additions & 1165 deletions

.github/configs/amd-master.yaml

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,6 +1350,115 @@ dsr1-fp8-mi355x-sglang-disagg-mtp:
13501350
- "DECODE_NODES=1"
13511351
- "DECODE_MTP_SIZE=2"
13521352

1353+
kimik2.5-fp4-mi355x-vllm-disagg:
1354+
image: vllm/vllm-openai-rocm:nightly-bf610c2f56764e1b30bc6065f4ceace3d6e59036
1355+
model: amd/Kimi-K2.5-MXFP4
1356+
model-prefix: kimik2.5
1357+
runner: mi355x-disagg
1358+
precision: fp4
1359+
framework: vllm-disagg
1360+
multinode: true
1361+
disagg: true
1362+
scenarios:
1363+
fixed-seq-len:
1364+
- isl: 1024
1365+
osl: 1024
1366+
search-space:
1367+
# 1P2D: 1 prefill node (co-located with proxy) + 2 decode nodes = 3 nodes total
1368+
- spec-decoding: "none"
1369+
conc-list: [ 8, 16, 32, 64, 128, 256, 512 ]
1370+
prefill:
1371+
num-worker: 1
1372+
tp: 8
1373+
ep: 1
1374+
dp-attn: false
1375+
additional-settings:
1376+
- "PREFILL_NODES=1"
1377+
- "VLLM_MORIIO_CONNECTOR_READ_MODE=1"
1378+
decode:
1379+
num-worker: 2
1380+
tp: 8
1381+
ep: 8
1382+
dp-attn: false
1383+
additional-settings:
1384+
- "DECODE_NODES=2"
1385+
1386+
- isl: 8192
1387+
osl: 1024
1388+
search-space:
1389+
- spec-decoding: "none"
1390+
conc-list: [ 8, 16, 32, 64, 128, 256, 512 ]
1391+
prefill:
1392+
num-worker: 1
1393+
tp: 8
1394+
ep: 1
1395+
dp-attn: false
1396+
additional-settings:
1397+
- "PREFILL_NODES=1"
1398+
- "VLLM_MORIIO_CONNECTOR_READ_MODE=1"
1399+
decode:
1400+
num-worker: 2
1401+
tp: 8
1402+
ep: 8
1403+
dp-attn: false
1404+
additional-settings:
1405+
- "DECODE_NODES=2"
1406+
1407+
minimaxm2.5-fp8-mi355x-vllm-disagg:
1408+
image: vllm/vllm-openai-rocm:nightly-a6682d1d259cca69a9ae737ea5608fbbe7520031
1409+
model: MiniMaxAI/MiniMax-M2.5
1410+
model-prefix: minimaxm2.5
1411+
runner: mi355x-disagg
1412+
precision: fp8
1413+
framework: vllm-disagg
1414+
multinode: true
1415+
disagg: true
1416+
scenarios:
1417+
fixed-seq-len:
1418+
- isl: 1024
1419+
osl: 1024
1420+
search-space:
1421+
# 1P2D: 1 prefill node (co-located with proxy) + 2 decode nodes = 3 nodes total
1422+
# Prefill also needs EP=8: MiniMax M2.5 expert intermediate_size=1536,
1423+
# TP8 shards to 192 which is not divisible by FP8 block_n=128.
1424+
- spec-decoding: "none"
1425+
conc-list: [ 8, 16, 32, 64, 128, 256, 512 ]
1426+
prefill:
1427+
num-worker: 1
1428+
tp: 8
1429+
ep: 8
1430+
dp-attn: false
1431+
additional-settings:
1432+
- "PREFILL_NODES=1"
1433+
- "VLLM_MORIIO_CONNECTOR_READ_MODE=1"
1434+
decode:
1435+
num-worker: 2
1436+
tp: 8
1437+
ep: 8
1438+
dp-attn: false
1439+
additional-settings:
1440+
- "DECODE_NODES=2"
1441+
1442+
- isl: 8192
1443+
osl: 1024
1444+
search-space:
1445+
- spec-decoding: "none"
1446+
conc-list: [ 8, 16, 32, 64, 128, 256, 512 ]
1447+
prefill:
1448+
num-worker: 1
1449+
tp: 8
1450+
ep: 8
1451+
dp-attn: false
1452+
additional-settings:
1453+
- "PREFILL_NODES=1"
1454+
- "VLLM_MORIIO_CONNECTOR_READ_MODE=1"
1455+
decode:
1456+
num-worker: 2
1457+
tp: 8
1458+
ep: 8
1459+
dp-attn: false
1460+
additional-settings:
1461+
- "DECODE_NODES=2"
13531462

13541463
dsr1-fp4-mi355x-sglang-disagg:
13551464
image: lmsysorg/sglang-rocm:v0.5.12-rocm720-mi35x-20260519

benchmarks/benchmark_lib.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ run_benchmark_serving() {
210210
local dsv4=false
211211
local trust_remote_code=false
212212
local server_pid=""
213+
local tokenizer=""
213214

214215
while [[ $# -gt 0 ]]; do
215216
case $1 in
@@ -278,6 +279,10 @@ run_benchmark_serving() {
278279
server_pid="$2"
279280
shift 2
280281
;;
282+
--tokenizer)
283+
tokenizer="$2"
284+
shift 2
285+
;;
281286
*)
282287
echo "Unknown parameter: $1"
283288
return 1
@@ -385,6 +390,10 @@ run_benchmark_serving() {
385390
benchmark_cmd+=(--trust-remote-code)
386391
fi
387392

393+
if [[ -n "$tokenizer" ]]; then
394+
benchmark_cmd+=(--tokenizer "$tokenizer")
395+
fi
396+
388397
# Run benchmark with optional server monitoring
389398
set -x
390399
if [[ -n "$server_pid" ]]; then
Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,108 @@
11
#!/bin/bash
2+
# Dual-Engine Disaggregated Benchmark Runner
3+
#
4+
# ENGINE=sglang (default): SGLang benchmark
5+
# ENGINE=vllm: vLLM benchmark
6+
#
7+
# Produces JSON result files via benchmark_serving.py so that the CI pipeline
8+
# can collect and process results.
9+
#
10+
# Usage: bash bench.sh <n_prefill> <n_decode> <prefill_gpus> <decode_gpus> \
11+
# <model_dir> <model_name> <log_path> <isl> <osl> \
12+
# <concurrency_list> <req_rate> <random_range_ratio> <num_prompts_multiplier>
13+
14+
ENGINE="${ENGINE:-sglang-disagg}"
215

316
n_prefill=$1
417
n_decode=$2
518
prefill_gpus=$3
619
decode_gpus=$4
720
model_path=$5
821
model_name=$6
9-
MODEL_PATH="${model_path}/${model_name}"
22+
MODEL_PATH="${MODEL_PATH:-${model_path}/${model_name}}"
23+
# vllm-disagg uses --served-model-name MODEL_NAME; sglang defaults to MODEL_PATH
24+
if [[ "$ENGINE" == "vllm-disagg" ]]; then
25+
BENCH_MODEL="${MODEL_NAME:-${MODEL_PATH}}"
26+
else
27+
BENCH_MODEL="${MODEL_PATH}"
28+
fi
1029
log_path=$7
1130

1231
chosen_isl=${8:-1024}
1332
chosen_osl=${9:-1024}
1433
concurrency_list=${10:-"512x1"}
15-
chosen_req_rate=${11:-1}
34+
if [[ "$ENGINE" == "vllm-disagg" ]]; then
35+
chosen_req_rate=${11:-inf}
36+
else
37+
chosen_req_rate=${11:-1}
38+
fi
1639
random_range_ratio=${12:-0.8}
1740
num_prompts_multiplier=${13:-10}
1841

1942
IFS='x' read -r -a chosen_concurrencies <<< "$concurrency_list"
2043

21-
echo "Config ${chosen_isl}; ${chosen_osl}; ${chosen_concurrencies[0]}; ${chosen_req_rate}"
44+
ROUTER_PORT="${ROUTER_PORT:-30000}"
2245

23-
head_node="localhost"
24-
head_port="30000"
46+
export TRANSFORMERS_VERBOSITY=error
47+
export TOKENIZERS_PARALLELISM=false
2548

49+
echo "Config ${chosen_isl}; ${chosen_osl}; ${chosen_concurrencies[0]}; ${chosen_req_rate}"
2650

27-
profile_folder="${log_path}/sglang_isl_${chosen_isl}_osl_${chosen_osl}"
28-
mkdir -p $profile_folder
51+
profile_folder="${log_path}/${ENGINE}_isl_${chosen_isl}_osl_${chosen_osl}"
52+
mkdir -p "$profile_folder"
2953

3054
source "$(dirname "$0")/../../benchmark_lib.sh"
3155

32-
# Repo root inside the container (3 levels up from this script's directory)
3356
REPO_ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
3457

35-
for max_concurrency in ${chosen_concurrencies[@]}; do
58+
for max_concurrency in "${chosen_concurrencies[@]}"; do
3659

3760
export_file="${profile_folder}/concurrency_${max_concurrency}_req_rate_${chosen_req_rate}_gpus_$((prefill_gpus+decode_gpus))_ctx_${prefill_gpus}_gen_${decode_gpus}"
3861

62+
num_prompts=$(( max_concurrency * num_prompts_multiplier ))
63+
if [[ "$num_prompts" -lt 16 ]]; then
64+
num_prompts=16
65+
fi
66+
3967
echo "profile_folder: $profile_folder"
4068
echo "max_concurrency: $max_concurrency"
4169
echo "chosen_req_rate: $chosen_req_rate"
4270
echo "MODEL_PATH: $MODEL_PATH"
43-
echo "head_port: $head_port"
71+
echo "ROUTER_PORT: $ROUTER_PORT"
4472
echo "chosen_isl: $chosen_isl"
4573
echo "chosen_osl: $chosen_osl"
74+
echo "num_prompts: $num_prompts"
4675
echo "export_file: $export_file"
4776

77+
# Engine-specific extra flags
78+
extra_flags=""
79+
if [[ "$ENGINE" == "vllm-disagg" ]]; then
80+
extra_flags="--trust-remote-code --tokenizer $MODEL_PATH"
81+
else
82+
if [ "$IS_MTP" = "true" ]; then
83+
extra_flags="--use-chat-template"
84+
fi
85+
fi
86+
4887
run_benchmark_serving \
4988
--bench-serving-dir "$REPO_ROOT" \
50-
--model ${MODEL_PATH} \
51-
--port ${head_port} \
89+
--model "$BENCH_MODEL" \
90+
--port "$ROUTER_PORT" \
5291
--backend openai \
53-
--input-len ${chosen_isl} \
54-
--output-len ${chosen_osl} \
55-
--random-range-ratio ${random_range_ratio} \
56-
--num-prompts $(( $max_concurrency * $num_prompts_multiplier )) \
92+
--input-len "$chosen_isl" \
93+
--output-len "$chosen_osl" \
94+
--random-range-ratio "$random_range_ratio" \
95+
--num-prompts "$num_prompts" \
5796
--max-concurrency "$max_concurrency" \
5897
--result-filename "$export_file" \
5998
--result-dir /workspace/ \
60-
$( [ "$IS_MTP" = "true" ] && echo "--use-chat-template" )
99+
$extra_flags
61100

62101
echo "-----------------------------------------"
102+
103+
# vLLM: cooldown between rounds for idle KV block reaper
104+
if [[ "$ENGINE" == "vllm-disagg" ]]; then
105+
echo "[BENCH] Cooldown: waiting 10s for idle KV block reaper..."
106+
sleep 10
107+
fi
63108
done

0 commit comments

Comments
 (0)