[XPU][MiniMax-M3] Add and optimize fused qknorm/rope/kv-insert SYCL kernel for BMG#422
Open
yangulei wants to merge 5 commits into
Open
[XPU][MiniMax-M3] Add and optimize fused qknorm/rope/kv-insert SYCL kernel for BMG#422yangulei wants to merge 5 commits into
yangulei wants to merge 5 commits into
Conversation
yangulei
force-pushed
the
pr/fused-qknorm-opt
branch
2 times, most recently
from
June 17, 2026 03:14
da5e416 to
9e59c69
Compare
yangulei
marked this pull request as ready for review
June 22, 2026 08:30
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new SYCL kernel and op registration for MiniMax-M3’s fused attention pre-processing on Intel XPU (BMG), plus XPU-side correctness tests to validate dense and sparse (cache-insert) behavior.
Changes:
- Register
torch.ops._C.fused_minimax_m3_qknorm_rope_kv_insertfor XPU and expose it via the test ops registry. - Add the SYCL implementation of the fused qk-norm + partial NeoX RoPE + KV/index-cache insert kernel (head_dim=128).
- Add dense + sparse correctness tests comparing against an fp32 reference.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
csrc/fused_minimax_m3_qknorm_rope_kv_insert.cpp |
New SYCL kernel + C++ entrypoint for fused M3 qknorm/rope/cache insert |
csrc/torch_bindings.cpp |
Registers the new op schema and XPU implementation |
csrc/ops.h |
Adds the C++ declaration for the new op |
tests/register_ops.py |
Adds Python wrapper used by tests to call the new op |
tests/test_fused_minimax_m3_qknorm_rope_kv_insert.py |
New correctness tests for dense + sparse/cache-insert paths |
CMakeLists.txt |
Adds the new source file to the build |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
yangulei
force-pushed
the
pr/fused-qknorm-opt
branch
from
June 22, 2026 09:26
9e59c69 to
bc86c5c
Compare
SYCL port of the horizontally-fused M3 attention pre-processing kernel from vllm-project/vllm#45381 (csrc/libtorch_stable/fused_minimax_m3_qknorm_rope_kv_insert_kernel.cu), registered in the _C extension as torch.ops._C.fused_minimax_m3_qknorm_rope_kv_insert so the unchanged upstream vllm._custom_ops wrapper resolves it on XPU (no vllm-side dispatch shim). Unlike DeepSeek-V4's qnorm_rope_kv_insert (head_dim 512, GPT-J interleaved rope, 2 standard RMSNorms, MLA layout), M3 uses head_dim 128, partial-NeoX rope (rotary_dim leading dims rotated, rest pass-through), four Gemma-style RMSNorms (x * rsqrt(mean(x^2)+eps) * (1+weight)), and the packed [q|k|v|index_q|index_k] layout. One work-item handles one (token, head-slot) and loops over the 128-dim head: - q -> Gemma-norm + rope -> q_out (sparse) / in place (dense) - k -> Gemma-norm + rope -> in place + scatter kv_cache[:,0] - v -> raw + scatter kv_cache[:,1] - index_q -> Gemma-norm + rope -> index_q_out - index_k -> Gemma-norm + rope -> in place + scatter index_cache Validated on Intel Arc B60 (tests/test_fused_minimax_m3_qknorm_rope_kv_insert.py, 20 cases: dense norm+rope parity and sparse-full mode incl. index branch + cache inserts) against a Gemma-RMSNorm + NeoX-partial-RoPE torch reference, and via the upstream vllm._custom_ops wrapper dispatching to torch.ops._C. Co-authored-by: GitHub Copilot Signed-off-by: Youlei Yang <youlei.yang@intel.com>
Profile-guided (unitrace) optimization on Intel BMG (Arc Pro B60), pinned @ 2.4 GHz, min-of-7 device timing. The original used a per-work-item buf[128] (16 KB private-memory spill) and a partial-sub-group launch geometry (~num_tokens hardware threads) -> 34% occupancy, 72% XVE stall. Changes: - Streaming two-pass norm+RoPE (sum-of-squares, then normalize+RoPE written straight to dst/cache): removes buf[128], private mem 16 KB -> 0. - One cooperative M3_SG_SIZE-lane sub-group per (token, head-slot); lanes split the 128-dim head, sum-of-squares via reduce_over_group, rotary pairs computed lane-locally (flat 1-D nd_range). Occupancy 34% -> 92%, stall 72% -> 31%. Result: 100,935 -> 30,224 ns/call (~3.34x), MBU 18% -> 56% of HBM. Tested: tests/test_fused_minimax_m3_qknorm_rope_kv_insert.py (20 passed). Note: builds on the in-flight MiniMax-M3 XPU enablement (csrc/utils.h and the _C kernel sources are not yet on main); this draft PR is for review of the kernel optimization. AI assistance (GitHub Copilot CLI) was used. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Youlei Yang <youlei.yang@intel.com>
Address review feedback on the fused qknorm/rope/kv-insert entrypoint: - Include <ATen/DeviceGuard.h> explicitly instead of relying on transitive includes. - Add dtype/device/contiguity/shape validation matching the conventions used by fused_qk_norm_rope, and guard the optional-input combinations (kv_cache requires slot_mapping + block_size, index_cache requires index_slot_mapping, num_index_heads>0 requires the index norm weights) so bad inputs fail with a clear error instead of an out-of-bounds access or null dereference inside the kernel. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Youlei Yang <youlei.yang@intel.com>
This wrapper was accidentally included; it is unrelated to the M3 kernel, has no backing op in this repo (references torch.ops._xpu_C) and no test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Youlei Yang <youlei.yang@intel.com>
Address review feedback: the SYCL kernel writes q_out/index_q_out and the kv/index caches using fixed stride math, so a mismatched shape would scatter out of bounds. Add shape checks that mirror the kernel's indexing: - q_out / index_q_out: numel == num_tokens * heads * head_dim, and reject index_q_out when num_index_heads == 0 (it is never written then). - kv_cache: 5-D [num_blocks, 2, block_size, num_kv_heads, head_dim]. - index_cache: trailing dim == head_dim (flattened [num_slots, head_dim]). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Youlei Yang <youlei.yang@intel.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the fused_minimax_m3_qknorm_rope_kv_insert SYCL kernel (horizontally-fused MiniMax-M3 attention pre-processing: Gemma-RMSNorm + partial-NeoX RoPE + KV/index-cache insert) on Intel BMG (Arc Pro B60), and then optimizes it. Two commits:
Commit 1 — Add fused qknorm_rope_kv_insert SYCL kernel
SYCL port of the horizontally-fused M3 attention pre-processing kernel from vllm-project/vllm#45381 (
csrc/libtorch_stable/fused_minimax_m3_qknorm_rope_kv_insert_kernel.cu), registered in the_Cextension astorch.ops._C.fused_minimax_m3_qknorm_rope_kv_insertso the unchanged upstreamvllm._custom_opswrapper resolves it on XPU (no vllm-side dispatch shim).Unlike DeepSeek-V4's
qnorm_rope_kv_insert(head_dim 512, GPT-J interleaved rope, 2 standard RMSNorms, MLA layout), M3 uses head_dim 128, partial-NeoX rope (rotary_dim leading dims rotated, rest pass-through), four Gemma-style RMSNorms (x * rsqrt(mean(x^2)+eps) * (1+weight)), and the packed[q|k|v|index_q|index_k]layout. One work-item handles one (token, head-slot) and loops over the 128-dim head:q→ Gemma-norm + rope → q_out (sparse) / in place (dense)k→ Gemma-norm + rope → in place + scatterkv_cache[:,0]v→ raw → scatterkv_cache[:,1]index_q→ Gemma-norm + rope → index_q_outindex_k→ Gemma-norm + rope → in place + scatter index_cacheCommit 2 — Optimize for BMG (~3.3×)
The original used a per-work-item
buf[128](16 KB private-memory spill) and a partial-sub-group launch geometry (~num_tokensthreads) → 34% occupancy, 72% XVE stall. The optimization:buf[128], private mem 16 KB → 0.M3_SG_SIZE-lane sub-group per (token, head-slot) on a flat 1-Dnd_range; lanes split the 128-dim head, sum-of-squares viareduce_over_group, rotary pairs computed lane-locally. Occupancy 34% → 92%, stall 72% → 31%.A register-cache-of-
srcvariant and a large-GRF build were both tried and measured worse (occupancy-bound), so they are not included.Testing
tests/test_fused_minimax_m3_qknorm_rope_kv_insert.py— 20 passed (dense norm+rope parity; sparse-full incl. index branch + KV/index cache inserts) vs an fp32 reference.mainheaders (csrc/utils.h); the op registration is a self-contained addition tocsrc/ops.h/csrc/torch_bindings.cpp/tests/register_ops.pyand oneCMakeLists.txtsource line. Builds standalone onmain.Not a duplicate
Checked
gh pr list --repo vllm-project/vllm-xpu-kernels --state open— no open PR touches this kernel.Notes