Skip to content

[XPU][MOE] Optimize XPU MoE activation by skipping invalid rows#401

Open
ranzhejiang wants to merge 1 commit into
vllm-project:mainfrom
ranzhejiang:zhejiang/fix_moe
Open

[XPU][MOE] Optimize XPU MoE activation by skipping invalid rows#401
ranzhejiang wants to merge 1 commit into
vllm-project:mainfrom
ranzhejiang:zhejiang/fix_moe

Conversation

@ranzhejiang

@ranzhejiang ranzhejiang commented Jun 8, 2026

Copy link
Copy Markdown

Summary
This PR optimizes the XPU fused MoE activation path for EP prefill by passing the valid routed row count into fusion and skipping invalid trailing rows on device.

In EP, the real routed rows can be smaller than num_rows * topk. Without this information, activation still runs on the full upper-bound shape even though grouped GEMM already uses the real routed rows. Carrying the valid row count into fusion avoids redundant activation work without introducing Python-side host synchronization.

This path is only enabled for EP prefill. Decode keeps the existing behavior, and TP is unaffected because it does not use this EP-specific valid-row path

In https://github.com/Tencent/hpc-ops, they also use valid_row_range_ptr to skip unused rows

Copilot AI review requested due to automatic review settings June 8, 2026 05:41
@ranzhejiang
ranzhejiang marked this pull request as draft June 8, 2026 05:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds MoE-specific activation variants that use a device-side valid_rows/valid_tokens scalar to skip padded rows on XPU, avoiding CPU↔GPU synchronization.

Changes:

  • Introduced *_moe Torch ops (bindings + headers) accepting valid_rows as an int32 device scalar to guard kernels on-device.
  • Added SYCL kernel variants for SiLU/GELU/ReLU2/SwiGLU* that early-exit when token_idx >= *valid_rows.
  • Updated Python MoE execution paths to compute valid_tokens on-device and call the new *_moe activation ops.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
vllm_xpu_kernels/fused_moe_interface.py Computes valid_tokens on-device and routes activation through new MoE-specific ops.
csrc/torch_bindings.cpp Registers new *_moe activation ops with valid_rows parameter.
csrc/ops.h Declares new MoE activation op entry points.
csrc/activation.cpp Implements SYCL kernels and launch macros that guard work-groups by valid_rows.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread csrc/activation.cpp Outdated
Comment on lines +932 to +975
#define LAUNCH_SWIGLUOAI_AND_MUL_MOE(KERNEL, ALPHA, LIMIT) \
int d = input.size(-1) / 2; \
int64_t num_tokens = input.numel() / input.size(-1); \
sycl::range<1> grid(num_tokens); \
sycl::range<1> block(std::min(d, 1024)); \
at::DeviceGuard device_guard(input.device()); \
auto& queue = vllm::xpu::vllmGetQueue(); \
VLLM_DISPATCH_FLOATING_TYPES( \
input.scalar_type(), "swigluoai_and_mul_kernel_moe", [&] { \
queue.submit([&](sycl::handler& cgh) { \
cgh.parallel_for( \
sycl::nd_range<1>(grid * block, block), \
vllm::swigluoai_and_mul_kernel_moe< \
scalar_t, KERNEL<scalar_t>>( \
out.data_ptr<scalar_t>(), \
input.data_ptr<scalar_t>(), \
valid_rows.data_ptr<int32_t>(), \
d, \
ALPHA, \
LIMIT)); \
}); \
});

#define LAUNCH_SWIGLUSTEP_AND_MUL_MOE(KERNEL, LIMIT) \
int d = input.size(-1) / 2; \
int64_t num_tokens = input.numel() / input.size(-1); \
sycl::range<1> grid(num_tokens); \
sycl::range<1> block(std::min(d, 1024)); \
at::DeviceGuard device_guard(input.device()); \
auto& queue = vllm::xpu::vllmGetQueue(); \
VLLM_DISPATCH_FLOATING_TYPES( \
input.scalar_type(), "swiglustep_and_mul_kernel_moe", [&] { \
queue.submit([&](sycl::handler& cgh) { \
cgh.parallel_for( \
sycl::nd_range<1>(grid * block, block), \
vllm::swiglustep_and_mul_kernel_moe< \
scalar_t, KERNEL<scalar_t>>( \
out.data_ptr<scalar_t>(), \
input.data_ptr<scalar_t>(), \
valid_rows.data_ptr<int32_t>(), \
d, \
LIMIT)); \
}); \
});
Comment thread csrc/activation.cpp Outdated
Comment on lines +977 to +995
void silu_and_mul_moe(
torch::Tensor& out, // [num_moe_inputs, d]
torch::Tensor& input, // [num_moe_inputs, 2*d]
torch::Tensor& valid_rows) // int32 device scalar = rows_per_expert.sum()
{
VLLM_DISPATCH_FLOATING_TYPES(input.scalar_type(), "silu_and_mul_moe", [&] {
LAUNCH_ACTIVATION_GATE_KERNEL_VEC_MOE(vllm::silu_kernel, true);
});
}

void gelu_and_mul_moe(
torch::Tensor& out,
torch::Tensor& input,
torch::Tensor& valid_rows)
{
VLLM_DISPATCH_FLOATING_TYPES(input.scalar_type(), "gelu_and_mul_moe", [&] {
LAUNCH_ACTIVATION_GATE_KERNEL_VEC_MOE(vllm::gelu_kernel, true);
});
}
Comment thread vllm_xpu_kernels/fused_moe_interface.py Outdated
Comment on lines +117 to +119
elif activation == "swigluoai" or ("SWIGLUOAI" in str(activation)):
torch.ops._C.swigluoai_and_mul_moe(act_output, gemm1_output,
valid_tokens, 1.702, 7.0)
Comment thread csrc/ops.h Outdated
Comment on lines +67 to +72
void swigluoai_and_mul_moe(torch::Tensor& out, torch::Tensor& input,
torch::Tensor& valid_rows, double alpha,
double limit);

void swiglustep_and_mul_moe(torch::Tensor& out, torch::Tensor& input,
torch::Tensor& valid_rows, double limit);
@ranzhejiang
ranzhejiang force-pushed the zhejiang/fix_moe branch 3 times, most recently from 127aa6b to b6c5156 Compare June 9, 2026 15:04
@xinyu-intel

Copy link
Copy Markdown
Collaborator

fix pre-commit

@mayuyuace

Copy link
Copy Markdown
Collaborator

I this if this code change is merged, modes other than EP mode will result in a performance decline, because other modes don't need this.
Please provide specific model execution data including TP only, EP and other mode.

@ranzhejiang

Copy link
Copy Markdown
Author

I this if this code change is merged, modes other than EP mode will result in a performance decline, because other modes don't need this. Please provide specific model execution data including TP only, EP and other mode.

ok,I will test it with performance data

@ranzhejiang
ranzhejiang force-pushed the zhejiang/fix_moe branch 2 times, most recently from faec530 to 0f55b6f Compare June 16, 2026 04:08
@ranzhejiang
ranzhejiang force-pushed the zhejiang/fix_moe branch 3 times, most recently from 1558c65 to a7ea252 Compare July 16, 2026 07:53
@ranzhejiang
ranzhejiang marked this pull request as ready for review July 16, 2026 08:05
@ranzhejiang

Copy link
Copy Markdown
Author

I this if this code change is merged, modes other than EP mode will result in a performance decline, because other modes don't need this. Please provide specific model execution data including TP only, EP and other mode.

I add _should_use_ep_valid_tokens to ensure the optimization only takes effect in EP prefill and does not affect TP.

Metric Before After Improvement
Mean TTFT (ms) 366.98 356.65 2.8%
Median TTFT (ms) 364.10 354.67 2.6%
P99 TTFT (ms) 373.97 363.29 2.9%

Tested with Qwen3-30B-A3B using --random-input-len 4096 --random-output-len 128, eager, TP4 with expert parallel, XPU is B60.

In theory, the time savings should become more significant as EP increases and sequence length becomes longer.

@mayuyuace

Copy link
Copy Markdown
Collaborator

Please fix pre-commit.

@mayuyuace

Copy link
Copy Markdown
Collaborator

BTW, can you please provide the performance data with tp=4 and without ep?
Although I think now this PR will not affect pure TP performance.

Signed-off-by: ranzhejiang <zhejiang.ran@intel.com>
@ranzhejiang

Copy link
Copy Markdown
Author

BTW, can you please provide the performance data with tp=4 and without ep? Although I think now this PR will not affect pure TP performance.

BTW, can you please provide the performance data with tp=4 and without ep? Although I think now this PR will not affect pure TP performance.

Metric Before After Improvement
Mean TTFT (ms) 359.50 358.68 0.2%
Median TTFT (ms) 358.02 356.57 0.4%
P99 TTFT (ms) 365.64 365.70 -0.0%

Tested with Qwen3-30B-A3B using --random-input-len 4096 --random-output-len 128, eager, pure TP4 without expert parallel, XPU is B60.

@mayuyuace

Copy link
Copy Markdown
Collaborator

@Liangliang-Ma
Please help review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants