Skip to content

Commit af1eb3a

Browse files
mgoincodex
andcommitted
Guard Humming DeepEP padding
Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: mgoin <mgoin64@gmail.com>
1 parent 9a1a8e5 commit af1eb3a

5 files changed

Lines changed: 75 additions & 17 deletions

File tree

csrc/libtorch_stable/moe/permute_unpermute_kernels/moe_permute_unpermute_kernel.cu

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,17 @@ __global__ void preprocessTopkIdKernel(int* topk_id_ptr, int size,
146146
}
147147
__syncthreads();
148148

149-
// query global expert id in expert map.
150-
// if global expert id = -1 in exert map, plus n_expert
151-
// else set global expert id = exert map[global expert id]
152149
if (offset + tidx < bound) {
153150
auto topk_id = topk_id_ptr[offset + tidx];
154-
auto local_expert_idx = smem_expert_map[topk_id];
155-
if (local_expert_idx == -1) {
156-
topk_id += num_experts;
151+
if (topk_id < 0 || topk_id >= num_experts) {
152+
topk_id = num_experts;
157153
} else {
158-
topk_id = local_expert_idx;
154+
auto local_expert_idx = smem_expert_map[topk_id];
155+
if (local_expert_idx == -1) {
156+
topk_id += num_experts;
157+
} else {
158+
topk_id = local_expert_idx;
159+
}
159160
}
160161
__syncwarp();
161162
topk_id_ptr[offset + tidx] = topk_id;

tests/kernels/core/test_activation.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,27 @@ def test_masked_moe_activation_rejects_unsupported_activation() -> None:
7575
)
7676

7777

78+
def test_masked_moe_activation_validates_tensor_contract() -> None:
79+
input = torch.empty(1, 1, 2)
80+
valid_token_counts = torch.ones(1, dtype=torch.int32)
81+
82+
with pytest.raises(AssertionError, match="dtypes must match"):
83+
apply_moe_activation(
84+
MoEActivation.SILU,
85+
torch.empty(1, 1, 1, dtype=torch.float16),
86+
input,
87+
valid_token_counts=valid_token_counts,
88+
)
89+
90+
with pytest.raises(AssertionError, match="Input must be contiguous"):
91+
apply_moe_activation(
92+
MoEActivation.SILU,
93+
torch.empty(1, 1, 1),
94+
torch.empty(1, 1, 4)[..., ::2],
95+
valid_token_counts=valid_token_counts,
96+
)
97+
98+
7899
@pytest.mark.parametrize(
79100
"activation",
80101
[

tests/kernels/moe/test_deepep_v2_moe.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -487,14 +487,10 @@ def _make_mxfp4_humming_experts(
487487
return experts, quant_config, layer.w13_weight, layer.w2_weight
488488

489489

490-
def _deep_ep_v2_moe_cudagraph(
490+
def _run_deep_ep_v2_backend_case(
491491
pgi: ProcessGroupInfo,
492492
dp_size: int,
493493
config: TestConfig,
494-
w1: torch.Tensor,
495-
w2: torch.Tensor,
496-
w1_scale: torch.Tensor | None,
497-
w2_scale: torch.Tensor | None,
498494
moe_backend: str,
499495
activation: MoEActivation,
500496
use_cudagraph: bool,
@@ -909,13 +905,9 @@ def _launch_deep_ep_v2_case(
909905

910906
parallel_launch(
911907
world_size,
912-
_deep_ep_v2_moe_cudagraph,
908+
_run_deep_ep_v2_backend_case,
913909
dp_size,
914910
config,
915-
None, # weights created inside worker
916-
None,
917-
None,
918-
None,
919911
moe_backend,
920912
activation,
921913
use_cudagraph,

tests/kernels/moe/test_moe_permute_unpermute.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,39 @@ def test_moe_permute_reuses_scratch_buffers(dtype: torch.dtype):
286286
permuted_idx_1.untyped_storage().data_ptr()
287287
== scratch.permuted_idx.untyped_storage().data_ptr()
288288
)
289+
290+
291+
def test_moe_permute_ignores_invalid_expert_ids_with_scratch() -> None:
292+
if not moe_permute_unpermute_supported():
293+
pytest.skip("moe_permute_unpermute is not supported on this platform.")
294+
295+
hidden_states = torch.arange(5 * 16, dtype=torch.bfloat16, device="cuda").view(
296+
5, 16
297+
)
298+
topk_ids = torch.tensor([[0], [-1], [1], [4], [2]], device="cuda")
299+
expert_map = torch.tensor([0, 1, -1, -1], dtype=torch.int32, device="cuda")
300+
scratch = MoEPermuteScratch(
301+
max_num_tokens=5,
302+
topk=1,
303+
num_experts=4,
304+
num_local_experts=2,
305+
device=hidden_states.device,
306+
hidden_size=16,
307+
hidden_dtype=hidden_states.dtype,
308+
)
309+
310+
permuted, _, expert_offsets, _, _ = moe_permute(
311+
hidden_states=hidden_states,
312+
a1q_scale=None,
313+
topk_ids=topk_ids,
314+
n_expert=4,
315+
n_local_expert=2,
316+
expert_map=expert_map,
317+
scratch=scratch,
318+
)
319+
320+
torch.testing.assert_close(
321+
expert_offsets,
322+
torch.tensor([0, 1, 2], dtype=torch.int64, device="cuda"),
323+
)
324+
torch.testing.assert_close(permuted[:2], hidden_states[[0, 2]])

vllm/model_executor/layers/fused_moe/activation.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,18 @@ def _apply_moe_activation_masked(
235235

236236
assert input.dim() in (2, 3), "Masked input must be 2D or 3D"
237237
_validate_moe_activation_shapes(activation, output, input, expected_dim=input.dim())
238+
assert input.dtype == output.dtype, "Input and output dtypes must match"
239+
assert input.device == output.device, "Input and output devices must match"
240+
assert input.is_contiguous(), "Input must be contiguous"
241+
assert output.is_contiguous(), "Output must be contiguous"
238242
assert valid_token_counts.dtype == torch.int32, (
239243
"valid_token_counts must use torch.int32"
240244
)
241245
assert valid_token_counts.dim() == 1, "valid_token_counts must be 1D"
246+
assert valid_token_counts.device == input.device, (
247+
"valid_token_counts must be on the input device"
248+
)
249+
assert valid_token_counts.is_contiguous(), "valid_token_counts must be contiguous"
242250
expected_counts = input.size(0) if input.dim() == 3 else 1
243251
assert valid_token_counts.size(0) == expected_counts, (
244252
f"valid_token_counts must have {expected_counts} element(s) for "

0 commit comments

Comments
 (0)