Heads up: posts on this site are drafted by Claude and fact-checked by Codex. Both can still get things wrong — read with care and verify anything load-bearing before relying on it.
why → how

Why FlashAttention was a breakthrough

Same math, same exact outputs, same asymptotic compute — and yet it made attention several times faster and unlocked long context. The trick was noticing attention was a memory problem, not a compute problem.

AI & ML intermediate Apr 30, 2026 · updated Aug 25, 2026 · 15 min read

On this page

The picture version

Six pictures for a reader who has never written a line of GPU code. The prose below fills in the seams the pictures skip.

1 · The problem

The model fits comfortably. The job dies anyway.

what is actually in memory the model fits fine a scratch table it builds and throws away one row and one column for every word of your input Feed it 8,000 words and that table is 64 million numbers — and that’s for one attention head, in one layer. out of memory the thing that blew up is a value the model never even keeps
The scratch table — every word scored against every other word — is the running example for the whole post. The standard way of computing attention writes all of it out to memory and reads it back, several times over.

2 · The mismatch

The maths didn’t change. Nothing was approximated. It just got much faster.

unchanged the answer, down to the last digit the count of multiplications the model itself no approximation, no new architecture, no retraining changed how long it takes several times faster and long inputs stopped running out of memory If the arithmetic is identical, the arithmetic was never the bottleneck.
Everyone assumed attention was slow because it does an enormous number of multiplications. Same multiplications, far less waiting — which means the time was going somewhere else entirely.

3 · Where it was going

A tiny fast shelf next to the workers, and a big slow warehouse across the yard.

the shelf, on the chip ~19 TB/s right next to the maths units holds tens of megabytes nowhere near enough for the table the warehouse, off the chip ~1.5 TB/s about a thirteenth of the speed holds tens of gigabytes roughly two thousand times the room write it out read it back The whole table crosses that yard three or four times, per layer. The maths units finish early and stand there waiting. these are the paper’s figures for one specific GPU generation, not a universal constant
Attention was never short of arithmetic; it was short of bandwidth. The cost was hauling the score table between fast on-chip memory and slow main memory, over and over, while the compute units idled.

4 · The obvious fix, and the wall it hits

Do it a tile at a time — except one step insists on seeing the whole row.

the plan: one small tile at a time each tile fits on the shelf, is used, and is thrown away the full table never has to exist anywhere but one step refuses to finish any one entry of this row, you need the total of the whole row the step that turns raw scores into shares of attention divides by a sum over every entry in the row the fix: carry two running numbers per row Keep a running biggest-so-far and a running total; when a new tile arrives, rescale what you had and fold the tile in. The end result is exact.
Splitting work into tiles is the oldest trick in numerical computing, and it works here for everything except the normalising step. Two running numbers per row let that step be done incrementally with no approximation — an idea published years earlier and never wired into a full attention kernel.

5 · The last leak

Do all that and the tiles still get carried to the warehouse between steps.

three separate programs, one per step score the pairs turn scores into shares build the output out to the warehouse, and back out to the warehouse, and back every boundary between programs is a round trip you just spent the whole design avoiding one program that does all three score → share → output, all on the shelf only the answer this is why it had to be one hand-written program rather than three library calls
Tiling and the running-numbers trick are algorithm-level fixes, and a framework that runs each step as a separate program undoes both. Fusing the whole of attention into one program is what keeps the tiles on the chip for the duration.

6 · Keep this card

None of the three ideas was new. Noticing which problem it was, was.

FlashAttention = the same exact attention + done in tiles, on the shelf, in one program so the score table never reaches the warehouse what the paper reported ~7.6× on the attention step itself ~3× end to end, on a 1k-token workload ~15% end to end, on a 512-token workload The shorter the input, the smaller the win — because attention was a smaller share of the work.
Picture to keep: a small window sliding over the score table, each tile computed, used and discarded next to the compute units, with two running numbers per row carried along to stitch the answer together. Tiling is decades old and the running-softmax trick was published in 2018 — the breakthrough was seeing that attention had been a memory problem all along.

Why it exists

You paste a long document into a chat model and it answers in a couple of seconds. Anyone who has tried to run a transformer on their own GPU knows the other version of that experience: the model itself fits in memory comfortably, you feed it a long input, and the job dies with an out-of-memory error anyway. The thing that blew up wasn’t the model. It was a scratch value the model computes and throws away — and that scratch value is the running example for this whole post: the N×N table of attention scores, one row and one column per token, that a transformer builds every time it reads a sequence of length N. At N = 8,000 that’s 64 million numbers per attention head, per layer, and the standard implementation writes all of them to memory and reads them back.

Now the confusing part. If you read the FlashAttention paper expecting a clever new approximation that avoids building that table, you’ll be confused. There isn’t one. The output is the same softmax attention the original transformer paper described in 2017 — exact, up to floating-point reordering. The asymptotic FLOP count is the same (the backward pass actually does more arithmetic, because it recomputes intermediates instead of storing them — more on that below). The model isn’t changed. And yet it ran several times faster on real GPUs and made it practical to train and serve transformers at sequence lengths that previously ran out of memory.

That mismatch — same math, dramatically different wall-clock — is the entire point. Before FlashAttention, the prevailing intuition was that attention was compute-bound: it does an N×N matmul, and matmuls are what GPUs are for, so what’s left to optimize? The answer turned out to be everything. The bottleneck was never the multiplications. It was that N×N table being shuffled in and out of HBM three or four times per attention layer, with the GPU’s actual compute units sitting idle waiting for memory.

The breakthrough was noticing this and writing a kernel that respected the memory hierarchy. The technique — tiling plus an online softmax trick — is not novel in computer science; it’s the standard playbook for memory-bound numerical kernels. The novelty was applying that playbook to attention, demonstrating that attention had been a memory-bandwidth problem all along, and shipping a kernel everyone could use. The 2022 paper by Tri Dao, Daniel Y. Fu, Stefano Ermon, Atri Rudra, and Christopher Ré (arXiv:2205.14135) made that case, and it was unusually consequential — the FA-2/FA-3 lineage continues today, and the underlying kernel (or a derivative) is widely available through major training and inference stacks. (My read on adoption breadth, not a sourced market study.)

Why it matters now

The reason FlashAttention is still a load-bearing piece of infrastructure four years later, instead of a paper everyone moved on from, is that the bandwidth gap it exploits has only gotten wider:

The short answer

FlashAttention = exact softmax attention + tiling + online softmax + kernel fusion

Picture to keep: the N×N score table never exists all at once. Picture a small window sliding over it, one tile at a time, right next to the compute units — each tile computed, used, and thrown away before the next arrives, with two running numbers per row carried along to stitch the answer together.

It’s the same attention as before — same inputs, same exact outputs, same asymptotic FLOP count — restructured so the N×N intermediate matrix never gets written to slow GPU memory. The work is done in small blocks that fit in fast on-chip memory and are processed in a single fused kernel. The math is unchanged; only the data movement is. (The backward pass does add some recomputation FLOPs as the price of not storing the attention matrix.)

How it works

The honest way to tell this is as three attempts to get rid of that 64-million-number table, each one breaking in a way that forces the next fix. None of the fixes is novel computer science on its own; the sequence is what nobody had run to completion for attention.

The naive kernel, and why it wastes the machine

A GPU has two memory tiers that matter here. SRAM is on-chip, sits next to the compute units, and is fast — but tiny, on the order of tens of MB total across all streaming multiprocessors. HBM is off-chip DRAM, much slower per byte but much bigger (tens of GB).

The original FlashAttention paper cites an A100 example where SRAM bandwidth is roughly 19 TB/s versus 1.5 TB/s for HBM — about 13× the throughput in roughly 1/2000th the capacity. Standard attention writes the full N×N scores matrix out to HBM, reads it back to apply softmax, writes the result back, and reads it again to multiply by V. Those round-trips are the bottleneck. The matmul units finish early and wait.

This is the core empirical claim of the paper: an IO analysis plus benchmarks argue that standard attention is memory-bound, not compute-bound. Once you see that, the fix is structural: don’t materialize the N×N matrix in HBM at all.

flowchart LR
    subgraph chip [On-chip — fast, tiny]
        CU[Compute units] <--> SRAM["SRAM · ~19 TB/s · tens of MB"]
    end
    SRAM <--> HBM["HBM · ~1.5 TB/s · tens of GB"]

Standard attention parks the N×N scores matrix in HBM and crosses that slow link three or four times per layer. FlashAttention keeps every block left of the HBM boundary and only writes back the small final output.

Attempt 1 — tile it, the way every good matmul kernel is tiled

Tiling is the textbook technique for memory-bound numerical work — it’s how good BLAS matmul kernels have always worked. FlashAttention applies it to attention.

Conceptually:

for each block of K, V (loaded into SRAM):
    for each block of Q (loaded into SRAM):
        compute partial scores = Q_block · K_blockᵀ   # in SRAM
        compute partial softmax + partial output       # in SRAM
        update running output and softmax statistics   # tiny

If that loop works, the N×N table is never assembled in HBM at all: each block is computed, used, and discarded inside SRAM, and the kernel writes back only the final output (shape N×d, same size as the input) plus a small O(N) per-row softmax statistic that the backward pass needs (the running max m and the running sum-of-exps l; some implementations store them combined as m + log l). Total HBM traffic drops from O(N²) to roughly O(N²·d²/M), where M is the SRAM size — a big concrete win because M is large enough that the d²/M factor is small.

The catch is hiding in the two innocuous middle lines of that pseudocode. Line 3 is fine — a matmul over a block is just a smaller matmul. Line 4 is not.

Why attempt 1 breaks: softmax needs the whole row

Tiling is only “trivial textbook stuff” if your operation is associative across blocks. Matmul is. Softmax isn’t, naively — softmax(x_i) = exp(x_i) / Σ exp(x_j) requires knowing the whole row to compute any entry, because of the denominator. That global dependency is what stops you from just tiling attention the obvious way.

The fix, often called the online softmax trick, predates FlashAttention — Milakov and Gimelshein described an online normalizer in 2018 (arXiv:1805.02867) — but FlashAttention is what plumbed it through to a full attention kernel. The idea: as you stream through blocks of a row, keep two running scalars per row — the running max m (for numerical stability) and the running sum-of-exps l. When a new block arrives with its own local max and local sum, you rescale the running quantities and the partial output, then fold in the new block. After the last block, the result equals what a one-shot softmax would have produced, up to floating-point reordering. No approximation, no drift.

This is the part of FlashAttention that took genuine engineering taste to land — getting the rescaling exactly right while staying numerically stable, doing it inside a single CUDA kernel, and making the backward pass also work. The forward pass keeps only O(N) softmax statistics; the backward pass uses recomputation (re-deriving the attention matrix on the fly during backprop instead of storing it) to keep memory linear too.

The last leak: the tiles still leave the chip between steps

Tiling and online softmax are algorithm-level fixes, and you could implement both and still leave much of the win on the table — because a framework runs each step as its own GPU kernel. The unfused baseline FlashAttention was measured against — attention written out as ordinary framework ops — launches the score matmul, then softmax, then the output matmul separately, and every kernel boundary is a place where results get written back to HBM and read in again. (Today’s frameworks ship fused attention by default.) Your carefully tiled blocks leave the chip between steps anyway.

The final ingredient closes that: fuse all of attention — score matmul, softmax, output matmul — into one CUDA kernel. FlashAttention does the whole thing inside one kernel, so blocks live in SRAM for the duration. This is the same fusion idea behind a lot of hand-tuned GPU work; FlashAttention’s contribution wasn’t inventing fusion, it was finding the version that fused all of attention without sacrificing exactness.

What the numbers actually showed

The reported speedups depend a lot on what you measure. The 2022 paper highlights:

End-to-end gains are smaller than attention-only gains because attention isn’t 100% of the work, especially at short sequence lengths. The longer the sequence, the bigger the fraction of total time attention takes, and the bigger FlashAttention’s relative win — which is part of why long-context training became practical around the time this kernel and its successors became standard. (I’m not claiming sole causation; that’s an oversimplification — sequence-parallel training, ring attention, and architectural changes all contributed.)

What it did not change

It’s worth being precise about the limits, because the reframing only goes so far.

The follow-ups, briefly

FlashAttention-2 (2023) reorganized the parallelism (different work partitioning across thread blocks, fewer non-matmul operations) and roughly doubled throughput on Ampere-class GPUs. FlashAttention-3 (2024) targets Hopper (H100) specifically — exploiting TMA, warp-specialized async pipelines, and FP8 / BF16 with block-quantized FP8 — and reports lifting H100 attention utilization well above FA-2’s roughly 35%. Be careful quoting the headline number, because the versions differ: the NeurIPS 2024 paper reports up to ~840 TFLOPs/s in BF16 (~85% utilization) and up to ~1.3 PFLOPs/s in FP8, while the July 2024 arXiv preprint reported ~740 TFLOPs/s in FP16 (~75%) and close to 1.2 PFLOPs/s in FP8. My read, not consensus: each follow-up is a constant-factor win that gets harder to find as the easy bandwidth wins have already been taken.

You started with FlashAttention = exact softmax attention + tiling + online softmax + kernel fusion. Which of those three additions had never been done before? — none of them, individually. Tiling is decades old, online softmax was published in 2018, kernel fusion is standard practice. What FlashAttention added is + the observation that attention was memory-bound in the first place. That observation is the breakthrough: once you believe the N×N table’s trips to memory are the cost, all three fixes are the obvious ones. My read on why nobody had assembled them earlier — the paper doesn’t argue this, so take it as interpretation — is that the field was busy trying to speed up the multiplications.

Check yourself

Before you go — a colleague benchmarks FlashAttention against standard attention at sequence length 128 and finds it barely faster. Did they do something wrong?

Answer

Probably not — that’s the expected result. At N = 128 the score table is 16,384 entries, small enough that it costs little to move and may well stay in cache anyway. The saving FlashAttention offers scales with the size of the thing it refuses to materialize, so the win grows with N. This is the same reason the 2022 paper’s headline end-to-end numbers differ so much by workload: ~15% on BERT-large at length 512 versus ~3× on GPT-2 at length 1k. If your sequences are short, attention probably isn’t where your time is going, so an attention kernel has little to give you back — whatever it does win there comes from fusion overhead, not from the table it avoided.

And a harder one: FlashAttention’s backward pass does more floating-point arithmetic than the standard implementation, and it’s still faster. How can spending more FLOPs be a win?

Answer

Because FLOPs weren’t the scarce resource — bytes moved were. The backward pass needs the attention matrix, and it has two options: read it back from HBM (cheap in arithmetic, expensive in bandwidth) or recompute it from Q and K in fast on-chip memory (expensive in arithmetic, nearly free in bandwidth). On a chip where compute throughput far outruns memory bandwidth, the second trade wins. Generalize it: any time you find yourself on the memory-bound side of a machine, recomputing is a legitimate way to buy speed — this is the same bargain as gradient checkpointing.

Going deeper