- needs the full X on every device (replicated input)
- yields exact values — each device holds a different part of Y
- comm none (GeLU applies locally)
kernel tutorials · tt-metal · multi-chip
Megatron and CCLs.
The two Megatron matmul cuts, then every collective in ttnn — drawn in one visual language: cell color = which device the data came from, grey Σ = summed, dashed = empty. Everything below is vector — zoom as far as you like.
Megatron tensor parallelism: Z = (X·A)·B
Two ways to cut a weight across devices:
- needs a 1/N input slice — exactly what column-split left behind
- yields full-size results, partial values
- comm one all-reduce, at the very end
Lock and key: column-split leaves Y sharded exactly the way row-split wants its input — zero communication between the matmuls, one all-reduce at the end. Reversed, the partials would need an all-reduce before the GeLU.
The same pattern runs both halves of a transformer layer — GeLU in the MLP, softmax·V in attention; both sit safely in the middle because column-split values are exact:
The full block — left operand beside the result, top operand above it: Y appears where X meets A, the partial Z's where Y meets B.
Every ttnn CCL, on 4 devices
Each panel is before → after, one row per device. Move ops shuffle colored
chunks around unchanged; reduce ops blend everyone's colors into a grey Σ.
(reduce_to_root is currently SDPA-specialized in ttnn, and
all_to_all ships as the MoE dispatch/combine pair —
the panels show the underlying primitive.)
How to remember them
- Two families, that's it. Data can only move (gather / broadcast / scatter / to-all) or be summed (anything with
reducein the name). all_prefix = no root. Every device ends with the result. Noall_= one special root device: broadcast from root, reduce to root.scatter/partition= sliced result. Each device keeps only its 1/N piece — look for the staircase in the panels.- Inverses.
mesh_partitionundoesall_gather: their panels are mirror images (staircase ↔ full rows). - Compositions.
all_reduce=reduce_scatter+all_gather— literally how it's implemented on a ring.all_broadcast= broadcast run from every root at once. all_to_allis a transpose. Horizontal color stripes become vertical ones. Picture the (device × chunk) grid rotating and you can't forget it.- Memory check by counting cells.
all_gathergrows ×N,mesh_partition&reduce_scattershrink ÷N,all_reduce&all_to_allkeep size.
On the wire — the T3K ring, animated
T3K wires its 8 chips in a ring — each one talks only to its two neighbours. All eight drawn below, one row per device. Watch a hop at a time: move packets are copied on unchanged, reduce packets pick up a stripe at every stop and turn grey Σ when the last contribution lands.
- both ways the real kernels drive both directions of every link at once — even chunks clockwise, odd chunks the other way — so the walk is N/2+1 hops and the final ⊕ takes packets from both neighbours in one go
- fabric a packet is a tt-fabric write that carries its destination address — it lands straight in the target tensor; forwarding chips never wake a compute core
- compute only
reduce_scatterruns math: one tile-add per hop, so the reduction cost is spread evenly around the ring