This document is relevant for: Trn2, Trn3
FX Passes Architecture Design#
This document describes the FX passes stage of the compilation pipeline — the graph transformations that run between FX tracing and HLO lowering.
Overview#
Scalable architecture for managing FX graph transformations in the vLLM Neuron compilation pipeline.
Architecture#
Directory Structure#
vllm_neuron/fx_passes/
├── __init__.py # get_default_pass_manager()
├── base.py # FXPass interface
├── aliasing_pass.py # AliasingOutputRewritePass
├── backend_config_pass.py # NkiKernelWriteBackendConfigPass
├── collective_replica_groups_pass.py # CollectiveReplicaGroupsPass
├── device_rewriter.py # DeviceRewriterPass
├── inplace_rewrite_pass.py # InPlaceToOutOfPlacePass
└── pass_manager.py # FXPassManager with timing logs
Base Pass Interface#
class FXPass(ABC):
@abstractmethod
def run(self, gm: torch.fx.GraphModule, **kwargs) -> torch.fx.GraphModule:
pass
@property
@abstractmethod
def name(self) -> str:
pass
Pass Manager with Debug Logging#
def run_passes(self, gm: torch.fx.GraphModule, **kwargs) -> torch.fx.GraphModule:
for pass_obj in self.passes:
start_time = time.perf_counter()
gm = pass_obj.run(gm, **kwargs)
elapsed_time = time.perf_counter() - start_time
self.logger.debug(f"FX Pass '{pass_obj.name}' completed in {elapsed_time:.4f}s")
return gm
Default Pass Manager#
def get_default_pass_manager() -> FXPassManager:
manager = FXPassManager()
manager.add_pass(DeviceRewriterPass())
manager.add_pass(AliasingOutputRewritePass())
manager.add_pass(InPlaceToOutOfPlacePass())
manager.add_pass(NkiKernelWriteBackendConfigPass())
manager.add_pass(CollectiveReplicaGroupsPass())
return manager
Pass ordering matters. The aliasing pass must run before the in-place rewrite pass because it analyzes mutations while in-place operations are still present in the graph.
Individual Pass Documentation#
device_rewriting_fx_pass aliasing_output_rewrite_pass inplace_to_outofplace_pass
Integration#
Pipeline Integration#
def compile(gm: torch.fx.GraphModule, example_inputs, options: dict = {}):
# Apply FX passes before XLA tracing
if options.get('enable_fx_passes', True):
pass_manager = get_default_pass_manager()
gm = pass_manager.run_passes(gm, target_device='xla')
# Existing XLA tracing
model = torch_neuronx.trace(lambda *args: gm(*args), ...)
Configuration Options#
enable_fx_passes(bool): Enable/disable FX pass pipeline (default: True)target_device(str): Target device for passes (default: ‘xla’)
Benefits#
Modularity: Self-contained passes with clear interface
Extensibility: New passes added by implementing
FXPassObservability: Debug logs track individual pass performance
Testability: Individual passes can be unit tested independently
Adding New Passes#
Implement FXPass interface:
class MyNewPass(FXPass):
@property
def name(self) -> str:
return "my_new_pass"
def run(self, gm: torch.fx.GraphModule, **kwargs) -> torch.fx.GraphModule:
# Transform logic here
return gm
Add to default pass manager:
def get_default_pass_manager() -> FXPassManager:
manager = FXPassManager()
manager.add_pass(DeviceRewriterPass())
manager.add_pass(MyNewPass()) # Add new pass
return manager
Unit test the pass independently
This document is relevant for: Trn2, Trn3