FP8 KV attention · H100 phase 1

The selected kernel family changes the FP8 ordering.

The diagnostic CUDA-core path makes every tested FP8 cell slower than BF16. The SM90 Tensor Core path makes symmetric K8/V8 slower at B=1,T=32K, 1.09× faster at B=32,T=2K, and about 1.5× faster at B=32,T=32K. The same-family comparison is now closed: with split-dtype Tensor Core kernels compiled and audited at cosine 1.00000, symmetric K8/V8 beats K16/V8 by 16–19% at every bandwidth-bound shape (K8/V8 reaches 1.40–1.51× over BF16; K16/V8 reaches 1.19–1.28×), the K tax is negative at scale, and FP8 loses only at batch 1. On Blackwell's TensorRT-LLM generation kernels the transform modes converge and plain-E4M3 FP8 saturates at 1.05× over BF16, limited by its own pipeline rather than DRAM. The kernel family, not the storage format, decides the sign.

PHASE 1 COMPLETESAME-FAMILY VERDICT: K8/V8 WINSDISPATCH AUDITS PASSEDCOSINE ≥ 0.99999

Use the exact H100 measurements

Keep the CUDA-core decomposition and the Tensor Core pair as separate experiments. They use different kernel families and therefore do not isolate scheduling by themselves.

CUDA-core FP32 online softmax

FP8 loses on every tested cell

K8/V8: 1,840.8 µs

At B=32,T=32K cold, BF16 completes in 1,337.2 µs. K and V taxes are comparable, and quantizing both creates a +262.2 µs interaction.

SM90 Tensor Core paged FA2 family

The measured ordering crosses with batch

1.49–1.51× at B=32,T=32K

The same K8/V8 storage loses at B=1,T=32K and wins at B=32,T=2K. Run the complete B-by-T cross before ranking batch, occupancy, and amortization.

CUDA-core four-cell matrix

shapeF16K8V8 / K16V8K8V8K taxV taxinteraction
B=1 T=32768 warm56.865.367.375.8+8.5+10.5-0.0
B=32 T=2048 warm99.1107.1108.1141.9+8.0+9.0+25.7
B=32 T=32768 warm1332.31461.01438.91826.4+128.7+106.6+258.8
B=32 T=32768 cold1337.21469.11446.71840.8+131.9+109.5+262.2

Medians in microseconds. Treat this implementation as conversion- and schedule-bound at these points. Warm and cold B=32,T=32K results remain effectively identical.

SM90 Tensor Core symmetric pair

shapeF16 µsK8V8 µsF16 / K8V8
B=1 T=32768 cold43.153.90.80×
B=32 T=2048 cold59.755.01.09×
B=32 T=32768 warm712.8471.11.51×
B=32 T=32768 cold712.6478.61.49×
Run batch before telling a bandwidth story. K8/V8 loses at B=1,T=32K and wins at B=32,T=2K. Context size alone does not explain the tested sign.

Bound the exposed preparation cost

Use the pure transform probe as an upper bound on exposed conversion. Use the QK-consuming probe to measure how readily a consumer overlaps it.

pure load and FP8 transform
+0.4 to +3.0 ns/tile

Warm BF16 loads can beat the FP8 transform despite reading twice the bytes. Cold traffic eventually exposes the FP8 byte advantage at the tested large tile.

load, prepare, and QK
about −0.8 to +0.8 ns/tile

A minimal QK consumer hides most of the isolated transform tax. Measure the complete Tensor Core mainloop before making K preparation the dominant explanation.

Apply bounded conclusions

LOCK: KERNEL FAMILY CHANGES THE OBSERVED ORDERING

Record the exact kernel, JIT URI, cubin, layout, transform mode, and launch policy for every result.

REJECT: K-ONLY EXPLANATION ON CUDA CORES

K-only and V-only taxes are comparable. The K8V8 interaction becomes large at batch 32.

LOCK: QK HIDES MOST ISOLATED CONVERSION

Keep conversion in the model, but measure the unhidden full-mainloop term.

OPEN: TRANSFORM SCHEDULE AT FIXED BYTES

Compare Full, KOnly, and SeparateKv with identical K8/V8 storage and one Tensor Core family.

OPEN: K16/V8 VERSUS K8/V8 IN ONE FAMILY

Hold V, scales, pages, mask, output type, and launch policy fixed.

OPEN: BATCH, OCCUPANCY, AND AMORTIZATION

Run the full B-by-T cross before attributing the crossover.

Measure the tile dependencies

Advance online softmax tile by tile. Complete K preparation before that tile's QK. Complete V preparation before PV. Measure overlap for the selected kernel.

K tile nload Kprepare KQKonline-softmax update
V tile nload Vprepare VP @ Voutput accumulation
T(K8/V8) − T(K16/V8) ≈ unhidden K8 preparation + layout/scale/occupancy pressure − saved K-byte time

Run the decisive phase 2 campaign

Use a cheap B200 capability gate. Pivot to the H100 split-dtype template patch immediately when B200 cannot provide the same-family asymmetric and symmetric cells.

Recover and commit the exact SM90 Tensor Core runner.Record its FlashInfer API, layouts, scales, pages, workspace, JIT URI, generated source, cubin, and checksums. Mark the source unrecoverable when it cannot be reconstructed exactly.
Audit B200 support from source.Pin FlashInfer at 4927c0e15cb63a2abb6df09019c39a172222f0eb. Separate paged generation attention from contiguous block-scaled FMHA.
Run a $5 B200 capability gate.Compile BF16, Full/KOnly/SeparateKv K8/V8, and same-family K16/V8. Print exact dispatch and terminate before timing when any decisive cell falls back or fails.
Hold bytes fixed and compare transform modes.Attribute a schedule effect only when one Tensor Core family, bytes, layouts, and scales remain fixed and a ≥3% paired delta reproduces across three processes.
Hold the Tensor Core family fixed and compare K16/V8 with K8/V8.Keep V and every non-K axis fixed. This closes the asymmetric-versus-symmetric question.
Run the complete B-by-T cross.Sweep B={1,2,4,8,16,32,64} and T={2K,8K,16K,32K,64K}; then add MHA and a second GQA topology.
Add captured scales and direct-layout MXFP8.Include scale traffic, Q quantization, final cache layout, paged support, output error, ITL, capacity, and goodput.
Collect counters on bare metal.Profile only reproduced winning and losing cells plus matched K16/V8 controls.
Integrate pre-bias K8/V8 after selecting the kernel path.Compare ordinary K8/V8, two bias-aware layouts, and K16/V8 across long-context quality and serving gates.
Budget: stop the B200 capability gate at $5, stop for owner review at $40, and never exceed $60 without a new committed authorization. Sync artifacts, terminate every pod, and verify zero running instances.

Open the executable phase 2 plan →

Preserve the phase 1 provenance

GPUH100 80GB HBM3 · sm_90 · 132 SMs
driver / CUDA580.126.09 / 13.0
PyTorch2.13.0+cu130
FlashInfer0.6.7 · fork 2b532f7b9236d89e45d571bc3bbf63d1e40d1f7d
fork branchpaper-memory-decode-v0.18
correctnesscos ≥ 0.99999 · rel L2 ≤ 0.0035 · LSE exact
profilerNCU blocked by ERR_NVGPUCTRPERM
cost / lifecycletwo pods · ~0.6 GPU-hours · ~$2 · zero pods left

Read the archived H100 findings →
Inspect the phase 1 result commit →