vllm.model_executor.models.transformers.fx_utils
¶
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:
-
aliasing_names–seedplus every name that may alias one of them. -
block_chain–Path of (statement list, index) pairs from
blockdown tonode. -
bypass_existence_guard–Fold a guard on
self.<name>'s existence to its constant value. -
compile_forward–Compile
funcdefinfn's module so tracebacks point at the source. -
downstream_linear–Nearest linear consuming
node's output, walking through casts/scalings. -
find_node–The first node in
graphmatchingpredicate, orNone. -
forward_input_count–The number of tensor inputs
cls.forwarddeclares, excludingselfand -
forward_parameters–cls.forward's signature parameters, or empty if uninspectable. -
is_fn–Is node
<target>(). -
is_leaf_call–Is node a call recorded by
_as_leaf_call(e.g. an attention interface). -
is_linear–Is node
nn.Linear.__call__(). -
is_method–Is node
.<name>(). -
is_op–Is node
<mod>.<name>()for torch, F, operator, or Tensor. -
output_value–The value the graph's
outputnode returns, if the trace reached one. -
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) withnewwithinmodule. -
returned_linear–Name of the Linear producing the graph's (first) output value.
-
self_call_and_refs–The unique
self.<name>(arg)call, plus every otherself.<name>reference. -
single_self_call–The unique
self.<name>(arg)call infuncdef. -
trace–Trace
module.forward, returning the partial graph on failure. -
upstream_linear–Nearest linear producing
node, walking back through splits/reshapes. -
written_names–Names
regionmay rebind or write through.
_MODULE_CALL = nn.Module.__call__
module-attribute
¶
The unpatched nn.Module.__call__. During tracing fx patches it to record
call_module nodes; meta execution must call modules for real.
_UNKNOWN = object()
module-attribute
¶
Sentinel meta value for proxies whose concrete value could not be inferred.
Distinct from None, which is a valid concrete value (e.g. attn_weights).
_AllLeafTracer
¶
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).
Every traced op is also executed on meta tensors (see _MetaProxy) so
shape unpacks and *-splats trace through; anything else untraceable ends
the trace early and the partial graph is matched.
Attributes:
Source code in vllm/model_executor/models/transformers/fx_utils.py
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
varkw = None
class-attribute
instance-attribute
¶
Name of the traced forward's **kwargs parameter, if any.
_infer_meta(kind, target, args, kwargs)
¶
Execute the op on meta tensors; PyTorch infers the output value.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_MetaAttribute
¶
Bases: _MetaProxy, Attribute
Attribute proxy (e.g. x.shape) carrying its meta value.
Proxy.__getattr__ constructs Attribute directly, bypassing
Tracer.proxy, so the meta value must be grafted on here too.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_MetaProxy
¶
Bases: Proxy
Proxy carrying the meta-tensor value of the traced expression.
Shape questions (len, iteration, .shape unpacks) are answered by
executing each op on the meta values, so PyTorch's meta kernels are the
single source of shape inference — no per-op rules.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_aliasing_reads(node)
¶
Names node reads in a way that could yield a view of them.
Metadata (x.shape, x.size(0), x.dtype) is ints and tuples sharing no
storage with x, so reaching a name only through metadata cannot alias it.
Shape arithmetic is pervasive between projections, so propagating through it
would taint nearly every later name.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_arg_names(call)
¶
Every name call reads through its arguments.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_as_leaf_call(fn, length=None)
¶
Wrap any callable so tracing records it as one opaque call_function node.
Lets the trace continue past untraceable bodies. Only the proxy arguments carry into
the node's dataflow; the rest are dropped rather than lifted into the graph.
length declares how many values the callable returns, so unpacking its result also
traces. Called without proxies (i.e. outside tracing), the wrapper is a passthrough.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_base_name(node)
¶
The root Name of an attribute/subscript chain (a.b[c] -> a).
Source code in vllm/model_executor/models/transformers/fx_utils.py
_call_name(call)
¶
The called function's own name, without its qualifier.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_in_boolean_context(funcdef, ref)
¶
Is ref used only for its truth value (a test, or a not operand)?
In these positions the object's identity never escapes, so a reference that
is always truthy can be replaced by True. and/or are excluded: they
yield an operand, so the module could escape (x and self.<name>).
Source code in vllm/model_executor/models/transformers/fx_utils.py
_inplace_target(node)
¶
Base name node mutates in place, if any.
A write through the name (x[i] = ..., x.attr = ...) or an in-place method
call (x.mul_(...)) leaves the base name in a Load context, so it is not a
plain Name store (see _rebound_names).
Source code in vllm/model_executor/models/transformers/fx_utils.py
_leaf_attention_interfaces()
¶
Patch AttentionInterface.get_interface so traced forwards see a leaf node.
vllm_attention_function needs runtime context so it is untraceable.
Every interface returns (attn_output, attn_weights).
Source code in vllm/model_executor/models/transformers/fx_utils.py
_mutated_names(region)
¶
Names mutated in place within region (see _inplace_target).
Source code in vllm/model_executor/models/transformers/fx_utils.py
_rebound_names(region)
¶
Names rebound outright within region (x = ..., del x).
These are Name nodes in a Store/Del context.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_reference_weight(module)
¶
A weight whose trailing dim is the module's hidden size.
Linears and 2-D gate weights are [out, hidden]; norm weights are
[hidden]. Used to fabricate a placeholder input of matching size/dtype.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_returns_fresh(node, module)
¶
Does evaluating node allocate, rather than return a view of its input?
A nn.Linear writes its output into new storage, so its result aliases
nothing that went in, and a chain of view ops on top of it aliases only that
fresh tensor. Walking the receiver chain down to a self.<linear>(...) call
therefore proves the value cannot alias the projection input. A literal
aliases nothing either, and a branch or sequence is fresh when every part is
-- which is how a guarded projection (p(x) if p is not None else None)
stays untracked. A call on an attribute that is missing or None cannot run
at all, so a branch selecting a different configuration is fresh too.
Source code in vllm/model_executor/models/transformers/fx_utils.py
_writes_through_args(call)
¶
Does call write through an argument rather than return a new value?
Torch spells this three ways: an out= destination, inplace=True, and the
trailing-underscore convention (torch.relu_(x)). The underscore is checked
on the function's own name, so it catches the free-function form that
_inplace_target cannot (there the base name is the module, torch).
Source code in vllm/model_executor/models/transformers/fx_utils.py
aliasing_names(funcdef, seed, module)
¶
seed plus every name that may alias one of them.
A view shares storage with its base (h = x.view(-1)), so mutating h
mutates x; tracking only seed would miss that. Any assignment reading a
tracked name therefore taints its targets, transitively, unless its value is
freshly allocated (_returns_fresh).
Source code in vllm/model_executor/models/transformers/fx_utils.py
block_chain(block, node)
¶
Path of (statement list, index) pairs from block down to node.
Each pair names a nested block and the index in it of the statement
containing node; the last pair is node's innermost block. Empty if
node is not in block. The longest common prefix of several nodes' chains
is the innermost block that dominates them all.
Source code in vllm/model_executor/models/transformers/fx_utils.py
bypass_existence_guard(funcdef, ref, name)
¶
Fold a guard on self.<name>'s existence to its constant value.
The fuser deletes self.<name> and binds only instances where it exists as a
truthy nn.Linear (guaranteed by the match, the cache key, and validate),
so a guard testing its presence is a fusion invariant. Two forms are folded:
- an identity
Nonecheckself.<name> is None->False,self.<name> is not None->True(either operand order).==/!=are not folded:is_linearacceptsnn.Linearsubclasses, which may override__eq__/__ne__, so equality is not guaranteed to track identity. - a bare truthiness test (
if self.<name>:,... if self.<name> else ...,not self.<name>): the reference itself toTrue.
Any other surviving reference escapes the projection's value, which no longer exists after fusion, so refuse rather than change semantics.
Source code in vllm/model_executor/models/transformers/fx_utils.py
compile_forward(funcdef, fn)
¶
Compile funcdef in fn's module so tracebacks point at the source.
Source code in vllm/model_executor/models/transformers/fx_utils.py
downstream_linear(node, module)
¶
Nearest linear consuming node's output, walking through casts/scalings.
Never walks through a leaf call (e.g. an attention interface): what crosses it is consumed by the attention computation, not projected.
Source code in vllm/model_executor/models/transformers/fx_utils.py
find_node(graph, predicate)
¶
The first node in graph matching predicate, or None.
forward_input_count(cls)
¶
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
forward_parameters(cls)
¶
cls.forward's signature parameters, or empty if uninspectable.
Source code in vllm/model_executor/models/transformers/fx_utils.py
is_fn(node, target)
¶
is_leaf_call(node)
¶
Is node a call recorded by _as_leaf_call (e.g. an attention interface).
is_linear(node, module)
¶
Is node nn.Linear.__call__().
is_method(node, name)
¶
is_op(node, name)
¶
Is node <mod>.<name>() for torch, F, operator, or Tensor.
Source code in vllm/model_executor/models/transformers/fx_utils.py
output_value(graph)
¶
The value the graph's output node returns, if the trace reached one.
Source code in vllm/model_executor/models/transformers/fx_utils.py
peel(node)
¶
Strip dtype-cast wrappers (.to(...), .float(), .type_as(...)).
Source code in vllm/model_executor/models/transformers/fx_utils.py
recover_forward(cls)
¶
Parse the source of cls.forward, ready for rewriting.
Source code in vllm/model_executor/models/transformers/fx_utils.py
replace_expr(module, old, new)
¶
Replace the expression old (by identity) with new within module.
Source code in vllm/model_executor/models/transformers/fx_utils.py
returned_linear(graph, module)
¶
Name of the Linear producing the graph's (first) output value.
Source code in vllm/model_executor/models/transformers/fx_utils.py
self_call_and_refs(funcdef, name)
¶
The unique self.<name>(arg) call, plus every other self.<name> reference.
Raises unless exactly one single-argument self.<name>(arg) call exists, so
one fx call_module node maps to one syntactic call site. The remaining
references (e.g. is not None guards) are returned for the caller to resolve.
Source code in vllm/model_executor/models/transformers/fx_utils.py
single_self_call(funcdef, name)
¶
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
trace(module)
¶
Trace module.forward, returning the partial graph on failure.
Source code in vllm/model_executor/models/transformers/fx_utils.py
upstream_linear(node, module)
¶
Nearest linear producing node, walking back through splits/reshapes.
Non-linear submodules are transparent too (e.g. the dropout GPT-style attentions apply after their output projection). Never walks through a leaf call (e.g. an attention interface): its inputs are what attention consumes, not what produced the value.
Source code in vllm/model_executor/models/transformers/fx_utils.py
written_names(region)
¶
Names region may rebind or write through.
Beyond plain rebinding and writes through the name itself (_rebound_names,
_mutated_names), a call can write through an argument without naming it as
a target: F.relu(x, inplace=True), torch.add(x, y, out=x),
torch.relu_(x). A statement-level call whose result is discarded is treated
the same way, since it can only be there for a side effect.