Kien Pham · roofline
The crossover

From the racing line to the roofline

A roofline model names the limiting factor before I write any code. Then I build the kernel, measure it, and check the prediction against reality, honestly, including every time the model was wrong. I'd never written an attention kernel at the metal before this. With the help of Claude's Fable 5, I built seventeen kernels.

predict before you cut
The journey · v1 → v12

Seventeen kernels, one measured speedup at a time

Three eras, each with a different limiting factor. The roofline predicted the limiter before every step; the honest misses are on the record.

the dead-ends beat · Era 2
Coda

Arm 2 Stage A, native FP4 compute doesn't help decode

I pre-registered “it won’t help,” then measured it on a B300: FP4 reaches only 5.8% of its 15 PF peak, FP8 21.7% of 5 PF, both HBM-bound. The packing gate is a red herring for decode; low precision is a KV-cache capacity + accuracy lever, not a decode-speed one.

The receipts

The receipts

A live benchmark run, correctness first, then the speedup and the counter-free %HBM that proves the limiter.

Every number on this site traces to a measured run in docs/results.md.

GitHub repo
github.com/gkienpham/flashattention-cuda ↗
Results

What the curve says

memory & capacity wins
125×
S-matrix elimination
2164 MB → 17 MB (v3)
202×
MLA KV capacity vs MHA
measured (v11)
the roofline scorecard

Limiter location right most steps; magnitude missed 5 straight, the reason the model became two-layered.

Independent validation

It reproduces

An independent review re-ran the roofline tool and reproduced every published arithmetic-intensity number exactly, and cross-checked the external claims against current literature, the B300 constants, the decode-is-work-starved characterization, and the “complement, not beat” positioning all held.

“The misses are productive failures. Each one ruled out a wrong explanation and redirected me toward the real limiting factor.”
Methodology · honest misses

The misses are the method

A pure FLOPs/bytes roofline is blind to the schedule. It named the limiter location right most steps but missed the wall-clock magnitude five straight, because L2 caching, occupancy, and launch overhead live in the schedule, not the arithmetic. Recording that honestly is the whole contribution.

“Deleting 99% of DRAM traffic made the kernel slower. Nothing was bandwidth-bound.”
the S-elimination paradox (v3)
“The M=128 packing advantage is a red herring for decode, the shape stays memory-bound.”
Arm 2 Stage A, measured KILL
“‘Per-CTA-bound’ was a statement about the engine, not the problem. The right engine converts work to throughput.”
the v12 correction
The work, in figures

The work, in figures

The paper

Roofline-Guided Characterization of Attention Decode on Blackwell

RGD · Roofline-Guided Decode

From per-CTA-bound to work-starvation across MHA, GQA, and MLA

Twelve attention kernels, each paired with a pre-registered two-layer roofline prediction and evaluated against measured results on T4, A100, B200, and B300. Central finding: decode's apparent per-CTA ceiling is work-starvation: the right engine converts work into throughput (0.75 → 1785 TFLOP/s on B300), but only in the high-throughput serving regime. The per-CTA-corrected layer matched the measured limiter at every decode step; pure roofline predicted the wrong regime at every single-stream step.

I complement, not beat, production kernels: the contribution is the open, prediction-vs-measured characterization, the two-layer model, and the boundary results.

Read the paper ↗
Author
Kien Pham · Tufts University
Status
In preparation · PMBS@SC 2026
Scope
12 kernels · 4 GPUs (T4 → B300)
MHA · GQA · MLA · FP8 · NVFP4
Boundary result
NVFP4 does not accelerate MLA decode, HBM-bound at M=128
Contact

Let's build fast things

Open to ML-systems / GPU-kernel / research internships. The kernels are the foundation for a from-scratch mini-vLLM.

Email me GitHub LinkedIn
primary bullet

Applied bottleneck-hunting from mechanical systems to GPU kernels: 17 CUDA kernels across 4 architectures, 8–16× over PyTorch, and characterized NVIDIA's flagship B300.