-
Notifications
You must be signed in to change notification settings - Fork 284
perf(amd): port MI355X Qwen3.5 FP8 disagg sweep to srt-slurm #2628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8ed78e6
cb49517
c67a656
8bf99a0
382bc0d
20c52f7
6809652
f85e772
004bba1
3f4f3fa
d2d9db8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # srt-slurm cluster profile for the MI355X AMD Slurm cluster. The login and | ||
| # compute nodes share /it-share, so source, output, image, and result paths do | ||
| # not require node-local transport. | ||
|
|
||
| cluster: mi355x-amds | ||
| default_partition: compute | ||
| default_time_limit: "01:00:00" | ||
| output_dir: /it-share/gharunners2/srt-slurm/outputs | ||
|
|
||
| gpus_per_node: 8 | ||
| accelerator_vendor: amd | ||
| network_interface: eno0 | ||
|
|
||
| gpu_sbatch_directive: gres | ||
| use_segment_sbatch_directive: false | ||
| use_exclusive_sbatch_directive: false | ||
| runtime_config_transport: shared-filesystem | ||
|
|
||
| default_sbatch_directives: | ||
| cpus-per-task: "32" | ||
| mem: "128G" | ||
|
|
||
| default_mounts: | ||
| /dev/kfd: /dev/kfd | ||
| /dev/dri: /dev/dri | ||
| /it-share/hf-hub-cache: /hf_hub_cache | ||
| # The launcher appends the exact shared workspace and result roots. | ||
|
|
||
| containers: | ||
| sglang-v0.5.16-mi35x: /it-share/gharunners2/srt-slurm/containers/sglang-rocm-v0.5.16-mi35x-20260728.sqsh | ||
|
|
||
| nginx_raise_ulimit: false |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,149 @@ | ||||||||||||||||||||
| # Production-scale MI355X port of the existing Qwen3.5 FP8 1P1D recipe. | ||||||||||||||||||||
| # Each role owns one full 8-GPU node; the native SGLang Router provides the | ||||||||||||||||||||
| # request plane and AMD MoRI moves KV directly between the P/D workers. | ||||||||||||||||||||
|
|
||||||||||||||||||||
| name: "mi355x-sglang-qwen3.5-fp8-disagg-1p1d-tp4p-tp8d-fixed-seq" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| model: | ||||||||||||||||||||
| path: "hf:Qwen/Qwen3.5-397B-A17B-FP8" | ||||||||||||||||||||
| container: "sglang-v0.5.16-mi35x" | ||||||||||||||||||||
| precision: "fp8" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| identity: | ||||||||||||||||||||
| model: | ||||||||||||||||||||
| repo: "Qwen/Qwen3.5-397B-A17B-FP8" | ||||||||||||||||||||
| container: | ||||||||||||||||||||
| image: "lmsysorg/sglang:v0.5.16-rocm720-mi35x" | ||||||||||||||||||||
| frameworks: | ||||||||||||||||||||
| sglang: "0.5.16" | ||||||||||||||||||||
| sglang-router: "0.3.2" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| slurm: | ||||||||||||||||||||
| time_limit: "08:00:00" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| # This topology owns every GPU on each MI355X node. Give SGLang the complete | ||||||||||||||||||||
| # 128-core cpuset as well: its ROCm image enables per-GPU CPU affinity, which | ||||||||||||||||||||
| # maps the eight TP ranks across the full dual-socket CPU topology. | ||||||||||||||||||||
| sbatch_directives: | ||||||||||||||||||||
| cpus-per-task: "128" | ||||||||||||||||||||
| mem: "0" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| resources: | ||||||||||||||||||||
| gpu_type: "mi355x" | ||||||||||||||||||||
| gpus_per_node: 8 | ||||||||||||||||||||
| prefill_nodes: 1 | ||||||||||||||||||||
| decode_nodes: 1 | ||||||||||||||||||||
| prefill_workers: 1 | ||||||||||||||||||||
| decode_workers: 1 | ||||||||||||||||||||
| gpus_per_prefill: 4 | ||||||||||||||||||||
| gpus_per_decode: 8 | ||||||||||||||||||||
|
|
||||||||||||||||||||
| frontend: | ||||||||||||||||||||
| type: sglang | ||||||||||||||||||||
| enable_multiple_frontends: false | ||||||||||||||||||||
| args: | ||||||||||||||||||||
| policy: round_robin | ||||||||||||||||||||
| prefill-policy: round_robin | ||||||||||||||||||||
| decode-policy: round_robin | ||||||||||||||||||||
|
|
||||||||||||||||||||
| backend: | ||||||||||||||||||||
| type: sglang | ||||||||||||||||||||
| prefill_environment: &common_environment | ||||||||||||||||||||
| HF_HOME: "/hf_hub_cache" | ||||||||||||||||||||
| # Hugging Face stores hub snapshots under $HF_HOME/hub. Keep the explicit | ||||||||||||||||||||
| # cache variables on that same path so srt-slurm's prefetch and every | ||||||||||||||||||||
| # backend process resolve the identical, current snapshot. | ||||||||||||||||||||
| HF_HUB_CACHE: "/hf_hub_cache/hub" | ||||||||||||||||||||
| HUGGINGFACE_HUB_CACHE: "/hf_hub_cache/hub" | ||||||||||||||||||||
| PYTHONUNBUFFERED: "1" | ||||||||||||||||||||
| IBDEVICES: "rdma0,rdma1,rdma2,rdma3,rdma4,rdma5,rdma6,rdma7" | ||||||||||||||||||||
| GLOO_SOCKET_IFNAME: "eno0" | ||||||||||||||||||||
| NCCL_SOCKET_IFNAME: "eno0" | ||||||||||||||||||||
| MORI_RDMA_TC: "104" | ||||||||||||||||||||
| MORI_IO_TC: "104" | ||||||||||||||||||||
| MORI_IO_SQ_BACKOFF_TIMEOUT_US: "50000" | ||||||||||||||||||||
| MORI_IO_QP_MAX_SEND_WR: "16384" | ||||||||||||||||||||
| MORI_IO_QP_MAX_CQE: "32768" | ||||||||||||||||||||
| MORI_IO_QP_MAX_SGE: "2" | ||||||||||||||||||||
| MORI_SHMEM_MODE: "ISOLATION" | ||||||||||||||||||||
| SGLANG_USE_AITER: "1" | ||||||||||||||||||||
| AITER_LOG_LEVEL: "ERROR" | ||||||||||||||||||||
| SGLANG_MORI_DISPATCH_DTYPE: "auto" | ||||||||||||||||||||
| SGLANG_MORI_QP_PER_TRANSFER: "4" | ||||||||||||||||||||
| SGLANG_MORI_NUM_WORKERS: "4" | ||||||||||||||||||||
| SGLANG_DISAGGREGATION_NUM_PRE_ALLOCATE_REQS: "32" | ||||||||||||||||||||
| SGLANG_DISAGGREGATION_BOOTSTRAP_TIMEOUT: "3600" | ||||||||||||||||||||
| SGLANG_DISAGGREGATION_WAITING_TIMEOUT: "3600" | ||||||||||||||||||||
| SGLANG_HEALTH_CHECK_TIMEOUT: "600" | ||||||||||||||||||||
| decode_environment: *common_environment | ||||||||||||||||||||
| sglang_config: | ||||||||||||||||||||
| prefill: &common_config | ||||||||||||||||||||
| served-model-name: "Qwen/Qwen3.5-397B-A17B-FP8" | ||||||||||||||||||||
| tensor-parallel-size: 4 | ||||||||||||||||||||
| disaggregation-transfer-backend: mori | ||||||||||||||||||||
| disaggregation-ib-device: "rdma0,rdma1,rdma2,rdma3,rdma4,rdma5,rdma6,rdma7" | ||||||||||||||||||||
| kv-cache-dtype: "fp8_e4m3" | ||||||||||||||||||||
| attention-backend: aiter | ||||||||||||||||||||
| moe-dense-tp-size: 1 | ||||||||||||||||||||
| load-balance-method: round_robin | ||||||||||||||||||||
| watchdog-timeout: 3600 | ||||||||||||||||||||
| decode-log-interval: 1000 | ||||||||||||||||||||
| log-level: warning | ||||||||||||||||||||
| mem-fraction-static: 0.80 | ||||||||||||||||||||
| max-running-requests: 128 | ||||||||||||||||||||
| chunked-prefill-size: 262144 | ||||||||||||||||||||
| context-length: 16384 | ||||||||||||||||||||
| disable-radix-cache: true | ||||||||||||||||||||
| cuda-graph-bs: [1, 2, 3, 4, 5, 6, 7, 8] | ||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. CUDA graph batch list truncatedHigh Severity
Reviewed by Cursor Bugbot for commit 70228fa. Configure here. |
||||||||||||||||||||
| enable-metrics: true | ||||||||||||||||||||
| decode: | ||||||||||||||||||||
| <<: *common_config | ||||||||||||||||||||
| mem-fraction-static: 0.85 | ||||||||||||||||||||
| prefill-round-robin-balance: true | ||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Decode inherits prefill TP4High Severity The decode block merges Additional Locations (1)Reviewed by Cursor Bugbot for commit 32d3ee2. Configure here.
Comment on lines
+99
to
+102
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 BLOCKING: Decode inherits Why it matters: Existing srt-slurm sglang recipes (e.g. Fix:
Suggested change
Also double-check the other inherited prefill-oriented values: decode inherits
Comment on lines
+80
to
+102
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 decode config merges *common_config (prefill's tensor-parallel-size: 4) via YAML anchor and never overrides it, so decode runs TP4 instead of TP8 despite the recipe name/gpus_per_decode: 8 and configs/amd-master.yaml decode.tp: 8 specifying TP8 decode. Extended reasoning...The benchmark topology silently regresses from the documented '1P TP4 + 1D TP8' to '1P TP4 + 1D TP4' on an 8-GPU decode node: decode either fails to start (TP size mismatch with the 8-GPU allocation/MoRI KV transfer expecting 8 decode ranks) or runs with half the GPUs actually used, producing throughput/latency numbers that do not reflect the intended TP8 decode topology and invalidating the perf-changelog claim of preserving 'the current one-prefill TP4 plus one-decode TP8 topology.' Verification: normal. The new recipe's decode block (benchmarks/multi_node/srt-slurm-recipes/sglang/qwen3.5/mi355x/disagg-1p1d-tp4p-tp8d-fixed-seq.yaml:100-103) is
cursor[bot] marked this conversation as resolved.
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| srun_options: | ||||||||||||||||||||
| container-writable: "" | ||||||||||||||||||||
| container-remap-root: "" | ||||||||||||||||||||
| mem: "0" | ||||||||||||||||||||
|
|
||||||||||||||||||||
| health_check: | ||||||||||||||||||||
| max_attempts: 720 | ||||||||||||||||||||
| interval_seconds: 5 | ||||||||||||||||||||
|
|
||||||||||||||||||||
| benchmark: | ||||||||||||||||||||
| type: custom | ||||||||||||||||||||
| command: | | ||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||
| result_root="/results/${SLURM_JOB_ID}" | ||||||||||||||||||||
| mkdir -p "${result_root}/fixed-seq" | ||||||||||||||||||||
| trap 'tar -C /logs -czf "'"${result_root}"'/runtime-logs.tar.gz" . 2>/dev/null || true' EXIT | ||||||||||||||||||||
| for concurrency in 8 16 32 64 128; do | ||||||||||||||||||||
| num_prompts=$((concurrency * 10)) | ||||||||||||||||||||
| if ((num_prompts < 16)); then | ||||||||||||||||||||
| num_prompts=16 | ||||||||||||||||||||
| fi | ||||||||||||||||||||
| python3 /infmax-workspace/utils/bench_serving/benchmark_serving.py \ | ||||||||||||||||||||
| --backend openai-chat \ | ||||||||||||||||||||
| --base-url "http://${SRT_FRONTEND_HOST}:${SRT_FRONTEND_PORT}" \ | ||||||||||||||||||||
| --endpoint /v1/chat/completions \ | ||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Benchmark backend switched to chatMedium Severity The custom client uses Reviewed by Cursor Bugbot for commit 70228fa. Configure here. |
||||||||||||||||||||
| --model Qwen/Qwen3.5-397B-A17B-FP8 \ | ||||||||||||||||||||
| --tokenizer Qwen/Qwen3.5-397B-A17B-FP8 \ | ||||||||||||||||||||
| --dataset-name random \ | ||||||||||||||||||||
| --random-input-len 8192 \ | ||||||||||||||||||||
| --random-output-len 1024 \ | ||||||||||||||||||||
| --random-range-ratio 1.0 \ | ||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Benchmark uses exact sequence lengthsMedium Severity The custom client hardcodes Reviewed by Cursor Bugbot for commit 32d3ee2. Configure here. |
||||||||||||||||||||
| --random-num-workers 1 \ | ||||||||||||||||||||
| --num-warmups "$((concurrency * 2))" \ | ||||||||||||||||||||
| --num-prompts "${num_prompts}" \ | ||||||||||||||||||||
| --max-concurrency "${concurrency}" \ | ||||||||||||||||||||
| --request-rate inf \ | ||||||||||||||||||||
| --ignore-eos \ | ||||||||||||||||||||
| --disable-tqdm \ | ||||||||||||||||||||
| --save-result \ | ||||||||||||||||||||
| --result-dir "${result_root}/fixed-seq" \ | ||||||||||||||||||||
| --result-filename "qwen3.5-fp8-disagg-isl8192-osl1024-c${concurrency}.json" | ||||||||||||||||||||
| done | ||||||||||||||||||||
| env: | ||||||||||||||||||||
| HF_HOME: /hf_hub_cache | ||||||||||||||||||||
| HF_HUB_CACHE: /hf_hub_cache/hub | ||||||||||||||||||||
| HUGGINGFACE_HUB_CACHE: /hf_hub_cache/hub | ||||||||||||||||||||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔴 The recipe's cuda-graph-bs is hard-coded to [1,2,3,4,5,6,7,8] for prefill (and inherited unchanged by decode via the *common_config anchor), even though max-running-requests is 128 and the benchmark sweeps concurrency up to 128. The legacy amd_utils config this replaces (benchmarks/multi_node/amd_utils/models.yaml, Qwen3.5-397B-A17B-FP8, no_dp branch used since dp-attn is false here) used cuda_graph_bs_range: "1-128", expanded via
seq 1 128in server_sglang.sh, i.e. a CUDA graph for every batch size 1-128.Extended reasoning...
During the c16/c32/c64/c128 points of the sweep (the majority of the 5-point search space), SGLang's running batch size exceeds 8, so no captured CUDA graph exists and the engine silently falls back to eager-mode execution for prefill and decode alike. This produces throughput/latency numbers for most of the sweep that no longer reflect the previously-measured, CUDA-graph-covered production performance -- a silent, undocumented perf regression relative to the pre-migration amd_utils path, despite the PR claiming to 'preserve the production 1P1D TP4P+TP8D topology' and complete search space with parity. Fix: restore cuda-graph-bs to cover 1-128 (or the actual running-request ceiling) for both prefill and decode.
Verification: normal — benchmark-fidelity regression vs base introduced by this change. The new recipe caps CUDA-graph capture at batch size 8 while admitting batches up to 128 and sweeping concurrency to 128: - disagg-1p1d-tp4p-tp8d-fixed-seq.yaml:97
cuda-graph-bs: [1, 2, 3, 4, 5, 6, 7, 8]in the prefill&common_configanchor. - :93max-running-requests: 128. - :100-102 decode does<<: *common_config…