Skip to content

Commit baca859

Browse files
committed
merge: sync upstream main
Merge current upstream/main and rebuild the append-only performance changelog with PR #2302 at the tail. 中文:同步上游 main。合并当前 upstream/main,并基于最新文件重新在性能变更日志末尾追加 PR #2302 条目。
2 parents 2c545dd + b38bf41 commit baca859

5 files changed

Lines changed: 191 additions & 31 deletions

File tree

benchmarks/multi_node/amd_utils/models.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,12 +409,12 @@ DeepSeek-V4-Pro-DI:
409409
max_running_requests: 1024
410410
chunked_prefill_size: 131072
411411
context_length: 9217
412-
max_total_tokens: 262144
412+
max_total_tokens: 2097152
413413
no_dp:
414414
max_running_requests: 128
415415
chunked_prefill_size: 131072
416416
context_length: 9217
417-
max_total_tokens: 262144
417+
max_total_tokens: 2097152
418418
decode:
419419
mem_fraction_static: 0.85
420420
prefill_round_robin_balance: true

benchmarks/multi_node/amd_utils/server_sglang.sh

Lines changed: 90 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -165,20 +165,23 @@ no_dp = decode.get('no_dp', {})
165165
# Decode DP config
166166
print(f'DECODE_MAX_RUNNING_REQUESTS_DP=\"{dp.get(\"max_running_requests\", 4096)}\"')
167167
print(f'DECODE_CHUNKED_PREFILL_SIZE_DP=\"{eval_formula(dp.get(\"chunked_prefill_size\", 262144))}\"')
168+
print(f'DECODE_CONTEXT_LENGTH_DP=\"{dp.get(\"context_length\", \"\")}\"')
168169
s, e = parse_range(dp.get('cuda_graph_bs_range', '1-160'), 1, 160)
169170
print(f'DECODE_CUDA_GRAPH_BS_DP_START=\"{s}\"')
170171
print(f'DECODE_CUDA_GRAPH_BS_DP_END=\"{e}\"')
171172
172173
# Decode EP-only config (EP enabled but DP disabled)
173174
print(f'DECODE_MAX_RUNNING_REQUESTS_EP_ONLY=\"{ep_only.get(\"max_running_requests\", 256)}\"')
174175
print(f'DECODE_CHUNKED_PREFILL_SIZE_EP_ONLY=\"{eval_formula(ep_only.get(\"chunked_prefill_size\", 262144))}\"')
176+
print(f'DECODE_CONTEXT_LENGTH_EP_ONLY=\"{ep_only.get(\"context_length\", \"\")}\"')
175177
s, e = parse_range(ep_only.get('cuda_graph_bs_range', '1-256'), 1, 256)
176178
print(f'DECODE_CUDA_GRAPH_BS_EP_ONLY_START=\"{s}\"')
177179
print(f'DECODE_CUDA_GRAPH_BS_EP_ONLY_END=\"{e}\"')
178180
179181
# Decode no-DP config
180182
print(f'DECODE_MAX_RUNNING_REQUESTS_NO_DP=\"{no_dp.get(\"max_running_requests\", 128)}\"')
181183
print(f'DECODE_CHUNKED_PREFILL_SIZE_NO_DP=\"{eval_formula(no_dp.get(\"chunked_prefill_size\", 262144))}\"')
184+
print(f'DECODE_CONTEXT_LENGTH_NO_DP=\"{no_dp.get(\"context_length\", \"\")}\"')
182185
s, e = parse_range(no_dp.get('cuda_graph_bs_range', '1-128'), 1, 128)
183186
print(f'DECODE_CUDA_GRAPH_BS_NO_DP_START=\"{s}\"')
184187
print(f'DECODE_CUDA_GRAPH_BS_NO_DP_END=\"{e}\"')
@@ -216,12 +219,23 @@ fi
216219
if [[ "$DECODE_ENABLE_DP" == "true" ]]; then
217220
decode_cuda_graph_bs=($(seq $DECODE_CUDA_GRAPH_BS_DP_START $DECODE_CUDA_GRAPH_BS_DP_END))
218221
decode_max_running_requests=$((DECODE_CUDA_GRAPH_BS_DP_END * DECODE_TP_SIZE))
222+
decode_context_length=$DECODE_CONTEXT_LENGTH_DP
219223
elif [[ "$DECODE_ENABLE_EP" == "true" ]]; then
220224
decode_cuda_graph_bs=($(seq $DECODE_CUDA_GRAPH_BS_EP_ONLY_START $DECODE_CUDA_GRAPH_BS_EP_ONLY_END))
221225
decode_max_running_requests=$DECODE_MAX_RUNNING_REQUESTS_EP_ONLY
226+
decode_context_length=$DECODE_CONTEXT_LENGTH_EP_ONLY
222227
else
223228
decode_cuda_graph_bs=($(seq $DECODE_CUDA_GRAPH_BS_NO_DP_START $DECODE_CUDA_GRAPH_BS_NO_DP_END))
224229
decode_max_running_requests=$DECODE_MAX_RUNNING_REQUESTS_NO_DP
230+
decode_context_length=$DECODE_CONTEXT_LENGTH_NO_DP
231+
fi
232+
# In PD-disaggregation the decode must admit requests against the SAME context
233+
# length as prefill; otherwise decode accepts over-length requests that prefill
234+
# rejects, and those requests hang forever waiting for a KV transfer that never
235+
# comes (the 8k1k conc-500 straggler). Fall back to the prefill value if the
236+
# decode context_length is not set in the model config, so the two always agree.
237+
if [[ -z "$decode_context_length" ]]; then
238+
decode_context_length=$prefill_context_length
225239
fi
226240

227241
# When both DP and EP are enabled, override max-running-requests and dispatch tokens
@@ -267,6 +281,10 @@ DECODE_MODE_FLAGS="--mem-fraction-static ${DECODE_MEM_FRACTION_STATIC} --max-run
267281
if [[ "$DECODE_PREFILL_ROUND_ROBIN_BALANCE" == "True" ]] || [[ "$DECODE_PREFILL_ROUND_ROBIN_BALANCE" == "true" ]]; then
268282
DECODE_MODE_FLAGS="$DECODE_MODE_FLAGS --prefill-round-robin-balance"
269283
fi
284+
if [[ -n "$decode_context_length" ]]; then
285+
DECODE_MODE_FLAGS="$DECODE_MODE_FLAGS --context-length ${decode_context_length}"
286+
fi
287+
270288
if [[ "$DECODE_DISAGG_ENABLE_RADIX_CACHE" == "True" ]] || [[ "$DECODE_DISAGG_ENABLE_RADIX_CACHE" == "true" ]]; then
271289
DECODE_MODE_FLAGS="$DECODE_MODE_FLAGS --disaggregation-decode-enable-radix-cache"
272290
fi
@@ -750,26 +768,37 @@ if [ "$NODE_RANK" -eq 0 ]; then
750768
fi
751769
echo "Congratulations!!! All prefill and decode servers are up . . ."
752770

753-
# Router resilience: a single prefill worker doing huge long-context prefills
754-
# (256K+ token agentic prompts in 65280-token chunks) can be slow to drain a
755-
# concurrent burst. With defaults the circuit breaker opens after 10 failures
756-
# and short-circuits the whole worker, so the aiperf profiling burst sees
757-
# "No available prefill workers (all circuits open or unhealthy)" and aborts
758-
# with 100% errors. Disable the breaker and relax health-check sensitivity so
759-
# a busy-but-alive worker is not ejected. Override via ROUTER_RESILIENCE_FLAGS.
760-
ROUTER_RESILIENCE_FLAGS="${ROUTER_RESILIENCE_FLAGS:---disable-circuit-breaker --health-failure-threshold 100 --health-check-timeout-secs 600 --health-check-interval-secs 30}"
761-
762-
# Router scheduling policy. cache_aware prefill routing exploits HiCache/radix
763-
# prefix reuse across the agentic trace; round_robin decode keeps the single
764-
# decode worker fed evenly. cache_threshold / balance_*_threshold tune the
765-
# cache_aware load-balancing (router defaults are 0.5 / 64 / 1.5). Override any
766-
# of these via env.
767-
ROUTER_PREFILL_POLICY="${ROUTER_PREFILL_POLICY:-cache_aware}"
768-
ROUTER_DECODE_POLICY="${ROUTER_DECODE_POLICY:-round_robin}"
769-
ROUTER_CACHE_THRESHOLD="${ROUTER_CACHE_THRESHOLD:-0.3}"
770-
ROUTER_BALANCE_ABS_THRESHOLD="${ROUTER_BALANCE_ABS_THRESHOLD:-2}"
771-
ROUTER_BALANCE_REL_THRESHOLD="${ROUTER_BALANCE_REL_THRESHOLD:-1.1}"
772-
ROUTER_POLICY_FLAGS="${ROUTER_POLICY_FLAGS:---policy ${ROUTER_PREFILL_POLICY} --prefill-policy ${ROUTER_PREFILL_POLICY} --decode-policy ${ROUTER_DECODE_POLICY} --cache-threshold ${ROUTER_CACHE_THRESHOLD} --balance-abs-threshold ${ROUTER_BALANCE_ABS_THRESHOLD} --balance-rel-threshold ${ROUTER_BALANCE_REL_THRESHOLD}}"
771+
if [[ "${IS_AGENTIC:-0}" == "1" || "${IS_AGENTIC:-}" == "true" ]]; then
772+
# Agentic router config (main): long-context prefills can look unhealthy to
773+
# the default circuit breaker during a concurrent burst. Disable the breaker
774+
# and relax health-check sensitivity so a busy-but-alive worker is not
775+
# ejected. cache_aware prefill routing exploits HiCache/radix prefix reuse
776+
# across the agentic trace; round_robin decode keeps the single decode worker
777+
# fed evenly. Override via ROUTER_RESILIENCE_FLAGS / ROUTER_POLICY_FLAGS.
778+
ROUTER_RESILIENCE_FLAGS="${ROUTER_RESILIENCE_FLAGS:---disable-circuit-breaker --health-failure-threshold 100 --health-check-timeout-secs 600 --health-check-interval-secs 30}"
779+
ROUTER_PREFILL_POLICY="${ROUTER_PREFILL_POLICY:-cache_aware}"
780+
ROUTER_DECODE_POLICY="${ROUTER_DECODE_POLICY:-round_robin}"
781+
ROUTER_CACHE_THRESHOLD="${ROUTER_CACHE_THRESHOLD:-0.3}"
782+
ROUTER_BALANCE_ABS_THRESHOLD="${ROUTER_BALANCE_ABS_THRESHOLD:-2}"
783+
ROUTER_BALANCE_REL_THRESHOLD="${ROUTER_BALANCE_REL_THRESHOLD:-1.1}"
784+
ROUTER_POLICY_FLAGS="${ROUTER_POLICY_FLAGS:---policy ${ROUTER_PREFILL_POLICY} --prefill-policy ${ROUTER_PREFILL_POLICY} --decode-policy ${ROUTER_DECODE_POLICY} --cache-threshold ${ROUTER_CACHE_THRESHOLD} --balance-abs-threshold ${ROUTER_BALANCE_ABS_THRESHOLD} --balance-rel-threshold ${ROUTER_BALANCE_REL_THRESHOLD}}"
785+
else
786+
# DI router config (8k1k branch, run 28696443568): with defaults the per-worker
787+
# circuit stays OPEN for cb-timeout-duration-secs=60 before a half-open retrial.
788+
# In that run every request 503'd from request #1 ("all circuits open or
789+
# unhealthy") for ~31s and lm_eval (max_retries=5) then gave up -- i.e. the
790+
# circuit was still open when the client budget ran out, so 0 result files were
791+
# produced. Shortening the open->half-open window (and letting the router itself
792+
# retry a failed worker selection) lets a transient trip re-close INSIDE the
793+
# client retry budget instead of nuking the whole eval. The breaker stays fully
794+
# ENABLED (thresholds unchanged); this only speeds recovery. Override via
795+
# ROUTER_CB_ARGS / ROUTER_POLICY_FLAGS.
796+
ROUTER_CB_ARGS="${ROUTER_CB_ARGS:---cb-timeout-duration-secs 15 --retry-max-retries 3}"
797+
ROUTER_POLICY_FLAGS="${ROUTER_POLICY_FLAGS:---policy random --prefill-policy random --decode-policy random}"
798+
ROUTER_RESILIENCE_FLAGS="${ROUTER_RESILIENCE_FLAGS:-${ROUTER_CB_ARGS}}"
799+
fi
800+
801+
echo "Router config: IS_AGENTIC=${IS_AGENTIC:-0} policy/resilience=${ROUTER_POLICY_FLAGS} ${ROUTER_RESILIENCE_FLAGS}"
773802

774803
ROUTER_CMD="python -m sglang_router.launch_router \
775804
--pd-disaggregation \
@@ -822,6 +851,47 @@ if [ "$NODE_RANK" -eq 0 ]; then
822851
wait_or_die "$prefill0_pid" bash -c "$HEALTH_BARRIER_CMD" || exit 1
823852
fi
824853

854+
# ---- End-to-end router readiness canary (run 28696443568) ----
855+
# The /readiness barrier above only proves the router PROCESS is up; it does
856+
# NOT prove the router can reach a prefill worker and complete a generation.
857+
# In that run the eval fired the instant /readiness passed and EVERY request
858+
# 503'd ("No available prefill workers (all circuits open or unhealthy)") from
859+
# request #1 -> lm_eval gave up -> 0 result files -> "Verify eval scores" failed.
860+
# Gate the benchmark on ONE successful generation THROUGH the router so the eval
861+
# never starts against a router whose prefill path is not yet actually serving.
862+
#
863+
# Run the poll loop under wait_or_die (like the barriers above) rather than
864+
# inline: the canary is the FIRST real generation through prefill, so a
865+
# prefill crash right after /readiness passes is plausible. Without
866+
# wait_or_die watching prefill0_pid, that just looks like repeated 503s and
867+
# the loop burns the full ROUTER_CANARY_TIMEOUT (default 600s) instead of
868+
# detecting the dead pid and aborting in ~5s.
869+
run_router_canary() {
870+
local canary_url="http://${NODE0_ADDR}:30000/v1/chat/completions"
871+
local canary_model="${MODEL_DIR}/${MODEL_NAME}"
872+
local canary_deadline=$(( $(date +%s) + ${ROUTER_CANARY_TIMEOUT:-600} ))
873+
local canary_code
874+
while [ "$(date +%s)" -lt "$canary_deadline" ]; do
875+
canary_code=$(curl -s -o /tmp/router_canary.out -w '%{http_code}' \
876+
-m "${ROUTER_CANARY_REQ_TIMEOUT:-120}" \
877+
-X POST "$canary_url" -H 'Content-Type: application/json' \
878+
-d "{\"model\":\"${canary_model}\",\"messages\":[{\"role\":\"user\",\"content\":\"ping\"}],\"max_tokens\":1,\"temperature\":0}" 2>/dev/null)
879+
if [ "$canary_code" = "200" ] && \
880+
! grep -qE "circuits open|server_selection_failed|No available" /tmp/router_canary.out 2>/dev/null; then
881+
echo "Router readiness canary passed (end-to-end generation OK)"
882+
return 0
883+
fi
884+
echo "Router readiness canary not ready yet (http=${canary_code}); retrying in 5s . . ."
885+
sleep 5
886+
done
887+
echo "ERROR: router readiness canary failed after ${ROUTER_CANARY_TIMEOUT:-600}s -- the router cannot complete a generation through a prefill worker (all circuits open/unhealthy). Refusing to start the eval against a non-serving router."
888+
head -c 800 /tmp/router_canary.out 2>/dev/null
889+
return 1
890+
}
891+
if [[ "${ROUTER_READINESS_CANARY:-1}" == "1" ]]; then
892+
wait_or_die "$prefill0_pid" run_router_canary || exit 1
893+
fi
894+
825895
echo "Router is ready for benchmarking"
826896
fi
827897

benchmarks/single_node/fixed_seq_len/minimaxm3_fp8_mi355x.sh

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@
33
# MiniMax-M3 MXFP8 MI355X (gfx950) single-node vLLM recipe.
44
# https://github.com/vllm-project/recipes/commit/2a3728ed9892debfd767a72a58ebc90b33f186e5
55
# The recipe recommends MXFP8 from TP=4 on gfx950 and requires block size 128.
6+
#
7+
# AITER page-16 sparse paged-attention fast path (vllm-project/vllm#47287,
8+
# merged into the pinned nightly): maps MiniMax-M3's top-k 128-token sparse
9+
# blocks onto AITER page-16 block tables and runs AITER Gluon paged attention
10+
# over only the selected KV pages. This is a kernel-level speedup of the same
11+
# sparse-attention computation (no FLOP reduction), enabled via
12+
# VLLM_ROCM_USE_AITER=1 + VLLM_ROCM_SHUFFLE_KV_CACHE_LAYOUT=1 with fp8 KV cache
13+
# on a TP where each rank has num_kv_heads == 1 (TP4). We deliberately do NOT
14+
# pass the #47269 --hf-overrides use_index_cache/index_topk_freq cross-layer
15+
# indexer-skip override: it reduces model-architecture FLOPs, which is
16+
# disallowed by docs/PR_REVIEW_CHECKLIST.md.
617

718
source "$(dirname "$0")/../../benchmark_lib.sh"
819

@@ -31,10 +42,39 @@ fi
3142
SERVER_LOG=/workspace/server.log
3243
export VLLM_ENGINE_READY_TIMEOUT_S=3600
3344
export VLLM_USE_BREAKABLE_CUDAGRAPH=0
34-
# MI355X mxfp8 recipe (vllm-project/recipes#581): INT6 quick all-reduce plus
35-
# the router-append shared-experts MoE fusion (vllm-project/vllm#46545).
45+
# MI355X mxfp8 recipe (vllm-project/recipes#581): INT4 quick all-reduce plus
46+
# the router-append shared-experts MoE fusion (vllm-project/vllm#46545). INT4
47+
# quick all-reduce is applied at all concurrencies (accuracy is guarded by the
48+
# 8k1k evals); #2003 used INT6.
3649
export VLLM_ROCM_USE_AITER_FUSION_SHARED_EXPERTS=1
37-
export VLLM_ROCM_QUICK_REDUCE_QUANTIZATION=INT6
50+
export VLLM_ROCM_QUICK_REDUCE_QUANTIZATION=INT4
51+
52+
# AITER page-16 sparse PA (vllm-project/vllm#47287) is a long-context,
53+
# high-concurrency optimization: it maps MiniMax-M3's top-k 128-token sparse
54+
# blocks onto AITER page-16 block tables. Measured on gfx950 MXFP8, it only wins
55+
# in the 8k1k high-concurrency tail and adds overhead at short context (1k1k) or
56+
# low batch. So enable the "high-conc fast path" (shuffled KV-cache layout for
57+
# sparse PA + the emulation dense-linear backend, see below) only for
58+
# isl>=8192 && conc>=64; everywhere else fall back to the #2003 path
59+
# (non-shuffled Triton attention + native linear). Overridable via
60+
# MM3_HIGH_CONC_FASTPATH=0/1.
61+
if [ -z "${MM3_HIGH_CONC_FASTPATH:-}" ]; then
62+
if [ "$ISL" -ge 8192 ] && [ "$CONC" -ge 64 ]; then
63+
MM3_HIGH_CONC_FASTPATH=1
64+
else
65+
MM3_HIGH_CONC_FASTPATH=0
66+
fi
67+
fi
68+
69+
if [ "$MM3_HIGH_CONC_FASTPATH" = "1" ]; then
70+
export VLLM_ROCM_SHUFFLE_KV_CACHE_LAYOUT=1
71+
# Quick all-reduce tuning from the MiniMax-M3 AITER recipe (vllm-project/vllm#47287):
72+
# keep the bf16 accumulation and only quantize all-reduces above 256 KB.
73+
export VLLM_ROCM_QUICK_REDUCE_CAST_BF16_TO_FP16=0
74+
export VLLM_ROCM_QUICK_REDUCE_QUANTIZATION_MIN_SIZE_KB=256
75+
else
76+
export VLLM_ROCM_SHUFFLE_KV_CACHE_LAYOUT=0
77+
fi
3878

3979
if [ "${EVAL_ONLY}" = "true" ]; then
4080
setup_eval_context
@@ -61,6 +101,18 @@ export VLLM_ROCM_USE_AITER=1
61101
# concurrency. Overridable via env.
62102
MAX_NUM_BATCHED_TOKENS="${MAX_NUM_BATCHED_TOKENS:-32768}"
63103

104+
# Dense-linear backend, gated on the same high-conc fast path as sparse PA. On
105+
# this nightly the native Triton MXFP8 linear GEMM wins in the memory-bound
106+
# low-concurrency regime, while --linear-backend emulation (bf16 hipBLASLT) wins
107+
# in the compute-bound high-concurrency regime (~+3-5% at 8k1k conc>=64).
108+
# LINEAR_BACKEND overrides (a backend name to force it, or "native" to disable).
109+
LINEAR_ARGS=()
110+
if [ -n "${LINEAR_BACKEND:-}" ]; then
111+
[ "$LINEAR_BACKEND" != "native" ] && LINEAR_ARGS=(--linear-backend "$LINEAR_BACKEND")
112+
elif [ "$MM3_HIGH_CONC_FASTPATH" = "1" ]; then
113+
LINEAR_ARGS=(--linear-backend emulation)
114+
fi
115+
64116
start_gpu_monitor
65117

66118
set -x
@@ -74,7 +126,7 @@ vllm serve "$MODEL" --port "$PORT" \
74126
--max-num-batched-tokens "$MAX_NUM_BATCHED_TOKENS" \
75127
--kv-cache-dtype fp8 \
76128
--attention-backend TRITON_ATTN \
77-
--linear-backend emulation \
129+
"${LINEAR_ARGS[@]}" \
78130
--tool-call-parser minimax_m3 \
79131
--reasoning-parser minimax_m3 \
80132
--enable-auto-tool-choice > "$SERVER_LOG" 2>&1 &

configs/amd-master.yaml

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,17 +1166,34 @@ dsv4-fp4-mi355x-sglang-disagg:
11661166
additional-settings:
11671167
- "DECODE_NODES=1"
11681168
- "DECODE_MTP_SIZE=0"
1169-
11701169
# 1P1D DEP8 (mori KV transfer + mori MoE a2a, dp-attention)
11711170
- spec-decoding: "none"
1172-
conc-list: [ 128, 256 ]
1171+
conc-list: [ 256 ]
11731172
prefill:
1174-
num-worker: 2
1173+
num-worker: 1
11751174
tp: 8
11761175
ep: 8
11771176
dp-attn: true
11781177
additional-settings:
1179-
- "PREFILL_NODES=2"
1178+
- "PREFILL_NODES=1"
1179+
decode:
1180+
num-worker: 1
1181+
tp: 8
1182+
ep: 8
1183+
dp-attn: true
1184+
additional-settings:
1185+
- "DECODE_NODES=1"
1186+
- "DECODE_MTP_SIZE=0"
1187+
1188+
- spec-decoding: "none"
1189+
conc-list: [ 512 ]
1190+
prefill:
1191+
num-worker: 1
1192+
tp: 8
1193+
ep: 8
1194+
dp-attn: true
1195+
additional-settings:
1196+
- "PREFILL_NODES=1"
11801197
decode:
11811198
num-worker: 1
11821199
tp: 8
@@ -1604,7 +1621,7 @@ dsv4-fp4-mi355x-atom-disagg:
16041621
- "DECODE_NODES=1"
16051622
# 1P1D TP8
16061623
minimaxm3-fp8-mi355x-vllm:
1607-
image: vllm/vllm-openai-rocm:nightly-09663abde0f50944a8d5ea30120666024b503faa
1624+
image: vllm/vllm-openai-rocm:nightly-9e57de7197f234f9d9187715d96e07e007048c0f
16081625
model: MiniMaxAI/MiniMax-M3-MXFP8
16091626
model-prefix: minimaxm3
16101627
runner: mi355x

0 commit comments

Comments
 (0)