First "Deep Dive" post — a step down from the Foundations series into one specific, widely-used piece of software. FlashAttention is a good subject for that: it's the attention implementation almost every modern LLM training and inference stack actually uses, and its three major versions (2022, 2023, 2024) are a clean case study in what "optimizing a kernel" actually looks like once the algorithm itself is already settled.
It's tempting to describe v2 and v3 as "the same idea, but faster." That's not really what happened. Each version fixed a specific, different bottleneck the previous one didn't address:
The problem all three versions share
Standard attention computes softmax(QK^T)V by materializing the full
N×N attention matrix — writing it to GPU high-bandwidth memory (HBM),
then reading it back for the softmax and the second matrix multiply. For
long sequences this is the dominant cost, not the matrix multiplies
themselves: attention is memory-bandwidth-bound, not compute-bound.
Every version of FlashAttention is attacking that same underlying fact
from a different angle.
FlashAttention (2022): don't materialize the matrix at all
The original paper's contribution is IO-awareness: restructure the
computation so the N×N intermediate matrix never touches HBM in the
first place. Two ideas make that possible:
- Tiling — process
Q,K,Vin blocks small enough to fit in on-chip SRAM. - Online softmax — since softmax normally needs the full row to compute a sum, FlashAttention keeps a running max and running sum per row and rescales as new blocks arrive, so the softmax can be computed incrementally without ever holding the whole row at once.
# one step of the streaming softmax used inside FlashAttention
m_new = max(m_running, max(scores_block))
correction = exp(m_running - m_new)
p = exp(scores_block - m_new)
l_new = correction * l_running + sum(p)
acc_new = correction * acc_running + p @ values_blockThe result is exact attention (not an approximation) that's both
faster and far more memory-efficient — O(N) memory instead of
O(N²) — purely by changing where the intermediate results live, not
what's being computed.
FlashAttention-2 (2023): stop wasting cycles on everything that isn't a matmul
FlashAttention-1 was IO-aware, but it still left GPU throughput on the table in ways that had nothing to do with HBM traffic. FlashAttention-2 targeted three separate inefficiencies:
- Fewer non-matmul FLOPs — rebalanced the algorithm to spend less time on the rescaling arithmetic around each block, since non-matmul operations are far more expensive per-FLOP on a GPU than Tensor Core matrix multiplies.
- Loop order swapped — the outer loop iterates over
Qblocks and the inner loop overK/Vblocks (reversed from v1), which reduces how often partial results need to be written back and re-read. - Parallelization over sequence length, not just batch size and
attention heads — important because for a single long sequence with a
small batch,
batch × headsalone isn't enough work to keep every SM on the GPU busy.
The result: roughly 2x faster than the original FlashAttention, reaching 50-73% of theoretical peak FLOPs/s on an A100 — and up to 72% model FLOPs utilization in actual end-to-end training runs.
FlashAttention-3 (2024): stop waiting, period
FlashAttention-2's remaining inefficiency wasn't algorithmic — it was that computation and data movement were still happening sequentially: load a block, then compute on it, then load the next block. On Hopper, FlashAttention-3 overlaps the two, using hardware this series has already covered:
- Warp specialization — some warps in a thread block ("producers") do nothing but issue asynchronous data movement via TMA, while other warps ("consumers") run the WGMMA matrix multiplies, pipelined against each other instead of run in sequence.
- Interleaved matmul and softmax — block-wise matrix multiplies and softmax rescaling are scheduled to overlap rather than strictly alternate.
- FP8 with incoherent processing — block-level quantization designed to keep FP8 accuracy competitive with full precision even when attention scores have outlier values, rather than a naive per-tensor quantization that degrades badly on outliers.
The result on H100: 1.5-2.0x faster than FlashAttention-2 in BF16 (up to 840 TFLOPs/s, ~85% utilization), and up to 1.3 PFLOPs/s using FP8 — a version that only makes sense on the hardware described in the GPU architecture history post and built with the exact tools covered in What is CUTLASS and CuTe Layouts: WGMMA, TMA, and warp-level pipelining aren't FlashAttention-3-specific inventions — they're Hopper primitives, and this paper is what using them for attention specifically looks like.
The pattern
v1 fixed a memory-traffic problem. v2 fixed a GPU-occupancy and instruction-mix problem. v3 fixed a sequencing problem — computation and data movement waiting on each other when the hardware can do both at once. None of these are the same bottleneck, which is exactly why the versions aren't interchangeable: FlashAttention-3's techniques don't help on pre-Hopper GPUs that lack TMA and WGMMA, and FlashAttention-2's loop reordering doesn't fix a problem that only shows up when data movement and compute are already overlapped. Each paper solved the bottleneck its predecessor's fix made visible next.
References
- FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness (arXiv:2205.14135)
- FlashAttention-2: Faster Attention with Better Parallelism and Work Partitioning (arXiv:2307.08691)
- FlashAttention-3: Fast and Accurate Attention with Asynchrony and Low-precision (arXiv:2407.08608)
- FlashAttention-3 — Together AI blog
Timeline diagram above is original artwork made for this post.