diff --git a/benchmarks/single_node/fixed_seq_len/dsv4_fp8_mi325x.sh b/benchmarks/single_node/fixed_seq_len/dsv4_fp8_mi325x.sh new file mode 100755 index 000000000..4dafff650 --- /dev/null +++ b/benchmarks/single_node/fixed_seq_len/dsv4_fp8_mi325x.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +set -eo pipefail + +# DeepSeek-V4-Pro FP8 single-node on MI325X (gfx942) via vLLM. +# +# EXTRAPOLATED bring-up recipe. The sglang path was abandoned: on gfx942 +# (no native FP4) the dsv4 sglang backend's nvfp4 MoE / TileLang-MLA kernels +# have no gfx942 equivalents (they exist only for gfx950/MI355X). vLLM instead +# runs the checkpoint in FP8 via --quantization deepseek_v4_fp8, which +# dequantizes the FP4 MoE experts to FP8 — the same path the H200 dsv4 vLLM +# recipe uses (H200 is also a no-FP4 SKU). Derived from: +# * same model + framework + AMD family: dsv4_fp4_mi355x_vllm.sh (ROCm vLLM +# dsv4 structure: AITER MoE, deepseek_v4 tokenizer/parser, mp executor, +# FULL_AND_PIECEWISE compile) +# * same model, FP8 path: dsv4_fp8_h200.sh (--quantization deepseek_v4_fp8) +# * same SKU, different model: minimaxm3_fp8_mi325x.sh (gfx942 vLLM/AITER) +# +# The FP4->FP8 dequant roughly doubles the MoE footprint (~1.05 TB total), +# which fits 8x256 GB comfortably at TP8, so the sweep is TP8-only. +# +# MoE backend is left at auto (NOT --moe-backend aiter) — see dsv4_fp8_mi300x.sh: +# on gfx942, forcing aiter selects AITER_MXFP4_MXFP4 (W4A4 native-mxfp4) which +# the gfx942 kernel rejects; auto's ROCm+DeepseekV4 path prefers +# AITER_MXFP4_BF16 (W4A16, dequant) with a TRITON_UNFUSED fallback. + +source "$(dirname "$0")/../../benchmark_lib.sh" + +check_env_vars \ + MODEL \ + TP \ + DP_ATTENTION \ + CONC \ + ISL \ + OSL \ + MAX_MODEL_LEN \ + RANDOM_RANGE_RATIO \ + RESULT_FILENAME + +if [[ -n "$SLURM_JOB_ID" ]]; then + echo "JOB $SLURM_JOB_ID running on $SLURMD_NODENAME" +fi + +if [[ "$MODEL" != /* ]]; then hf download "$MODEL"; fi + +if [ -n "$ROCR_VISIBLE_DEVICES" ]; then + export HIP_VISIBLE_DEVICES="$ROCR_VISIBLE_DEVICES" +fi + +export VLLM_ROCM_USE_AITER=1 +export VLLM_ROCM_USE_AITER_MOE=1 + +# gsm8k eval at high concurrency (8k1k) OOM-kills the server: hundreds of +# concurrent 9472-token requests exceed the ~20x KV budget even on 256GB MI325X +# (c128 fit, so this was originally left at the default, but c512 crashed the +# EngineCore mid-eval). Cap the eval to a safe in-flight count; only run_eval is +# affected (throughput jobs use CONC directly). Matches the MI300X script. +export EVAL_CONCURRENT_REQUESTS=8 + +SERVER_LOG=/workspace/server.log + +if [ "${EVAL_ONLY}" = "true" ]; then + setup_eval_context + MAX_MODEL_LEN="$EVAL_MAX_MODEL_LEN" +fi + +start_gpu_monitor + +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 + +EP_ARGS=() +if [ "${EP_SIZE:-1}" -gt 1 ]; then + EP_ARGS=(--enable-expert-parallel) +fi + +set -x +vllm serve $MODEL --port $PORT \ + "${PARALLEL_ARGS[@]}" \ + "${EP_ARGS[@]}" \ + --quantization deepseek_v4_fp8 \ + --async-scheduling \ + --no-enable-prefix-caching \ + --distributed-executor-backend mp \ + --gpu-memory-utilization 0.9 \ + --max-model-len "$MAX_MODEL_LEN" \ + --kv-cache-dtype fp8 \ + --trust-remote-code \ + --tokenizer-mode deepseek_v4 \ + --reasoning-parser deepseek_v4 \ + --compilation-config '{"mode":3,"cudagraph_mode":"FULL_AND_PIECEWISE"}' > $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 diff --git a/benchmarks/single_node/fixed_seq_len/dsv4_fp8_mi325x_mtp.sh b/benchmarks/single_node/fixed_seq_len/dsv4_fp8_mi325x_mtp.sh new file mode 100755 index 000000000..7233da9dd --- /dev/null +++ b/benchmarks/single_node/fixed_seq_len/dsv4_fp8_mi325x_mtp.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash +set -eo pipefail + +# DeepSeek-V4-Pro FP8 single-node on MI325X (gfx942) via vLLM, MTP variant. +# +# MTP sibling of dsv4_fp8_mi325x.sh: adds --speculative-config +# '{"method":"mtp","num_speculative_tokens":2}' (DeepSeek-V4 built-in MTP) +# and --dsv4 chat-template encoding for run_benchmark_serving. +# +# EXTRAPOLATED bring-up recipe. The sglang path was abandoned: on gfx942 +# (no native FP4) the dsv4 sglang backend's nvfp4 MoE / TileLang-MLA kernels +# have no gfx942 equivalents (they exist only for gfx950/MI355X). vLLM instead +# runs the checkpoint in FP8 via --quantization deepseek_v4_fp8, which +# dequantizes the FP4 MoE experts to FP8 — the same path the H200 dsv4 vLLM +# recipe uses (H200 is also a no-FP4 SKU). Derived from: +# * same model + framework + AMD family: dsv4_fp4_mi355x_vllm.sh (ROCm vLLM +# dsv4 structure: AITER MoE, deepseek_v4 tokenizer/parser, mp executor, +# FULL_AND_PIECEWISE compile) +# * same model, FP8 path: dsv4_fp8_h200.sh (--quantization deepseek_v4_fp8) +# * same SKU, different model: minimaxm3_fp8_mi325x.sh (gfx942 vLLM/AITER) +# +# The FP4->FP8 dequant roughly doubles the MoE footprint (~1.05 TB total), +# which fits 8x256 GB comfortably at TP8, so the sweep is TP8-only. +# +# MoE backend is left at auto (NOT --moe-backend aiter) — see dsv4_fp8_mi300x.sh: +# on gfx942, forcing aiter selects AITER_MXFP4_MXFP4 (W4A4 native-mxfp4) which +# the gfx942 kernel rejects; auto's ROCm+DeepseekV4 path prefers +# AITER_MXFP4_BF16 (W4A16, dequant) with a TRITON_UNFUSED fallback. + +source "$(dirname "$0")/../../benchmark_lib.sh" + +check_env_vars \ + MODEL \ + TP \ + DP_ATTENTION \ + CONC \ + ISL \ + OSL \ + MAX_MODEL_LEN \ + RANDOM_RANGE_RATIO \ + RESULT_FILENAME + +if [[ -n "$SLURM_JOB_ID" ]]; then + echo "JOB $SLURM_JOB_ID running on $SLURMD_NODENAME" +fi + +if [[ "$MODEL" != /* ]]; then hf download "$MODEL"; fi + +if [ -n "$ROCR_VISIBLE_DEVICES" ]; then + export HIP_VISIBLE_DEVICES="$ROCR_VISIBLE_DEVICES" +fi + +export VLLM_ROCM_USE_AITER=1 +export VLLM_ROCM_USE_AITER_MOE=1 + +# gsm8k eval at high concurrency (8k1k) OOM-kills the server: hundreds of +# concurrent 9472-token requests exceed the ~20x KV budget even on 256GB MI325X +# (c128 fit, so this was originally left at the default, but c512 crashed the +# EngineCore mid-eval). Cap the eval to a safe in-flight count; only run_eval is +# affected (throughput jobs use CONC directly). Matches the MI300X script. +export EVAL_CONCURRENT_REQUESTS=8 + +SERVER_LOG=/workspace/server.log + +if [ "${EVAL_ONLY}" = "true" ]; then + setup_eval_context + MAX_MODEL_LEN="$EVAL_MAX_MODEL_LEN" +fi + +start_gpu_monitor + +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 + +EP_ARGS=() +if [ "${EP_SIZE:-1}" -gt 1 ]; then + EP_ARGS=(--enable-expert-parallel) +fi + +# Use 2 speculative tokens (matches dsv4_fp4_mi355x_vllm_mtp.sh). +NUM_SPEC_TOKENS=2 + +set -x +vllm serve $MODEL --port $PORT \ + "${PARALLEL_ARGS[@]}" \ + "${EP_ARGS[@]}" \ + --quantization deepseek_v4_fp8 \ + --async-scheduling \ + --no-enable-prefix-caching \ + --distributed-executor-backend mp \ + --gpu-memory-utilization 0.9 \ + --max-model-len "$MAX_MODEL_LEN" \ + --kv-cache-dtype fp8 \ + --trust-remote-code \ + --tokenizer-mode deepseek_v4 \ + --reasoning-parser deepseek_v4 \ + --speculative-config "{\"method\": \"mtp\", \"num_speculative_tokens\": $NUM_SPEC_TOKENS}" \ + --compilation-config '{"mode":3,"cudagraph_mode":"FULL_AND_PIECEWISE"}' > $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 \ + --dsv4 + +if [ "${RUN_EVAL}" = "true" ]; then + run_eval --framework lm-eval --port "$PORT" + append_lm_eval_summary +fi + +stop_gpu_monitor +set +x diff --git a/configs/amd-master.yaml b/configs/amd-master.yaml index 4b1ea4aed..56ff8da58 100644 --- a/configs/amd-master.yaml +++ b/configs/amd-master.yaml @@ -119,6 +119,64 @@ dsr1-fp8-mi325x-sglang: search-space: - { tp: 8, conc-start: 4, conc-end: 64 } +# DeepSeek-V4-Pro FP8 single-node on MI325X (gfx942) via vLLM. +# EXTRAPOLATED bring-up. Same rationale as dsv4-fp8-mi300x-vllm: sglang has no +# gfx942 build of the dsv4 nvfp4 MoE / TileLang-MLA kernels, so vLLM runs the +# checkpoint in FP8 via --quantization deepseek_v4_fp8 (dequant FP4 MoE -> FP8), +# the H200 dsv4 vLLM path. Config mirrors the same-model dsv4-fp4-mi355x-vllm +# (TP8, conc 4-512); 8x256GB (2TB) has ample headroom for the ~1.05TB FP8 +# footprint. Launch script dsv4_fp8_mi325x.sh carries the deepseek_v4 + gfx942 +# AITER flags. +dsv4-fp8-mi325x-vllm: + image: vllm/vllm-openai-rocm:nightly-09663abde0f50944a8d5ea30120666024b503faa + model: deepseek-ai/DeepSeek-V4-Pro + model-prefix: dsv4 + # mi325x (mi325x-amds pool) runners are down; use the mi325x-tw cluster. + runner: cluster:mi325x-tw + precision: fp8 + framework: vllm + multinode: false + scenarios: + fixed-seq-len: + - isl: 1024 + osl: 1024 + search-space: + - { tp: 8, conc-start: 4, conc-end: 512 } + - isl: 8192 + osl: 1024 + search-space: + # 8k1k KV fits only ~20x concurrency (9472-token requests), so conc512 is + # ~25x oversubscribed -> request timeouts. conc256 is proven green; cap here. + - { tp: 8, conc-start: 4, conc-end: 256 } + +# MTP variant of dsv4-fp8-mi325x-vllm. Mirrors the base recipe and adds +# DeepSeek-V4 built-in MTP via --speculative-config (num_speculative_tokens=2), +# routing to dsv4_fp8_mi325x_mtp.sh; benchmark uses --dsv4 chat-template +# encoding (required for meaningful MTP acceptance). +dsv4-fp8-mi325x-vllm-mtp: + image: vllm/vllm-openai-rocm:nightly-09663abde0f50944a8d5ea30120666024b503faa + model: deepseek-ai/DeepSeek-V4-Pro + model-prefix: dsv4 + # mi325x (mi325x-amds pool) runners are down; use the mi325x-tw cluster. + runner: cluster:mi325x-tw + precision: fp8 + framework: vllm + multinode: false + scenarios: + fixed-seq-len: + - isl: 1024 + osl: 1024 + search-space: + - { tp: 8, conc-start: 4, conc-end: 512, spec-decoding: mtp } + - isl: 8192 + osl: 1024 + search-space: + # 8k1k MTP KV is tighter than normal (draft model): conc256 is borderline + # (MI300X 19.2% req failures, flaked pass->fail across runs) and conc512 + # is 55.8%. conc128 passed cleanly on the memory-tightest SKU (MI300X); + # cap 8k1k MTP at 128 (normal holds 256, 1k1k holds 512). + - { tp: 8, conc-start: 4, conc-end: 128, spec-decoding: mtp } + dsr1-fp8-mi355x-sglang: image: lmsysorg/sglang:v0.5.12-rocm700-mi35x model: deepseek-ai/DeepSeek-R1-0528 diff --git a/perf-changelog.yaml b/perf-changelog.yaml index d77c35f1f..eec5dde49 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -4781,3 +4781,21 @@ - "Bump image to lmsysorg/sglang-rocm:v0.5.14-rocm720-mi35x-20260708" - "Clean the export envs" pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2198 + +- config-keys: + - dsv4-fp8-mi325x-vllm + description: + - "Add DeepSeek-V4-Pro FP8 single-node MI325X vLLM benchmark (new SKU, previously no dsv4 data on gfx942)" + - "vLLM, not sglang: same rationale as dsv4-fp8-mi300x-vllm — sglang has no gfx942 build of the dsv4 nvfp4 MoE / TileLang-MLA kernels (gfx950/MI355X only). vLLM runs the checkpoint in FP8 via --quantization deepseek_v4_fp8 (dequant FP4 MoE -> FP8), the no-FP4 H200 dsv4 vLLM path" + - "Recipe mirrors the same-model dsv4-fp4-mi355x-vllm (ROCm vLLM dsv4: deepseek_v4 tokenizer/reasoning-parser, mp executor, FULL_AND_PIECEWISE compile) plus gfx942 AITER infra from minimaxm3-fp8-mi325x-vllm; TP8 conc 4-512, ample headroom on 8x256GB" + - "MoE backend left at auto (unlike MI355X's --moe-backend aiter): forcing aiter on gfx942 selects AITER_MXFP4_MXFP4 (W4A4 native-mxfp4) which the gfx942 kernel rejects; auto's ROCm+DeepseekV4 path prefers AITER_MXFP4_BF16 (W4A16, dequant) with TRITON_UNFUSED fallback (see dsv4-fp8-mi300x-vllm)" + - "Image vllm/vllm-openai-rocm:nightly-09663abde0f50944a8d5ea30120666024b503faa (the DSv4-validated ROCm vLLM build)" + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2195 + +- config-keys: + - dsv4-fp8-mi325x-vllm-mtp + description: + - "Add DeepSeek-V4-Pro FP8 MI325X vLLM MTP (speculative-decoding) variant, mirroring dsv4-fp8-mi325x-vllm plus --speculative-config {\"method\":\"mtp\",\"num_speculative_tokens\":2} (DeepSeek-V4 built-in MTP)" + - "run_benchmark_serving uses --dsv4 chat-template encoding, required for meaningful MTP acceptance rate; routes to dsv4_fp8_mi325x_mtp.sh via the launcher's spec-decoding=mtp suffix" + - "256GB MI325X keeps the default eval concurrency (no KV cap needed)" + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2195 diff --git a/runners/launch_mi325x-tw.sh b/runners/launch_mi325x-tw.sh new file mode 100644 index 000000000..0ed4be196 --- /dev/null +++ b/runners/launch_mi325x-tw.sh @@ -0,0 +1,35 @@ +#!/usr/bin/bash +set -euo pipefail + +# mi325x-tw is a NON-SLURM cluster: the runner executes on the GPU node itself +# (docker + ROCm, no salloc/srun). So run the container directly on the node, +# like launch_h100-cr.sh but AMD/ROCm (--device=/dev/kfd,/dev/dri instead of +# --runtime=nvidia --gpus). dsv4 MI325X is single-node (TP8), so one node's +# 8 GPUs suffice. Runs the same _mi325x.sh benchmark as the amds launcher. + +HF_HUB_CACHE_MOUNT="${HF_HUB_CACHE_MOUNT:-/home/gharunner/hf_hub_cache/}" +mkdir -p "$HF_HUB_CACHE_MOUNT" +export HF_HUB_CACHE="${HF_HUB_CACHE:-/hf_hub_cache}" +PORT=8888 +server_name="bmk-server-${RUNNER_NAME:-mi325x-tw}" + +# Route spec-decoding=mtp configs to the _mtp benchmark script. +SPEC_SUFFIX=$([[ "${SPEC_DECODING:-}" == "mtp" ]] && printf '_mtp' || printf '') + +export GPU_COUNT="${GPU_COUNT:-${TP:?TP must be set}}" + +set -x +docker rm -f "$server_name" >/dev/null 2>&1 || true +docker run --rm --network=host --name="$server_name" \ +--device=/dev/kfd --device=/dev/dri --group-add video --group-add render \ +--ipc=host --privileged --shm-size=32g --ulimit memlock=-1 --ulimit stack=67108864 \ +--security-opt seccomp=unconfined --cap-add=SYS_PTRACE \ +-v "$HF_HUB_CACHE_MOUNT:$HF_HUB_CACHE" \ +-v "$GITHUB_WORKSPACE:/workspace/" -w /workspace/ \ +-e HF_TOKEN -e HF_HUB_CACHE -e MODEL -e TP -e PP_SIZE -e DCP_SIZE -e PCP_SIZE -e GPU_COUNT -e CONC -e MAX_MODEL_LEN -e ISL -e OSL -e RUN_EVAL -e EVAL_ONLY -e RUNNER_TYPE -e RESULT_FILENAME -e RANDOM_RANGE_RATIO -e PORT="$PORT" \ +-e DP_ATTENTION -e EP_SIZE -e DP_SIZE -e EVAL_MAX_MODEL_LEN -e SPEC_DECODING -e NUM_SPEC_TOKENS \ +-e PROFILE -e SGLANG_TORCH_PROFILER_DIR -e VLLM_TORCH_PROFILER_DIR -e VLLM_RPC_TIMEOUT \ +-e PYTHONPYCACHEPREFIX=/tmp/pycache/ -e CUDA_DEVICE_ORDER=PCI_BUS_ID \ +--entrypoint=/bin/bash \ +"$IMAGE" \ +benchmarks/single_node/${SCENARIO_SUBDIR}"${EXP_NAME%%_*}_${PRECISION}_mi325x${SPEC_SUFFIX}.sh"