Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ae81a2c
feat(agentic): split DeepSeek-V4 B300 vLLM recipe
cquil11 Jul 15, 2026
50ec3b7
docs(changelog): link B300 replacement PR
cquil11 Jul 15, 2026
3d57813
chore: update conc
ivanium Jul 15, 2026
4acd3c4
update dep8 args
majunze2001 Jul 16, 2026
4392489
add more tp configs
majunze2001 Jul 16, 2026
739a667
dep8 reduce gpu mem util to 0.92
majunze2001 Jul 16, 2026
46a3566
chore: update conc list
ivanium Jul 16, 2026
8f023a5
docs(changelog): point B300 entry to PR #2241
ivanium Jul 16, 2026
10f30ed
fix(changelog): keep perf-changelog additions-only
ivanium Jul 16, 2026
31f4ed1
add mtp
majunze2001 Jul 17, 2026
800da49
Merge remote-tracking branch 'origin' into agentx/dsv4-v300-vllm-mtp
majunze2001 Jul 17, 2026
9656e75
[AgentX] DeepSeek-V4 B300 vLLM: MTP (num_speculative_tokens=3) across…
majunze2001 Jul 17, 2026
5887e1a
fix(changelog): accept single-node agentic eval rows in matrix valida…
majunze2001 Jul 17, 2026
d26aba5
[AgentX] B300 vLLM: split MTP + TP8 into separate config-keys
majunze2001 Jul 17, 2026
4c5b4a1
align synthetic acceptance length
majunze2001 Jul 17, 2026
82a90ab
Merge remote-tracking branch 'origin/main' into agentx/dsv4-v300-vllm…
majunze2001 Jul 17, 2026
ce0f164
reduce GPU memory utilization to 0.95 (except DEP8)
majunze2001 Jul 17, 2026
bc4fe4b
trim B300 MTP search space: fold TP8 into -mtp, drop -tp8 key, trim DEP4
majunze2001 Jul 18, 2026
9b7264a
Revert "fix(changelog): accept single-node agentic eval rows in matri…
majunze2001 Jul 18, 2026
1d4c7f9
Merge remote-tracking branch 'origin/main' into agentx/dsv4-v300-vllm…
majunze2001 Jul 18, 2026
1866bd6
MTP synthetic acceptance for throughput, real verification for eval
majunze2001 Jul 18, 2026
4e37ef7
Merge branch 'main' into agentx/dsv4-v300-vllm-mtp
majunze2001 Jul 18, 2026
0b46ecb
fix(agentic): wire B300 MTP context parallelism
cquil11 Jul 20, 2026
7b940f8
fix(agentic): derive B300 MTP GPU count from topology
cquil11 Jul 20, 2026
9e950fa
Merge remote-tracking branch 'origin/main' into agentx/dsv4-v300-vllm…
cquil11 Jul 20, 2026
ee9ebec
Merge branch 'main' into agentx/dsv4-v300-vllm-mtp
cquil11 Jul 21, 2026
0c675b8
Update perf-changelog.yaml
cquil11 Jul 21, 2026
384a09a
fix(changelog): restore PR 2258 entry indentation
cquil11 Jul 21, 2026
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
326 changes: 326 additions & 0 deletions benchmarks/single_node/agentic/dsv4_fp4_b300_vllm_mtp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
#!/usr/bin/env bash
set -eo pipefail
set -x

# Agentic trace replay benchmark for DeepSeek-V4-Pro FP4 on B300 using vLLM,
# with MTP speculative decoding (num_speculative_tokens=2).
#
# Identical to dsv4_fp4_b300_vllm.sh (same image, engine args, offload, GPU
# topologies, and agentic aiperf rig) with exactly two MTP deltas:
# --speculative-config '{"method": "mtp", "num_speculative_tokens": 2}'
# cudagraph capture sizes expressed in TOKENS (see the capture block below).
#
# Image is configured in nvidia-master.yaml. The recipe uses FP8 KV cache,
# sparse DeepSeek-V4 FlashInfer attention with an FP4 indexer cache, mega-MoE,
# and FULL_DECODE_ONLY CUDA graphs with every decode batch captured explicitly.
#
# Required env vars:
# MODEL, TP, CONC, KV_OFFLOADING, TOTAL_CPU_DRAM_GB, RESULT_DIR
#
# TP4, TP8, and DEP8 (TP8 + DP-attention) are GPU-resident (KV_OFFLOADING=none).
# DEP4 uses KV_OFFLOADING=dram with KV_OFFLOAD_BACKEND=vllm-simple or mooncake.

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

GPU_COUNT=$TP
if [[ ! "$GPU_COUNT" =~ ^[1-9][0-9]*$ ]]; then
echo "Error: GPU_COUNT must be a positive integer, got '$GPU_COUNT'" >&2
exit 1
fi
export GPU_COUNT

# Under DP-attention the DP world size equals TP, and the DEP recipe sizes
# per-rank batch as MAX_NUM_SEQS = 2*CONC/TP, which must be an integer.
if [ "$DP_ATTENTION" = "true" ] && [ $((2 * CONC % TP)) -ne 0 ]; then
echo "Error: DEP requires 2*CONC divisible by TP, got CONC='$CONC' and TP='$TP'" >&2
exit 1
fi

# DEP8 (TP8 + DP-attention) is a GPU-resident, high-concurrency arm that is
# tuned separately from the smaller DEP4 arm (larger prefill token budget,
# long-prefill chunking, and a lower GPU-memory-utilization headroom).
IS_DEP8=false
if [ "$DP_ATTENTION" = "true" ] && [ "$TP" -eq 8 ]; then
IS_DEP8=true
fi

if [[ -n "$SLURM_JOB_ID" ]]; then
echo "JOB $SLURM_JOB_ID running on $SLURMD_NODENAME"
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 traces and install deps ----------------------------------------
resolve_trace_source
install_agentic_deps

# vllm-project/router expands the one HTTP backend into one logical worker per
# DP rank. Bind every turn of a conversation to the same rank by mapping
# AIPerf's stable correlation ID to the router's X-Session-ID header.
USE_VLLM_ROUTER=false
VLLM_BACKEND_PORT="$PORT"
if [ "$DP_ATTENTION" = "true" ]; then
USE_VLLM_ROUTER=true
VLLM_BACKEND_PORT=$((PORT + 1))
VLLM_ROUTER_VERSION=0.1.14
VLLM_ROUTER_POLICY=consistent_hash
VLLM_ROUTER_METRICS_PORT=$((PORT + 10000))
export AIPERF_HTTP_X_SESSION_ID_FROM_CORRELATION_ID=1
agentic_pip_install --quiet "vllm-router==$VLLM_ROUTER_VERSION"
fi

# Match the environment used by v4pro-b300.yaml.
export VLLM_USE_V2_MODEL_RUNNER=1
export VLLM_ENGINE_READY_TIMEOUT_S=3600
export VLLM_PREFIX_CACHE_RETENTION_INTERVAL=32768
export VLLM_DSV4_MEGA_FP8_COMBINE=1
export NCCL_NVLS_ENABLE=1
export VLLM_USE_RUST_FRONTEND=1

# ---- Server config ----------------------------------------------------------
SERVER_LOG="$RESULT_DIR/server.log"
ROUTER_LOG="$RESULT_DIR/router.log"
MOONCAKE_MASTER_LOG="$RESULT_DIR/mooncake_master.log"
mkdir -p "$RESULT_DIR"

SERVER_PID=""
ROUTER_PID=""
MOONCAKE_MASTER_PID=""

# The generated TOTAL_CPU_DRAM_GB budget is proportional to allocated GPUs.
# On cluster:b300-nv, dram-utilization=0.80 and DEP4 resolve to roughly the
# source recipe's 280 GiB per DP rank. TP4 remains GPU-resident.
OFFLOAD_ARGS=()
case "$KV_OFFLOAD_BACKEND" in
"")
require_agentic_kv_offload_none
;;
vllm-simple)
require_agentic_kv_offload_backend vllm-simple
CPU_BYTES_PER_RANK=$(( TOTAL_CPU_DRAM_GB * 1000 * 1000 * 1000 / GPU_COUNT ))
# Identical prefixes must hash to identical block keys across DP ranks.
export PYTHONHASHSEED=42
# The plain-TP (non-DP-attention) offload ladder uses lazy offload;
# DEP keeps eager offload for cross-rank block-hash stability.
SIMPLE_LAZY_OFFLOAD=false
if [ "$DP_ATTENTION" != "true" ]; then
SIMPLE_LAZY_OFFLOAD=true
fi
OFFLOAD_CONFIG=$(cat <<EOF
{
"kv_connector": "SimpleCPUOffloadConnector",
"kv_role": "kv_both",
"kv_connector_extra_config": {
"cpu_bytes_to_use": ${CPU_BYTES_PER_RANK},
"enable_cross_layers_blocks": "true",
"lazy_offload": ${SIMPLE_LAZY_OFFLOAD}
}
}
EOF
)
OFFLOAD_ARGS=(
--kv-transfer-config
"$OFFLOAD_CONFIG"
)
;;
mooncake)
require_agentic_kv_offload_backend mooncake
# Embedded mode contributes one global segment per DP rank to the
# shared store, so divide the aggregate host budget across ranks.
PER_RANK_GB=$((TOTAL_CPU_DRAM_GB / GPU_COUNT))
MOONCAKE_VERSION=0.3.11.post1
agentic_pip_install --quiet --no-cache-dir --no-deps \
--force-reinstall "mooncake-transfer-engine-cuda13==$MOONCAKE_VERSION"
python3 -c "from mooncake.store import MooncakeDistributedStore" >/dev/null

MOONCAKE_MASTER_PORT=$((PORT + 12000))
MOONCAKE_CONFIG_PATH="$RESULT_DIR/mooncake_config.json"
cat > "$MOONCAKE_CONFIG_PATH" <<EOF
{
"mode": "embedded",
"metadata_server": "P2PHANDSHAKE",
"master_server_address": "127.0.0.1:$MOONCAKE_MASTER_PORT",
"global_segment_size": "${PER_RANK_GB}GB",
"local_buffer_size": "4GB",
"protocol": "rdma",
"device_name": "",
"enable_offload": false
}
EOF
export MOONCAKE_CONFIG_PATH
export MC_ENABLE_DEST_DEVICE_AFFINITY=1
# Identical prefixes must hash to identical store keys across DP ranks.
export PYTHONHASHSEED=0
export WITH_NVIDIA_PEERMEM=0
export MC_SLICE_SIZE=1048576
export MC_WORKERS_PER_CTX=4

# The store is shared, but each rank contributes a separate segment.
# Start eviction before an imbalanced rank exhausts its segment, and
# reclaim enough space for several concurrent multi-GB batch puts.
MOONCAKE_EVICTION_HIGH_WATERMARK_RATIO=0.80
MOONCAKE_EVICTION_RATIO=0.10

echo "Starting Mooncake master on port $MOONCAKE_MASTER_PORT..."
mooncake_master --port "$MOONCAKE_MASTER_PORT" \
--eviction_high_watermark_ratio="$MOONCAKE_EVICTION_HIGH_WATERMARK_RATIO" \
--eviction_ratio="$MOONCAKE_EVICTION_RATIO" \
> "$MOONCAKE_MASTER_LOG" 2>&1 &
MOONCAKE_MASTER_PID=$!
sleep 2
if ! kill -0 "$MOONCAKE_MASTER_PID" 2>/dev/null; then
echo "Mooncake master died during startup." >&2
cat "$MOONCAKE_MASTER_LOG" >&2
exit 1
fi

unset VLLM_USE_SIMPLE_KV_OFFLOAD
OFFLOAD_CONFIG='{"kv_connector":"MooncakeStoreConnector","kv_role":"kv_both","kv_connector_extra_config":{"load_async":true}}'
OFFLOAD_ARGS=(--kv-transfer-config "$OFFLOAD_CONFIG")
;;
*)
echo "Error: unsupported B300 KV_OFFLOAD_BACKEND='$KV_OFFLOAD_BACKEND'" >&2
exit 1
;;
esac

PARALLEL_ARGS=(--tensor-parallel-size "$TP" --data-parallel-size 1)
if [ "$DP_ATTENTION" = "true" ]; then
PARALLEL_ARGS=(--tensor-parallel-size 1 --data-parallel-size "$TP")
fi

TP_ARGS=()
if [ "$DP_ATTENTION" = "true" ]; then
export PYTORCH_ALLOC_CONF=expandable_segments:True
else
export VLLM_ALLREDUCE_USE_FLASHINFER=1
export VLLM_FLASHINFER_ALLREDUCE_BACKEND=auto
TP_ARGS+=(--disable-custom-all-reduce)
fi

MODE_ARGS=()
if [ "$EP_SIZE" -gt 1 ]; then
MODE_ARGS+=(
--enable-expert-parallel
--enable-ep-weight-filter
--moe-backend deep_gemm_amxf4_mega_moe
)
fi
if [ "$DP_ATTENTION" = "true" ]; then
MODE_ARGS+=(--prefill-schedule-interval 8)
if [ "$IS_DEP8" = "true" ]; then
# GPU-resident DEP8 gets a larger prefill token budget and chunks long
# prefills so decode latency stays bounded at high concurrency.
MODE_ARGS+=(
--max-num-batched-tokens 16384
--long-prefill-token-threshold 4096
)
else
MODE_ARGS+=(--max-num-batched-tokens 8192)
fi
fi

if [ "$DP_ATTENTION" = "true" ]; then
# The DEP source recipe enforces 2*CONC = DP_WORLD_SIZE*MAX_NUM_SEQS.
MAX_NUM_SEQS=$((2 * CONC / TP))
else
# Preserve the previous TP4 scheduler headroom for agentic fan-out.
MAX_NUM_SEQS=$((2 * CONC))
fi
# MTP: cudagraph capture sizes are in TOKENS. With num_speculative_tokens=N,
# every uniform decode batch of S seqs verifies S*(1+N) tokens, so capture the
# explicit multiples (1+N), 2*(1+N), ..., MAX_NUM_SEQS*(1+N) -- one graph per
# decode batch of 1..MAX_NUM_SEQS seqs. vLLM rounds configured sizes up to
# multiples of (1+N) and dedups (adjust_cudagraph_sizes_for_spec_decode), so a
# plain 1..MAX_NUM_SEQS list would collapse to coverage of only
# MAX_NUM_SEQS/(1+N) seqs and drop the largest decode batches to eager.
NUM_SPEC_TOKENS=2
TOKENS_PER_SEQ=$((1 + NUM_SPEC_TOKENS))
CUDA_GRAPH_CAPTURE_SIZES=""
for ((num_seqs = 1; num_seqs <= MAX_NUM_SEQS; num_seqs++)); do
if [ -n "$CUDA_GRAPH_CAPTURE_SIZES" ]; then
CUDA_GRAPH_CAPTURE_SIZES+=","
fi
CUDA_GRAPH_CAPTURE_SIZES+="$((num_seqs * TOKENS_PER_SEQ))"
done
COMPILATION_CONFIG="{\"cudagraph_mode\":\"FULL_DECODE_ONLY\",\"cudagraph_capture_sizes\":[${CUDA_GRAPH_CAPTURE_SIZES}],\"mode\":0}"

echo "Starting vllm server..."
export TORCH_CUDA_ARCH_LIST="10.0"
export PYTHONNOUSERSITE=1
export VLLM_FLOAT32_MATMUL_PRECISION=high

# DEP8 leaves more headroom for its larger prefill token budget.
GPU_MEM_UTIL=0.96
if [ "$IS_DEP8" = "true" ]; then
GPU_MEM_UTIL=0.92
fi

{ set +x; } 2>/dev/null
VLLM_CMD=(
vllm serve "$MODEL_PATH" --served-model-name "$MODEL"
--host 0.0.0.0
--port "$VLLM_BACKEND_PORT"
--gpu-memory-utilization "$GPU_MEM_UTIL"
--trust-remote-code
--no-enable-flashinfer-autotune
--no-disable-hybrid-kv-cache-manager
--max-num-seqs "$MAX_NUM_SEQS"
--kv-cache-dtype fp8
--block-size 256
--max-model-len 1048576
--attention-config '{"use_fp4_indexer_cache":true,"backend":"FLASHINFER_MLA_SPARSE_DSV4","use_prefill_query_quantization":true}'
--speculative-config "{\"method\": \"mtp\", \"num_speculative_tokens\": $NUM_SPEC_TOKENS}"
--disable-uvicorn-access-log
--tokenizer-mode deepseek_v4
--tool-call-parser deepseek_v4
--enable-auto-tool-choice
--reasoning-parser deepseek_v4
--compilation-config "$COMPILATION_CONFIG"
"${PARALLEL_ARGS[@]}"
"${TP_ARGS[@]}"
"${MODE_ARGS[@]}"
"${OFFLOAD_ARGS[@]}"
)
printf '%q ' "${VLLM_CMD[@]}" | tee "$RESULT_DIR/vllm_command.txt"
printf '\n' | tee -a "$RESULT_DIR/vllm_command.txt"
"${VLLM_CMD[@]}" > "$SERVER_LOG" 2>&1 &
SERVER_PID=$!
echo "Server PID: $SERVER_PID"

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

if [ "$USE_VLLM_ROUTER" = "true" ]; then
echo "Starting native vLLM router on port $PORT for $TP DP ranks..."
vllm-router \
--worker-urls "http://localhost:$VLLM_BACKEND_PORT" \
--policy "$VLLM_ROUTER_POLICY" \
--intra-node-data-parallel-size "$TP" \
--host 0.0.0.0 \
--port "$PORT" \
--prometheus-host 127.0.0.1 \
--prometheus-port "$VLLM_ROUTER_METRICS_PORT" \
--request-timeout-secs 14400 \
--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

Check warning on line 322 in benchmarks/single_node/agentic/dsv4_fp4_b300_vllm_mtp.sh

View check run for this annotation

Claude / Claude Code Review

Missing EVAL_ONLY branch in new MTP agentic script

The new `dsv4_fp4_b300_vllm_mtp.sh` never checks `EVAL_ONLY`, unlike every other agentic script (including its non-MTP sibling and 23 peers), so under CI's `all-evals`/`evals-only` PR labels the newly-added MTP arm would silently run the throughput replay instead of SWE-bench eval and exit successfully with no eval results. This mirrors a pre-existing, unfixed gap in `kimik2.5_fp4_b300_mtp.sh`, and is only reachable via the opt-in eval labels (the default eval-selection path routes eval to the D
Comment thread
majunze2001 marked this conversation as resolved.
Resolved
# ---- Run benchmark ----------------------------------------------------------
build_replay_cmd "$RESULT_DIR"

run_agentic_replay_and_write_outputs "$RESULT_DIR"
8 changes: 6 additions & 2 deletions configs/nvidia-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3954,10 +3954,14 @@
agentic-coding:
- dram-utilization: 0.80
search-space:
# TP8 GPU-resident
- { tp: 8, kv-offloading: none, conc-list: [1, 2, 4, 6, 8] }
# TP4 GPU-resident
- { tp: 4, kv-offloading: none, conc-list: [1, 2, 4, 6, 8, 12, 16, 20, 24, 28, 32] }
- { tp: 4, kv-offloading: none, conc-list: [1, 2, 4, 6, 8, 12, 16, 20] }
# TP4 GPU-resident + MTP (num_speculative_tokens=2)
- { tp: 4, kv-offloading: none, spec-decoding: mtp, conc-list: [1, 2, 4, 6, 8, 12, 16, 20] }
# TP4 SimpleCPU
- { tp: 4, kv-offloading: dram, kv-offload-backend: { name: vllm-simple, version: "904e4ec" }, conc-list: [28, 32, 36, 40] }
- { tp: 4, kv-offloading: dram, kv-offload-backend: { name: vllm-simple, version: "904e4ec" }, conc-list: [20, 24, 28, 32, 36, 40] }

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

View check run for this annotation

Claude / Claude Code Review

Missing perf-changelog.yaml entry for nvidia-master.yaml change

This PR changes the dsv4-fp4-b300-vllm-agentic search-space in configs/nvidia-master.yaml (new TP8 arm, new TP4+MTP spec-decoding arm, and reworked TP4/SimpleCPU conc-lists) but does not append a corresponding perf-changelog.yaml entry. Per AGENTS.md, perf-changelog.yaml is what triggers the push-to-main sweep to actually benchmark new/changed configs, so without an entry these new arms will silently never run. The prior PR (#2241) that touched this exact config key did append one — please add a
Comment thread
majunze2001 marked this conversation as resolved.
Resolved
# DEP4 SimpleCPU
- { tp: 4, ep: 4, dp-attn: true, kv-offloading: dram, kv-offload-backend: { name: vllm-simple, version: "904e4ec" }, conc-list: [32, 40, 48, 56, 64, 72], router: { name: vllm-router, version: "0.1.14" } }
# DEP8 SimpleCPU
Expand Down