[XPU][Tests] Make tests device-agnostic (#51968)

Signed-off-by: pmanczak <pawel.manczak@intel.com>

pmanczak committed Aug 20, 2026 at 11:25 UTC 44cf3f046604188729572e22cabd747357098c2a
12 files changed +148 -111
tests/conftest.py
+6 -7
@@ -284,19 +284,18 @@ def cleanup_fixture(should_do_global_cleanup_after_test: bool):
284 def workspace_init():
285 """Initialize the workspace manager for tests that need it.
286
287 - This fixture initializes the workspace manager with a CUDA device
288 - if available, and resets it after the test completes. Tests that
289 - create a full vLLM engine should NOT use this fixture as the engine
290 - will initialize the workspace manager itself.
287 + This fixture initializes the workspace manager with the current
288 + platform's accelerator device if available, and resets it after the test
289 + completes. Tests that create a full vLLM engine should NOT use this
290 + fixture as the engine will initialize the workspace manager itself.
291 """
292 from vllm.v1.worker.workspace import (
293 init_workspace_manager,
294 reset_workspace_manager,
295 )
296
297 - if torch.cuda.is_available():
298 - device = torch.device("cuda:0")
299 - init_workspace_manager(device)
297 + if torch.accelerator.is_available():
298 + init_workspace_manager(torch.device(0))
299 yield
300 reset_workspace_manager()
301
tests/kernels/attention/test_merge_attn_states.py
+46 -42
@@ -5,7 +5,7 @@ import pytest
5 import torch
6
7 from vllm._custom_ops import (
8 - merge_attn_states as merge_attn_states_cuda,
8 + merge_attn_states as merge_attn_states_native,
9 )
10 from vllm._custom_ops import (
11 scaled_fp8_quant,
@@ -15,11 +15,13 @@ from vllm.v1.attention.ops.triton_merge_attn_states import (
15 merge_attn_states as merge_attn_states_triton,
16 )
17
18 +DEVICE = current_platform.device_type
19 +
20 pytestmark = [
21 pytest.mark.skip_global_cleanup,
22 pytest.mark.skipif(
21 - not current_platform.is_cuda_alike(),
22 - reason="merge_attn_states kernels require CUDA or ROCm.",
23 + not (current_platform.is_cuda_alike() or current_platform.is_xpu()),
24 + reason="merge_attn_states kernels require CUDA, ROCm or XPU.",
25 ),
26 ]
27
@@ -81,20 +83,22 @@ DTYPES = [torch.float32, torch.half, torch.bfloat16]
83 all_case_info: list[tuple] = []
84
85
84 -@pytest.mark.parametrize("merge_fn", [merge_attn_states_cuda, merge_attn_states_triton])
86 +@pytest.mark.parametrize(
87 + "merge_fn", [merge_attn_states_native, merge_attn_states_triton]
88 +)
89 @pytest.mark.parametrize("output_dtype", [torch.float32, torch.half, torch.bfloat16])
90 def test_merge_attn_states_both_empty(merge_fn, output_dtype) -> None:
91 """When a token is empty on both sides (both LSE -inf), the 0/0 softmax
92 scales must not surface as NaN in the merged output."""
93 num_tokens, num_heads, head_size = 6, 8, 128
94 prefix_output = torch.zeros(
91 - num_tokens, num_heads, head_size, device="cuda", dtype=output_dtype
95 + num_tokens, num_heads, head_size, device=DEVICE, dtype=output_dtype
96 )
93 - prefix_lse = torch.randn(num_heads, num_tokens, device="cuda")
97 + prefix_lse = torch.randn(num_heads, num_tokens, device=DEVICE)
98 suffix_output = torch.zeros(
95 - num_tokens, num_heads, head_size, device="cuda", dtype=output_dtype
99 + num_tokens, num_heads, head_size, device=DEVICE, dtype=output_dtype
100 )
97 - suffix_lse = torch.randn(num_heads, num_tokens, device="cuda")
101 + suffix_lse = torch.randn(num_heads, num_tokens, device=DEVICE)
102
103 # Tokens 2 and 3 are empty on both sides.
104 empty = slice(2, 4)
@@ -111,7 +115,7 @@ def generate_markdown_table():
115 global all_case_info
116 table_header = (
117 "| tokens | heads | headsize | dtype "
114 - "| device | torch | triton | cuda | speedup |"
118 + "| device | torch | triton | native | speedup |"
119 )
120 table_separator = "| --- | --- | --- | --- | --- | --- | --- | --- | --- |"
121
@@ -132,7 +136,7 @@ def generate_markdown_table():
136 device,
137 avg_time_torch_kernel,
138 avg_time_triton_kernel,
135 - avg_time_cuda_kernel,
139 + avg_time_native_kernel,
140 performance_improved,
141 ) = info
142 dtype = shortly_dtype(dtype)
@@ -141,7 +145,7 @@ def generate_markdown_table():
145 f"| {num_tokens} | {num_heads} | {head_size} "
146 f"| {dtype} | {device} | {avg_time_torch_kernel:.5f}ms "
147 f"| {avg_time_triton_kernel:.5f}ms "
144 - f"| {avg_time_cuda_kernel:.5f}ms "
148 + f"| {avg_time_native_kernel:.5f}ms "
149 f"| {performance_improved:.4f}x |"
150 )
151
@@ -171,7 +175,7 @@ def test_merge_attn_states(
175 output_scale = None
176 if use_fp8:
177 output_dtype = current_platform.fp8_dtype()
174 - output_scale = torch.tensor([0.05], dtype=torch.float32, device="cuda")
178 + output_scale = torch.tensor([0.05], dtype=torch.float32, device=DEVICE)
179
180 print(
181 f"\nNUM_TOKENS:{NUM_TOKENS}, NUM_HEADS:{NUM_HEADS}, "
@@ -182,8 +186,8 @@ def test_merge_attn_states(
186 )
187
188 # prefix_lse and suffix_lse contain inf and normal values
185 - prefix_lse = torch.randn(NUM_HEADS, NUM_TOKENS, dtype=torch.float32, device="cuda")
186 - suffix_lse = torch.randn(NUM_HEADS, NUM_TOKENS, dtype=torch.float32, device="cuda")
189 + prefix_lse = torch.randn(NUM_HEADS, NUM_TOKENS, dtype=torch.float32, device=DEVICE)
190 + suffix_lse = torch.randn(NUM_HEADS, NUM_TOKENS, dtype=torch.float32, device=DEVICE)
191
192 # Generate boolean masks
193 mask_prefix = torch.rand(NUM_HEADS, NUM_TOKENS) < 0.1
@@ -199,16 +203,16 @@ def test_merge_attn_states(
203 # Other input tensors (need to be initialized but
204 # no actual calculation needed)
205 output = torch.zeros(
202 - (NUM_TOKENS, NUM_HEADS, HEAD_SIZE), dtype=output_dtype, device="cuda"
206 + (NUM_TOKENS, NUM_HEADS, HEAD_SIZE), dtype=output_dtype, device=DEVICE
207 )
208 output_lse = torch.zeros(
205 - (NUM_HEADS, NUM_TOKENS), dtype=torch.float32, device="cuda"
209 + (NUM_HEADS, NUM_TOKENS), dtype=torch.float32, device=DEVICE
210 )
211 prefix_output = torch.randn(
208 - (NUM_TOKENS, NUM_HEADS, HEAD_SIZE), dtype=input_dtype, device="cuda"
212 + (NUM_TOKENS, NUM_HEADS, HEAD_SIZE), dtype=input_dtype, device=DEVICE
213 )
214 suffix_output = torch.randn(
211 - (NUM_TOKENS, NUM_HEADS, HEAD_SIZE), dtype=input_dtype, device="cuda"
215 + (NUM_TOKENS, NUM_HEADS, HEAD_SIZE), dtype=input_dtype, device=DEVICE
216 )
217
218 warmup_times = 2
@@ -293,19 +297,19 @@ def test_merge_attn_states(
297
298 avg_time_triton_kernel = total_time_triton_kernel / repeat_times
299
296 - # 2. Run the CUDA kernel
297 - total_time_cuda_kernel = 0
298 - output_cuda = output.clone()
299 - output_lse_cuda = output_lse.clone()
300 + # 2. Run the native (CUDA/XPU) kernel
301 + total_time_native_kernel = 0
302 + output_native = output.clone()
303 + output_lse_native = output_lse.clone()
304
305 for _ in range(warmup_times):
302 - merge_attn_states_cuda(
303 - output_cuda,
306 + merge_attn_states_native(
307 + output_native,
308 prefix_output,
309 prefix_lse,
310 suffix_output,
311 suffix_lse,
308 - output_lse_cuda,
312 + output_lse_native,
313 prefill_tokens_with_context,
314 output_scale,
315 )
@@ -313,28 +317,28 @@ def test_merge_attn_states(
317
318 for _ in range(repeat_times):
319 start.record()
316 - merge_attn_states_cuda(
317 - output_cuda,
320 + merge_attn_states_native(
321 + output_native,
322 prefix_output,
323 prefix_lse,
324 suffix_output,
325 suffix_lse,
322 - output_lse_cuda,
326 + output_lse_native,
327 prefill_tokens_with_context,
328 output_scale,
329 )
330 end.record()
331 torch.accelerator.synchronize()
328 - total_time_cuda_kernel += start.elapsed_time(end)
332 + total_time_native_kernel += start.elapsed_time(end)
333
330 - avg_time_cuda_kernel = total_time_cuda_kernel / repeat_times
334 + avg_time_native_kernel = total_time_native_kernel / repeat_times
335
336 # 3. Performance compare
333 - performance_improved = avg_time_triton_kernel / avg_time_cuda_kernel
337 + performance_improved = avg_time_triton_kernel / avg_time_native_kernel
338 print(f" Torch time: {avg_time_torch_kernel:.6f}ms")
339 print(f"Triton time: {avg_time_triton_kernel:.6f}ms")
340 print(
337 - f" CUDA time: {avg_time_cuda_kernel:.6f}ms, "
341 + f"Native time: {avg_time_native_kernel:.6f}ms, "
342 f"Performance: {performance_improved:.5f}x"
343 )
344 print("-" * 100)
@@ -362,12 +366,12 @@ def test_merge_attn_states(
366 return max_diff
367
368 # Use Triton output as reference because we want to replace
365 - # the Triton kernel with custom CUDA kernel for merge attn
369 + # the Triton kernel with the custom native kernel for merge attn
370 # states operation.
371 output_ref = output_ref_triton
372 output_lse_ref = output_lse_ref_triton
373 torch.testing.assert_close(
370 - output_cuda.float() * scale,
374 + output_native.float() * scale,
375 output_ref.float() * scale,
376 atol=atol,
377 rtol=rtol,
@@ -379,19 +383,19 @@ def test_merge_attn_states(
383 )
384 _diff = diff(output_ref.float() * scale, output_torch.float() * scale)
385 print(f"(Triton vs Torch) : {_diff}")
382 - _diff = diff(output_torch.float() * scale, output_cuda.float() * scale)
383 - print(f" (CUDA vs Torch) : {_diff}")
384 - _diff = diff(output_ref.float() * scale, output_cuda.float() * scale)
385 - print(f" (CUDA vs Triton): {_diff}")
386 + _diff = diff(output_torch.float() * scale, output_native.float() * scale)
387 + print(f"(Native vs Torch) : {_diff}")
388 + _diff = diff(output_ref.float() * scale, output_native.float() * scale)
389 + print(f"(Native vs Triton): {_diff}")
390 print("-" * 100)
391
392 torch.testing.assert_close(
389 - output_lse_cuda.float(), output_lse_ref.float(), atol=atol, rtol=rtol
393 + output_lse_native.float(), output_lse_ref.float(), atol=atol, rtol=rtol
394 )
395 print("Output LSE all match, max abs diff:")
396 print(f"(Triton vs Torch) : {diff(output_lse_torch, output_lse_ref)}")
393 - print(f" (CUDA vs Torch) : {diff(output_lse_torch, output_lse_cuda)}")
394 - print(f" (CUDA vs Triton): {diff(output_lse_ref, output_lse_cuda)}")
397 + print(f"(Native vs Torch) : {diff(output_lse_torch, output_lse_native)}")
398 + print(f"(Native vs Triton): {diff(output_lse_ref, output_lse_native)}")
399 print("-" * 100)
400
401 print(
@@ -410,7 +414,7 @@ def test_merge_attn_states(
414 device,
415 avg_time_torch_kernel,
416 avg_time_triton_kernel,
413 - avg_time_cuda_kernel,
417 + avg_time_native_kernel,
418 performance_improved,
419 )
420 )
tests/kernels/mamba/test_replayssm_prefill_decode_equivalence_mamba2.py
+6 -2
@@ -36,6 +36,7 @@ from vllm.model_executor.layers.mamba.ops.selective_state_update_replayssm_outpu
36 from vllm.model_executor.layers.mamba.ops.ssd_combined import (
37 mamba_chunk_scan_combined_varlen,
38 )
39 +from vllm.platforms import current_platform
40 from vllm.utils.torch_utils import set_random_seed
41 from vllm.v1.attention.backends.mamba2_attn import compute_varlen_chunk_metadata
42
@@ -68,7 +69,7 @@ def _run_prefill_decode_equivalence(
69 flow (raw dt + softplus + a per-head dt_bias), so this also checks prefill
70 and decode apply the softplus/bias preprocessing consistently. ``state_dtype``
71 is the recurrent-state precision; ``act_dtype`` the activation/buffer one."""
71 - device = "cuda"
72 + device = current_platform.device_type
73 rtol, atol = _prefill_tolerances(act_dtype)
74 set_random_seed(seed)
75
@@ -203,7 +204,10 @@ def _run_prefill_decode_equivalence(
204 )
205
206
206 -@pytest.mark.skipif(not torch.cuda.is_available(), reason="Need CUDA device")
207 +@pytest.mark.skipif(
208 + not (current_platform.is_cuda_alike() or current_platform.is_xpu()),
209 + reason="Mamba2 ReplaySSM kernels require a CUDA-alike or XPU device.",
210 +)
211 @pytest.mark.parametrize(
212 "precision",
213 # fp32 state is the default; bf16/fp16 are reduced-footprint configs. fp16
tests/kernels/moe/test_batched_moe.py
+28 -23
@@ -23,6 +23,13 @@ from vllm.platforms import current_platform
23 from vllm.triton_utils import tl
24 from vllm.utils.torch_utils import set_random_seed
25
26 +DEVICE = current_platform.device_type
27 +
28 +pytestmark = pytest.mark.skipif(
29 + not (current_platform.is_cuda_alike() or current_platform.is_xpu()),
30 + reason="Triton MoE kernels require CUDA/ROCm/XPU.",
31 +)
32 +
33 MNK_FACTORS = [
34 (1, 128, 128),
35 (1, 512, 512),
@@ -71,19 +78,19 @@ class BatchedMMTensors:
78 A = (
79 torch.randn(
80 (config.num_experts, config.max_tokens_per_expert, config.K),
74 - device="cuda",
81 + device=DEVICE,
82 dtype=config.in_dtype,
83 )
84 / 10
85 )
86 B = torch.randn(
87 (config.num_experts, config.N, config.K),
81 - device="cuda",
88 + device=DEVICE,
89 dtype=config.in_dtype,
90 )
91 C = torch.zeros(
92 (config.num_experts, config.max_tokens_per_expert, config.N),
86 - device="cuda",
93 + device=DEVICE,
94 dtype=config.out_dtype,
95 )
96
@@ -91,7 +98,7 @@ class BatchedMMTensors:
98 low=0,
99 high=config.max_tokens_per_expert,
100 size=(config.num_experts,),
94 - device="cuda",
101 + device=DEVICE,
102 dtype=torch.int32,
103 )
104
@@ -120,8 +127,10 @@ def test_batched_mm(
127
128 use_fp8_w8a8 = dtype == torch.float8_e4m3fn
129
123 - if (dtype == torch.float8_e4m3fn) and not current_platform.has_device_capability(
124 - 89
130 + if (
131 + dtype == torch.float8_e4m3fn
132 + and current_platform.is_cuda_alike()
133 + and not current_platform.has_device_capability(89)
134 ):
135 pytest.skip(
136 "Triton limitation: fp8e4nv data type is not supported on CUDA arch < 89"
@@ -144,7 +153,7 @@ def test_batched_mm(
153 low=0,
154 high=max_tokens_per_expert,
155 size=(num_experts,),
147 - device="cuda",
156 + device=DEVICE,
157 dtype=torch.int32,
158 )
159
@@ -169,9 +178,9 @@ def test_batched_mm(
178 )
179
180 out_shape = (num_experts, max_tokens_per_expert, N)
172 - test_output = torch.zeros(out_shape, dtype=act_dtype, device="cuda")
173 - ref_output = torch.zeros(out_shape, dtype=act_dtype, device="cuda")
174 - q_ref_output = torch.zeros(out_shape, dtype=act_dtype, device="cuda")
181 + test_output = torch.zeros(out_shape, dtype=act_dtype, device=DEVICE)
182 + ref_output = torch.zeros(out_shape, dtype=act_dtype, device=DEVICE)
183 + q_ref_output = torch.zeros(out_shape, dtype=act_dtype, device=DEVICE)
184
185 compute_tl_dtype = {
186 torch.float16: tl.float16,
@@ -257,8 +266,10 @@ def test_fused_moe_batched_experts(
266
267 use_fp8_w8a8 = dtype == torch.float8_e4m3fn
268
260 - if (dtype == torch.float8_e4m3fn) and not current_platform.has_device_capability(
261 - 89
269 + if (
270 + dtype == torch.float8_e4m3fn
271 + and current_platform.is_cuda_alike()
272 + and not current_platform.has_device_capability(89)
273 ):
274 pytest.skip(
275 "Triton limitation: fp8e4nv data type is not supported on CUDA arch < 89"
@@ -273,8 +284,8 @@ def test_fused_moe_batched_experts(
284 if per_act_token_quant and block_shape is not None:
285 pytest.skip("Skip illegal quantization test.")
286
276 - a = torch.randn((m, k), device="cuda", dtype=torch.bfloat16) / 10
277 - score = torch.randn((m, e), device="cuda", dtype=torch.bfloat16)
287 + a = torch.randn((m, k), device=DEVICE, dtype=torch.bfloat16) / 10
288 + score = torch.randn((m, e), device=DEVICE, dtype=torch.bfloat16)
289
290 if dtype.itemsize == 1:
291 act_dtype = torch.bfloat16
@@ -294,8 +305,8 @@ def test_fused_moe_batched_experts(
305 )
306
307 if input_scales and quant_dtype is not None:
297 - a1_scale = torch.tensor(1, device="cuda", dtype=torch.float32)
298 - a2_scale = torch.tensor(1, device="cuda", dtype=torch.float32)
308 + a1_scale = torch.tensor(1, device=DEVICE, dtype=torch.float32)
309 + a2_scale = torch.tensor(1, device=DEVICE, dtype=torch.float32)
310 else:
311 a1_scale = None
312 a2_scale = None
@@ -489,10 +500,7 @@ def test_batched_triton_experts_supports_current_device():
500 BatchedTritonExperts,
501 )
502
492 - if current_platform.is_xpu() or current_platform.is_cuda_alike():
493 - assert BatchedTritonExperts._supports_current_device()
494 - else:
495 - pytest.skip("No GPU device available")
503 + assert BatchedTritonExperts._supports_current_device()
504
505
506 @pytest.mark.parametrize("m,n,k,e,topk", [(32, 512, 512, 8, 2), (45, 1024, 128, 8, 1)])
@@ -500,9 +508,6 @@ def test_batched_experts_end_to_end(m, n, k, e, topk):
508 """End-to-end BatchedTritonExperts via the reference (no-comms)
509 BatchedPrepareAndFinalize, validated against a torch reference. Exercises
510 the device-enablement path."""
503 - if not (current_platform.is_xpu() or current_platform.is_cuda_alike()):
504 - pytest.skip("No GPU device available")
505 -
511 from vllm.v1.worker.workspace import init_workspace_manager
512
513 set_random_seed(7)
tests/kernels/moe/test_count_expert_num_tokens.py
+10 -2
@@ -10,6 +10,14 @@ import pytest
10 import torch
11
12 from vllm.model_executor.layers.fused_moe.utils import count_expert_num_tokens
13 +from vllm.platforms import current_platform
14 +
15 +DEVICE = current_platform.device_type
16 +
17 +pytestmark = pytest.mark.skipif(
18 + not (current_platform.is_cuda_alike() or current_platform.is_xpu()),
19 + reason="Triton MoE kernels require CUDA/ROCm/XPU.",
20 +)
21
22
23 @dataclasses.dataclass
@@ -88,9 +96,9 @@ def do_test_compute_expert_num_tokens(
96 (num_local_experts), device="cpu", dtype=torch.int32
97 )
98 ref_impl(tt_rank, ref_expert_num_tokens)
91 - ref_expert_num_tokens = ref_expert_num_tokens.to("cuda")
99 + ref_expert_num_tokens = ref_expert_num_tokens.to(DEVICE)
100
93 - tt_rank.to_device("cuda")
101 + tt_rank.to_device(DEVICE)
102 # Test with expert_map
103 triton_expert_num_tokens_w_emap = count_expert_num_tokens(
104 tt_rank.topk_ids, num_local_experts, tt_rank.expert_map
tests/kernels/moe/test_silu_mul_per_token_group_quant_fp8_colmajor.py
+4 -3
@@ -13,6 +13,7 @@ from vllm.triton_utils import triton
13 from vllm.utils.deep_gemm import is_deep_gemm_e8m0_used
14 from vllm.utils.torch_utils import set_random_seed
15
16 +DEVICE = current_platform.device_type
17 FLOAT8_DTYPE = torch.float8_e4m3fn
18 GROUP_SIZE = 128
19
@@ -61,7 +62,7 @@ def reference_quant(x: torch.Tensor, use_ue8m0: bool):
62
63 def reference(x: torch.Tensor, use_ue8m0: bool) -> tuple[torch.Tensor, torch.Tensor]:
64 T, N = x.size()
64 - ref_act_out = torch.empty((T, N // 2), dtype=torch.bfloat16, device="cuda")
65 + ref_act_out = torch.empty((T, N // 2), dtype=torch.bfloat16, device=DEVICE)
66 torch.ops._C.silu_and_mul(ref_act_out, x)
67 return reference_quant(ref_act_out, use_ue8m0)
68
@@ -93,7 +94,7 @@ def reference_with_clamp(
94 def test_silu_mul_fp8_quant_deep_gemm(T: int, N: int):
95 set_random_seed(42)
96
96 - input = torch.rand((T, N), dtype=torch.bfloat16, device="cuda")
97 + input = torch.rand((T, N), dtype=torch.bfloat16, device=DEVICE)
98
99 use_ue8m0 = is_deep_gemm_e8m0_used()
100
@@ -122,7 +123,7 @@ def test_silu_mul_fp8_quant_deep_gemm_clamp(T: int, N: int, clamp_limit: float):
123 # Use a wide distribution so values routinely exceed both clamp limits and
124 # the clamp branch is actually exercised (uniform [0, 1) inputs would never
125 # trigger it).
125 - input = torch.randn((T, N), dtype=torch.bfloat16, device="cuda") * 8.0
126 + input = torch.randn((T, N), dtype=torch.bfloat16, device=DEVICE) * 8.0
127
128 use_ue8m0 = is_deep_gemm_e8m0_used()
129
tests/kernels/moe/test_triton_moe_no_act_mul.py
+15 -13
@@ -23,6 +23,20 @@ from vllm.model_executor.layers.fused_moe.config import (
23 from vllm.model_executor.layers.fused_moe.experts.triton_moe import TritonExperts
24 from vllm.platforms import current_platform
25
26 +DEVICE = current_platform.device_type
27 +
28 +pytestmark = [
29 + pytest.mark.skipif(
30 + not (current_platform.is_cuda_alike() or current_platform.is_xpu()),
31 + reason="Triton MoE kernels require a CUDA-alike or XPU device.",
32 + ),
33 + pytest.mark.skipif(
34 + current_platform.is_cuda_alike()
35 + and not current_platform.has_device_capability(80),
36 + reason="Triton MoE kernels require compute capability >= 8.0 on CUDA/ROCm.",
37 + ),
38 +]
39 +
40 # Test parameters
41 M_SIZES = [1, 16, 64]
42 N_SIZES = [128, 256]
@@ -86,7 +100,7 @@ def make_test_tensors(
100 num_experts: int,
101 topk: int,
102 dtype: torch.dtype = torch.bfloat16,
89 - device: str = "cuda",
103 + device: str = DEVICE,
104 ):
105 """Create test tensors for MoE with non-gated activation.
106
@@ -106,10 +120,6 @@ def make_test_tensors(
120 return hidden_states, w1, w2, topk_weights, topk_ids
121
122
109 -@pytest.mark.skipif(
110 - not current_platform.has_device_capability(80),
111 - reason="Requires compute capability >= 8.0",
112 -)
123 @pytest.mark.parametrize("m", M_SIZES)
124 @pytest.mark.parametrize("n", N_SIZES)
125 @pytest.mark.parametrize("k", K_SIZES)
@@ -192,10 +202,6 @@ def test_triton_experts_no_mul_activation(
202 assert output.abs().sum() > 0, "Output is all zeros"
203
204
195 -@pytest.mark.skipif(
196 - not current_platform.has_device_capability(80),
197 - reason="Requires compute capability >= 8.0",
198 -)
205 @torch.inference_mode()
206 def test_workspace_shapes_no_mul_vs_gated():
207 """Test that workspace shapes differ correctly between gated and non-gated."""
@@ -233,10 +239,6 @@ def test_workspace_shapes_no_mul_vs_gated():
239 assert out_no_mul == out_gated == (M, K)
240
241
236 -@pytest.mark.skipif(
237 - not current_platform.has_device_capability(80),
238 - reason="Requires compute capability >= 8.0",
239 -)
242 @torch.inference_mode()
243 def test_adjust_n_for_activation():
244 """Test the adjust_N_for_activation method."""
tests/kernels/moe/utils.py
+9 -7
@@ -40,6 +40,8 @@ from vllm.platforms import current_platform
40 from vllm.utils.deep_gemm import per_block_cast_to_fp8
41 from vllm.utils.math_utils import round_up
42
43 +DEVICE = current_platform.device_type
44 +
45
46 def shuffle_weight(w: torch.Tensor) -> torch.Tensor:
47 """Fold weights to adjacent locations for Triton MoE / SwiGLU kernel layout."""
@@ -80,7 +82,7 @@ def make_dummy_moe_config(
82 moe_parallel_config=FusedMoEParallelConfig.make_no_parallel(),
83 activation=activation,
84 in_dtype=in_dtype,
83 - device="cuda",
85 + device=DEVICE,
86 routing_method=RoutingMethodType.TopK,
87 max_num_tokens=max_num_tokens,
88 )
@@ -238,7 +240,7 @@ def make_quantized_test_activations(
240 block_shape: list[int] | None = None,
241 per_act_token_quant: bool = False,
242 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None]:
241 - a = torch.randn((E, m, k), device="cuda", dtype=in_dtype) / 10
243 + a = torch.randn((E, m, k), device=DEVICE, dtype=in_dtype) / 10
244 a_q = a
245 a_scale = None
246
@@ -369,7 +371,7 @@ def make_test_weight(
371 block_shape: list[int] | None = None,
372 per_out_ch_quant: bool = False,
373 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None, torch.Tensor | None]:
372 - w_16 = torch.randn((e, rows, cols), device="cuda", dtype=in_dtype) / 15
374 + w_16 = torch.randn((e, rows, cols), device=DEVICE, dtype=in_dtype) / 15
375
376 if quant_dtype is not None:
377 w, w_s, w_gs = moe_quantize_weights(
@@ -449,8 +451,8 @@ def make_test_quant_config(
451 a1_gscale: torch.Tensor | None = None
452 a2_gscale: torch.Tensor | None = None
453 if quant_dtype == "nvfp4":
452 - a1_gscale = torch.ones((e,), device="cuda", dtype=torch.float32)
453 - a2_gscale = torch.ones((e,), device="cuda", dtype=torch.float32)
454 + a1_gscale = torch.ones((e,), device=DEVICE, dtype=torch.float32)
455 + a2_gscale = torch.ones((e,), device=DEVICE, dtype=torch.float32)
456 a1_scale = a1_gscale
457 a2_scale = a2_gscale
458 else:
@@ -551,8 +553,8 @@ def make_naive_shared_experts(
553 K: int,
554 in_dtype: torch.dtype = torch.bfloat16,
555 ) -> torch.nn.Module:
554 - w1 = torch.randn((K, N * 2), device="cuda", dtype=in_dtype) / 15
555 - w2 = torch.randn((N, K), device="cuda", dtype=in_dtype) / 15
556 + w1 = torch.randn((K, N * 2), device=DEVICE, dtype=in_dtype) / 15
557 + w2 = torch.randn((N, K), device=DEVICE, dtype=in_dtype) / 15
558 return TestMLP(w1, w2, out_dtype=in_dtype)
559
560
tests/kernels/quant_utils.py
+2 -1
@@ -13,10 +13,11 @@ from vllm.utils.deep_gemm import _ceil_to_ue8m0, is_deep_gemm_e8m0_used
13 from vllm.utils.math_utils import round_up
14
15 FP8_DTYPE = current_platform.fp8_dtype()
16 +DEVICE = current_platform.device_type
17
18
19 def as_float32_tensor(x: float | torch.Tensor) -> torch.Tensor:
19 - return torch.as_tensor(x, dtype=torch.float32, device="cuda")
20 + return torch.as_tensor(x, dtype=torch.float32, device=DEVICE)
21
22
23 def ref_dynamic_per_token_quant(
tests/kernels/quantization/test_per_token_group_quant.py
+8 -4
@@ -18,19 +18,20 @@ from vllm.platforms import current_platform
18 @pytest.mark.parametrize("scale_ue8m0", [False, True])
19 @pytest.mark.parametrize("group_size", [64, 128])
20 @pytest.mark.skipif(
21 - not current_platform.is_cuda_alike(), reason="Only test on CUDA/ROCm."
21 + not (current_platform.is_cuda_alike() or current_platform.is_xpu()),
22 + reason="Only test on CUDA/ROCm/XPU.",
23 )
24 def test_per_token_group_quant_fp8(
25 shape, column_major: bool, tma_aligned: bool, scale_ue8m0: bool, group_size: int
26 ):
26 - device = "cuda"
27 + device = current_platform.device_type
28
29 torch.manual_seed(42)
30 num_tokens, hidden_dim = shape
31
32 x = torch.randn((num_tokens, hidden_dim), device=device, dtype=torch.bfloat16) * 8
33
33 - # cuda path
34 + # native kernel path
35 out_q, scale = fp8_utils.per_token_group_quant_fp8(
36 x,
37 group_size,
@@ -40,7 +41,10 @@ def test_per_token_group_quant_fp8(
41 )
42
43 # triton ref
43 - with patch("vllm.platforms.current_platform.is_cuda_alike", return_value=False):
44 + with (
45 + patch("vllm.platforms.current_platform.is_cuda_alike", return_value=False),
46 + patch("vllm.platforms.current_platform.is_xpu", return_value=False),
47 + ):
48 ref_q, ref_s = fp8_utils.per_token_group_quant_fp8(
49 x,
50 group_size,
tests/kernels/test_fused_recurrent_packed_decode.py
+10 -4
@@ -4,13 +4,20 @@
4 import pytest
5 import torch
6
7 +from vllm.platforms import current_platform
8 from vllm.third_party.flash_linear_attention.ops import (
9 fused_recurrent_gated_delta_rule,
10 fused_recurrent_gated_delta_rule_packed_decode,
11 )
12
13 +DEVICE = current_platform.device_type
14 +
15 +pytestmark = pytest.mark.skipif(
16 + not (current_platform.is_cuda_alike() or current_platform.is_xpu()),
17 + reason="Gated delta rule Triton kernels require a CUDA-alike or XPU device.",
18 +)
19 +
20
13 -@pytest.mark.skipif(not torch.cuda.is_available(), reason="Need CUDA device")
21 @pytest.mark.parametrize("dtype", [torch.float16, torch.bfloat16, torch.float32])
22 @pytest.mark.parametrize("strided_mixed_qkv", [False, True])
23 def test_fused_recurrent_packed_decode_matches_reference(
@@ -26,7 +33,7 @@ def test_fused_recurrent_packed_decode_matches_reference(
33 V = 128
34 qkv_dim = 2 * (H * K) + (HV * V)
35
29 - device = torch.device("cuda")
36 + device = torch.device(DEVICE)
37
38 if strided_mixed_qkv:
39 # Simulate a packed view into a larger projection buffer:
@@ -102,10 +109,9 @@ def test_fused_recurrent_packed_decode_matches_reference(
109 torch.testing.assert_close(state_packed, state_ref, rtol=rtol, atol=atol)
110
111
105 -@pytest.mark.skipif(not torch.cuda.is_available(), reason="Need CUDA device")
112 def test_packed_decode_supports_large_batch_head_grid():
113 B, H, HV, K, V = 1024, 8, 64, 1, 1
108 - device = torch.device("cuda")
114 + device = torch.device(DEVICE)
115 gates = torch.empty((B, HV), device=device)
116 params = torch.empty((HV,), device=device)
117 out = torch.empty((B, 1, HV, V), device=device)
vllm/model_executor/layers/fused_moe/experts/fused_batched_moe.py
+4 -3
@@ -37,9 +37,10 @@ from vllm.triton_utils.allocation import set_triton_allocator
37
38
39 def _is_capturing_or_compiling() -> bool:
40 - # torch.cuda.is_current_stream_capturing() is unavailable on non-CUDA (XPU) torch.
41 - return torch.compiler.is_compiling() or (
42 - current_platform.is_cuda_alike() and torch.cuda.is_current_stream_capturing()
40 + # The accelerator API dispatches to the active backend.
41 + return (
42 + torch.compiler.is_compiling()
43 + or torch.accelerator.current_stream().is_capturing()
44 )
45
46