This document is relevant for: Trn2, Trn3
How to develop and test vLLM Neuron in CPU mode#
Task overview#
This guide covers the full CPU-based development workflow for vLLM Neuron, including CPU development mode, CPU compilation mode, the NKI CPU simulator, and debugging techniques. These modes enable rapid iteration without Neuron hardware.
Prerequisites#
Python 3.10+
Git access to the
vllm-neuronrepositoryDocker (optional, for the dev container workflow)
No Neuron hardware required
When to use each mode#
Mode |
Use case |
Speed |
|---|---|---|
CPU mode (sim off) |
General development, feature iteration, most debugging |
Fast |
CPU mode + simulator |
Kernel development, accuracy debugging, small reproducing examples |
Slow |
CPU compilation |
Pre-compiling NEFFs without hardware, validating graph capture |
Medium |
On-device |
Final validation, performance testing, large model scale-up |
Requires hardware |
Instructions#
1. Clone and install in development mode#
git clone git@github.com:aws-neuron/vllm-neuron.git
cd vllm-neuron
pip install --extra-index-url=https://pip.repos.neuron.amazonaws.com \
-e ".[dev]"
2. Enable CPU development mode#
Set the environment variable to run without Neuron hardware:
export VLLM_NEURON_CPU_MODE=1
In CPU mode:
Tensor operations run on CPU (no NeuronCores needed)
Model compilation is simulated (no NEFF generation)
Functional correctness can be verified without hardware
NKI kernels fall back to PyTorch reference implementations
Catches wrong weight mappings, shape mismatches, incorrect collectives, bad RoPE variants, and transposition errors
3. Use the NKI CPU simulator (optional)#
The NKI CPU simulator executes NKI kernels on CPU using NumPy, enabling correctness validation without Neuron hardware. It must be explicitly enabled — it is not auto-activated by CPU mode. Set both environment variables:
export VLLM_NEURON_CPU_MODE=1
export NKI_SIMULATOR=1
Note
The simulator is slow — it runs NKI kernels through a Python-based NumPy backend. Use it only for single functions, modules, or layers with small tensor shapes or tiny model configs (<10M params).
How the simulator works#
When both VLLM_NEURON_CPU_MODE=1 and NKI_SIMULATOR=1 are set, the
simulator integrates through the NKI HOP dispatch chain:
wrap_nki(kernel) → NKIHOPCaller
NKIHOPCaller[grid](**kwargs)
→ nki_kernel_wrapper HOP (NKIKernelWrapper.__call__)
→ DispatchKey.CPU dispatch (_cpu_impl)
→ simulate_nki_kernel(func, lnc, kwargs)
→ torch tensors → numpy arrays
→ nki.simulator.simulate_kernel(func, args, kwargs, _lnc)
→ numpy arrays → torch tensors
The simulator supports both eager mode (--enforce-eager) and
torch.compile (dynamo) mode:
Eager mode:
torch.compiler.set_stance("force_eager")makestorch.compilea no-op. The HOP fires directly.Dynamo mode: Dynamo traces the FX graph, uses
FakeTensorModedispatch with ones-filled tensors for shape inference, then runs the simulator with real data at runtime.
NKI simulator limitations#
Numerical differences between CPU float and NeuronCore arithmetic require appropriate tolerances in tests
Simulator execution is not representative of hardware performance
Some kernels may not yet be supported by the simulator
4. Use CPU compilation mode#
CPU Compilation (VLLM_NEURON_CPU_COMPILE=1) compiles model graphs on
a CPU instance without executing them. This eliminates the need for
Neuron instances during compilation and enables pre-compiling NEFFs for
later device execution.
VLLM_NEURON_CPU_COMPILE=1 \
NEURON_PLATFORM_TARGET_OVERRIDE=trn2 \
python3 -m vllm.entrypoints.openai.api_server \
--model openai/gpt-oss-20b \
--tensor-parallel-size 8 \
--max-model-len 4096
Warning
VLLM_NEURON_CPU_COMPILE and VLLM_NEURON_CPU_MODE cannot be enabled
together. CPU Mode runs inference on CPU; CPU Compilation only compiles
graphs without execution.
Remote cache workflow for production#
Compile on CPU instance — set
VLLM_NEURON_REMOTE_CACHEto a shared filesystem (NFS/FSx):VLLM_NEURON_CPU_COMPILE=1 \ NEURON_PLATFORM_TARGET_OVERRIDE=trn2 \ VLLM_NEURON_REMOTE_CACHE=/shared/neff_cache \ VLLM_NEURON_PARALLEL_COMPILE_WORKERS=16 \ python3 -m vllm.entrypoints.openai.api_server \ --model openai/gpt-oss-20b \ --tensor-parallel-size 8
Deploy to production Neuron instances — ensure the remote cache is accessible, then disable compilation entirely:
VLLM_NEURON_REMOTE_CACHE=/shared/neff_cache \ VLLM_NEURON_DISABLE_GRAPH_CAPTURE_BACKEND=1 \ VLLM_NEURON_DISABLE_WARMUP_COMPILE=1 \ python3 -m vllm.entrypoints.openai.api_server \ --model openai/gpt-oss-20b \ --tensor-parallel-size 8
The VLLM_NEURON_DISABLE_WARMUP_COMPILE=1 flag treats any cache miss as
a fatal RuntimeError, ensuring production never silently compiles.
CPU compilation limitations#
Speculative decoding is not supported in CPU compile mode
Cannot validate numerical outputs — only confirms compilation succeeds
Debugging techniques#
Debugging with torch eager on CPU mode#
With VLLM_NEURON_CPU_MODE=1 and --enforce-eager, print statements
work for all models. For pdb support with world_size=1:
VLLM_NEURON_CPU_MODE=1 VLLM_ENABLE_V1_MULTIPROCESSING=0 \
python3 -m vllm.entrypoints.openai.api_server \
--model <model> --enforce-eager
For pdb with world_size > 1, install forked-pdb:
pip install fpdb
Then insert in your code:
__import__('fpdb').ForkedPdb().set_trace()
Debugging with torch.compile (pdb)#
When using torch.compile, dynamo runs in child processes. Use the
original_stdio context manager to redirect I/O for debugging:
def forward(self, hidden_states, positions, ...):
residual = hidden_states
hidden_states = self.input_layernorm(hidden_states)
with original_stdio():
breakpoint()
# Inspect variables here
This lets you inspect tensor shapes, values, and TP ranks:
(Pdb) p hidden_states.shape
torch.Size([19, 4096])
(Pdb) get_tensor_model_parallel_rank()
1
Warning
Stepping through code (next/step) is not supported in torch.compile
debug mode. Dynamo generates resume functions that cause BdbQuit
exceptions when the debugger attempts to step. Use breakpoints only
for inspection, not stepping.
Printing during tracing#
Print statements work in CPU mode for inspecting tensor shapes and
values during torch.compile tracing:
q, k, v = torch.tensor_split(qkv, self.qkv_split_indices, dim=-1)
print(f'--- q {q[:, 0]}')
Warning
On Neuron devices (not CPU mode), printing tensor shapes inside
torch.compile causes dynamo graph breaks that trigger:
NCC_ITEN406errors from neuronxcc (strided access patterns)config.recompile_limiterrors leading to dtype mismatchRuntimeError
Only use print debugging in CPU mode. Remove all prints before running on device.
Confirm your work#
Your CPU development environment is working when:
Unit tests pass with
VLLM_NEURON_CPU_MODE=1You can import
vllm_neuronwithout errorsFunctional tests detect CPU mode and skip hardware-specific assertions
Code changes are reflected immediately (editable install)
Environment variables reference#
Variable |
Default |
Description |
|---|---|---|
|
|
Enable CPU development mode |
|
unset |
Enable NKI CPU simulator (must be explicit) |
|
|
Enable ml_dtypes for low-precision accuracy |
|
|
Enable CPU compilation mode (no execution) |
|
— |
Target platform for CPU compilation |
|
|
Number of parallel compile workers |
|
— |
Path to shared remote NEFF cache |
|
|
Disable graph capture backend entirely |
|
|
Treat cache miss as fatal error |
|
|
Set to 0 for single-process pdb |
Common issues#
“No module named torch_neuronx”#
Possible solution: In pure CPU mode, most tests skip the paths that require
torch_neuronxautomatically. Run in an environment wheretorch_neuronxis installed if you need those paths.
Tests hang indefinitely#
Possible solution: Always use
--timeoutflags. CPU-mode simulation can be slow for large shapes. Reduce model size or use smaller test configs.
“NeuronCore not available” errors#
Possible solution: Ensure
VLLM_NEURON_CPU_MODE=1is set. Some test fixtures require this variable to bypass hardware checks.
Recompilation limit errors with print statements#
Possible solution: Remove print statements from model code before running with
torch.compile. Dynamo treats each print as a graph break, triggering recompilation until the limit is hit.
BdbQuit when stepping in pdb#
Possible solution: Only use
breakpoint()for inspection (print variables, check shapes). Do not usenext/stepcommands. Dynamo’s resume functions are incompatible with the debugger’s line-tracing mechanism.