Repository navigation
feat(kimi-k3): add gfx1250 monokernel - #2894
XiaobingSuper wants to merge 8 commits into
Conversation
🏷️ CI GuideRuns automatically on every eligible PR before approval:
Heavy model tests:
|
5d1cdba to
31f505d
Compare
Co-authored-by: Cursor <cursoragent@cursor.com>
31f505d to
fd3d2d7
Compare
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Trying #2894 end to end: Kimi-K3, TP8 across two MI455 trays (gfx1250)We merged #2894 at Setup
1. A TP group that spans nodes is refused before the gfx1250 runner is chosen
(
not getattr(atom_config, "is_multinode_tp", False),
"TP group spans nodes (HIP IPC peer memory)",
),so every rank logs diff --git a/atom/models/kimi_k3/mono/config.py b/atom/models/kimi_k3/mono/config.py
--- a/atom/models/kimi_k3/mono/config.py
+++ b/atom/models/kimi_k3/mono/config.py
@@ -253,6 +253,9 @@
SUPPORTED_TP,
supported_gfx=("gfx950", "gfx1250"),
refuse_decode_cp=False,
+ # runner_gfx1250 keeps no peer memory: its TP collectives are RCCL's,
+ # which reach the ranks of a TP group on the other node as well
+ multinode_gfx=("gfx1250",),
)
+ resident_grid_refusals(atom_config)
) + [
diff --git a/atom/mono/runtime/deployment.py b/atom/mono/runtime/deployment.py
--- a/atom/mono/runtime/deployment.py
+++ b/atom/mono/runtime/deployment.py
@@ -88,6 +88,7 @@
refuse_tr_hybrid: bool = True,
supported_gfx: tuple[str, ...] = ("gfx950",),
refuse_decode_cp: bool = True,
+ multinode_gfx: tuple[str, ...] = (),
) -> list[tuple[bool, str]]:
"""``(holds, why not)`` of the conditions every mono model needs: ``dims``
(the model's ``Dims``) shards at this TP, which is one of ``supported_tp``,
@@ -113,7 +114,12 @@
(its attention layers stay on the production path, which handles the
split) or are written for that split and refuse any other themselves
(the shared DSA indexer, ``dsa_indexer.bind``) passes
- ``refuse_decode_cp=False``."""
+ ``refuse_decode_cp=False``.
+
+ ``multinode_gfx``: the architectures on which the model's runner serves a
+ TP group that spans nodes. Mono's peer buffers are HIP IPC mappings, which
+ cannot reach a GPU on another node, so a TP group across nodes is refused
+ unless the runner for this architecture keeps no peer memory at all."""
tp = atom_config.tensor_parallel_size
dpa = dp_attention_ranks(atom_config)
if dpa not in (0, *supported_dpa):
@@ -147,7 +153,7 @@
# another node. Read like `compilation_config` below: a config without
# the attribute (plugin modes) is a single-node one.
(
- not getattr(atom_config, "is_multinode_tp", False),
+ gfx in multinode_gfx or not getattr(atom_config, "is_multinode_tp", False),
"TP group spans nodes (HIP IPC peer memory)",
),
(not (atom_config.enable_tbo or atom_config.enable_tbo_decode), "TBO"),2. The five bf16 projections (already documented; FYI)Our launch quantizes the checkpoint's BF16 layers online, so the bind refused with 3. Blocking: the gate/up layout of the routed expertsOn gfx1250 our launch sets and again in the gfx1250 With So on gfx1250, with today's aiter, the production MoE needs the interleaved layout and #2894's K2 What this does not coverNo mono kernel ran, because the runner never got past its bind. So nothing here says anything about |
Co-authored-by: Cursor <cursoragent@cursor.com>
|
@gbyu-amd Thanks — your diagnosis is correct. The earlier TP8 A/B used the non-interleaved operator setup; it did not prove that the current production prefill layout could bind and hit the gfx1250 mono path. The production-readiness claim was too strong. I pushed
I also fixed the gfx1250 scale-size check: native n32k4 Validation on MI455/gfx1250:
The remaining missing proof is your actual two-node TP8 model run. Please retry with the same production |
|
Retried with 520e5b6, thanks for the quick fix. The setup is the same two-node TP8 one as in my previous comment, now also with #2942's latest commits, plus 520e5b6. The launch keeps the production layout:
The bind now passes. All eight ranks log One merge note: our image already carries #2647's multinode refusal in Blocking: no width builds K1, so mono never launches a kernel. During CUDA-graph capture, every rank fails the K1 build for every width: It fails for all nine widths the run needs: rows 5, 10, …, 45 at qlen 5 (width keys 90 … 770). The cause is a one-slot mismatch with the pool ATOM allocates:
The conv itself looks fine with ATOM's window:
With We are trying |
|
Follow-up: with the K1 bound relaxed to Setup. ATOM is the image from my first comment, plus #2942's latest commits, 520e5b6 and the one-line K1 change below. The launch is:
--- a/atom/models/kimi_k3/mono/kernels/attention/kda_builder_gfx1250.py
+++ b/atom/models/kimi_k3/mono/kernels/attention/kda_builder_gfx1250.py
@@ -353,10 +353,13 @@ class K1LocalBuildSpec:
- if self.state_len < self.qlen + 3:
+ # ATOM's conv pool keeps the last `kernel - 1 + num_spec` inputs
+ # (`_state_shape`): the history read at `acc_idx <= qlen - 1` ends at
+ # `acc_idx + 2`, so qlen + 2 entries serve every accepted count.
+ if self.state_len < self.qlen + 2:
raise ValueError(
- "local K1 state_len must cover qlen plus the three-entry "
- "causal-convolution history"
+ "local K1 state_len must cover qlen plus the two history "
+ "entries the conv window keeps"
)Mono runs, and the output is right.
But it is much slower. Both points are MLPerf Endpoints at concurrency 8 with a 10-minute issue cap, on the same harness and the same image:
The two runs differ in mono, and in the five projections being BF16 in the mono run. Draft acceptance is unchanged: 40.8% vs 42.1%, 2.63 vs 2.68 tokens per forward. So each decode step got slower, from about 23 ms to about 86 ms (TPOT x tokens per forward). We have not profiled it yet. One candidate is K2's collectives. Was the operator A/B measured with these same collectives? And what did one S32 or S48 step break down into? A per-kernel breakdown would tell us where to look. |
Co-authored-by: Cursor <cursoragent@cursor.com>
|
@gbyu-amd Thanks — both findings are correct. I pushed
The earlier isolated K1 gains remain valid, but the previous full TP8 operator-path performance claim was not measured with this production cross-node collective stack and should not be used. The real model numbers in your comment are the current E2E baseline. I am preparing a conc8/MTP4 rerun with the production online-quant baseline unchanged. Mono ON alone will carry the five required BF16 exclusions; Mono OFF will remain the original recipe. |
Co-authored-by: Cursor <cursoragent@cursor.com>
|
gfx1250 now keeps K2 on the production path (commit |
Summary
Add a production Kimi-K3 Monokernel path for gfx1250:
The path is limited to TP8, 256-CU gfx1250 and non-ReplaySSM deployments. Full-attention layers, DSA indexers and every post-K1 operation remain on their ordinary production paths.
Only the two projections consumed inside K1 need to remain BF16:
*self_attn.in_proj**self_attn.f_b_proj*o_projand both shared-expert projections use the normal online-quant configuration.Performance
Single-GPU operator microbenchmarks compare the one-launch K1 with the repaired six-launch wave32 staged implementation using the same corrected KDA backend:
95.2 usvs286.1 us)96.1 usvs281.3 us)95.1 usvs271.9 us)161.3 usvs300.6 us)160.4 usvs272.7 us)The projection pipeline computes both 16-row output groups from one x staging pass and delays the second weight group until the first MFMA chain has issued. S48 plain decode uses a wave32 head task with CTA-local norm reduction, removing cross-CTA QK/ONRM handoffs while keeping K1 at one launch.
An earlier two-node run used an experimental custom K2 and regressed E2E performance. That K2 path is no longer selected: commit
4004b393chands K1's core directly to the model's productiono_projand latent MoE. A matched TP8 E2E rerun of the revised path is pending.Validation
prefix,core_outand conv-state match; recurrent-state maximum absolute error7.45e-9474 passedgit diff --check: cleanThe earlier two-node production run passed accuracy (
GSM8K 0.985/200, MLPerf inline accuracy 64.11%). A checkpoint rerun is still required for the revised performance number.Related: https://github.com/wuhuikx/LLM-Booster/issues/366