Add Kimi-K3 MI300X (gfx942) serving recipes (3 colocated + 2P/2D EP16 disagg, NIAH to 900K) - #193
Add Kimi-K3 MI300X (gfx942) serving recipes (3 colocated + 2P/2D EP16 disagg, NIAH to 900K)#193raviguptaamd wants to merge 16 commits into
Conversation
Adds scripts/vllm/kimik3_mi300x/ with three self-contained colocated vLLM serving recipes for Kimi-K3 (MXFP4) on AMD Instinct MI300X / gfx942, complementing MAD's existing single-node gfx950/MI355X K3 recipe. MI300X has 192 GB/GPU, so the ~1.5 TB K3 checkpoint does not fit a single 8-GPU node under TP8; all recipes shard across 2 nodes (16x MI300X) with PP2xTP8 (~102 GB/GPU). gfx942 also requires VLLM_ROCM_USE_AITER_MLA=0. Recipes (each: run.sh + README.md + niah_probe.py): - pp2xtp8 PP2xTP8 baseline, no expert parallelism - wideep_int4_allgather +EP16, generic allgather_reducescatter all2all, a8w4 - wideep_int4_moriep +EP16, true MoRI-EP (mori_low_latency) all2all, a8w4 Uses the public vendor image amdsiloai/vllm:kimi-k3-mi325x-release-v2 (anonymous pull). Recipes only; no benchmark results included. Scripts are env-parameterized (IMAGE/MODEL_DIR/MASTER/PORT/...) and bash -n / py_compile clean. RDMA fabric env (NCCL_IB_HCA/GID, MORI_*) is cluster-specific and documented as overridable. AI-assisted (Claude); human-reviewed. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Ravi Gupta <ravi.gupta@amd.com>
…-node PP uses NCCL
…ays TP (not a product)
Adds scripts/vllm/kimik3_mi300x/wideep_disagg_2p2d/ — a prefill/decode DISAGGREGATED Kimi-K3 (MXFP4) recipe across 4 MI300X nodes: 2 prefill + 2 decode, TP2xDP8 -> EP16 per pool via MoRI-EP all2all (no pipeline parallelism), joined by the MoRIIO connector for prefill->decode transfer of both the MLA attention KV and the Kimi-Delta-Attention (KDA/mamba) recurrent+conv state. STATUS: WORK IN PROGRESS, lands as reviewable infra + honest STATUS.md, NOT a production deployment. The MoRIIO transport is byte-perfect (attention KV and KDA state arrive element-identical on all 8 decode ranks, verified by the probes under patchers/diagnostics/) and all connector-level bugs are fixed, but an open decode-side accuracy bug means exact long-context (NIAH) recall does not pass yet. Short single-token recall and coherent generation work; multi-token exact recall is wrong and non-deterministic at greedy temp=0 (non-determinism => forward-pass bug, below the sampler). STATUS.md carries the exact repro and the full ruled-out list; use the three colocated recipes for serving today. Connector fixes (folded into the vLLM source branch the image builds; also kept here as reference patchers under patchers/): - mamba block-id routing: transfer KDA state by the mamba KV-cache group's block ids, not the attention group's - remote_tp_size normalize: degenerate remote_tp_size<=1 -> world_size so KV fans out to all decode TP ranks - mamba N-1 boundary: producer computes h(N-1), decoder recomputes token N (mirrors vLLM's nixl/mooncake hybrid-PD handling) - gated diagnostics (default OFF): K3_WRITE_FENCE/K3_WRITE_DEVSYNC ordering, K3_MLA_SINGLE_SPLIT deterministic reduction (both inert on the known bug) Scripts are env-parameterized (node IPs/hostnames, MODEL_DIR, IMAGE); Dockerfile bases are ARG-driven placeholders. No benchmark results included. bash -n / py_compile clean; no local paths, IPs, tokens, or private tags. AI-assisted (Claude); human-reviewed. Co-authored-by: Claude <noreply@anthropic.com> Signed-off-by: Ravi Gupta <ravi.gupta@amd.com>
|
Pushed a 4th recipe subfolder: Status: WIP / known-issue — not a working deployment. The disagg transport is byte-perfect (attention KV + KDA/mamba state arrive byte-identical on all 8 decode ranks) and all connector-level bugs are fixed, but exact multi-token NIAH recall is still wrong and non-deterministic at greedy temp=0 (a forward-pass bug below the sampler, downstream of the proven-correct KV). Full repro + ruled-out list in Unlike the colocated recipes, this folder ships a self-contained Rebased cleanly on top of the recent docs commits already on this branch. Intend to split the disagg work into its own PR later; grouping here for review context. |
Bring the wideep_disagg_2p2d recipe from WIP to validated. Single-needle NIAH passes deterministically through 300K tokens (all depths) on the 2-prefill + 2-decode EP16 disagg serve. Two root-cause fixes for the decode-recall bug: - 4-KV-cache-group block routing (apply_kimik3_moriio_group_routing.py): K3 has 4 KV groups (3 KDA/mamba + 1 MLA); the connector hardcoded 2-group indices and sent MLA KV to mamba block-ids. Now routes each layer by its own group. - Multi-chunk prefill transfer (apply_kimik3_chunk_gate_fix.py + chunked_allgrp.py): the final-chunk gate used block count, which fires after chunk 1 when a prompt fits in <=1 padded block, so only max_num_batched_tokens of KV crossed. Now gates on compute progress from scheduler_output (map -> entry defer -> accum final-detect -> post-loop sweep). Also: run_2p2d.sh fabric now env-overridable (validated Thor2 bnxt defaults ON, THOR2_BNXT_FIX toggle) + LOAD_STRATEGY/chunk-gate knobs; STATUS.md rewritten to VALIDATED with the root-cause writeup; README winning-config + fabric-override + debugging sections; RESULTS.md (NIAH 10K-300K + latency/throughput 5.7x@8, 7.3x@16); benchmark_niah.py + concurrency_bench.py; niah_probe.py --ctx-list sweep. Remove 4 dead-end patchers (hma_fix, kda_fix, kda_offsets, sampler_fix). Co-Authored-By: Claude <noreply@anthropic.com>
Bump Dockerfile VLLM_REF to kimi-k3-wideep-disagg-fullsource-v2 — the base fullsource branch plus the two decode-recall fixes folded into vLLM source (4-KV-group block routing + multi-chunk compute-progress gate). The rebuilt image now has the fixes baked in; the runtime patchers stay in patchers/ and no-op idempotently on a v2 image (and still work on an older image). README updated to name the v2 branch and explain the baked-in vs patcher relationship. Co-Authored-By: Claude <noreply@anthropic.com>
…build crash)
The vLLM wheel build fails with `ValueError: invalid literal for int() with
base 10: ''` in setup.py compute_num_jobs when MAX_JOBS reaches the pip
subprocess empty (the ENV MAX_JOBS=${MAX_JOBS} did not propagate under the
legacy builder). Set MAX_JOBS/NVCC_THREADS inline on the pip install command so
the build is reproducible regardless of builder.
Co-Authored-By: Claude <noreply@anthropic.com>
…timization + scratch-build validation - RESULTS.md: single-needle NIAH now recorded to 500K (3/3 PASS ~301s); 900K documented as a known hang (prefill freezes, GPUs 100%, no result; serve recovers on client kill — confined to the one oversized request). Wall is between 500K and 900K. - OPTIMIZATION.md (new): validated KV-cache lever — KV_CACHE_MEMORY_BYTES 8e9->40e9 raises the GPU KV cache 542K->2.84M tokens (5.2x, 2.84x concurrency at 1M ctx), required for single requests >~600K; the 8e9 pin was only a profile_run-hang workaround, not a mem limit. Plus max_num_seqs guidance, the batched-tokens dead end, the single-stream-latency trade, the residual write race, and base-image digest-pin durability. - README: add KV_CACHE_MEMORY_BYTES to the config table + link OPTIMIZATION.md; note MAX_MODEL_LEN=1000000 for full native ctx. - STATUS: note the recipe was validated from a from-scratch image build (fixes baked into the v2 vLLM branch; patchers idempotent no-ops on it). Co-Authored-By: Claude <noreply@anthropic.com>
…AH to 900K) Contexts above ~500K used to hang. py-spy root-caused it to gather_initial_states running a bool((indices>=n).any()) device->CPU sync per KDA layer per prefill chunk (~25k full stream drains at 750K) purely to log a warning; the index clamp above already made the GPU address safe. Gate the diagnostic behind K3_KDA_GATHER_LOG=1 (default OFF); correctness unchanged. Result: single-needle NIAH now PASSES the full native range 10K-900K (500K 301s, 750K 542s, 900K 717s; sub-quadratic), where 750K/900K previously hung indefinitely. - Fold: vLLM branch kimi-k3-wideep-disagg-fullsource-v3 (Dockerfile VLLM_REF bumped) - Ship: patchers/apply_kimik3_kda_gather_nosync.py + wired into run_2p2d.sh (no-op idempotent on a v3 image) - Docs: STATUS/RESULTS/OPTIMIZATION updated to the 10K-900K range + the fix writeup; noted batched=8192 still corrupts generation (keep 2048). Co-Authored-By: Claude <noreply@anthropic.com>
…kage) - concurrency_bench.py: hardcoded router IP -> ROUTER_URL env var (default 127.0.0.1), matching the other test scripts. - run_2p2d.sh: drop internal cluster name from a fabric-defaults comment. - kimi_k3_moriep_report.html: replace node hostnames, an internal home path, and the internal cluster name with generic descriptions. No credentials were ever committed; this removes the remaining environment-specific identifiers so the recipe reads as a generic MI300X + Thor2 reference. Co-Authored-By: Claude <noreply@anthropic.com>
Summary
Adds
scripts/vllm/kimik3_mi300x/— self-contained vLLM serving recipes forKimi-K3 (MXFP4) on AMD Instinct MI300X / gfx942, complementing MAD's existing
single-node gfx950/MI355X K3 recipe (
benchmark/kimi_k3/).Why MI300X needs its own recipe: MI300X has 192 GB/GPU, so the ~1.5 TB K3 checkpoint
does not fit a single 8-GPU node under TP8. The colocated recipes shard across 2 nodes
(16× MI300X) using PP2×TP8 (~102 GB/GPU per node). gfx942 also requires
VLLM_ROCM_USE_AITER_MLA=0(the AITER MLA kernel is gfx950-only).This PR contains three colocated recipes plus a fourth prefill/decode
disaggregated (2P/2D) recipe — validated: single-needle NIAH passes deterministically
across the full native context range 10K–900K.
Colocated recipes — each:
run.sh+README.md+niah_probe.pypp2xtp8/wideep_int4_allgather/allgather_reducescatter(generic)AITER_SITUV2_A8W4=1)wideep_int4_moriep/mori_low_latency(MoRI-EP)AITER_SITUV2_A8W4=1)All colocated (single instance; no prefill/decode disaggregation). These use the public
vendor image
amdsiloai/vllm:kimi-k3-mi325x-release-v2, overridable via-e IMAGE=.wideep_disagg_2p2d/— 2P/2D EP16 MoRIIO disaggregation (✅ validated)A prefill/decode disaggregated Kimi-K3 recipe across 4 MI300X nodes: 2 prefill +
2 decode, TP2×DP8 → EP16 per pool via MoRI-EP all2all (no pipeline parallelism),
joined by the MoRIIO connector for prefill→decode transfer of both the MLA attention
KV and the Kimi-Delta-Attention (KDA/mamba) recurrent+conv state.
Three root-cause fixes (all folded into vLLM source on the branch below):
groups (3 KDA/mamba + 1 MLA); the connector hardcoded 2-group indices and sent MLA KV to
mamba block-ids → decode read empty blocks (fluent but context-free). Fix routes each
layer by its own group index.
after chunk 1 when a prompt fits in ≤1 padded block → only
max_num_batched_tokensof KVcrossed (a razor cliff at 2048). Fix gates on compute progress from
scheduler_output.gather_initial_statesran a diagnosticbool((indices>=n).any())device→CPU sync per KDA layer per prefill chunk (~25k fullstream drains at 750K), stalling long-context prefills into an apparent hang (py-spy'd:
the DP rank with real work stuck in the sync while other DP ranks waited at the batch
all_reduce). The clamp above already made the address safe; the diagnostic is now gated
behind
K3_KDA_GATHER_LOG=1(default OFF), correctness unchanged.Results — single-needle NIAH (
HELIOTROPE-7492, greedy, depths 0.1/0.5/0.9)Deterministic across the full range; sub-quadratic scaling. Throughput (the DP disagg
payoff, 20K ctx): 5.7× at concurrency 8, 7.3× at 16 vs single-stream. Single-stream
latency is ~4× a colocated PP2×TP8 serve by design (1 request on 2 GPUs vs all 16) — use
disagg for high-QPS/batch, colocated for low-latency interactive. Tables in
RESULTS.md;tuning in
OPTIMIZATION.md(KV_CACHE_MEMORY_BYTES=40e9→ 2.84M-token KV cache, requiredfor single requests > ~600K;
MAX_MODEL_LEN=1000000for full native ctx).Known residual (does not block single-needle NIAH): the stricter 10-needle stress dips
to ~9/10 at ≥20K (an RDMA write-visibility race); single-needle is unaffected. Documented in
STATUS.md. Note:MAX_NUM_BATCHED_TOKENS=8192still corrupts generation on this stack —keep the default
2048.Self-contained image: this folder ships
Dockerfile.kimik3_disagg, which builds thewhole stack from source on a public base (
rocm/vllm-dev:ci_base-...): MoRI v1.2.2 +AITER 0.1.19 + vLLM (from the fork branch below, all fixes baked in) + the
DP-rank/KV-notify vllm-router. Validated from a scratch build (NIAH re-passed with the
runtime patchers reporting "already applied" — idempotent no-ops on a folded image).
Companion vLLM branch: the connector + KDA fixes are folded into vLLM source at
raviguptaamd/vllmbranchkimi-k3-wideep-disagg-fullsource-v3; the Dockerfile builds itdirectly (
VLLM_REF=kimi-k3-wideep-disagg-fullsource-v3). The runtime patchers underwideep_disagg_2p2d/patchers/no-op idempotently on a v3 image (so the recipe also works onan unfolded image).
Notes
NCCL_IB_HCA/GID,MORI_*,SOCKET_IFNAME) is fully overridable; defaultsare the validated Broadcom Thor2 (bnxt) values with a
THOR2_BNXT_FIXtoggle. Overridefor other fabrics (e.g. Mellanox mlx5) per the README.
15 min) on the first ≥200K request;cached thereafter.
Test plan
bash -non allrun.sh/ launch scripts — pass.python3 -m py_compileon all.py(probes + patchers) — pass.MAX_JOBSempty-env build fix).deterministic; fixes served from the baked-in image.
AI assistance (Claude) was used to prepare this PR; changes were human-reviewed.