Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benchmarks/benchmark_lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1660,7 +1660,7 @@ resolve_trace_source() {
# WEKA_LOADER_OVERRIDE.
local default_loader
case "${MODEL_PREFIX:-}" in
dsv4*|minimaxm3*)
dsv4*|glm5.2*|minimaxm3*)
default_loader="semianalysis_cc_traces_weka_062126"
;;
*)
Expand Down
150 changes: 150 additions & 0 deletions benchmarks/single_node/agentic/glm5.2_fp4_b300_sglang.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/usr/bin/env bash
set -euo pipefail
set -x

# Agentic trace replay benchmark for GLM-5.2 NVFP4 on B300 using SGLang.

Check warning on line 5 in benchmarks/single_node/agentic/glm5.2_fp4_b300_sglang.sh

View check run for this annotation

Claude / Claude Code Review

PR title/description missing required Chinese translation

This PR's title and description are English-only, violating the AGENTS.md rule that all PR titles/descriptions must be bilingual (title format '<English> / <中文标题>' plus a mirrored Chinese section in the body).
Comment on lines +1 to +5

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.

🟡 This PR's title and description are English-only, violating the AGENTS.md rule that all PR titles/descriptions must be bilingual (title format ' / <中文标题>' plus a mirrored Chinese section in the body).

Extended reasoning...

AGENTS.md line 7 states as an explicit, mandatory rule: "PR and GitHub-issue titles & descriptions must be bilingual — include a Simplified Chinese version in addition to English. Title format: <English title> / <中文标题>. In the PR/issue body, follow the English content with its Chinese translation (e.g. a ## 中文说明 section mirroring the summary...)". This applies to every PR, with no carve-out for benchmark-recipe PRs.

This PR's title is 'Add GLM-5.2 NVFP4 B300 SGLang single-node agentic benchmarks' — no '/ <中文标题>' suffix — and the description's Summary, Changes, and Validation sections are entirely in English with no mirrored '## 中文说明' section or equivalent.

This is not a matter of subjective style: the repo's own commit log shows a sibling recipe PR following the rule correctly. Commit d85fa13 (PR #2182) has the bilingual title 'Add MiniMax M3 8k/1k Dynamo vLLM B300 EAGLE recipes / 新增 MiniMax M3 8k/1k Dynamo vLLM B300 EAGLE 配方', proving other contributors in this exact benchmark-recipe workflow are expected to (and do) satisfy the rule. This PR is the outlier.

Step-by-step proof:

  1. AGENTS.md:7 mandates bilingual title format ' / <中文标题>' and a mirrored Chinese section in the body for every PR.
  2. This PR's title metadata reads 'Add GLM-5.2 NVFP4 B300 SGLang single-node agentic benchmarks' — checking the string for '/' followed by CJK characters finds none.
  3. The description contains only '## Summary', '## Changes', '## Validation' — all English — with no '## 中文说明' or any CJK text anywhere in the body.
  4. Comparing against PR Add MiniMax M3 8k/1k Dynamo vLLM B300 EAGLE recipes / 新增 MiniMax M3 8k/1k Dynamo vLLM B300 EAGLE 配方 #2182 in the git log (same repo, same benchmark-recipe category, merged 3 commits prior) shows the correctly-formatted bilingual title, confirming the rule is actively enforced/followed elsewhere and this PR is non-compliant.

Impact: none on benchmark correctness or CI — this is a process/documentation compliance gap, not a code defect. Fix is simple: the author (or whoever finalizes the merge) should append '/ <一句中文标题>' to the PR title and add a '## 中文说明' section mirroring the Summary/Changes/Validation content before merge.

#
# Server flags follow the SGLang cookbook B300 NVFP4 single-node recipes
# (https://docs.sglang.io/cookbook/autoregressive/GLM/GLM-5.2), STP only:
# the cookbook's EAGLE MTP variants are intentionally not wired up yet.
# DP_ATTENTION=false -> low-latency arm (TP8, fp8 KV, cutedsl bf16 GEMM)
# DP_ATTENTION=true -> high-throughput arm (TP8 + DP8 attention-DP)
#
# Required env vars:
# MODEL, TP, CONC, KV_OFFLOADING, TOTAL_CPU_DRAM_GB, RESULT_DIR, DURATION,
# EP_SIZE, DP_ATTENTION

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

check_env_vars MODEL TP CONC KV_OFFLOADING TOTAL_CPU_DRAM_GB RESULT_DIR DURATION EP_SIZE DP_ATTENTION

if [[ "$KV_OFFLOADING" != "none" ]]; then
echo "Error: KV_OFFLOADING=$KV_OFFLOADING is not supported by this recipe" >&2
exit 1
fi

if [[ -n "${SLURM_JOB_ID:-}" ]]; then
echo "JOB $SLURM_JOB_ID running on ${SLURMD_NODENAME:-unknown}"
fi

# `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.
# Either way, MODEL_PATH 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
else
hf download "$MODEL"
export MODEL_PATH="$MODEL"
fi
nvidia-smi

resolve_trace_source
install_agentic_deps

SERVER_LOG="$RESULT_DIR/server.log"
mkdir -p "$RESULT_DIR"

# With attention-DP, front the DP ranks with sglang-router using consistent
# hashing on the AIPerf correlation id so multi-turn sessions stay on the DP
# rank that holds their radix-cache prefix.
USE_SGLANG_ROUTER=false
SGLANG_BACKEND_PORT="$PORT"
ROUTER_LOG="$RESULT_DIR/router.log"
if [ "$DP_ATTENTION" = "true" ]; then
USE_SGLANG_ROUTER=true
export AIPERF_HTTP_X_SMG_ROUTING_KEY_FROM_CORRELATION_ID=true
SGLANG_BACKEND_PORT=$((PORT + 1))
SGLANG_ROUTER_METRICS_PORT=$((PORT + 10000))
fi

PARALLEL_ARGS=(--tp "$TP" --ep-size "$EP_SIZE")
if [ "$DP_ATTENTION" = "true" ]; then
PARALLEL_ARGS+=(
--dp "$TP"
--enable-dp-attention
--tokenizer-worker-num "$TP"
--dist-init-addr "127.0.0.1:$((PORT + 2000))"
)
else
# Cookbook low-latency levers; the DP-attention cell omits them.
PARALLEL_ARGS+=(
--kv-cache-dtype fp8_e4m3
--bf16-gemm-backend cutedsl
--max-prefill-tokens 8192
)
fi

# AgentX concurrency counts live session trees, not individual requests.
# Allow subagent fan-out to exceed CONC without clipping request bursts.
MAX_RUNNING_REQUESTS=$((2 * CONC))
GRAPH_ARGS=()
if [ "$DP_ATTENTION" != "true" ]; then
# Cookbook low-latency captures graphs up to its request cap; the
# DP-attention cell leaves the CUDA-graph batch list at SGLang defaults.
CUDA_GRAPH_MAX_BS=$MAX_RUNNING_REQUESTS
[ "$CUDA_GRAPH_MAX_BS" -gt 64 ] && CUDA_GRAPH_MAX_BS=64
GRAPH_ARGS=(--cuda-graph-max-bs "$CUDA_GRAPH_MAX_BS")
fi

export PYTHONNOUSERSITE=1
export TORCH_CUDA_ARCH_LIST=10.0
# Agentic warmup dispatches hundreds of large prompts at once; allow up to
# 15 minutes of TCP progress before AIPerf declares a connection dead.
export AIPERF_HTTP_TCP_USER_TIMEOUT=900000

SGLANG_CMD=(
python3 -m sglang.launch_server
--model-path "$MODEL_PATH"
--served-model-name "$MODEL"
--host 0.0.0.0
--port "$SGLANG_BACKEND_PORT"
--trust-remote-code
"${PARALLEL_ARGS[@]}"
--quantization modelopt_fp4
--chunked-prefill-size 8192
--mem-fraction-static 0.85
--max-running-requests "$MAX_RUNNING_REQUESTS"
"${GRAPH_ARGS[@]}"
--watchdog-timeout 1800
--enable-metrics
)

printf '%q ' "${SGLANG_CMD[@]}" | tee "$RESULT_DIR/sglang_command.txt"
printf '\n' | tee -a "$RESULT_DIR/sglang_command.txt"

echo "Starting SGLang server for B300..."
"${SGLANG_CMD[@]}" > "$SERVER_LOG" 2>&1 &
SERVER_PID=$!
echo "Server PID: $SERVER_PID"

wait_for_server_ready --port "$SGLANG_BACKEND_PORT" --server-log "$SERVER_LOG" --server-pid "$SERVER_PID"

if [ "$USE_SGLANG_ROUTER" = "true" ]; then
echo "Starting SGLang router on port $PORT for $TP DP ranks..."
python3 -m sglang_router.launch_router \
--worker-urls "http://localhost:$SGLANG_BACKEND_PORT" \
--policy consistent_hashing \
--request-id-headers x-correlation-id \
--dp-aware \
--host 0.0.0.0 \
--port "$PORT" \
--prometheus-host 127.0.0.1 \
--prometheus-port "$SGLANG_ROUTER_METRICS_PORT" \
--connect-timeout-secs 900 \
--request-timeout-secs 14400 \
--disable-health-check \
--disable-retries > "$ROUTER_LOG" 2>&1 &
ROUTER_PID=$!
echo "Router PID: $ROUTER_PID"
wait_for_server_ready --port "$PORT" --server-log "$ROUTER_LOG" --server-pid "$ROUTER_PID"
fi

if [ "${EVAL_ONLY}" = "true" ]; then
run_eval --port "$PORT"
else
build_replay_cmd "$RESULT_DIR"
REPLAY_CMD+=" --server-metrics http://localhost:$SGLANG_BACKEND_PORT/metrics"
run_agentic_replay_and_write_outputs "$RESULT_DIR"
fi
22 changes: 22 additions & 0 deletions configs/nvidia-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9891,3 +9891,25 @@
tp: 16
ep: 16
dp-attn: true

# GLM-5.2 B300 NVFP4 AgentX frontier from the SGLang cookbook B300 NVFP4
# single-node recipes (https://docs.sglang.io/cookbook/autoregressive/GLM/GLM-5.2),
# STP only (the cookbook's EAGLE MTP variants are deferred). The TP8 arm is the
# cookbook low-latency recipe (fp8 KV, cutedsl bf16 GEMM) and covers the
# interactivity end; the TP8/DP8 attention-DP arm is the cookbook
# high-throughput recipe behind sglang-router consistent hashing for session
# affinity. Conc lists are disjoint between arms so exp-names stay unique.
glm5.2-fp4-b300-sglang-agentic:
image: lmsysorg/sglang:v0.5.15.post1-cu130
model: nvidia/GLM-5.2-NVFP4
model-prefix: glm5.2
runner: cluster:b300-nv
precision: fp4
framework: sglang
multinode: false
scenarios:
agentic-coding:
- dram-utilization: 0.80
search-space:
- { tp: 8, kv-offloading: none, conc-list: [1, 2, 4, 8, 16, 32] }
- { tp: 8, dp-attn: true, kv-offloading: none, conc-list: [48, 64, 96, 128, 192, 256, 512], router: { name: sglang-router, version: "0.3.2" } }

Check failure on line 9915 in configs/nvidia-master.yaml

View check run for this annotation

Claude / Claude Code Review

GLM-5.2 dp-attn arm omits ep, defaulting EP_SIZE to 1 (no expert parallelism)

The high-throughput arm (`{ tp: 8, dp-attn: true, ... }`) omits the `ep` key, so `generate_sweep_configs.py` defaults `EP_SIZE` to 1, and `glm5.2_fp4_b300_sglang.sh` unconditionally passes `--ep-size $EP_SIZE` to the server. This launches attention-DP (dp=8) with ep-size=1, i.e. no expert parallelism across the 8 DP ranks for this MoE model — every other `dp-attn: true` entry in this file (including the DSv4 recipe this PR says it copies) pairs it with an explicit `ep` equal to `tp`. Add `ep: 8`
Comment on lines +7864 to +7877

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 high-throughput arm ({ tp: 8, dp-attn: true, ... }) omits the ep key, so generate_sweep_configs.py defaults EP_SIZE to 1, and glm5.2_fp4_b300_sglang.sh unconditionally passes --ep-size $EP_SIZE to the server. This launches attention-DP (dp=8) with ep-size=1, i.e. no expert parallelism across the 8 DP ranks for this MoE model — every other dp-attn: true entry in this file (including the DSv4 recipe this PR says it copies) pairs it with an explicit ep equal to tp. Add ep: 8 to match the intended/validated recipe.

Extended reasoning...

The bug: The high-throughput search-space entry for glm5.2-fp4-b300-sglang-agentic is:

- { tp: 8, dp-attn: true, kv-offloading: none, conc-list: [48, 64, 96, 128, 192, 256, 512], router: { name: sglang-router, version: "0.3.2" } }

It sets tp: 8 and dp-attn: true but never sets ep. In utils/matrix_logic/generate_sweep_configs.py (single-node agentic branch, line 1055 — mirrored at lines 756/943 for the other scenario branches), the EP field is computed as:

Fields.EP.value: ep if ep is not None else 1,

Since the config never supplies ep, this resolves to EP_SIZE=1. That value flows straight into benchmarks/single_node/agentic/glm5.2_fp4_b300_sglang.sh, which builds PARALLEL_ARGS=(--tp "$TP" --ep-size "$EP_SIZE") unconditionally (no override or reset for the dp-attn branch — it only adds --dp "$TP" --enable-dp-attention ... on top). So the actual server launch for the documented '34,429 tok/s' high-throughput arm is --tp 8 --ep-size 1 --dp 8 --enable-dp-attention.

Why this is wrong: GLM-5.2 is an MoE model (glm_moe_dsa architecture). The whole point of pairing attention-DP with expert parallelism is to shard the MoE experts across the 8 DP ranks instead of replicating the full expert set on every GPU. With ep-size=1, SGLang runs with no expert parallelism — each of the 8 DP ranks holds/replicates the entire MoE expert set, which is a materially different (and much more memory- and compute-heavy) execution than the intended sharded layout.

Why nothing catches this today: There's no validation in generate_sweep_configs.py (or the launch script) requiring ep to be set — or to equal tp — whenever dp-attn: true is set for an MoE recipe. The default-to-1 behavior is silent, so a missing key produces a syntactically valid but semantically wrong config rather than an error.

Comparison to every other recipe in the file: Grepping configs/nvidia-master.yaml shows dozens of dp-attn: true entries (dsv4, minimaxm3, qwen3.5, etc.), and every single one pairs it with an explicit ep: equal to tp (e.g. { tp: 8, ep: 8, dp-attn: true }, { tp: 4, ep: 4, dp-attn: true }, { tp: 16, ep: 16, dp-attn: true } at lines 9892-9893 just above this diff). The PR description itself says the router setup is 'same pattern as the DSv4 B300 agentic recipe' (dsv4-fp4-b300-sglang-agentic-hicache), whose equivalent high-throughput arm is { tp: 8, ep: 8, dp-attn: true, ... }. This confirms the missing ep: 8 here is a copy-paste omission, not an intentional deviation.

Step-by-step proof:

  1. Config entry: { tp: 8, dp-attn: true, kv-offloading: none, conc-list: [...], router: {...} } — no ep key.
  2. generate_sweep_configs.py reads ep = bmk.get(Fields.EP.value)None (key absent).
  3. It writes Fields.EP.value: ep if ep is not None else 1EP_SIZE=1 in the generated matrix entry/env.
  4. glm5.2_fp4_b300_sglang.sh builds PARALLEL_ARGS=(--tp "$TP" --ep-size "$EP_SIZE") = --tp 8 --ep-size 1, then appends --dp "$TP" --enable-dp-attention ... since DP_ATTENTION=true.
  5. Resulting server launch: --tp 8 --ep-size 1 --dp 8 --enable-dp-attention — attention-DP is on, but expert parallelism is off.
  6. This is not the config that was on-node validated to get 34,429 tok/s @ conc 256 if that run used --ep-size 8 (matching every analogous recipe); the committed sweep will benchmark a different, degraded parallelism layout than what's documented.

Fix: add ep: 8 to the high-throughput arm, matching tp and the DSv4 reference recipe:

- { tp: 8, ep: 8, dp-attn: true, kv-offloading: none, conc-list: [48, 64, 96, 128, 192, 256, 512], router: { name: sglang-router, version: "0.3.2" } }

10 changes: 10 additions & 0 deletions perf-changelog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4933,3 +4933,13 @@
description:
- "Add MiniMax M3 NVFP4 B300 Dynamo-vLLM disaggregated EAGLE3 recipes"
pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2182

- config-keys:
- glm5.2-fp4-b300-sglang-agentic
description:
- "Add GLM-5.2 NVFP4 B300 SGLang single-node agentic benchmarks from the SGLang cookbook B300 NVFP4 recipes (STP only, no spec decoding)"
- "Image: lmsysorg/sglang:v0.5.15.post1-cu130; model nvidia/GLM-5.2-NVFP4"
- "Low-latency arm: TP8 (fp8 KV cache, cutedsl bf16 GEMM backend) at conc [1, 2, 4, 8, 16, 32]"
- "High-throughput arm: TP8/DP8 attention-DP behind sglang-router consistent hashing at conc [48, 64, 96, 128, 192, 256, 512]"
- "New 1M-context model prefix glm5.2 added to the unfiltered agentic corpus branch in benchmark_lib.sh"
pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/XXX
Loading