-
Notifications
You must be signed in to change notification settings - Fork 292
feat: add Qwen3.5 RTX PRO 6000 SGLang recipe / 新增 Qwen3.5 RTX PRO 6000 SGLang 基准配置 #2312
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
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
47133a8
feat: add RTX PRO 6000 Latitude runner
Oseltamivir b29acc2
feat: add Qwen3.5 RTX PRO 6000 vLLM sweep
Oseltamivir 905f89d
docs: record Qwen3.5 RTX PRO 6000 sweep
Oseltamivir cca657c
feat: switch Qwen3.5 RTX PRO 6000 recipe from vLLM to SGLang
Oseltamivir ca09d82
Merge remote-tracking branch 'origin/main' into agent/qwen35-rtx6000p…
Oseltamivir a28493b
fix: restore Qwen3.5 RTX PRO 6000 SGLang changelog entry
Oseltamivir a071d99
feat: add MTP arm to the Qwen3.5 RTX PRO 6000 SGLang recipe
Oseltamivir 772ae0e
Merge remote-tracking branch 'origin/main' into agent/qwen35-rtx6000p…
Oseltamivir a32ebb3
Merge origin/main into agent/qwen35-rtx6000pro-vllm
functionstackx a45bd32
chore: refresh PR #2312 for sweep reuse [skip-sweep]
functionstackx File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
128 changes: 128 additions & 0 deletions
128
benchmarks/single_node/fixed_seq_len/qwen3.5_fp4_rtx6000pro_sglang.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| # Qwen3.5-397B-A17B NVFP4 on four RTX PRO 6000 Blackwell GPUs. | ||
| # SM120 has no trtllm-gen kernels, so the routed experts and the NVFP4 GEMMs | ||
| # run on FlashInfer CUTLASS and attention runs on FlashInfer. The node is | ||
| # PCIe-only, so collectives use plain NCCL rather than the custom all-reduce. | ||
|
|
||
| source "$(dirname "$0")/../../benchmark_lib.sh" | ||
|
|
||
| check_env_vars \ | ||
| MODEL \ | ||
| TP \ | ||
| EP_SIZE \ | ||
| CONC \ | ||
| ISL \ | ||
| OSL \ | ||
| RANDOM_RANGE_RATIO \ | ||
| RESULT_FILENAME | ||
|
|
||
| # `hf download` creates the target dir if missing and is itself idempotent. | ||
| # When MODEL_PATH is unset (stand-alone runs), fall back to the HF_HUB_CACHE | ||
| # copy. Either way, SERVE_MODEL is what the server is launched with. | ||
| if [[ -n "${MODEL_PATH:-}" ]]; then | ||
| if [[ ! -d "$MODEL_PATH" || -z "$(ls -A "$MODEL_PATH" 2>/dev/null)" ]]; then | ||
| hf download "$MODEL" --local-dir "$MODEL_PATH" | ||
| fi | ||
| SERVE_MODEL="$MODEL_PATH" | ||
| else | ||
| hf download "$MODEL" | ||
| SERVE_MODEL="$MODEL" | ||
| fi | ||
|
|
||
| if [[ -n "${SLURM_JOB_ID:-}" ]]; then | ||
| echo "JOB $SLURM_JOB_ID running on $SLURMD_NODENAME" | ||
| fi | ||
|
|
||
| nvidia-smi | ||
|
|
||
| export SGLANG_ENABLE_JIT_DEEPGEMM=false | ||
| export PYTHONUNBUFFERED=1 | ||
|
|
||
| SERVER_LOG=/workspace/server.log | ||
|
|
||
| # 96 GiB per GPU leaves far less headroom than the B300 recipe assumes. The | ||
| # weights take ~56 GiB per rank and the prefill/decode CUDA graphs another | ||
| # ~7 GiB, so the static fraction has to stay low enough that a prefill chunk's | ||
| # activations still fit: at 0.8 the KV pool grew to 2.2M tokens (30x what | ||
| # concurrency 64 needs) and the first 8k prefill OOM'd. 0.7 still leaves ~1M | ||
| # KV tokens, and a 2-request prefill chunk keeps the activation peak bounded. | ||
| MEM_FRAC_STATIC="${MEM_FRAC_STATIC:-0.7}" | ||
| CHUNKED_PREFILL_SIZE=$((ISL * 2)) | ||
| MAX_PREFILL_TOKENS=$((ISL * 2)) | ||
| MAX_RUNNING_REQUESTS=128 | ||
| CONTEXT_LENGTH=$((ISL + OSL + 20)) | ||
|
|
||
| # Default: recv every ~10 requests; if CONC >= 16, relax to ~30 requests between scheduler recv polls. | ||
| if [[ $CONC -ge 16 ]]; then | ||
| SCHEDULER_RECV_INTERVAL=30 | ||
| else | ||
| SCHEDULER_RECV_INTERVAL=10 | ||
| fi | ||
|
|
||
| if [[ "$EVAL_ONLY" == "true" ]]; then | ||
| setup_eval_context | ||
| CONTEXT_LENGTH="$EVAL_MAX_MODEL_LEN" | ||
| fi | ||
|
|
||
| echo "SCHEDULER_RECV_INTERVAL: $SCHEDULER_RECV_INTERVAL, CONC: $CONC, ISL: $ISL, OSL: $OSL" | ||
|
|
||
| start_gpu_monitor | ||
|
|
||
| set -x | ||
| PYTHONNOUSERSITE=1 python3 -m sglang.launch_server \ | ||
| --model-path "$SERVE_MODEL" \ | ||
| --served-model-name "$MODEL" \ | ||
| --host 0.0.0.0 \ | ||
| --port "$PORT" \ | ||
| --trust-remote-code \ | ||
| --tensor-parallel-size "$TP" \ | ||
| --data-parallel-size 1 \ | ||
| --ep-size "$EP_SIZE" \ | ||
| --reasoning-parser qwen3 \ | ||
| --tool-call-parser qwen3_coder \ | ||
| --quantization modelopt_fp4 \ | ||
| --fp4-gemm-backend flashinfer_cutlass \ | ||
| --moe-runner-backend flashinfer_cutlass \ | ||
| --attention-backend flashinfer \ | ||
| --kv-cache-dtype fp8_e4m3 \ | ||
| --mamba-ssm-dtype bfloat16 \ | ||
| --mamba-scheduler-strategy no_buffer \ | ||
| --disable-custom-all-reduce \ | ||
| --disable-radix-cache \ | ||
| --mem-fraction-static "$MEM_FRAC_STATIC" \ | ||
| --chunked-prefill-size "$CHUNKED_PREFILL_SIZE" \ | ||
| --max-prefill-tokens "$MAX_PREFILL_TOKENS" \ | ||
| --context-length "$CONTEXT_LENGTH" \ | ||
| --cuda-graph-max-bs-decode "$CONC" \ | ||
| --max-running-requests "$MAX_RUNNING_REQUESTS" \ | ||
| --scheduler-recv-interval "$SCHEDULER_RECV_INTERVAL" \ | ||
| --stream-interval 20 > "$SERVER_LOG" 2>&1 & | ||
|
|
||
| SERVER_PID=$! | ||
|
|
||
| wait_for_server_ready \ | ||
| --port "$PORT" \ | ||
| --server-log "$SERVER_LOG" \ | ||
| --server-pid "$SERVER_PID" | ||
|
|
||
| run_benchmark_serving \ | ||
| --model "$MODEL" \ | ||
| --port "$PORT" \ | ||
| --backend vllm \ | ||
| --input-len "$ISL" \ | ||
| --output-len "$OSL" \ | ||
| --random-range-ratio "$RANDOM_RANGE_RATIO" \ | ||
| --num-prompts "$((CONC * 10))" \ | ||
| --max-concurrency "$CONC" \ | ||
| --result-filename "$RESULT_FILENAME" \ | ||
| --result-dir /workspace/ \ | ||
| --trust-remote-code | ||
|
|
||
| if [[ "$RUN_EVAL" == "true" ]]; then | ||
| run_eval --framework lm-eval --port "$PORT" | ||
| append_lm_eval_summary | ||
| fi | ||
|
|
||
| stop_gpu_monitor | ||
| set +x |
141 changes: 141 additions & 0 deletions
141
benchmarks/single_node/fixed_seq_len/qwen3.5_fp4_rtx6000pro_sglang_mtp.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| # Qwen3.5-397B-A17B NVFP4 on four RTX PRO 6000 Blackwell GPUs, with the | ||
| # built-in MTP draft head driven through SGLang's EAGLE speculative path. | ||
| # SM120 has no trtllm-gen kernels, so the routed experts and the NVFP4 GEMMs | ||
| # run on FlashInfer CUTLASS and attention runs on FlashInfer. The node is | ||
| # PCIe-only, so collectives use plain NCCL rather than the custom all-reduce. | ||
|
|
||
| source "$(dirname "$0")/../../benchmark_lib.sh" | ||
|
|
||
| check_env_vars \ | ||
| MODEL \ | ||
| TP \ | ||
| EP_SIZE \ | ||
| CONC \ | ||
| ISL \ | ||
| OSL \ | ||
| RANDOM_RANGE_RATIO \ | ||
| RESULT_FILENAME | ||
|
|
||
| # `hf download` creates the target dir if missing and is itself idempotent. | ||
| # When MODEL_PATH is unset (stand-alone runs), fall back to the HF_HUB_CACHE | ||
| # copy. Either way, SERVE_MODEL is what the server is launched with. | ||
| if [[ -n "${MODEL_PATH:-}" ]]; then | ||
| if [[ ! -d "$MODEL_PATH" || -z "$(ls -A "$MODEL_PATH" 2>/dev/null)" ]]; then | ||
| hf download "$MODEL" --local-dir "$MODEL_PATH" | ||
| fi | ||
| SERVE_MODEL="$MODEL_PATH" | ||
| else | ||
| hf download "$MODEL" | ||
| SERVE_MODEL="$MODEL" | ||
| fi | ||
|
|
||
| if [[ -n "${SLURM_JOB_ID:-}" ]]; then | ||
| echo "JOB $SLURM_JOB_ID running on $SLURMD_NODENAME" | ||
| fi | ||
|
|
||
| nvidia-smi | ||
|
|
||
| export SGLANG_ENABLE_JIT_DEEPGEMM=false | ||
| export PYTHONUNBUFFERED=1 | ||
|
|
||
| SERVER_LOG=/workspace/server.log | ||
|
|
||
| # SGLang holds back total * (1 - mem-fraction-static) as slack and gives the | ||
| # rest to the KV and Mamba pools, so the MTP draft head (Qwen3_5ForCausalLMMTP, | ||
| # 4.05 GiB per rank on top of the 56.12 GiB target model) has to be paid for by | ||
| # raising the fraction, not lowering it. 0.65 and 0.75 both left the pools | ||
| # empty on this 96 GiB SKU once the draft's own Mamba state was accounted for. | ||
| # 0.85 came up but left only 4.56 GiB free per rank, too thin for a 16k prefill | ||
| # chunk, so 0.80 trades surplus KV (1.7M tokens, ~3x what concurrency 64 needs) | ||
| # for activation headroom. | ||
| MEM_FRAC_STATIC="${MEM_FRAC_STATIC:-0.80}" | ||
| CHUNKED_PREFILL_SIZE=$((ISL * 2)) | ||
| MAX_PREFILL_TOKENS=$((ISL * 2)) | ||
| # The client never opens more than CONC connections, so sizing the Mamba state | ||
| # pool for 128 requests (as the B300 recipe does) just strands memory that the | ||
| # draft head needs here. | ||
| MAX_RUNNING_REQUESTS="$CONC" | ||
| CONTEXT_LENGTH=$((ISL + OSL + 20)) | ||
|
|
||
| # Default: recv every ~10 requests; if CONC >= 16, relax to ~30 requests between scheduler recv polls. | ||
| if [[ $CONC -ge 16 ]]; then | ||
| SCHEDULER_RECV_INTERVAL=30 | ||
| else | ||
| SCHEDULER_RECV_INTERVAL=10 | ||
| fi | ||
|
|
||
| if [[ "$EVAL_ONLY" == "true" ]]; then | ||
| setup_eval_context | ||
| CONTEXT_LENGTH="$EVAL_MAX_MODEL_LEN" | ||
| fi | ||
|
|
||
| echo "SCHEDULER_RECV_INTERVAL: $SCHEDULER_RECV_INTERVAL, CONC: $CONC, ISL: $ISL, OSL: $OSL" | ||
|
|
||
| start_gpu_monitor | ||
|
|
||
| set -x | ||
| PYTHONNOUSERSITE=1 python3 -m sglang.launch_server \ | ||
| --model-path "$SERVE_MODEL" \ | ||
| --served-model-name "$MODEL" \ | ||
| --host 0.0.0.0 \ | ||
| --port "$PORT" \ | ||
| --trust-remote-code \ | ||
| --tensor-parallel-size "$TP" \ | ||
| --data-parallel-size 1 \ | ||
| --ep-size "$EP_SIZE" \ | ||
| --reasoning-parser qwen3 \ | ||
| --tool-call-parser qwen3_coder \ | ||
| --quantization modelopt_fp4 \ | ||
| --fp4-gemm-backend flashinfer_cutlass \ | ||
| --moe-runner-backend flashinfer_cutlass \ | ||
| --attention-backend flashinfer \ | ||
| --kv-cache-dtype fp8_e4m3 \ | ||
| --mamba-ssm-dtype bfloat16 \ | ||
| --mamba-scheduler-strategy no_buffer \ | ||
| --disable-custom-all-reduce \ | ||
| --disable-radix-cache \ | ||
| --mem-fraction-static "$MEM_FRAC_STATIC" \ | ||
| --chunked-prefill-size "$CHUNKED_PREFILL_SIZE" \ | ||
| --max-prefill-tokens "$MAX_PREFILL_TOKENS" \ | ||
| --context-length "$CONTEXT_LENGTH" \ | ||
| --cuda-graph-max-bs-decode "$CONC" \ | ||
| --max-running-requests "$MAX_RUNNING_REQUESTS" \ | ||
| --scheduler-recv-interval "$SCHEDULER_RECV_INTERVAL" \ | ||
| --stream-interval 20 \ | ||
| --speculative-algorithm EAGLE \ | ||
| --speculative-num-steps 3 \ | ||
| --speculative-eagle-topk 1 \ | ||
| --speculative-num-draft-tokens 4 > "$SERVER_LOG" 2>&1 & | ||
|
|
||
| SERVER_PID=$! | ||
|
|
||
| wait_for_server_ready \ | ||
| --port "$PORT" \ | ||
| --server-log "$SERVER_LOG" \ | ||
| --server-pid "$SERVER_PID" | ||
|
|
||
| # EAGLE-style spec decoding is trained against chat-formatted inputs, so the | ||
| # benchmark must send chat prompts or the acceptance rate silently collapses. | ||
| run_benchmark_serving \ | ||
| --model "$MODEL" \ | ||
| --port "$PORT" \ | ||
| --backend vllm \ | ||
| --input-len "$ISL" \ | ||
| --output-len "$OSL" \ | ||
| --random-range-ratio "$RANDOM_RANGE_RATIO" \ | ||
| --num-prompts "$((CONC * 10))" \ | ||
| --max-concurrency "$CONC" \ | ||
| --result-filename "$RESULT_FILENAME" \ | ||
| --result-dir /workspace/ \ | ||
| --use-chat-template \ | ||
| --trust-remote-code | ||
|
|
||
| if [[ "$RUN_EVAL" == "true" ]]; then | ||
| run_eval --framework lm-eval --port "$PORT" | ||
| append_lm_eval_summary | ||
| fi | ||
|
|
||
| stop_gpu_monitor | ||
| set +x |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
🔴 BLOCKING: Master config was modified but
perf-changelog.yamlwas not updated. This is the same issue flagged in the previous review — it now applies to the renamed keyqwen3.5-fp4-rtx6000pro-sglang(the changelog still has nortx6000proentry at all).Why it matters: Per AGENTS.md,
perf-changelog.yamlis the append-only benchmark trigger log. Without an entry, the new recipe won't be picked up for benchmarking after merge, which defeats the purpose of the PR.Fix: Append this to the end of
perf-changelog.yaml(it's read chronologically, newest at the bottom):Fix this →
🔴 阻断性问题:修改了 master 配置但没有更新
perf-changelog.yaml。这与上次审阅指出的问题相同——现在适用于重命名后的配置项qwen3.5-fp4-rtx6000pro-sglang(变更日志中仍然没有任何rtx6000pro条目)。根据 AGENTS.md,该文件是仅追加的基准测试触发日志;缺少条目会导致合并后新配方不会被触发进行基准测试。请将上述条目追加到perf-changelog.yaml文件末尾(按时间顺序读取,最新的在底部)。