fx tracing and forward-source rewriting for the Transformers backend fusers.
A small engine, independent of any particular pattern: trace a module's forward with torch.fx (tolerating a partial graph), inspect the resulting nodes, and rewrite the forward's source (AST) so only matched calls change while the rest stays live Python. fusion.py builds the concrete fusion patterns on top.
Functions:
-
compile_forward – Compile funcdef in fn's module so tracebacks point at the source.
-
find_node – The first node in graph matching predicate, or None.
-
forward_input_count – The number of tensor inputs cls.forward declares, excluding self and
-
innermost_block – The innermost statement list containing node, and the index within.
-
is_fn – -
is_linear – Is node nn.Linear.__call__().
-
is_method – -
is_op – Is node torch.<name>(), F.<name>(), operator.<name>(), or Tensor.<name>().
-
peel – Strip dtype-cast wrappers (.to(...), .float(), .type_as(...)).
-
recover_forward – Parse the source of cls.forward, ready for rewriting.
-
replace_expr – Replace the expression old (by identity) with new within module.
-
single_self_call – The unique self.<name>(arg) call in funcdef.
-
trace – Trace module.forward, returning the partial graph on failure.
Bases: Tracer
Tracer that treats every submodule as a leaf.
Each child stays one call_module node, so matching sees the module's own forward structure (activations aren't decomposed into e.g. sigmoid * x). iter traces through the leading shape unpacks (see _infer_len); anything else untraceable ends the trace early and the partial graph is matched.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| class _AllLeafTracer(fx.Tracer):
"""Tracer that treats every submodule as a leaf.
Each child stays one `call_module` node, so matching sees the module's own
forward structure (activations aren't decomposed into e.g. `sigmoid * x`).
`iter` traces through the leading shape unpacks (see `_infer_len`); anything
else untraceable ends the trace early and the partial graph is matched.
"""
def is_leaf_module(self, m: nn.Module, module_qualified_name: str) -> bool:
return True
def proxy(self, node: fx.Node) -> fx.Proxy:
return _SizedProxy(node, self)
def iter(self, obj: fx.Proxy):
length = _infer_len(obj.node)
if length is None:
return super().iter(obj)
return iter([obj[i] for i in range(length)])
|
Bases: Proxy
Proxy whose len is inferred from the graph (see _infer_len).
Source code in vllm/model_executor/models/transformers/fx_utils.py
| class _SizedProxy(fx.Proxy):
"""Proxy whose `len` is inferred from the graph (see `_infer_len`)."""
def __len__(self) -> int:
length = _infer_len(self.node)
if length is None:
return super().__len__()
return length
|
Concrete length of a proxy's value, inferred from its node chain.
Lets tracing pass through the shape unpacks and *-splats (e.g. (*input_shape, -1, head_dim)) that precede the patterns in HF attention.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def _infer_len(node: fx.Node) -> int | None:
"""Concrete length of a proxy's value, inferred from its node chain.
Lets tracing pass through the shape unpacks and `*`-splats (e.g.
`(*input_shape, -1, head_dim)`) that precede the patterns in HF attention.
"""
# `x.shape` has the rank of `x`, when known
if (
node.op == "call_function"
and node.target is getattr
and node.args[1] == "shape"
and (rank := _rank(node.args[0])) is not None
):
return rank
# Slices of known-length values
if node.op == "call_function" and node.target is operator.getitem:
src_len = _infer_len(node.args[0])
index = node.args[1]
if src_len is not None and isinstance(index, slice):
return len(range(*index.indices(src_len)))
return None
|
The tensor rank of node's value, if known.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def _rank(node: fx.Node) -> int | None:
"""The tensor rank of `node`'s value, if known."""
# vLLM always feeds the model [1, seq_len, hidden_size] hidden states
if node.op == "placeholder" and node.target == "hidden_states":
return 3
return None
|
Compile funcdef in fn's module so tracebacks point at the source.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def compile_forward(funcdef: ast.FunctionDef, fn: Callable) -> Callable:
"""Compile `funcdef` in `fn`'s module so tracebacks point at the source."""
module = ast.Module(body=[funcdef], type_ignores=[])
ast.fix_missing_locations(module)
ast.increment_lineno(module, fn.__code__.co_firstlineno - 1)
code = compile(module, fn.__code__.co_filename, "exec")
namespace: dict = {}
exec(code, fn.__globals__, namespace)
return namespace[funcdef.name]
|
The first node in graph matching predicate, or None.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def find_node(graph: fx.Graph, predicate: Callable[[fx.Node], bool]) -> fx.Node | None:
"""The first node in `graph` matching `predicate`, or `None`."""
return next((n for n in graph.nodes if predicate(n)), None)
|
The number of tensor inputs cls.forward declares, excluding self and any *args/**kwargs. Read from the signature, so it is independent of whether the trace completes (unlike counting placeholders).
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def forward_input_count(cls: type[nn.Module]) -> int:
"""The number of tensor inputs `cls.forward` declares, excluding `self` and
any `*args`/`**kwargs`. Read from the signature, so it is independent of
whether the trace completes (unlike counting placeholders)."""
try:
params = list(inspect.signature(cls.forward).parameters.values())[1:]
except (ValueError, TypeError):
return 1 # uninspectable: assume a single input and let matching decide
fixed = (
inspect.Parameter.POSITIONAL_ONLY,
inspect.Parameter.POSITIONAL_OR_KEYWORD,
inspect.Parameter.KEYWORD_ONLY,
)
return sum(1 for p in params if p.kind in fixed)
|
The innermost statement list containing node, and the index within.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def innermost_block(
block: list[ast.stmt], node: ast.AST
) -> tuple[list[ast.stmt], int] | None:
"""The innermost statement list containing `node`, and the index within."""
for index, stmt in enumerate(block):
if not any(child is node for child in ast.walk(stmt)):
continue
child_blocks = [
getattr(stmt, fld, None) for fld in ("body", "orelse", "finalbody")
]
child_blocks += [h.body for h in getattr(stmt, "handlers", [])]
child_blocks += [c.body for c in getattr(stmt, "cases", [])]
for child_block in child_blocks:
if (
isinstance(child_block, list)
and child_block
and (found := innermost_block(child_block, node)) is not None
):
return found
return block, index
return None
|
Is node <target>().
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def is_fn(node: object, target: Callable) -> bool:
"""Is node `<target>()`."""
return (
isinstance(node, fx.Node)
and node.op == "call_function"
and node.target is target
)
|
Is node nn.Linear.__call__().
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def is_linear(node: fx.Node, module: nn.Module) -> bool:
"""Is node `nn.Linear.__call__()`."""
return node.op == "call_module" and isinstance(
module.get_submodule(node.target), nn.Linear
)
|
Is node .<name>().
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def is_method(node: object, name: str) -> bool:
"""Is node `.<name>()`."""
return (
isinstance(node, fx.Node) and node.op == "call_method" and node.target == name
)
|
Is node torch.<name>(), F.<name>(), operator.<name>(), or Tensor.<name>().
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def is_op(node: object, name: str) -> bool:
"""
Is node `torch.<name>()`, `F.<name>()`, `operator.<name>()`, or `Tensor.<name>()`.
"""
return any(
is_fn(node, getattr(module, name, None)) for module in (torch, F, operator)
) or (hasattr(torch.Tensor, name) and is_method(node, name))
|
Strip dtype-cast wrappers (.to(...), .float(), .type_as(...)).
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def peel(node: object) -> object:
"""Strip dtype-cast wrappers (`.to(...)`, `.float()`, `.type_as(...)`)."""
while (
isinstance(node, fx.Node)
and node.op == "call_method"
and node.target in _DTYPE_CASTS
):
node = node.args[0]
return node
|
Parse the source of cls.forward, ready for rewriting.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def recover_forward(cls: type[nn.Module]) -> tuple[ast.FunctionDef, Callable]:
"""Parse the source of `cls.forward`, ready for rewriting."""
fn = inspect.unwrap(cls.forward)
if fn.__code__.co_freevars:
raise ValueError("forward is a closure")
tree = ast.parse(textwrap.dedent(inspect.getsource(fn)))
funcdef = tree.body[0]
if not isinstance(funcdef, ast.FunctionDef):
raise ValueError("source is not a plain function definition")
# `fn` is already unwrapped; don't re-apply its decorators
funcdef.decorator_list.clear()
# Annotations may not evaluate outside the defining module (e.g. with
# postponed evaluation); they're not needed at runtime
funcdef.returns = None
args = funcdef.args
for arg in (
*args.posonlyargs,
*args.args,
*args.kwonlyargs,
*filter(None, (args.vararg, args.kwarg)),
):
arg.annotation = None
# Recompiling outside the class body would break name mangling
for node in ast.walk(funcdef):
name = getattr(node, "attr", None) or getattr(node, "id", None)
if name and name.startswith("__") and not name.endswith("__"):
raise ValueError(f"{name} would be name mangled")
return funcdef, fn
|
Replace the expression old (by identity) with new within module.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def replace_expr(module: ast.AST, old: ast.expr, new: ast.expr) -> None:
"""Replace the expression `old` (by identity) with `new` within `module`."""
class _Replacer(ast.NodeTransformer):
def visit(self, node: ast.AST) -> ast.AST:
if node is old:
return new
return super().generic_visit(node)
_Replacer().visit(module)
|
The unique self.<name>(arg) call in funcdef.
Raises unless name appears exactly once, as such a call, so the source rewrite agrees with the fx match.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def single_self_call(funcdef: ast.FunctionDef, name: str) -> ast.Call:
"""The unique `self.<name>(arg)` call in `funcdef`.
Raises unless `name` appears exactly once, as such a call, so the source
rewrite agrees with the fx match.
"""
uses = [
node
for node in ast.walk(funcdef)
if isinstance(node, ast.Attribute) and node.attr == name
]
if len(uses) != 1:
raise ValueError(f"{name} is referenced {len(uses)} times")
calls = [
node
for node in ast.walk(funcdef)
if isinstance(node, ast.Call)
and node.func is uses[0]
and len(node.args) == 1
and not isinstance(node.args[0], ast.Starred)
and not node.keywords
]
if (
len(calls) != 1
or not isinstance(uses[0].value, ast.Name)
or uses[0].value.id != "self"
):
raise ValueError(f"{name} is not a single-argument call on self")
return calls[0]
|
Trace module.forward, returning the partial graph on failure.
The graph is only evidence for matching, and the patterns sit at the top of their forwards, so a trace that fails partway can still be matched.
Source code in vllm/model_executor/models/transformers/fx_utils.py
| def trace(module: nn.Module) -> fx.Graph | None:
"""Trace `module.forward`, returning the partial graph on failure.
The graph is only evidence for matching, and the patterns sit at the top of
their forwards, so a trace that fails partway can still be matched."""
tracer = _AllLeafTracer()
try:
return tracer.trace(module)
except Exception as exc:
logger.debug("Could not fully trace %s: %s", type(module), exc)
return getattr(tracer, "graph", None)
|