TPUv7 Ironwood serving benchmark — PrivateUse1 backend with retained Pallas kernels — What does it mean?
The news. On September 7, 2026, SemiAnalysis published third-party Qwen3.5-397B FP8 serving results for TPUv7 Ironwood against NVIDIA B200 and B300, run on Google's native TorchTPU stack. The headline is economic — at 100 tokens/s/user it models $0.181 per million total tokens on Ironwood against $0.222 on B200 — but the enabling detail is the software path: ordinary PyTorch tensors, on a TPU. TorchTPU is still in private beta, with open-sourcing expected around mid-October. Read the benchmark →
Start at the empty station. PyTorch keeps a slot on the shelf labelled for a guest — a device key nobody owns, that any vendor may claim and fill. A backend registered in that slot is reached through the ordinary dispatcher, so an ordinary .to(device) call can land on it — and it does not have to persuade PyTorch's maintainers to merge anything. The slot does not do the cooking, though. It is an entry point, and the backend still has to implement what it claims to support. That slot is PrivateUse1, and native in TorchTPU's description is the result of having done that work: the report describes ordinary PyTorch tensors on a TPU.
Then the recipe book. Once torch.compile has captured your Python into a graph, that graph still describes PyTorch operations, and a TPU compiler has no reason to know what those are. StableHLO is the translation step: a portable, versioned operation set that the framework writes and the hardware compiler reads, so neither side has to track the other's internals. XLA is the line cook — it takes the book and produces machine code for the chip, fusing operations as it goes.
And then the dishes nobody hands to the book. The report says only that TorchTPU retains TPU-specific Pallas kernels alongside the compiled path; it does not say which ones, or why. The general reason a stack keeps hand-written kernels is familiar enough, though: a compiler is strong on average and is not always the best available code for the few operations that dominate a hot loop. Pallas is the TPU's Triton: a Python dialect for writing tile-level kernels by hand, for people who do not want to write the machine's native low-level code. The shape worth noticing is the hybrid one — a compiled path plus retained hand-written kernels, rather than all of one or all of the other — which is the shape vLLM arrived at on NVIDIA hardware too, where an attention backend is a pluggable object carrying its own kernels.
GPU Abstraction Stack
Write Python ops — runs immediately, one kernel per op
Annotate with @torch.compile — compiler fuses & optimizes for you
Write tile-level kernels in Python — full control, no C++ needed
Write thread-level kernels — maximum control, maximum complexity
What the plug is worth. Put the two modelled costs side by side at the benchmark's 100 tokens/s/user point: $0.181 per million total tokens on Ironwood against $0.222 on B200 — a gap of $0.041 per million, or about 18%. Now fix the volume at one trillion total tokens a month (illustrative — the report models cost per token, not anyone's traffic). That is 1,000,000 million-token units, so the gap comes to 1,000,000 × $0.041 = $41,000 a month. None of that is reachable by a team whose framework cannot target the chip, and that is the whole point of the PrivateUse1 route: the cost advantage is a hardware-and-cost-model result, but it only becomes a purchasing decision if ordinary PyTorch code runs there unmodified. The stack is the precondition for the number, not a footnote to it.
| Route to new hardware | How the tensor behaves | What the vendor maintains | What it costs |
|---|---|---|---|
| Fork the framework | native — but only inside the fork | a whole parallel PyTorch | permanent merge debt against upstream |
| Tracing / lazy-tensor layer | deferred; not ordinary eager semantics | a tracing layer plus a compiler | reading a value forces the graph to run |
| PrivateUse1 registration | eager, once the backend implements the operations | a backend, kept out of tree | must supply that operation coverage itself |
| Hand-written kernels only | no framework integration at all | one kernel per operation | does not scale past a few models |
Goes deeper in: Inside vLLM → Attention Backends & the Platform Layer → Adding a Backend
Related explainers
- Why attention went data-parallel while the experts did not — the parallelism layout the same benchmark runs on, and what two KV heads rule out