@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / aaf4b70aae
Fork 0

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 10, 09:00 UTC

[Misc][BE] Type coverage for vllm/compilation [2/3] (#31744)

Lucas Kabela committed Jan 9, 2026 at 15:30 UTC aaf4b70aae5976115eb5f8caead3d4eeb3657136
12 files changed +161 -91
vllm/compilation/backends.py
+6 -6
@@ -179,7 +179,7 @@ class CompilerManager:
179 example_inputs: list[Any],
180 graph_index: int,
181 compile_range: Range,
182 - ) -> Callable | None:
182 + ) -> Callable[..., Any] | None:
183 if (compile_range, graph_index, self.compiler.name) not in self.cache:
184 return None
185 handle = self.cache[(compile_range, graph_index, self.compiler.name)]
@@ -199,7 +199,7 @@ class CompilerManager:
199 self,
200 graph: fx.GraphModule,
201 example_inputs: list[Any],
202 - additional_inductor_config,
202 + additional_inductor_config: dict[str, Any],
203 compilation_config: CompilationConfig,
204 compile_range: Range,
205 graph_index: int = 0,
@@ -355,7 +355,7 @@ def split_graph(
355 compilation_start_time = 0.0
356
357
358 -class PiecewiseCompileInterpreter(torch.fx.Interpreter):
358 +class PiecewiseCompileInterpreter(torch.fx.Interpreter): # type: ignore[misc]
359 """Code adapted from `torch.fx.passes.shape_prop.ShapeProp`.
360 It runs the given graph with fake inputs, and compile some
361 submodules specified by `compile_submod_names` with the given
@@ -506,9 +506,9 @@ class VllmBackend:
506 # the stiching graph module for all the piecewise graphs
507 split_gm: fx.GraphModule
508 piecewise_graphs: list[SplitItem]
509 - returned_callable: Callable
509 + returned_callable: Callable[..., Any]
510 # Inductor passes to run on the graph pre-defunctionalization
511 - post_grad_passes: Sequence[Callable]
511 + post_grad_passes: Sequence[Callable[..., Any]]
512 sym_tensor_indices: list[int]
513 input_buffers: list[torch.Tensor]
514 compiler_manager: CompilerManager
@@ -821,7 +821,7 @@ class VllmBackend:
821 ]
822
823 # this is the callable we return to Dynamo to run
824 - def copy_and_call(*args):
824 + def copy_and_call(*args: Any) -> Any:
825 list_args = list(args)
826 for i, index in enumerate(self.sym_tensor_indices):
827 runtime_tensor = list_args[index]
vllm/compilation/caching.py
+16 -7
@@ -4,6 +4,8 @@
4 import inspect
5 import os
6 import pickle
7 +from collections.abc import Callable, Sequence
8 +from typing import Any, Literal
9 from unittest.mock import patch
10
11 import torch
@@ -25,7 +27,7 @@ assert isinstance(SerializableCallable, type)
27 logger = init_logger(__name__)
28
29
28 -class VllmSerializableFunction(SerializableCallable):
30 +class VllmSerializableFunction(SerializableCallable): # type: ignore[misc]
31 """
32 A wrapper around a compiled function by vllm. It will forward the tensor
33 inputs to the compiled function and return the result.
@@ -38,8 +40,13 @@ class VllmSerializableFunction(SerializableCallable):
40 """
41
42 def __init__(
41 - self, graph_module, example_inputs, prefix, optimized_call, is_encoder=False
42 - ):
43 + self,
44 + graph_module: torch.fx.GraphModule,
45 + example_inputs: Sequence[Any],
46 + prefix: str,
47 + optimized_call: Callable[..., Any],
48 + is_encoder: bool = False,
49 + ) -> None:
50 assert isinstance(graph_module, torch.fx.GraphModule)
51 self.graph_module = graph_module
52 self.example_inputs = example_inputs
@@ -53,7 +60,7 @@ class VllmSerializableFunction(SerializableCallable):
60 if sym_input is not None:
61 self.shape_env = sym_input.node.shape_env
62
56 - def __call__(self, *args, **kwargs):
63 + def __call__(self, *args: Any, **kwargs: Any) -> Any:
64 return self.optimized_call(*args, **kwargs)
65
66 @classmethod
@@ -73,7 +80,9 @@ class VllmSerializableFunction(SerializableCallable):
80
81 graph_reducer_override = GraphPickler.reducer_override
82
76 - def _graph_reducer_override(self, obj):
83 + def _graph_reducer_override(
84 + self: GraphPickler, obj: Any
85 + ) -> tuple[Callable[..., Any], tuple[Any, ...]] | Any:
86 if (
87 inspect.isclass(obj)
88 and issubclass(obj, sympy.Function)
@@ -114,7 +123,7 @@ class VllmSerializableFunction(SerializableCallable):
123 get_current_vllm_config(), state["prefix"], is_encoder
124 )
125
117 - def optimized_call(*example_inputs):
126 + def optimized_call(*example_inputs: Any) -> Any:
127 """
128 On the first run of the optimized call, we rerun the compiler
129 backend which should result in a cache hit. After the backend
@@ -136,7 +145,7 @@ class VllmSerializableFunction(SerializableCallable):
145 return fn
146
147 @property
139 - def co_name(self):
148 + def co_name(self) -> Literal["VllmSerializableFunction"]:
149 """
150 Used for depyf debugging.
151 """
vllm/compilation/cuda_graph.py
+12 -10
@@ -42,7 +42,9 @@ class CUDAGraphLogging:
42 "Count",
43 ]
44
45 - def __init__(self, cg_mode: CUDAGraphMode, cg_capture_sizes: list[int] | None):
45 + def __init__(
46 + self, cg_mode: CUDAGraphMode, cg_capture_sizes: list[int] | None
47 + ) -> None:
48 self.reset()
49 self.cg_mode = str(cg_mode)
50 self.cg_capture_sizes = str(cg_capture_sizes or [])
@@ -54,10 +56,10 @@ class CUDAGraphLogging:
56 "**CUDAGraph Stats:**\n\n"
57 )
58
57 - def reset(self):
58 - self.stats = []
59 + def reset(self) -> None:
60 + self.stats: list[CUDAGraphStat] = []
61
60 - def observe(self, cudagraph_stat: CUDAGraphStat):
62 + def observe(self, cudagraph_stat: CUDAGraphStat) -> None:
63 self.stats.append(cudagraph_stat)
64
65 def generate_metric_table(self) -> str:
@@ -109,7 +111,7 @@ class CUDAGraphLogging:
111 + "\n"
112 )
113
112 - def log(self, log_fn=logger.info):
114 + def log(self, log_fn: Callable[..., Any] = logger.info) -> None:
115 if not self.stats:
116 return
117 log_fn(self.generate_metric_table())
@@ -161,11 +163,11 @@ class CUDAGraphWrapper:
163
164 def __init__(
165 self,
164 - runnable: Callable,
166 + runnable: Callable[..., Any],
167 vllm_config: VllmConfig,
168 runtime_mode: CUDAGraphMode,
169 cudagraph_options: CUDAGraphOptions | None = None,
168 - ):
170 + ) -> None:
171 self.runnable = runnable
172 self.vllm_config = vllm_config
173 self.runtime_mode = runtime_mode
@@ -189,7 +191,7 @@ class CUDAGraphWrapper:
191 # cudagraphs for.
192 self.concrete_cudagraph_entries: dict[BatchDescriptor, CUDAGraphEntry] = {}
193
192 - def __getattr__(self, key: str):
194 + def __getattr__(self, key: str) -> Any:
195 # allow accessing the attributes of the runnable.
196 if hasattr(self.runnable, key):
197 return getattr(self.runnable, key)
@@ -198,11 +200,11 @@ class CUDAGraphWrapper:
200 f"cudagraph wrapper: {self.runnable}"
201 )
202
201 - def unwrap(self) -> Callable:
203 + def unwrap(self) -> Callable[..., Any]:
204 # in case we need to access the original runnable.
205 return self.runnable
206
205 - def __call__(self, *args, **kwargs):
207 + def __call__(self, *args: Any, **kwargs: Any) -> Any | None:
208 forward_context = get_forward_context()
209 batch_descriptor = forward_context.batch_descriptor
210 cudagraph_runtime_mode = forward_context.cudagraph_runtime_mode
vllm/compilation/decorators.py
+42 -20
@@ -6,8 +6,8 @@ import hashlib
6 import inspect
7 import os
8 import sys
9 -from collections.abc import Callable
10 -from typing import TypeVar, overload
9 +from collections.abc import Callable, Generator
10 +from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload
11 from unittest.mock import patch
12
13 import torch
@@ -32,6 +32,14 @@ from vllm.utils.torch_utils import is_torch_equal_or_newer, supports_dynamo
32
33 from .monitor import start_monitoring_torch_compile
34
35 +if TYPE_CHECKING:
36 + # Only added on nightly/2.10 so wrap
37 + try:
38 + from torch._dynamo.package import SourceInfo
39 + except ImportError:
40 + # Fallback for old versions not supporting
41 + SourceInfo = Any
42 +
43 logger = init_logger(__name__)
44
45 IGNORE_COMPILE_KEY = "_ignore_compile_vllm"
@@ -59,7 +67,7 @@ def ignore_torch_compile(cls: _T) -> _T:
67 return cls
68
69
62 -def _should_ignore_torch_compile(cls) -> bool:
70 +def _should_ignore_torch_compile(cls: _T) -> bool:
71 """
72 Check if the class should be ignored for torch.compile.
73 """
@@ -224,7 +232,7 @@ def support_torch_compile(
232 return cls_decorator_helper
233
234
227 -def _model_hash_key(fn) -> str:
235 +def _model_hash_key(fn: Callable[..., Any]) -> str:
236 import vllm
237
238 sha256_hash = hashlib.sha256()
@@ -234,7 +242,9 @@ def _model_hash_key(fn) -> str:
242 return sha256_hash.hexdigest()
243
244
237 -def _verify_source_unchanged(source_info, vllm_config) -> None:
245 +def _verify_source_unchanged(
246 + source_info: "SourceInfo", vllm_config: VllmConfig
247 +) -> None:
248 from .caching import _compute_code_hash, _compute_code_hash_with_content
249
250 file_contents = {}
@@ -275,8 +285,12 @@ def _support_torch_compile(
285 setattr(cls, IGNORE_COMPILE_KEY, False)
286
287 def __init__(
278 - self, *, vllm_config: VllmConfig | None = None, prefix: str = "", **kwargs
279 - ):
288 + self: _T,
289 + *,
290 + vllm_config: VllmConfig | None = None,
291 + prefix: str = "",
292 + **kwargs: Any,
293 + ) -> None:
294 if vllm_config is None:
295 vllm_config = get_current_vllm_config()
296
@@ -309,13 +323,17 @@ def _support_torch_compile(
323
324 compilation_counter.num_models_seen += 1
325 self.compiled = False
312 - TorchCompileWithNoGuardsWrapper.__init__(self)
326 +
327 + # Handled by monkeypatching `TorchCompileWithNoGuardsWrapper` into base class
328 + TorchCompileWithNoGuardsWrapper.__init__(self) # type: ignore[arg-type]
329
330 cls.__init__ = __init__
331
316 - def _mark_dynamic_inputs(mod, type, *args, **kwargs):
317 - def mark_dynamic(arg, dims):
318 - if type == DynamicShapesType.UNBACKED:
332 + def _mark_dynamic_inputs(
333 + mod: _T, ds_type: DynamicShapesType, *args: Any, **kwargs: Any
334 + ) -> None:
335 + def mark_dynamic(arg: torch.Tensor, dims: list[int]) -> None:
336 + if ds_type == DynamicShapesType.UNBACKED:
337 if is_torch_equal_or_newer("2.10.0.dev"):
338 for dim in dims:
339 torch._dynamo.decorators.mark_unbacked(
@@ -326,7 +344,7 @@ def _support_torch_compile(
344 else:
345 torch._dynamo.mark_dynamic(arg, dims)
346
329 - sig = inspect.signature(mod.__class__.forward)
347 + sig = inspect.signature(mod.__class__.forward) # type: ignore[attr-defined]
348 bound_args = sig.bind(mod, *args, **kwargs)
349 bound_args.apply_defaults()
350 for k, dims in dynamic_arg_dims.items():
@@ -364,7 +382,7 @@ def _support_torch_compile(
382 else:
383 torch._dynamo.decorators.mark_unbacked(arg, dims)
384
367 - def __call__(self, *args, **kwargs):
385 + def __call__(self: _T, *args: Any, **kwargs: Any) -> Any:
386 # torch.compiler.is_compiling() means we are inside the compilation
387 # e.g. TPU has the compilation logic in model runner, so we don't
388 # need to compile the model inside.
@@ -444,7 +462,7 @@ def _support_torch_compile(
462 not envs.VLLM_USE_AOT_COMPILE
463 or self.vllm_config.compilation_config.backend == "eager"
464 )
447 - return TorchCompileWithNoGuardsWrapper.__call__(self, *args, **kwargs)
465 + return TorchCompileWithNoGuardsWrapper.__call__(self, *args, **kwargs) # type: ignore[arg-type]
466
467 # This is the path for the first compilation.
468 # the first compilation needs to have dynamic shapes marked
@@ -477,7 +495,7 @@ def _support_torch_compile(
495 # during Dynamo tracing, and their corresponding files
496 inline_call = InliningInstructionTranslator.inline_call_
497
480 - def patched_inline_call(self_):
498 + def patched_inline_call(self_: Any) -> Any:
499 code = self_.f_code
500 self.compilation_config.traced_files.add(code.co_filename)
501 return inline_call(self_)
@@ -535,7 +553,7 @@ def _support_torch_compile(
553 str(e),
554 )
555 else:
538 - output = TorchCompileWithNoGuardsWrapper.__call__(self, *args, **kwargs)
556 + output = TorchCompileWithNoGuardsWrapper.__call__(self, *args, **kwargs) # type: ignore[arg-type]
557
558 self.compiled = True
559 return output
@@ -545,7 +563,9 @@ def _support_torch_compile(
563
564
565 @contextlib.contextmanager
548 -def maybe_use_cudagraph_partition_wrapper(vllm_config: VllmConfig):
566 +def maybe_use_cudagraph_partition_wrapper(
567 + vllm_config: VllmConfig,
568 +) -> Generator[None, None, None]:
569 """
570 Context manager to set/unset customized cudagraph partition wrappers.
571
@@ -572,7 +592,9 @@ def maybe_use_cudagraph_partition_wrapper(vllm_config: VllmConfig):
592 current_platform.get_static_graph_wrapper_cls()
593 )
594
575 - def customized_cudagraph_wrapper(f, metadata: CUDAGraphWrapperMetadata):
595 + def customized_cudagraph_wrapper(
596 + f: Callable[..., Any], metadata: CUDAGraphWrapperMetadata
597 + ) -> Any:
598 partition_id = metadata.partition_index
599 num_partitions = metadata.num_partitions
600 return static_graph_wrapper_class(
@@ -600,7 +622,7 @@ def maybe_use_cudagraph_partition_wrapper(vllm_config: VllmConfig):
622
623
624 @contextlib.contextmanager
603 -def _torch27_patch_tensor_subclasses():
625 +def _torch27_patch_tensor_subclasses() -> Generator[None, None, None]:
626 """
627 Add support for using tensor subclasses (ie `BasevLLMParameter`, ect) when
628 using torch 2.7.0. This enables using weight_loader_v2 and the use of
@@ -614,7 +636,7 @@ def _torch27_patch_tensor_subclasses():
636 _ColumnvLLMParameter,
637 )
638
617 - def return_false(*args, **kwargs):
639 + def return_false(*args: Any, **kwargs: Any) -> Literal[False]:
640 return False
641
642 if version.parse("2.7") <= version.parse(torch.__version__) < version.parse("2.8"):
vllm/compilation/fix_functionalization.py
+5 -5
@@ -26,7 +26,7 @@ class FixFunctionalizationPass(VllmInductorPass):
26 """
27
28 @VllmInductorPass.time_and_log
29 - def __call__(self, graph: torch.fx.Graph):
29 + def __call__(self, graph: torch.fx.Graph) -> None:
30 # XPU does not support auto-functionalization yet.
31 # Will enable this when switch to vllm-xpu-kernels.
32 if current_platform.is_xpu():
@@ -179,7 +179,7 @@ class FixFunctionalizationPass(VllmInductorPass):
179 )
180 self.nodes_to_remove.clear()
181
182 - def _remove(self, node_or_nodes: torch.fx.Node | Iterable[torch.fx.Node]):
182 + def _remove(self, node_or_nodes: torch.fx.Node | Iterable[torch.fx.Node]) -> None:
183 """
184 Stage a node (or nodes) for removal at the end of the pass.
185 """
@@ -194,7 +194,7 @@ class FixFunctionalizationPass(VllmInductorPass):
194 node: torch.fx.Node,
195 mutated_args: dict[int, torch.fx.Node | str],
196 args: tuple[torch.fx.Node | str, ...] | None = None,
197 - ):
197 + ) -> None:
198 """
199 De-functionalize a node by replacing it with a call to the original.
200 It also replaces the getitem users with the mutated arguments.
@@ -206,7 +206,7 @@ class FixFunctionalizationPass(VllmInductorPass):
206
207 def replace_users_with_mutated_args(
208 self, node: torch.fx.Node, mutated_args: dict[int, torch.fx.Node | str]
209 - ):
209 + ) -> None:
210 """
211 Replace all getitem users of the auto-functionalized node with the
212 mutated arguments.
@@ -237,7 +237,7 @@ class FixFunctionalizationPass(VllmInductorPass):
237 graph: torch.fx.Graph,
238 node: torch.fx.Node,
239 args: tuple[torch.fx.Node | str, ...] | None = None,
240 - ):
240 + ) -> None:
241 """
242 Insert a new defunctionalized node into the graph before node.
243 If one of the kwargs is 'out', provide args directly,
vllm/compilation/inductor_pass.py
+3
@@ -29,6 +29,9 @@ else:
29 Torch25CustomGraphPass as CustomGraphPass,
30 )
31
32 +# Re-export CustomGraphPass for external usage
33 +__all__ = ["CustomGraphPass"]
34 +
35 _pass_context = None
36 P = ParamSpec("P")
37 R = TypeVar("R")
vllm/compilation/noop_elimination.py
+2 -2
@@ -65,7 +65,7 @@ class NoOpEliminationPass(VllmInductorPass):
65 """
66
67 @VllmInductorPass.time_and_log
68 - def __call__(self, graph: torch.fx.Graph):
68 + def __call__(self, graph: torch.fx.Graph) -> None:
69 count = 0
70 # Remove no-op reshapes/views:
71 for node in graph.nodes:
@@ -117,7 +117,7 @@ class NoOpEliminationPass(VllmInductorPass):
117 2. The dimensions both correspond to the same SymInt
118 """
119 # Case 1
120 - return statically_known_true(dim == i_dim)
120 + return statically_known_true(dim == i_dim) # type: ignore[no-any-return]
121
122 def all_dims_equivalent(
123 self, dims: Iterable[int | SymInt], i_dims: Iterable[int | SymInt]
vllm/compilation/pass_manager.py
+19 -12
@@ -1,6 +1,8 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 import functools
4 +from collections.abc import Callable
5 +from typing import Any, ParamSpec, TypeVar
6
7 from torch import fx as fx
8
@@ -40,8 +42,11 @@ from .noop_elimination import NoOpEliminationPass
42
43 logger = init_logger(__name__)
44
45 +P = ParamSpec("P")
46 +R = TypeVar("R")
47
44 -def with_pattern_match_debug(fn):
48 +
49 +def with_pattern_match_debug(fn: Callable[P, R]) -> Callable[P, R]:
50 """
51 Function decorator that turns on inductor pattern match debug
52 for the duration of the call.
@@ -49,7 +54,7 @@ def with_pattern_match_debug(fn):
54 """
55
56 @functools.wraps(fn)
52 - def wrapper(*args, **kwargs):
57 + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
58 if (debug_val := envs.VLLM_PATTERN_MATCH_DEBUG) is not None:
59 # optionally check rank here
60 with set_env_var("TORCHINDUCTOR_PATTERN_MATCH_DEBUG", debug_val):
@@ -59,7 +64,7 @@ def with_pattern_match_debug(fn):
64 return wrapper
65
66
62 -class PostGradPassManager(CustomGraphPass):
67 +class PostGradPassManager(CustomGraphPass): # type: ignore[misc]
68 """
69 The pass manager for post-grad passes.
70 It handles configuration, adding custom passes, and running passes.
@@ -74,11 +79,11 @@ class PostGradPassManager(CustomGraphPass):
79 This way, all passes operate on a functionalized graph.
80 """
81
77 - def __init__(self):
82 + def __init__(self) -> None:
83 self.passes: list[InductorPass] = []
84
85 @with_pattern_match_debug
81 - def __call__(self, graph: fx.Graph):
86 + def __call__(self, graph: fx.Graph) -> None:
87 VllmInductorPass.dump_prefix = 0 # reset dump index
88
89 compile_range = get_pass_context().compile_range
@@ -98,7 +103,7 @@ class PostGradPassManager(CustomGraphPass):
103 self.fix_functionalization(graph)
104 VllmInductorPass.dump_prefix = None # Cleanup index
105
101 - def configure(self, config: VllmConfig):
106 + def configure(self, config: VllmConfig) -> None:
107 self.pass_config = config.compilation_config.pass_config
108
109 # Set the current vllm config to allow tracing CustomOp instances
@@ -135,23 +140,25 @@ class PostGradPassManager(CustomGraphPass):
140 self.post_cleanup = PostCleanupPass(config)
141 self.fix_functionalization = FixFunctionalizationPass(config)
142
138 - def add(self, pass_: InductorPass):
143 + def add(self, pass_: InductorPass) -> None:
144 assert isinstance(pass_, InductorPass)
145 self.passes.append(pass_)
146
142 - def uuid(self):
147 + def uuid(self) -> str:
148 """
149 The PostGradPassManager is set as a custom pass in the Inductor and
150 affects compilation caching. Its uuid depends on the UUIDs of all
151 dependent passes and the pass config. See InductorPass for more info.
152 """
148 - state = {"pass_config": self.pass_config.compute_hash(), "passes": []}
153 + passes = []
154 +
155 + state: dict[str, Any] = {"pass_config": self.pass_config.compute_hash()}
156 for pass_ in self.passes:
150 - state["passes"].append(pass_.uuid())
151 - state["passes"].append(self.fix_functionalization.uuid())
157 + passes.append(pass_.uuid())
158 + passes.append(self.fix_functionalization.uuid())
159
160 # Include the compile range in the uuid to ensure that inductor
161 # recompiles the graph for the new dynamic compile range.
162 state["compile_range"] = str(get_pass_context().compile_range)
156 -
163 + state["passes"] = passes
164 return InductorPass.hash_dict(state)
vllm/compilation/piecewise_backend.py
+29 -15
@@ -86,27 +86,36 @@ class PiecewiseBackend:
86 self.to_be_compiled_ranges: set[Range] = set(self.compile_ranges)
87
88 # We only keep compilation management inside this class directly.
89 - for size in self.compile_sizes:
90 - range = Range(start=size, end=size)
91 - if range not in self.compile_ranges:
92 - self.range_entries[range] = RangeEntry(
93 - compile_range=range,
94 - )
95 - self.to_be_compiled_ranges.add(range)
89 + if self.compile_sizes is not None:
90 + for size in self.compile_sizes:
91 + if isinstance(size, str):
92 + assert size == "cudagraph_capture_sizes"
93 + raise NotImplementedError(
94 + "cudagraph_capture_sizes not supported in compile_sizes."
95 + "This should be handled in `post_init_cudagraph_sizes`."
96 + )
97 + else:
98 + assert isinstance(size, int)
99 + range = Range(start=size, end=size)
100 + if range not in self.compile_ranges:
101 + self.range_entries[range] = RangeEntry(
102 + compile_range=range,
103 + )
104 + self.to_be_compiled_ranges.add(range)
105
106 for range in self.compile_ranges:
107 self.range_entries[range] = RangeEntry(
108 compile_range=range,
109 )
110
102 - def check_for_ending_compilation(self):
111 + def check_for_ending_compilation(self) -> None:
112 if self.is_last_graph and not self.to_be_compiled_ranges:
113 # no specific sizes to compile
114 # save the hash of the inductor graph for the next run
115 self.vllm_backend.compiler_manager.save_to_file()
116 end_monitoring_torch_compile(self.vllm_config)
117
109 - def _fakify_args(self, args: list[Any]) -> list[Any]:
118 + def _fakify_args(self, args: tuple[Any, ...]) -> list[Any]:
119 # We need to pass fake example_inputs, otherwise torch.compile
120 # will fakify the example_inputs potentially causing some non dynamic
121 # dimension to be be duck shaped to other existing shapes that have hints
@@ -127,7 +136,9 @@ class PiecewiseBackend:
136 assert len(fake_example_inputs) == len(args)
137 return fake_example_inputs
138
130 - def _maybe_compile_for_range_entry(self, range_entry: RangeEntry, args) -> Any:
139 + def _maybe_compile_for_range_entry(
140 + self, range_entry: RangeEntry, args: tuple[Any, ...]
141 + ) -> Any:
142 if not range_entry.compiled:
143 range_entry.compiled = True
144 self.to_be_compiled_ranges.remove(range_entry.compile_range)
@@ -136,14 +147,14 @@ class PiecewiseBackend:
147 # fakify for range, real args for concrete size.
148 # For concrete size, we clear the shape env in
149 # compiler_manager.compile() so no need to fakify.
139 - args = (
150 + args_list = (
151 self._fakify_args(args)
152 if not range_entry.compile_range.is_single_size()
142 - else args
153 + else list(args)
154 )
155 range_entry.runnable = self.vllm_backend.compiler_manager.compile(
156 self.graph,
146 - args,
157 + args_list,
158 self.vllm_backend.inductor_config,
159 self.compilation_config,
160 compile_range=range_entry.compile_range,
@@ -153,10 +164,13 @@ class PiecewiseBackend:
164
165 self.check_for_ending_compilation()
166
156 - def _find_range_for_shape(self, runtime_shape: int) -> Range | None:
167 + def _find_range_for_shape(self, runtime_shape: int) -> RangeEntry | None:
168 # First we try to find the range entry for the concrete compile size
169 # If not found, we search for the range entry
170 # that contains the runtime shape.
171 + if self.compile_sizes is None:
172 + return None
173 +
174 if runtime_shape in self.compile_sizes:
175 return self.range_entries[Range(start=runtime_shape, end=runtime_shape)]
176 else:
@@ -165,7 +179,7 @@ class PiecewiseBackend:
179 return self.range_entries[range]
180 return None
181
168 - def __call__(self, *args) -> Any:
182 + def __call__(self, *args: Any) -> Any:
183 runtime_shape = args[self.sym_shape_indices[0]]
184 range_entry = self._find_range_for_shape(runtime_shape)
185
vllm/compilation/wrapper.py
+23 -13
@@ -4,9 +4,10 @@
4 import os
5 import sys
6 from abc import abstractmethod
7 +from collections.abc import Callable, Generator
8 from contextlib import contextmanager, nullcontext
9 from types import CodeType
9 -from typing import Any
10 +from typing import Any, ParamSpec, TypeVar
11
12 import torch
13 import torch._C._dynamo.guards
@@ -19,19 +20,26 @@ from vllm.utils.nvtx_pytorch_hooks import layerwise_nvtx_marker_context
20
21 logger = init_logger(__name__)
22
23 +R = TypeVar("R")
24 +P = ParamSpec("P")
25
23 -def _noop_add_global_state_guard(self, *args, **kwargs):
26 +
27 +def _noop_add_global_state_guard(
28 + self: torch._C._dynamo.guards.GuardManager, *args: Any, **kwargs: Any
29 +) -> None:
30 """No-op to skip the GLOBAL_STATE guard entirely"""
31 pass
32
33
28 -def _noop_add_torch_function_mode_stack_guard(self, *args, **kwargs):
34 +def _noop_add_torch_function_mode_stack_guard(
35 + self: torch._C._dynamo.guards.GuardManager, *args: Any, **kwargs: Any
36 +) -> None:
37 """No-op to skip the TORCH_FUNCTION_MODE_STACK guard entirely"""
38 pass
39
40
41 @contextmanager
34 -def _compilation_context():
42 +def _compilation_context() -> Generator[None, None, None]:
43 """Context manager for compilation settings and patches.
44
45 This manager:
@@ -88,13 +96,15 @@ class TorchCompileWithNoGuardsWrapper:
96 since we drop all guards.
97 """
98
91 - def check_invariants_and_forward(self, *args, **kwargs):
99 + def check_invariants_and_forward(self, *args: Any, **kwargs: Any) -> Any:
100 assert hasattr(self, "_check_shape_invariants")
101 self._check_shape_invariants(*args, **kwargs)
102
103 return self.forward(*args, **kwargs)
104
97 - def _call_with_optional_nvtx_range(self, callable_fn, *args, **kwargs):
105 + def _call_with_optional_nvtx_range(
106 + self, callable_fn: Callable[P, R], *args: P.args, **kwargs: P.kwargs
107 + ) -> Any:
108 if self.layerwise_nvtx_tracing_enabled:
109 args_list = list(args)
110 kwargs_dict = dict(kwargs)
@@ -108,7 +118,7 @@ class TorchCompileWithNoGuardsWrapper:
118 return ctx.result
119 return callable_fn(*args, **kwargs)
120
111 - def __init__(self):
121 + def __init__(self) -> None:
122 self.compiled = False
123
124 vllm_config = get_current_vllm_config()
@@ -192,9 +202,9 @@ class TorchCompileWithNoGuardsWrapper:
202
203 if envs.VLLM_USE_BYTECODE_HOOK and mode != CompilationMode.STOCK_TORCH_COMPILE:
204 torch._dynamo.convert_frame.register_bytecode_hook(self.bytecode_hook)
195 - self._compiled_bytecode = None
205 + self._compiled_bytecode: CodeType | None = None
206
197 - def aot_compile(self, *args, **kwargs):
207 + def aot_compile(self, *args: Any, **kwargs: Any) -> Any:
208 if not hasattr(self._compiled_callable, "aot_compile"):
209 raise RuntimeError(
210 "aot_compile is not supported by the current configuration. "
@@ -203,7 +213,7 @@ class TorchCompileWithNoGuardsWrapper:
213 )
214 return self._compiled_callable.aot_compile((args, kwargs))
215
206 - def __call__(self, *args, **kwargs):
216 + def __call__(self, *args: Any, **kwargs: Any) -> Any:
217 if envs.VLLM_USE_BYTECODE_HOOK:
218 if (
219 self.vllm_config.compilation_config.mode
@@ -236,13 +246,13 @@ class TorchCompileWithNoGuardsWrapper:
246 )
247
248 @abstractmethod
239 - def forward(self, *args, **kwargs): ...
249 + def forward(self, *args: Any, **kwargs: Any) -> Any: ...
250
251 def original_code_object(self) -> CodeType:
252 """Return the original code object of the forward method."""
253 return self.__class__.forward.__code__
254
245 - def bytecode_hook(self, old_code: CodeType, new_code: CodeType):
255 + def bytecode_hook(self, old_code: CodeType, new_code: CodeType) -> None:
256 """Hook to save the compiled bytecode for direct execution."""
257 if old_code is not self.original_code_object():
258 return
@@ -299,7 +309,7 @@ class TorchCompileWithNoGuardsWrapper:
309 raise RuntimeError(msg)
310
311 @contextmanager
302 - def _dispatch_to_compiled_code(self):
312 + def _dispatch_to_compiled_code(self) -> Generator[None, None, None]:
313 # noqa: E501
314 """
315 Context manager to dispatch to internally compiled code for torch<2.8.
vllm/config/compilation.py
+3
@@ -32,6 +32,9 @@ else:
32
33 logger = init_logger(__name__)
34
35 +# Explicitly exports Range
36 +__all__ = ["Range"]
37 +
38
39 class CompilationMode(enum.IntEnum):
40 """The compilation approach used for torch.compile-based compilation of the
vllm/distributed/device_communicators/pynccl_allocator.py
+1 -1
@@ -60,7 +60,7 @@ def is_symmetric_memory_tensor(tensor: torch.Tensor):
60 return False
61
62
63 -def set_graph_pool_id(graph_pool_id):
63 +def set_graph_pool_id(graph_pool_id: Any) -> None:
64 global _graph_pool_id
65 _graph_pool_id = graph_pool_id
66