feat: optimize w8a8 block fp8 matmul for Hopper - #693
Open
zikong20 wants to merge 3 commits into
Open
Conversation
zikong20
force-pushed
the
w8a8_block_matmul_optimizate
branch
from
August 18, 2026 03:27
b3f2e08 to
e74d601
Compare
Signed-off-by: Lingjie Wu <113422314+zikong20@users.noreply.github.com>
Signed-off-by: zikong20 <1873666867@qq.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Category
Operator (W8A8 Block-FP8 GEMM, Hopper)
Type of Change
Performance Optimization
Description
Optimize the Hopper
w8a8_block_fp8_matmuloperator (per-token/per-block FP8 E4M3 inputswith
[block_n, block_k]de-quant scales) for the decode/small-batch shapes that dominateDeepSeek-V4-Flash inference traffic. The operator previously had only a single generic GEMM
kernel whose tile geometry is a poor fit for the tall-skinny (small
M, largeN/K) shapesproduced by MoE-style traffic, so it loses to DeepGEMM on exactly the shapes that are called
most often.
The core of this PR is a set of purpose-built GEMM kernels for those shapes, plus a dispatch in
general_w8a8_block_fp8_matmulthat routes each shape by(M, N, K)to the best-fit kernel (thegeneric kernel remains the fallback). All changes are confined to
w8a8_block_fp8_matmul.py(plus the two TLE helper modules it imports); the math and output dtype are unchanged.
Specialized kernels and the optimization idea
short_k256— for short-Kprojection shapes: fully unroll theKloop and pre-fold eachN-group's scalarb_sintoa_s, removing loop overhead and the per-tile scale multiply.swap_ab— for skinny GEMMs (smallM, largeN): swap A/B to computeC.T = B @ A.T,so the small
Mlands on the free dimension of the output tile and keeps the tensor core fedand the MMA issue efficient.
swap_ab_splitk— for skinny shapes with longK: on top of swap-AB, split-K alongKtoparallelize the long reduction across more SMs (summed via
atomic_add), relieving the SMunder-occupancy at small
M.general(+ TLE 2-consumer) — for the remaining large shapes: a TMA + warp-specialized2-consumer TLE kernel that uses async TMA loads and a producer/consumer pipeline to overlap
memory and compute; otherwise it falls back to the generic tuned kernel.
Each specialized kernel's tile/pipeline meta-parameters (
BLOCK_M/N/K,GROUP_M,num_warps,num_stages,SPLIT_K) are tuned offline per shape by FlagTune expand-tune and stored inw8a8_block_fp8_matmul_hopper_expand.yaml.Numerical safety
dtype (bf16 / fp16 / fp32) exactly as the generic kernel does.
atomic_addinto a zero-initializedC, so the partials sum to thesame value (bf16 atomic accumulation is not bit-reproducible across launches, but stays
within FP8-GEMM tolerance).
guards falls through to the generic kernel, so there is no correctness regression for
untested geometries.
_can_use_tle_2c(FP8 dtypes, contiguous strides,group_k == 128,N % TLE2C_BLOCK_N_HALF == 0,group_n == TLE2C_BLOCK_N_HALF) and onlyruns where TLE + device TMA are present; otherwise it transparently falls back.
Issue
N/A
Progress
Performance
Hardware: Hopper (H20-class), CUDA Graph pretune harness,
warmup=5 / rep=5.Reference (
DeepGEMM): DeepGEMM latency. Gems: FlagGems Triton kernels (this PR'sspecialized kernels). Speedup =
T_DeepGEMM / T_Gems. In the tables, Default isbefore-optimization (untuned default config) and Expand is after-optimization (this PR's
specialized kernels + per-shape tuning); Speedup Gain =
(Expand_speedup − Default_speedup) / Default_speedup, i.e. how much this optimization improvesthe Gems-vs-DeepGEMM ratio. Shapes come from four real DeepSeek-V4-Flash traces (prefill = 1024 /
4096 / 32768 / 65536;
N ∈ {512, 1536, 4096, 8192},K ∈ {256, 1024, 4096},M ∈ [1, 16384]).Where the optimization helps (the gains). The largest gains land on the decode→mid-
Mband(
M ≈ 36–264) where the pre-optimization path sits below DeepGEMM and the specialized kernelspull it back to a lead:
K == 256(short_k256): the biggest wins on the board — e.g.1,184,4096,2560.576 →1.107 (+92.19%),
1,214,4096,2560.615 → 1.169 (+90.08%); the 218k-count1,100,4096,256goes 0.696 → 1.079 (+55.03%).N == 512, K == 4096(swap_ab_splitk): e.g.1,158,512,40960.771 → 1.278 (+65.76%),the 216k-count
1,64,512,40961.120 → 1.338 (+19.46%).N == 8192, K == 1024at smallM(swap_ab/TLE): e.g.1,2,8192,10241.375 → 1.806(+31.35%),
1,8,8192,10241.363 → 1.764 (+29.42%).Where the geometry already suits the original kernel, the optimization correctly barely moves:
on
M = 1shapes (which make up almost all of the p65536 trace) the pre-optimization pathalready runs at 1.5–2.1× vs DeepGEMM, and at
M ≥ 2048it already leads ~1.0–1.2×; in bothregions the after value matches it within noise, which is why the p32768/p65536 averages are
nearly flat.
What still needs optimizing (open gap). Even after this optimization, one region stays below
DeepGEMM (
speedup < 1.0): theN ∈ {4096, 8192}, K == 1024shapes in the mid-Mband(
M ≈ 36–184) — 28/165 rows in p1024 and 27/185 in p4096, e.g.1,100,8192,10240.799,1,100,4096,10240.901,1,64,8192,10240.857. These are not fixed by tuningmeta-parameters: the bottleneck is the per-CTA pipeline efficiency of the
K = 1024reductionat this tile geometry, which is a kernel/compiler-layer problem (WGMMA issue + LSU overlap) left
for a follow-up. The p32768/p65536 traces have no below-parity shapes.
Per-trace summary
Full per-shape data
DeepSeek-V4-Flash-p65536d1024_w8a8_block_fp8_matmul_deepgemm.xlsx
DeepSeek-V4-Flash-p1024d1024_w8a8_block_fp8_matmul_deepgemm.xlsx
DeepSeek-V4-Flash-p4096d1024_w8a8_block_fp8_matmul_deepgemm.xlsx
DeepSeek-V4-Flash-p32768d1024_w8a8_block_fp8_matmul_deepgemm.xlsx