From 89d5ec0d41f6a15fb468dfb9e9a627e9305a6bfc Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 25 Sep 2026 13:03:12 -0400 Subject: [PATCH 1/8] perf: tune MiniMax-M3 AgentX on B200 and B300 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更新 B200 与 B300 的 MiniMax-M3 AgentX vLLM 镜像、内存预算和吞吐配置。 --- .../agentic/minimaxm3_fp4_b200_mtp.sh | 27 ++-- .../agentic/minimaxm3_fp4_b300_mtp.sh | 23 ++- configs/nvidia-master.yaml | 35 ++--- perf-changelog.yaml | 10 ++ runners/patch_vllm_simple_kv_offload.py | 133 ------------------ 5 files changed, 64 insertions(+), 164 deletions(-) delete mode 100755 runners/patch_vllm_simple_kv_offload.py diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh index ce28224f88..b7fdd9e35a 100755 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh @@ -11,10 +11,11 @@ set -x source "$(dirname "$0")/../../benchmark_lib.sh" -check_env_vars MODEL TP CONC KV_OFFLOADING TOTAL_CPU_DRAM_GB RESULT_DIR DURATION +check_env_vars MODEL TP CONC KV_OFFLOADING TOTAL_CPU_DRAM_GB RESULT_DIR DURATION PORT EVAL_ONLY DRAFT_MODEL="Inferact/MiniMax-M3-EAGLE3-GQA" NUM_SPEC_TOKENS=3 +TOKENS_PER_SEQ=$((1 + NUM_SPEC_TOKENS)) # Golden AL for the GQA draft head: golden_al_distribution/minimaxm3_eagle3_gqa.yaml # minimax-m3.thinking_on[3]. The non-GQA curve (minimaxm3_eagle3.yaml) reads 2.83. SYNTHETIC_ACCEPT_LEN=2.78 @@ -103,8 +104,8 @@ install_agentic_deps OFFLOAD_ARGS=() if require_agentic_kv_offload_backend vllm-simple; then - python3 "$(dirname "$0")/../../../runners/patch_vllm_simple_kv_offload.py" - CPU_OFFLOAD_BYTES=$((TOTAL_CPU_DRAM_GB * 1024 * 1024 * 1024)) + # The matrix emits decimal GB; SimpleCPUOffloadConnector expects bytes. + CPU_OFFLOAD_BYTES=$((TOTAL_CPU_DRAM_GB * 1000 * 1000 * 1000)) export VLLM_USE_SIMPLE_KV_OFFLOAD=1 OFFLOAD_CONFIG=$(printf \ '{"kv_connector":"SimpleCPUOffloadConnector","kv_role":"kv_both","kv_connector_extra_config":{"cpu_bytes_to_use":%d,"lazy_offload":true}}' \ @@ -116,10 +117,18 @@ export PYTHONNOUSERSITE=1 export VLLM_ENGINE_READY_TIMEOUT_S=3600 export VLLM_FLOAT32_MATMUL_PRECISION=high export VLLM_FLASHINFER_ALLREDUCE_BACKEND=trtllm - -# B200's 180 GB leaves little beyond the ~250 GB checkpoint: TP2 cannot -# host 1M-context KV for one request at 0.9, so TP4 is the smallest topology. -GPU_MEMORY_UTILIZATION="0.9" +export AIPERF_SERVER_METRICS_URLS="http://localhost:${PORT}/metrics" +export AIPERF_REQUIRED_SERVER_METRIC_PREFIX="vllm:" + +# Reserve 5% of HBM for runtime spikes while giving the KV pool more room. +# TP2 failed the full-context startup check at 0.90; it needs a separate GPU +# qualification before joining the sweep at this higher utilization. +GPU_MEMORY_UTILIZATION="0.95" +MAX_NUM_SEQS=$((2 * CONC)) +MAX_CUDAGRAPH_CAPTURE_SIZE=$((TOKENS_PER_SEQ * MAX_NUM_SEQS)) +if (( MAX_CUDAGRAPH_CAPTURE_SIZE > 512 )); then + MAX_CUDAGRAPH_CAPTURE_SIZE=512 +fi SERVER_LOG="$RESULT_DIR/server.log" mkdir -p "$RESULT_DIR" @@ -157,6 +166,7 @@ VLLM_CMD=( --block-size 128 --language-model-only --enable-prefix-caching + --enable-chunked-prefill --no-enable-flashinfer-autotune --reasoning-parser minimax_m3 --tool-call-parser minimax_m3 @@ -164,7 +174,8 @@ VLLM_CMD=( --default-chat-template-kwargs '{"thinking_mode":"enabled"}' --attention-config '{"backend":"FLASHINFER","use_trtllm_attention":true,"indexer_kv_dtype":"fp8"}' --kv-cache-dtype fp8 - --max-cudagraph-capture-size 512 + --max-cudagraph-capture-size "$MAX_CUDAGRAPH_CAPTURE_SIZE" + --max-num-seqs "$MAX_NUM_SEQS" --max-num-batched-tokens 16384 --stream-interval 20 --trust-remote-code diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh index c606792017..976f419d93 100755 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh @@ -7,10 +7,11 @@ set -x source "$(dirname "$0")/../../benchmark_lib.sh" -check_env_vars MODEL TP CONC KV_OFFLOADING TOTAL_CPU_DRAM_GB RESULT_DIR DURATION +check_env_vars MODEL TP CONC KV_OFFLOADING TOTAL_CPU_DRAM_GB RESULT_DIR DURATION PORT EVAL_ONLY DRAFT_MODEL="Inferact/MiniMax-M3-EAGLE3-GQA" NUM_SPEC_TOKENS=3 +TOKENS_PER_SEQ=$((1 + NUM_SPEC_TOKENS)) # Golden AL for the GQA draft head: golden_al_distribution/minimaxm3_eagle3_gqa.yaml # minimax-m3.thinking_on[3]. The non-GQA curve (minimaxm3_eagle3.yaml) reads 2.83. SYNTHETIC_ACCEPT_LEN=2.78 @@ -40,8 +41,8 @@ install_agentic_deps OFFLOAD_ARGS=() if require_agentic_kv_offload_backend vllm-simple; then - python3 "$(dirname "$0")/../../../runners/patch_vllm_simple_kv_offload.py" - CPU_OFFLOAD_BYTES=$((TOTAL_CPU_DRAM_GB * 1024 * 1024 * 1024)) + # The matrix emits decimal GB; SimpleCPUOffloadConnector expects bytes. + CPU_OFFLOAD_BYTES=$((TOTAL_CPU_DRAM_GB * 1000 * 1000 * 1000)) export VLLM_USE_SIMPLE_KV_OFFLOAD=1 OFFLOAD_CONFIG=$(printf \ '{"kv_connector":"SimpleCPUOffloadConnector","kv_role":"kv_both","kv_connector_extra_config":{"cpu_bytes_to_use":%d,"lazy_offload":true}}' \ @@ -53,6 +54,14 @@ export PYTHONNOUSERSITE=1 export VLLM_ENGINE_READY_TIMEOUT_S=3600 export VLLM_FLOAT32_MATMUL_PRECISION=high export VLLM_FLASHINFER_ALLREDUCE_BACKEND=trtllm +export AIPERF_SERVER_METRICS_URLS="http://localhost:${PORT}/metrics" +export AIPERF_REQUIRED_SERVER_METRIC_PREFIX="vllm:" + +MAX_NUM_SEQS=$((2 * CONC)) +MAX_CUDAGRAPH_CAPTURE_SIZE=$((TOKENS_PER_SEQ * MAX_NUM_SEQS)) +if (( MAX_CUDAGRAPH_CAPTURE_SIZE > 512 )); then + MAX_CUDAGRAPH_CAPTURE_SIZE=512 +fi SERVER_LOG="$RESULT_DIR/server.log" mkdir -p "$RESULT_DIR" @@ -86,10 +95,11 @@ VLLM_CMD=( --host 0.0.0.0 --port "$PORT" --tensor-parallel-size "$TP" - --gpu-memory-utilization 0.9 + --gpu-memory-utilization 0.95 --block-size 128 --language-model-only --enable-prefix-caching + --enable-chunked-prefill --no-enable-flashinfer-autotune --reasoning-parser minimax_m3 --tool-call-parser minimax_m3 @@ -97,8 +107,9 @@ VLLM_CMD=( --default-chat-template-kwargs '{"thinking_mode":"enabled"}' --attention-config '{"backend":"FLASHINFER","use_trtllm_attention":true,"indexer_kv_dtype":"fp8"}' --kv-cache-dtype fp8 - --max-cudagraph-capture-size 512 - --max-num-batched-tokens 16384 + --max-cudagraph-capture-size "$MAX_CUDAGRAPH_CAPTURE_SIZE" + --max-num-seqs "$MAX_NUM_SEQS" + --max-num-batched-tokens 32768 --stream-interval 20 --trust-remote-code --speculative-config "$SPEC_CONFIG" diff --git a/configs/nvidia-master.yaml b/configs/nvidia-master.yaml index 7ee2ca0bee..6af0e8913e 100644 --- a/configs/nvidia-master.yaml +++ b/configs/nvidia-master.yaml @@ -5562,7 +5562,7 @@ qwen3.5-fp4-gb200-dynamo-sglang-agentic-mtp: additional-settings: - "CONFIG_FILE=recipes/qwen3.5/sglang/gb200-fp4/agentx/agg-tp2ep2-mtp-hicache-cap48.yaml" minimaxm3-fp4-b300-vllm-agentic-mtp: - image: vllm/vllm-openai:nightly-1dc464d42681d22f38caf1fdc1eb632dc4421c45 + image: vllm/vllm-openai:nightly-29468dde8b515031dc6d4d9d06bf0a2fa0442098 model: nvidia/MiniMax-M3-NVFP4 model-prefix: minimaxm3 runner: cluster:b300-dsxe @@ -5571,14 +5571,14 @@ minimaxm3-fp4-b300-vllm-agentic-mtp: multinode: false scenarios: agentic-coding: - - dram-utilization: 0.683 + - dram-utilization: 1.0 search-space: - { tp: 8, spec-decoding: mtp, kv-offloading: none, conc-list: [1] } - { tp: 4, spec-decoding: mtp, kv-offloading: none, conc-list: [1, 5, 10, 15, 20] } - - { tp: 4, spec-decoding: mtp, kv-offloading: dram, kv-offload-backend: { name: vllm-simple }, conc-list: [30] } + - { tp: 4, spec-decoding: mtp, kv-offloading: dram, kv-offload-backend: { name: vllm-simple }, conc-list: [30, 40, 48, 64] } - dram-utilization: 1.0 search-space: - - { tp: 2, spec-decoding: mtp, kv-offloading: dram, kv-offload-backend: { name: vllm-simple }, conc-list: [24] } + - { tp: 2, spec-decoding: mtp, kv-offloading: dram, kv-offload-backend: { name: vllm-simple }, conc-list: [24, 32, 40] } minimaxm3-fp4-gb300-dynamo-vllm-agentic-mtp-disagg: image: vllm/vllm-openai:nightly-5e35a6f4f9bbc217c599692157ca985c894373f7 @@ -5690,33 +5690,34 @@ minimaxm3-fp4-b300-trtllm-agentic-mtp: # MiniMax-M3's only active B200 configuration -- the 8k1k scenario that carried # the previous B200 curves was removed in #2493. # -# TP4-only. The B300 sibling also runs a TP2 arm, but TP2 does not fit on B200: +# TP4-only until a new TP2 arm is qualified. At 0.90 HBM utilization TP2 +# does not fit on B200: # the ~250 GB NVFP4 checkpoint leaves a 31.72 GiB KV pool at # --gpu-memory-utilization 0.9, and one request at the model's 1,048,576-token # max_model_len needs 37.62 GiB, so vLLM raises in _check_enough_kv_cache_memory # and the engine never reaches serving (run 31141913741 -- both TP2 cells, c1 -# and c2, died identically at init; every TP4 cell passed). This is structural, -# not a concurrency cliff: the estimated max model length at TP2 is 883,840, -# below the corpus context, so no conc-list would have made the arm run. +# and c2, died identically at init; every TP4 cell passed). This is a startup +# capacity limit at 0.90, not a concurrency cliff: the estimated max model +# length at TP2 is 883,840, below the corpus context. The new 0.95 limit may +# clear that check, but needs a live full-context run. # -# Concurrency on the surviving arms still differs from B300, whose TP4 pool is -# ~787 GB against B200's ~398 GB: +# Concurrency on the surviving arms still differs from B300; at the prior +# 0.90 HBM limit, its TP4 KV pool was ~787 GB against B200's ~398 GB: # TP4 B300 runs 1-20; B200 samples 5-15 densely because the cliff lands # inside that range at roughly half the KV, and retains 20 past it. # TP4 + SimpleCPU picks up at 20 rather than B300's 30, since the host tier # has to start absorbing the working set one step earlier, and stops at -# 40 rather than following B300 to 75. Past 40 the host tier is +# 40 rather than following B300's new sweep to 64. Past 40 the host tier is # absorbing a working set that never fit in B200's ~398 GB TP4 pool to # begin with, so those points cost four engine starts each to trace a # tail that is offload bandwidth, not the SKU. # -# dram-utilization 0.683 is the B300 value verbatim, and it resolves to the same -# 1,024 GB engine-level CPU KV budget at TP4: b200-nscale and b300-nv both report -# more installed DRAM than MAX_AGENTIC_AVAILABLE_CPU_DRAM_MIB, so both clamp to -# the same 3 TB AgentX ceiling before the proportional-GPU rule is applied. -# GPU-resident points receive a zero budget. +# B200's 1.0 offload arm uses the full declared host budget: 2,063,920 MiB +# times TP4/8, or about 1,082 GB for this server. GPU-resident points receive +# no host KV budget. B300 has a higher, 3 TB capped node budget (1,499 GB for +# TP4, 749 GB for TP2 after whole-GB rounding). minimaxm3-fp4-b200-vllm-agentic-mtp: - image: vllm/vllm-openai:nightly-1dc464d42681d22f38caf1fdc1eb632dc4421c45 + image: vllm/vllm-openai:nightly-29468dde8b515031dc6d4d9d06bf0a2fa0442098 model: nvidia/MiniMax-M3-NVFP4 model-prefix: minimaxm3 runner: cluster:b200-nscale diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 95afb7e976..acef0594ca 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8902,3 +8902,13 @@ - "server_atom.sh exports PORT before sourcing benchmark_lib.sh on the eval path. run_lm_eval's check_env_vars guard runs before it parses --port and job.slurm's docker -e allowlist forwards ROUTER_PORT but never PORT, so every multi-node lm-eval cell aborted 8 s in; because check_env_vars exits rather than returning, node 0 also skipped its router teardown and the decode node hung in 'Waiting until router closes...' until the job was cancelled (run 35643358891)." - "Per ATOM DeepSeek-V4-Agentic-PD-Max recipe: prefix caching on, FP8 KV and index cache, block-size 256, TBO on prefill only, max-num-seqs = 2x concurrency." pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3158 + +- config-keys: + - minimaxm3-fp4-b200-vllm-agentic-mtp + - minimaxm3-fp4-b300-vllm-agentic-mtp + scenario-type: + - agentic-coding + description: + - "Pin MiniMax-M3 B200/B300 AgentX to vLLM nightly-29468dde8b515031dc6d4d9d06bf0a2fa0442098 and remove the obsolete SimpleCPU KV patch." + - "Increase HBM and B300 host KV budgets, tune serving limits, expand the B300 sweep, and correct host-capacity units." + pr-link: XXX diff --git a/runners/patch_vllm_simple_kv_offload.py b/runners/patch_vllm_simple_kv_offload.py deleted file mode 100755 index 872bd9960a..0000000000 --- a/runners/patch_vllm_simple_kv_offload.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python3 -"""Split heterogeneous vLLM KV backing storage into valid CPU offload regions.""" - -from __future__ import annotations - -import importlib.util -import sys -from pathlib import Path - -OLD_SETUP = """ logical_storage_bytes = self.kv_cache_config.kv_cache_tensors[0].size - - # The DMA backend copies whole blocks as base + block_id * stride(0), -""" -NEW_SETUP = """ logical_storage_bytes = self.kv_cache_config.kv_cache_tensors[0].size - split_storage_by_layer = any( - logical_storage_bytes - % (num_blocks * cache_tensor.block_stride) - != 0 - for cache_tensor in self.kv_cache_config.kv_cache_tensors - ) - - # The DMA backend copies whole blocks as base + block_id * stride(0), -""" -OLD_LOOP = """ unique_gpu_caches: dict[str, torch.Tensor] = {} - seen: set[tuple[torch.device, int]] = set() - for name, tensor in kv_caches.items(): - storage = tensor.untyped_storage() - key = (tensor.device, storage.data_ptr()) - if key in seen: - continue - seen.add(key) - - physical_per_block, remainder = divmod(tensor.shape[0], num_blocks) - assert remainder == 0, ( - f"KV cache {name!r} has {tensor.shape[0]} physical blocks, which " - f"is not divisible by {num_blocks} scheduler blocks" - ) - block_bytes = tensor.stride(0) * tensor.element_size() * physical_per_block - raw = torch.empty(0, dtype=torch.int8, device=tensor.device).set_(storage) - assert raw.numel() >= logical_storage_bytes, ( - f"KV cache {name!r} storage has {raw.numel()} bytes, smaller " - f"than the configured {logical_storage_bytes}-byte allocation" - ) - regions = raw[:logical_storage_bytes].view(-1, num_blocks, block_bytes) - for idx, region in enumerate(regions): - key_name = name if len(regions) == 1 else f"{name}.{idx}" - unique_gpu_caches[key_name] = region -""" -NEW_LOOP = """ unique_gpu_caches: dict[str, torch.Tensor] = {} - seen: set[tuple[torch.device, int, int, int]] = set() - for name, tensor in kv_caches.items(): - physical_per_block, remainder = divmod(tensor.shape[0], num_blocks) - assert remainder == 0, ( - f"KV cache {name!r} has {tensor.shape[0]} physical blocks, which " - f"is not divisible by {num_blocks} scheduler blocks" - ) - block_bytes = tensor.stride(0) * tensor.element_size() * physical_per_block - storage = tensor.untyped_storage() - raw = torch.empty(0, dtype=torch.int8, device=tensor.device).set_(storage) - - if split_storage_by_layer: - region_offset = tensor.storage_offset() * tensor.element_size() - region_bytes = num_blocks * block_bytes - else: - region_offset = 0 - region_bytes = logical_storage_bytes - - key = (tensor.device, storage.data_ptr(), region_offset, region_bytes) - if key in seen: - continue - seen.add(key) - - region_end = region_offset + region_bytes - assert raw.numel() >= region_end, ( - f"KV cache {name!r} storage has {raw.numel()} bytes, smaller " - f"than the required {region_end}-byte region" - ) - regions = raw[region_offset:region_end].view( - -1, num_blocks, block_bytes - ) - for idx, region in enumerate(regions): - key_name = name if len(regions) == 1 else f"{name}.{idx}" - unique_gpu_caches[key_name] = region -""" - - -def installed_worker_path() -> Path: - """Return the SimpleCPUOffload worker module from the installed vLLM.""" - spec = importlib.util.find_spec("vllm") - if spec is None or not spec.submodule_search_locations: - raise RuntimeError("vllm package is not installed") - package_root = Path(next(iter(spec.submodule_search_locations))) - return package_root / "v1/simple_kv_offload/worker.py" - - -def patch_worker(worker_path: Path) -> bool: - """Patch heterogeneous layer-region sizing and return whether source changed.""" - source = worker_path.read_text() - if NEW_SETUP in source and NEW_LOOP in source: - return False - if NEW_SETUP in source or NEW_LOOP in source: - raise RuntimeError(f"partially patched vLLM worker at {worker_path}") - if source.count(OLD_SETUP) != 1 or source.count(OLD_LOOP) != 1: - raise RuntimeError( - f"unsupported vLLM SimpleCPUOffload worker at {worker_path}" - ) - - patched = source.replace(OLD_SETUP, NEW_SETUP).replace(OLD_LOOP, NEW_LOOP) - worker_path.write_text(patched) - return True - - -def main(argv: list[str]) -> int: - if len(argv) > 2: - print(f"Usage: {argv[0]} [WORKER_PATH]", file=sys.stderr) - return 2 - - try: - worker_path = ( - Path(argv[1]).resolve() if len(argv) == 2 else installed_worker_path() - ) - changed = patch_worker(worker_path) - except (OSError, RuntimeError) as error: - print(f"ERROR: failed to patch vLLM CPU offload: {error}", file=sys.stderr) - return 1 - - state = "Patched" if changed else "Already patched" - print(f"{state} vLLM SimpleCPUOffload heterogeneous layer regions") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main(sys.argv)) From 78beae3829340307e692101057b89b3256731e6b Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 25 Sep 2026 13:06:09 -0400 Subject: [PATCH 2/8] chore: link MiniMax-M3 AgentX changelog to PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将性能变更日志中的占位链接替换为本次拉取请求的实际链接。 --- perf-changelog.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perf-changelog.yaml b/perf-changelog.yaml index acef0594ca..95ea6ef992 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8911,4 +8911,4 @@ description: - "Pin MiniMax-M3 B200/B300 AgentX to vLLM nightly-29468dde8b515031dc6d4d9d06bf0a2fa0442098 and remove the obsolete SimpleCPU KV patch." - "Increase HBM and B300 host KV budgets, tune serving limits, expand the B300 sweep, and correct host-capacity units." - pr-link: XXX + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435 From 3b7cd43fc7f2d99ee72493027b36196b1efacac8 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 25 Sep 2026 13:12:03 -0400 Subject: [PATCH 3/8] test: handle git config flag in SRT clone stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复单节点 SRT 测试桩,使其识别克隆命令前的 Git 配置参数。 --- utils/test_srt_single_node.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/test_srt_single_node.py b/utils/test_srt_single_node.py index 979f286daf..5afec027f1 100644 --- a/utils/test_srt_single_node.py +++ b/utils/test_srt_single_node.py @@ -278,7 +278,7 @@ def test_pool_launcher_stages_artifacts_and_propagates_failure(point, tmp_path, # Only external executables are stubbed; run the real pool launcher, shared # setup/profile/acceptance helpers, binder, and artifact collection. scripts = { - "git": 'if [[ "$1" == clone ]]; then mkdir -p "${@: -1}/configs"; else echo test-commit; fi', + "git": 'if [[ "$1" == -c ]]; then shift 2; fi; if [[ "$1" == clone ]]; then mkdir -p "${@: -1}/configs"; else echo test-commit; fi', "uv": 'if [[ "$1" == venv ]]; then mkdir -p .venv/bin; echo ":" > .venv/bin/activate; fi', "make": '[[ "$TEST_FAILURE" == bootstrap ]] && exit 13; mkdir -p bin; touch bin/uv', "squeue": '[[ "$TEST_FAILURE" == submission || "$TEST_FAILURE" == agentic ]] && echo "42"; exit 0', From 37d6595e1143f261fcaa8eab06cbb903293fb707 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 25 Sep 2026 14:09:07 -0400 Subject: [PATCH 4/8] fix: avoid FA4 FP8 draft KV startup failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 MiniMax-M3 的 EAGLE3 草稿模型 KV 缓存改为 BF16,避开当前 vLLM 夜间版中 FA4 对 FP8 缩放张量步长的启动错误。目标模型仍使用 FP8 KV 缓存。 --- benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh | 4 ++-- benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh | 4 ++-- perf-changelog.yaml | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh index b7fdd9e35a..fcae86aba1 100755 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh @@ -147,11 +147,11 @@ trap 'exit 143' TERM if [ "${EVAL_ONLY:-}" = "true" ]; then SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN"}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","kv_cache_dtype":"bfloat16"}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS") else SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","kv_cache_dtype":"bfloat16","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS" "$SYNTHETIC_ACCEPT_LEN") fi diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh index 976f419d93..5b49a6473c 100755 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh @@ -80,11 +80,11 @@ trap 'exit 143' TERM if [ "${EVAL_ONLY:-}" = "true" ]; then SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN"}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","kv_cache_dtype":"bfloat16"}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS") else SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","kv_cache_dtype":"bfloat16","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS" "$SYNTHETIC_ACCEPT_LEN") fi diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 95ea6ef992..5a998cd501 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8912,3 +8912,12 @@ - "Pin MiniMax-M3 B200/B300 AgentX to vLLM nightly-29468dde8b515031dc6d4d9d06bf0a2fa0442098 and remove the obsolete SimpleCPU KV patch." - "Increase HBM and B300 host KV budgets, tune serving limits, expand the B300 sweep, and correct host-capacity units." pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435 + +- config-keys: + - minimaxm3-fp4-b200-vllm-agentic-mtp + - minimaxm3-fp4-b300-vllm-agentic-mtp + scenario-type: + - agentic-coding + description: + - "Use BF16 EAGLE3 draft KV cache to avoid the FA4 FP8 descale startup failure." + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435 From 9a1fc30a5e1ec6cef802d250c8323fe9b2262c0f Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 25 Sep 2026 14:45:53 -0400 Subject: [PATCH 5/8] fix: use FlashInfer for FP8 MiniMax EAGLE3 draft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 使用 FlashInfer 为 MiniMax EAGLE3 草稿模型保留 FP8 KV 缓存。 --- benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh | 4 ++-- benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh | 4 ++-- perf-changelog.yaml | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh index fcae86aba1..66f38e83e0 100755 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh @@ -147,11 +147,11 @@ trap 'exit 143' TERM if [ "${EVAL_ONLY:-}" = "true" ]; then SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","kv_cache_dtype":"bfloat16"}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASHINFER","kv_cache_dtype":"fp8"}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS") else SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","kv_cache_dtype":"bfloat16","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASHINFER","kv_cache_dtype":"fp8","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS" "$SYNTHETIC_ACCEPT_LEN") fi diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh index 5b49a6473c..62fc04102b 100755 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh @@ -80,11 +80,11 @@ trap 'exit 143' TERM if [ "${EVAL_ONLY:-}" = "true" ]; then SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","kv_cache_dtype":"bfloat16"}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASHINFER","kv_cache_dtype":"fp8"}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS") else SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASH_ATTN","kv_cache_dtype":"bfloat16","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASHINFER","kv_cache_dtype":"fp8","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS" "$SYNTHETIC_ACCEPT_LEN") fi diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 5a998cd501..675146ff5d 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8921,3 +8921,12 @@ description: - "Use BF16 EAGLE3 draft KV cache to avoid the FA4 FP8 descale startup failure." pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435 + +- config-keys: + - minimaxm3-fp4-b200-vllm-agentic-mtp + - minimaxm3-fp4-b300-vllm-agentic-mtp + scenario-type: + - agentic-coding + description: + - "Use FlashInfer with FP8 EAGLE3 draft KV cache on B200 and B300." + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435 From 849d36406a220f0e43f268516147b4d1d017e4f7 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 25 Sep 2026 22:59:25 -0400 Subject: [PATCH 6/8] fix: use FP8 Triton attention for MiniMax draft MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MiniMax 草稿模型改用支持 FP8 KV 缓存的 Triton 注意力实现。 --- benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh | 4 ++-- benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh | 4 ++-- perf-changelog.yaml | 9 +++++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh index 66f38e83e0..34eb6dcd5a 100755 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_b200_mtp.sh @@ -147,11 +147,11 @@ trap 'exit 143' TERM if [ "${EVAL_ONLY:-}" = "true" ]; then SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASHINFER","kv_cache_dtype":"fp8"}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"TRITON_ATTN","kv_cache_dtype":"fp8"}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS") else SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASHINFER","kv_cache_dtype":"fp8","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"TRITON_ATTN","kv_cache_dtype":"fp8","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS" "$SYNTHETIC_ACCEPT_LEN") fi diff --git a/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh b/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh index 62fc04102b..a6bc6997ea 100755 --- a/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh +++ b/benchmarks/single_node/agentic/minimaxm3_fp4_b300_mtp.sh @@ -80,11 +80,11 @@ trap 'exit 143' TERM if [ "${EVAL_ONLY:-}" = "true" ]; then SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASHINFER","kv_cache_dtype":"fp8"}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"TRITON_ATTN","kv_cache_dtype":"fp8"}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS") else SPEC_CONFIG=$(printf \ - '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"FLASHINFER","kv_cache_dtype":"fp8","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ + '{"method":"eagle3","model":"%s","num_speculative_tokens":%d,"attention_backend":"TRITON_ATTN","kv_cache_dtype":"fp8","rejection_sample_method":"synthetic","synthetic_acceptance_length":%.2f}' \ "$DRAFT_MODEL_PATH" "$NUM_SPEC_TOKENS" "$SYNTHETIC_ACCEPT_LEN") fi diff --git a/perf-changelog.yaml b/perf-changelog.yaml index abaa8d9570..57368c108b 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8959,3 +8959,12 @@ description: - "Use FlashInfer with FP8 EAGLE3 draft KV cache on B200 and B300." pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435 + +- config-keys: + - minimaxm3-fp4-b200-vllm-agentic-mtp + - minimaxm3-fp4-b300-vllm-agentic-mtp + scenario-type: + - agentic-coding + description: + - "Use Triton attention with FP8 EAGLE3 draft KV cache." + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435 From 33fe1211e986043b5b97d74ad7dada5fef352902 Mon Sep 17 00:00:00 2001 From: Xin Li Date: Fri, 25 Sep 2026 23:06:14 -0400 Subject: [PATCH 7/8] fix: limit sweep changelog to MiniMax entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 仅保留本次 MiniMax 更新的扫描变更日志条目。 --- perf-changelog.yaml | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 095b1a2f24..f2db071f18 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -8951,35 +8951,6 @@ - "Update SGLang image from v0.5.19-cu130 to v0.5.20-cu130 and pass --cuda-graph-max-bs-decode after the alias removal." pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3334 -- config-keys: - - qwen3.5-fp8-mi355x-sglang - - qwen3.5-fp8-mi355x-sglang-mtp - description: - - "Update SGLang ROCm image from v0.5.18-rocm720-mi35x-20260828 to v0.5.20-rocm720-mi35x-20260924 (latest nightly)" - pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3423 - -- config-keys: - - dsv41flash-fp4-mi355x-vllm-agentic-dspark - scenario-type: - - agentic-coding - description: - - "Re-sweep the MI355X DeepSeek-V4.1-Flash vLLM AgentX arm on the next ROCm 10.0 nightly, replacing nightly-rocm100-7f1a5398. Only the image changes: the TP=4 and TP=2 rows keep concurrency 1, 2, 4, 8, 16, 32, 64 and 128, and every recipe setting is unchanged, including Engram placement per TP and concurrency, the prefill chunk and sequence cap ladder, graph capture, and five-token DSpark with golden acceptance 3.51 for throughput and real block verification for evals." - - "The pin is mainly for vllm-project/vllm#58510, which computes the MXFP8 GEMM on native 32x32 block scales for gfx950. This arm serves a checkpoint whose non-routed weights are MXFP8 on exactly that architecture, so the target image is the first nightly whose commit contains that merge rather than simply the next one published. The exact tag, its publication time and digest are filled in once that build exists." - - "在下一个 ROCm 10.0 nightly 上重新扫描 MI355X DeepSeek-V4.1-Flash vLLM AgentX 臂,替换 nightly-rocm100-7f1a5398。本次仅更换镜像:TP=4 与 TP=2 两行保持并发 1、2、4、8、16、32、64 与 128,其余 recipe 设置全部不变,包括按 TP 与并发决定的 Engram 放置、prefill 分块与序列上限阶梯、图捕获,以及吞吐用黄金接受长度 3.51、评测用真实分块验证的五 token DSpark。" - - "此次固定主要是为了 vllm-project/vllm#58510:它在 gfx950 上使用原生 32x32 block scale 计算 MXFP8 GEMM。本臂所服务的 checkpoint 其非 routed 权重正是该架构上的 MXFP8,因此目标镜像是第一个其提交包含该合并的 nightly,而非简单地取下一个发布的 nightly。具体标签、发布时间与摘要将在该构建出现后补充。" - pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3420 - -- config-keys: - - dsv41flash-fp4-mi355x-atom-agentic-dspark - scenario-type: - - agentic-coding - description: - - "Add DeepSeek-V4.1-Flash FP4 ATOM AgentX on MI355X following the upstream TP2 / TP4 recipe: TP2 concurrency [1, 2, 8, 16, 32, 64], TP4 concurrency [2, 8, 16, 32, 64], no expert parallelism or KV offload." - - "Use rocm/atom-dev:nightly_202609250902 (digest sha256:9aaeed59d78decfc51eaabda072ba095c1d64d6cfbdb64ecb28ea74cf3deb18a), BF16 KV, FP8 index cache, max-num-seqs 128, 16K batching/prefill chunks, prefix caching with block size 16, 8K state checkpoints, level 3 and FULL graphs with dense capture sizes through 32 at concurrency 32." - - "Use five-token DSpark with thinking_on golden AL 3.51 for throughput and real acceptance for eval, the shipped draft, and dsml_v41 tool parsing. Replay semianalysis_cc_traces_weka_062126 for 3600 seconds per point with five warmup requests per lane." - - "DSpark draft layers 37-39 keep their checkpoint precision: the recipe passes no --online_quant_config, so online_quant_config resolves to None and make_v4_quant_config builds the same per-layer quant spec for the drafter as for the target. The MTP weights (mtp.0/1/2) load inline from the same checkpoint with spec_decode=True, and config.get_layer_quant_config has no mtp.* special case, so layers 37-39 are neither re-quantized nor up/down-cast by ATOM and retain their on-disk dtype. --kv_cache_dtype bf16 and --index-cache-dtype fp8 touch cache storage only, not draft/MTP weights." - pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3387 - - config-keys: - minimaxm3-fp4-b200-vllm-agentic-mtp - minimaxm3-fp4-b300-vllm-agentic-mtp From baa8b1937580d1c999de0385056abe4923574ddf Mon Sep 17 00:00:00 2001 From: Xin Li Date: Sat, 26 Sep 2026 13:19:40 -0400 Subject: [PATCH 8/8] fix: reserve B300 TP2 MSA workspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 仅将 B300 TP2 CPU KV 卸载配置的 GPU 内存利用率降至 0.92,为 MSA 预填充临时缓冲区预留空间。其他配置保持原值。 --- .../minimaxm3/vllm/b300-fp4-mtp/agentic.yaml | 3 +++ perf-changelog.yaml | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/benchmarks/single_node/srt-slurm-recipes/minimaxm3/vllm/b300-fp4-mtp/agentic.yaml b/benchmarks/single_node/srt-slurm-recipes/minimaxm3/vllm/b300-fp4-mtp/agentic.yaml index 49e690b11e..5318501648 100644 --- a/benchmarks/single_node/srt-slurm-recipes/minimaxm3/vllm/b300-fp4-mtp/agentic.yaml +++ b/benchmarks/single_node/srt-slurm-recipes/minimaxm3/vllm/b300-fp4-mtp/agentic.yaml @@ -164,6 +164,7 @@ override_tp2_c24_dram: gpus: 2 args: tensor-parallel-size: 2 + gpu-memory-utilization: 0.92 max-num-seqs: 48 max-cudagraph-capture-size: 192 kv-transfer-config: '{"kv_connector":"SimpleCPUOffloadConnector","kv_role":"kv_both","kv_connector_extra_config":{"cpu_bytes_to_use":749000000000,"lazy_offload":true}}' @@ -232,6 +233,7 @@ override_tp2_c32_dram: gpus: 2 args: tensor-parallel-size: 2 + gpu-memory-utilization: 0.92 max-num-seqs: 64 max-cudagraph-capture-size: 256 kv-transfer-config: '{"kv_connector":"SimpleCPUOffloadConnector","kv_role":"kv_both","kv_connector_extra_config":{"cpu_bytes_to_use":749000000000,"lazy_offload":true}}' @@ -248,6 +250,7 @@ override_tp2_c40_dram: gpus: 2 args: tensor-parallel-size: 2 + gpu-memory-utilization: 0.92 max-num-seqs: 80 max-cudagraph-capture-size: 320 kv-transfer-config: '{"kv_connector":"SimpleCPUOffloadConnector","kv_role":"kv_both","kv_connector_extra_config":{"cpu_bytes_to_use":749000000000,"lazy_offload":true}}' diff --git a/perf-changelog.yaml b/perf-changelog.yaml index 4f160f0cee..a9e710931b 100644 --- a/perf-changelog.yaml +++ b/perf-changelog.yaml @@ -9008,3 +9008,11 @@ description: - "Port the settings to active srt-slurm recipes and use FlashInfer draft attention with inherited FP8 KV." pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435 + +- config-keys: + - minimaxm3-fp4-b300-vllm-agentic-mtp + scenario-type: + - agentic-coding + description: + - "Set B300 TP2 offload to 0.92 GPU memory utilization to reserve MSA prefill workspace." + pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/3435