A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 9, 18:15 UTC
[torch.compile] Compile `CustomOp.forward_native` for `SiluAndMul` and `QuantFP8` to avoid raw torch ops inside opaque custom ops (#32806)
Signed-off-by: Luka Govedič <lgovedic@redhat.com> Signed-off-by: Luka Govedič <ProExpertProg@users.noreply.github.com> Co-authored-by: Michael Goin <mgoin64@gmail.com>
Luka Govedič committed
Jan 22, 2026 at 22:52 UTC
5e4e0e51f4fbb6d6fbf7a94feef07bd3617bfa5f
7 files changed
+52
-13
tests/compile/test_silu_mul_quant_fusion.py
+2
-1
@@ -222,7 +222,7 @@ def test_fusion_silu_and_mul_quant(
222
x = torch.rand(num_tokens, hidden_size * 2)
223
224
# Reshape pass is needed for the fusion pass to work
225
- custom_ops = []
225
+ custom_ops = ["none"]
226
if enable_silu_mul_custom_op:
227
custom_ops.append("+silu_and_mul")
228
if enable_quant_fp8_custom_op:
@@ -231,6 +231,7 @@ def test_fusion_silu_and_mul_quant(
231
compilation_config=CompilationConfig(
232
mode=CompilationMode.VLLM_COMPILE,
233
custom_ops=custom_ops,
234
+ backend="eager", # avoid compilation for SiluAndMul and QuantFP8
235
pass_config=PassConfig(fuse_act_quant=True, eliminate_noops=True),
236
),
237
)
tests/kernels/core/test_activation.py
+1
-1
@@ -57,7 +57,7 @@ def test_act_and_mul(
57
torch.set_default_device(device)
58
x = torch.randn(num_tokens, 2 * d, dtype=dtype)
59
if activation == "silu_and_mul":
60
- layer = SiluAndMul()
60
+ layer = SiluAndMul(compile_native=False)
61
fn = torch.ops._C.silu_and_mul
62
if activation == "mul_and_silu":
63
layer = MulAndSilu()
vllm/compilation/matcher_utils.py
+1
@@ -336,6 +336,7 @@ class MatcherQuantFP8(MatcherCustomOp):
336
quant_key.scale.group_shape,
337
column_major_scales=has_col_major_scales,
338
use_ue8m0=is_e8m0,
339
+ compile_native=False,
340
)
341
342
def forward_rocm_aiter(
vllm/model_executor/custom_op.py
+42
-7
@@ -1,16 +1,15 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-
3
+import torch
4
import torch.nn as nn
5
6
from vllm.config import get_cached_compilation_config
7
from vllm.logger import init_logger
8
+from vllm.model_executor.utils import maybe_disable_graph_partition
9
from vllm.platforms import current_platform
10
11
logger = init_logger(__name__)
12
13
-
13
# Dictionary of all custom ops (classes, indexed by registered name).
14
# To check if an op with a name is enabled, call .enabled() on the class.
15
# Examples:
@@ -118,10 +117,10 @@ class CustomOp(nn.Module):
117
)
118
return super().__new__(op_cls_to_instantiate)
119
121
- def __init__(self, enforce_enable: bool = False):
120
+ def __init__(self, *, enforce_enable: bool = False, compile_native: bool = False):
121
super().__init__()
122
self._enforce_enable = enforce_enable
124
- self._forward_method = self.dispatch_forward()
123
+ self._forward_method = self.dispatch_forward(compile_native=compile_native)
124
125
def forward(self, *args, **kwargs):
126
return self._forward_method(*args, **kwargs)
@@ -162,7 +161,7 @@ class CustomOp(nn.Module):
161
# PyTorch-native implementation.
162
return self.forward_native(*args, **kwargs)
163
165
- def dispatch_forward(self):
164
+ def dispatch_forward(self, compile_native: bool):
165
# NOTE(woosuk): Here we assume that vLLM was built for only one
166
# specific backend. Currently, we do not support dynamic dispatching.
167
compilation_config = get_cached_compilation_config()
@@ -180,7 +179,9 @@ class CustomOp(nn.Module):
179
compilation_config.disabled_custom_ops.update([self.__class__.name])
180
181
if not enabled:
183
- return self.forward_native
182
+ # Compile forward_native to avoid eager torch ops if inside
183
+ # opaque torch custom op (e.g. fused_moe, unified_attention, etc.)
184
+ return self.maybe_compile(self.forward_native, enable=compile_native)
185
186
if current_platform.is_rocm():
187
return self.forward_hip
@@ -195,6 +196,40 @@ class CustomOp(nn.Module):
196
else:
197
return self.forward_cuda
198
199
+ def maybe_compile(self, fn, *, enable: bool = True):
200
+ """
201
+ Compile fn if compilation enabled.
202
+ Useful for CustomOp instances called from within a torch custom op,
203
+ meaning the forward call is hidden from the model-level torch.compile.
204
+
205
+ NOTE: this does not enable fusion across ops, so opaque custom ops
206
+ should still be unwrapped wherever possible.
207
+ """
208
+ # Do not compile if compilation disabled
209
+ from vllm.config.compilation import CompilationMode
210
+
211
+ if not enable:
212
+ return fn
213
+
214
+ # Do not compile if global compilation disabled
215
+ compilation_config = get_cached_compilation_config()
216
+ if compilation_config.mode == CompilationMode.NONE:
217
+ return fn
218
+
219
+ # If eager backend is used, do not compile either
220
+ if compilation_config.backend == "eager":
221
+ return fn
222
+
223
+ # dynamic=True to avoid recompilations
224
+ return torch.compile(
225
+ fn,
226
+ dynamic=True,
227
+ backend=current_platform.simple_compile_backend,
228
+ options=maybe_disable_graph_partition(
229
+ current_platform.simple_compile_backend
230
+ ),
231
+ )
232
+
233
@classmethod
234
def enabled(cls) -> bool:
235
# if no name, then it was not registered
vllm/model_executor/layers/activation.py
+2
-2
@@ -75,8 +75,8 @@ class SiluAndMul(CustomOp):
75
76
# --8<-- [end:silu_and_mul]
77
78
- def __init__(self):
79
- super().__init__()
78
+ def __init__(self, *, compile_native: bool = True):
79
+ super().__init__(compile_native=compile_native)
80
if current_platform.is_cuda_alike():
81
self.op = torch.ops._C.silu_and_mul
82
elif current_platform.is_xpu():
vllm/model_executor/layers/quantization/input_quant_fp8.py
+3
-1
@@ -38,6 +38,7 @@ class QuantFP8(CustomOp):
38
column_major_scales: bool = False,
39
tma_aligned_scales: bool = False,
40
use_ue8m0: bool | None = None, # for Torch compile
41
+ compile_native: bool = True,
42
):
43
"""
44
:param static: static or dynamic quantization
@@ -49,8 +50,9 @@ class QuantFP8(CustomOp):
50
TMA-aligned layout
51
:param column_major_scales: For group quantization, output scales in
52
column major format
53
+ :param compile_native: Manually compile forward_native if compile mode > None
54
"""
53
- super().__init__()
55
+ super().__init__(compile_native=compile_native)
56
self.static = static
57
self.group_shape = group_shape
58
self.use_per_token_if_dynamic = group_shape == GroupShape.PER_TOKEN
vllm/model_executor/layers/rotary_embedding/common.py
+1
-1
@@ -129,7 +129,7 @@ class ApplyRotaryEmb(CustomOp):
129
is_neox_style: bool = True,
130
enable_fp32_compute: bool = False,
131
) -> None:
132
- super().__init__(enforce_enable)
132
+ super().__init__(enforce_enable=enforce_enable)
133
self.is_neox_style = is_neox_style
134
self.enable_fp32_compute = enable_fp32_compute
135