[XPU] Add & optimize silu_and_mul_with_clamp activation kernel#461
Open
yangulei wants to merge 2 commits into
Open
[XPU] Add & optimize silu_and_mul_with_clamp activation kernel#461yangulei wants to merge 2 commits into
yangulei wants to merge 2 commits into
Conversation
Implement the `_C::silu_and_mul_with_clamp` op for XPU: a SwiGLU
activation with input clamping (SwiGLU-OAI style) over contiguous
gate/up halves.
gate = gate.clamp(max=limit)
up = up.clamp(min=-limit, max=limit)
out = (gate * sigmoid(alpha * gate)) * (up + beta)
Defaults alpha=1.0, beta=0.0 reduce this to silu(gate) * up.
Adds the SYCL kernel, dispatch function, op declaration, torch
binding, and tests. Validated on Intel Arc B60 (BMG): 72 passed
across fp16/bf16/fp32 and (alpha, beta) in {(1.0, 0.0), (1.702, 1.0)}.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Youlei Yang <youlei.yang@intel.com>
Replace the scalar one-workgroup-per-token kernel with a bandwidth-optimized path: 16-byte aligned vector loads/stores (8x bf16/half, 4x float) over a flat grid-stride dispatch, so occupancy is independent of the token count. Falls back to the scalar per-token kernel when d is not divisible by the vector width. On Intel Arc Pro B60 (BMG) the dominant MiniMax-M3 MoE activation shape [16384, 1536]->[16384, 768] improves from 262 to 390 GB/s (+49%, 85.7% of the 456 GB/s DRAM roofline); small token counts no longer starve the GPU. Add a non-vectorizable d=17 test case to cover the scalar fallback (54/54 pass). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Youlei Yang <youlei.yang@intel.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new XPU fused activation op, silu_and_mul_with_clamp (SwiGLU-OAI-style with clamping), including a bandwidth-optimized vectorized SYCL implementation, PyTorch dispatcher registration, and Python-side tests/wrappers to validate correctness and schema behavior.
Changes:
- Implement
silu_and_mul_with_clampincsrc/activation.cpp, including a vectorized grid-stride fast path and a scalar fallback. - Register the new op in
csrc/torch_bindings.cppand expose its C++ signature incsrc/ops.h. - Add a dedicated test (
tests/test_silu_and_mul_with_clamp.py) plus test wrappers (tests/register_ops.py,tests/ops/silu_and_mul_with_clamp_op.py).
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
csrc/activation.cpp |
Adds the scalar + vectorized SYCL kernels and launch logic for silu_and_mul_with_clamp. |
csrc/ops.h |
Declares the new op entry point for compilation/linking. |
csrc/torch_bindings.cpp |
Registers the op schema and XPU implementation with the PyTorch dispatcher. |
tests/register_ops.py |
Adds a Python wrapper to invoke the new registered op for tests. |
tests/ops/silu_and_mul_with_clamp_op.py |
Adds a CustomOp test wrapper and a native reference implementation. |
tests/test_silu_and_mul_with_clamp.py |
Adds correctness + opcheck coverage across dtypes, shapes, and scalar/vector paths. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+14
to
+16
| XPU_DEVICES = [ | ||
| f"xpu:{i}" for i in range(1 if torch.xpu.device_count() == 1 else 2) | ||
| ] |
Comment on lines
+56
to
+58
| seed: int, | ||
| device: str, | ||
| ) -> None: |
Comment on lines
+59
to
+62
| seed_everything(seed) | ||
| torch.set_default_device(device) | ||
| alpha, beta = params | ||
| x = torch.randn(num_tokens, 2 * d, dtype=dtype) |
Comment on lines
+846
to
+852
| int d = input.size(-1) / 2; \ | ||
| int64_t num_tokens = input.numel() / input.size(-1); \ | ||
| at::DeviceGuard device_guard(input.device()); \ | ||
| auto& queue = vllm::xpu::vllmGetQueue(); \ | ||
| if (num_tokens == 0) { \ | ||
| return; \ | ||
| } \ |
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
silu_and_mul_with_clampXPU activation kernel (SwiGLU-OAI with inputclamping, used by MiniMax-M3 MoE) and a bandwidth-optimized SYCL implementation.
Semantics (matches the CUDA reference and
torch.clamp-based native path):Implementation
silu_and_mul_with_clamp_vec_kernel<T, ACT_FN, VEC>— the fast path usedwhen
d % VEC == 0(VEC = 16/sizeof(T), i.e. 8×bf16/half, 4×float):vllm::xpu::aligned_vec, so eachwork-item moves a full cache-line-friendly chunk instead of scalar 2-byte
elements.
(token, chunk)pairs (WG=256, gridcapped at 2560 workgroups) so GPU occupancy is independent of the token
count — small-batch shapes no longer launch just a handful of workgroups.
d % VEC != 0, preserving correctness for arbitraryd.Performance (Intel Arc Pro B60 / BMG, bf16)
Profile-guided optimization on the MiniMax-M3 shape matrix. Effective bandwidth
of the fused op (read 2·d + write d):
The dominant shape reaches 85.7% of the 456 GB/s theoretical peak and
99.5% of the empirical streaming roofline (a trivial same-traffic copy tops
out at 393 GB/s), i.e. it is at the memory-bandwidth wall. ISA analysis
confirmed the remaining ALU (clamp
cmp/sel, sigmoidexp) is fully hiddenbehind memory latency, so no further ISA-level tuning helps.
Versus the PyTorch-native (
torch.clamp/sigmoid/mul) path, the fused kernelis ~8.4× faster (geomean) across the shape matrix and also more accurate
(fp32 intermediates, single cast: err 0.125 vs 0.24 against an fp32 golden).
Tests
tests/test_silu_and_mul_with_clamp.pyvalidates the op against the nativereference across
{half, bfloat16, float}, multiple token counts, and bothddivisible by the vector width (vectorized path) andd = 17(scalarfallback). Plus
opcheckfor schema/meta.