Skip to content

Commit 06d8d5f

Browse files
committed
fix(amd): align Kimi-K3 DSpark with ROCm baseline
Use the exact GPU-only c1 DSpark serving defaults requested for MI355X: block rejection, 128 sequences, 4096 batched tokens, 0.95 GPU memory utilization, multimodal data parallelism, and no eager or prefix-cache override. Add regression coverage for the wrapper and generated matrix. 中文:将 MI355X Kimi-K3 DSpark 对齐到指定的 ROCm GPU-only c1 基线:使用 block rejection、128 个序列、4096 个批处理 token、0.95 GPU 显存利用率、multimodal data 并行,并移除 eager 与显式 prefix-cache 覆盖。同时为 wrapper 和生成矩阵添加回归测试。
1 parent 4c2c8f1 commit 06d8d5f

5 files changed

Lines changed: 107 additions & 46 deletions

File tree

benchmarks/single_node/agentic/kimik3_fp4_mi355x.sh

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ set -x
4949
# KV_BLOCK_SIZE unset (unset -> vLLM sizes the page; 128 under fp8)
5050
# MAX_MODEL_LEN unset (unset -> vLLM derives K3's 1M context)
5151
# SPEC_DECODE false (enabled by the _mtp DSpark wrapper)
52-
# ENFORCE_EAGER false (enabled by the _mtp DSpark wrapper)
52+
# ENFORCE_EAGER false (reference; DSpark wrapper keeps it false)
5353

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

@@ -600,7 +600,7 @@ fi
600600
# and hash sizes only align with prefix caching on -- an omission has been
601601
# reported to trip "tokens_per_block not divisible by tokens_per_hash" at load.
602602
# Set PREFIX_CACHING=true/false to force it either way.
603-
# ON by default for EVERY arm. This trace is built around large shared
603+
# ON by default for non-DSpark arms. This trace is built around large shared
604604
# prefixes -- theoretical prefix-cache hit is 98.1%, and a live kvnone cell
605605
# measured 92.8% server-side -- so a run with reuse disabled is not measuring
606606
# the workload. Reuse also costs essentially no KV (1,414,660 vs 1,420,824
@@ -620,43 +620,35 @@ fi
620620
#
621621
# Note vLLM resolves the flag's default to False for this model, so ON must be
622622
# passed explicitly. PREFIX_CACHING=false forces it off for a deliberate A/B.
623-
PREFIX_CACHE_ARGS=(--enable-prefix-caching)
624-
if [ "${PREFIX_CACHING:-}" = "false" ]; then
625-
PREFIX_CACHE_ARGS=(--no-enable-prefix-caching)
626-
fi
623+
case "${PREFIX_CACHING:-true}" in
624+
true)
625+
PREFIX_CACHE_ARGS=(--enable-prefix-caching)
626+
;;
627+
false)
628+
PREFIX_CACHE_ARGS=(--no-enable-prefix-caching)
629+
;;
630+
auto)
631+
# Match the upstream AMD command by letting vLLM resolve its default.
632+
PREFIX_CACHE_ARGS=()
633+
;;
634+
*)
635+
echo "Error: PREFIX_CACHING must be true, false, or auto." >&2
636+
exit 1
637+
;;
638+
esac
627639

628640
# The upstream DSpark config pins "attention_backend": "FLASHINFER_MLA", which
629641
# is CUDA-only and cannot be used verbatim on gfx950; SPEC_ATTN_BACKEND
630-
# overrides it. AgentX throughput uses synthetic acceptance pinned to the
631-
# committed golden curve. Eval-only runs use real block verification because
632-
# synthetic acceptance bypasses correctness verification.
642+
# overrides it. Use real block rejection for both throughput and evaluation so
643+
# this path is the exact AMD reproducer and exercises target-model verification.
633644
SPEC_ARGS=()
634645
if [ "${SPEC_DECODE:-false}" = "true" ]; then
635646
SPEC_DRAFT_MODEL="${SPEC_DRAFT_MODEL:-Inferact/Kimi-K3-DSpark}"
636647
SPEC_NUM_TOKENS="${SPEC_NUM_TOKENS:-7}"
637648
SPEC_ATTN_BACKEND="${SPEC_ATTN_BACKEND:-TRITON_MLA}"
638-
SPEC_GOLDEN_AL="${SPEC_GOLDEN_AL:-3.84}"
639-
SPEC_GOLDEN_AL_FILE="${SPEC_GOLDEN_AL_FILE:-golden_al_distribution/kimik3_dspark_probabilistic_sample_method_block_rejection_sample_method.yaml}"
640-
FILE_GOLDEN_AL=$(awk -v k="$SPEC_NUM_TOKENS" '
641-
/^kimi-k3:/ { in_model = 1; next }
642-
/^[^[:space:]#]/ { in_model = 0 }
643-
in_model && /thinking_on:/ { in_thinking = 1; next }
644-
in_thinking && $1 == k":" { print $2; exit }
645-
' "$SPEC_GOLDEN_AL_FILE" 2>/dev/null)
646-
if [ "$FILE_GOLDEN_AL" != "$SPEC_GOLDEN_AL" ]; then
647-
echo "Error: DSpark golden AL mismatch: $SPEC_GOLDEN_AL_FILE gives" >&2
648-
echo " '${FILE_GOLDEN_AL:-<unreadable>}' for k=$SPEC_NUM_TOKENS," >&2
649-
echo " but the recipe pins $SPEC_GOLDEN_AL." >&2
650-
exit 1
651-
fi
652-
if [ "${EVAL_ONLY:-false}" = "true" ]; then
653-
SPEC_REJECTION_CONFIG="\"rejection_sample_method\":\"block\""
654-
else
655-
SPEC_REJECTION_CONFIG="\"rejection_sample_method\":\"synthetic\",\"synthetic_acceptance_length\":$SPEC_GOLDEN_AL"
656-
fi
657649
SPEC_ARGS=(
658650
--speculative-config
659-
"{\"model\":\"$SPEC_DRAFT_MODEL\",\"num_speculative_tokens\":$SPEC_NUM_TOKENS,\"method\":\"dspark\",\"attention_backend\":\"$SPEC_ATTN_BACKEND\",\"draft_sample_method\":\"probabilistic\",$SPEC_REJECTION_CONFIG}"
651+
"{\"model\":\"$SPEC_DRAFT_MODEL\",\"num_speculative_tokens\":$SPEC_NUM_TOKENS,\"method\":\"dspark\",\"attention_backend\":\"$SPEC_ATTN_BACKEND\",\"draft_sample_method\":\"probabilistic\",\"rejection_sample_method\":\"block\"}"
660652
)
661653
fi
662654

benchmarks/single_node/agentic/kimik3_fp4_mi355x_mtp.sh

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ set -euo pipefail
55
# spec-decoding=mtp rows to this suffix, while the shared base recipe owns the
66
# model, KV-offload, AgentX replay, and eval plumbing.
77
#
8-
# These overrides are the DSpark + SimpleCPUOffloadConnector combination
9-
# validated on gfx950 in PR #2367. Keep them together: widening the batch or
10-
# re-enabling CUDA graphs reproduced an eight-rank GPU memory access fault.
8+
# Keep this wrapper aligned with the upstream AMD Kimi-K3 DSpark reproducer.
9+
# The first AgentX validation is deliberately GPU-only at c1 so a server or
10+
# kernel failure cannot be attributed to a KV-offload connector.
1111
export SPEC_DECODE=true
1212
export KV_CACHE_DTYPE="${KV_CACHE_DTYPE:-auto}"
13-
export MAX_NUM_SEQS="${MAX_NUM_SEQS:-32}"
14-
export EVAL_MAX_NUM_SEQS="${EVAL_MAX_NUM_SEQS:-32}"
15-
export MAX_NUM_BATCHED_TOKENS="${MAX_NUM_BATCHED_TOKENS:-1024}"
16-
export LANGUAGE_MODEL_ONLY="${LANGUAGE_MODEL_ONLY:-true}"
17-
export SIMPLE_LAZY_OFFLOAD="${SIMPLE_LAZY_OFFLOAD:-true}"
18-
export ENFORCE_EAGER="${ENFORCE_EAGER:-true}"
13+
export GPU_MEM_UTIL="${GPU_MEM_UTIL:-0.95}"
14+
export MAX_NUM_SEQS="${MAX_NUM_SEQS:-128}"
15+
export EVAL_MAX_NUM_SEQS="${EVAL_MAX_NUM_SEQS:-128}"
16+
export MAX_NUM_BATCHED_TOKENS="${MAX_NUM_BATCHED_TOKENS:-4096}"
17+
export LANGUAGE_MODEL_ONLY="${LANGUAGE_MODEL_ONLY:-false}"
18+
export PREFIX_CACHING="${PREFIX_CACHING:-auto}"
19+
export ENFORCE_EAGER="${ENFORCE_EAGER:-false}"
1920

2021
exec "$(dirname "$0")/kimik3_fp4_mi355x.sh" "$@"

configs/amd-master.yaml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -664,12 +664,10 @@ kimik3-fp4-mi355x-vllm-agentic-mtp:
664664
agentic-coding:
665665
- dram-utilization: 0.80
666666
search-space:
667-
# DSpark speculative decoding with Inferact/Kimi-K3-DSpark, seven draft
668-
# tokens, probabilistic draft sampling, and the committed thinking-on
669-
# golden AL. The _mtp wrapper applies the gfx950 settings validated in
670-
# PR #2367 as one unit: eager execution, max-num-batched-tokens 1024,
671-
# max-num-seqs 32, bf16 KV, and lazy SimpleCPUOffloadConnector allocation.
672-
- { tp: 8, kv-offloading: dram, kv-offload-backend: { name: vllm-simple }, spec-decoding: mtp, conc-list: [1, 2, 4, 8] }
667+
# Exact upstream AMD DSpark reproducer: GPU-only TP8, seven draft tokens,
668+
# probabilistic draft sampling, TRITON_MLA, and real block rejection.
669+
# Start at c1; expand only after the AgentX-fast preflight is healthy.
670+
- { tp: 8, kv-offloading: none, spec-decoding: mtp, conc-list: [1] }
673671

674672
kimik3-fp4-mi355x-vllm-agentic-fp8kvtest:
675673
image: vllm/vllm-openai-rocm:kimi-k3

perf-changelog.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5316,6 +5316,6 @@
53165316
- kimik3-fp4-mi355x-vllm-agentic-mtp
53175317
description:
53185318
- "Add the Kimi-K3 MXFP4 MI355X AgentX DSpark variant with Inferact/Kimi-K3-DSpark, seven draft tokens, probabilistic draft sampling, and TRITON_MLA on ROCm."
5319-
- "Pin throughput to the committed thinking-on golden acceptance length 3.84 with synthetic rejection sampling; eval-only runs retain real block verification."
5320-
- "Run TP8 with SimpleCPUOffloadConnector at concurrency 1/2/4/8. The _mtp wrapper keeps the gfx950 bring-up settings validated in PR #2367 together: --enforce-eager, --max-num-batched-tokens 1024, --max-num-seqs 32, bf16 KV cache, language-model-only mode, and lazy host allocation."
5319+
- "Align the first AgentX validation with the upstream AMD reproducer: GPU-only TP8 at concurrency 1, real block rejection, --gpu-memory-utilization 0.95, --max-num-batched-tokens 4096, --max-num-seqs 128, multimodal encoder data parallelism, and no --enforce-eager or explicit prefix-cache override."
5320+
- "Use VLLM_ROCM_USE_AITER=1, SAFETENSORS_FAST_GPU=1, AITER_SITUV2_A8W4=1, AITER_BF16_FP8_MOE_BOUND=0, and VLLM_USE_BREAKABLE_CUDAGRAPH=0 with the stock vllm/vllm-openai-rocm:kimi-k3 image."
53215321
pr-link: https://github.com/SemiAnalysisAI/InferenceX/pull/2403
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from pathlib import Path
2+
import re
3+
4+
import yaml
5+
6+
7+
REPO_ROOT = Path(__file__).resolve().parents[2]
8+
MTP_WRAPPER = (
9+
REPO_ROOT / "benchmarks/single_node/agentic/kimik3_fp4_mi355x_mtp.sh"
10+
)
11+
BASE_RECIPE = REPO_ROOT / "benchmarks/single_node/agentic/kimik3_fp4_mi355x.sh"
12+
MASTER_CONFIG = REPO_ROOT / "configs/amd-master.yaml"
13+
14+
15+
def _shell_default(script: str, variable: str) -> str:
16+
match = re.search(
17+
rf'export {re.escape(variable)}="\$\{{{re.escape(variable)}:-(.*?)\}}"',
18+
script,
19+
)
20+
assert match is not None, f"{variable} must have an overridable default"
21+
return match.group(1)
22+
23+
24+
def test_dspark_wrapper_matches_oren_rocm_baseline() -> None:
25+
wrapper = MTP_WRAPPER.read_text()
26+
27+
assert _shell_default(wrapper, "KV_CACHE_DTYPE") == "auto"
28+
assert _shell_default(wrapper, "GPU_MEM_UTIL") == "0.95"
29+
assert _shell_default(wrapper, "MAX_NUM_SEQS") == "128"
30+
assert _shell_default(wrapper, "EVAL_MAX_NUM_SEQS") == "128"
31+
assert _shell_default(wrapper, "MAX_NUM_BATCHED_TOKENS") == "4096"
32+
assert _shell_default(wrapper, "LANGUAGE_MODEL_ONLY") == "false"
33+
assert _shell_default(wrapper, "PREFIX_CACHING") == "auto"
34+
assert _shell_default(wrapper, "ENFORCE_EAGER") == "false"
35+
36+
37+
def test_dspark_defaults_to_real_block_rejection() -> None:
38+
recipe = BASE_RECIPE.read_text()
39+
spec_section = recipe.split("# ---- Eval-only path", maxsplit=1)[0].split(
40+
"SPEC_ARGS=()", maxsplit=1
41+
)[1]
42+
43+
assert '\\"rejection_sample_method\\":\\"block\\"' in spec_section
44+
assert "synthetic_acceptance_length" not in spec_section
45+
46+
47+
def test_reference_prefix_cache_mode_emits_no_override() -> None:
48+
recipe = BASE_RECIPE.read_text()
49+
prefix_section = recipe.split("# The upstream DSpark config", maxsplit=1)[0].split(
50+
"PREFIX_CACHE_ARGS=", maxsplit=1
51+
)[1]
52+
53+
assert "auto)" in prefix_section
54+
assert "PREFIX_CACHE_ARGS=()" in prefix_section
55+
56+
57+
def test_dspark_diagnostic_matrix_is_gpu_only_c1() -> None:
58+
master = yaml.safe_load(MASTER_CONFIG.read_text())
59+
search_space = master["kimik3-fp4-mi355x-vllm-agentic-mtp"]["scenarios"][
60+
"agentic-coding"
61+
][0]["search-space"]
62+
63+
assert search_space == [
64+
{
65+
"tp": 8,
66+
"kv-offloading": "none",
67+
"spec-decoding": "mtp",
68+
"conc-list": [1],
69+
}
70+
]

0 commit comments

Comments
 (0)