perf(configs): tune bf16 GEMM for gfx1250 DeepSeek-V4-Flash shapes - #4804
Open
yichiche wants to merge 1 commit into
Open
perf(configs): tune bf16 GEMM for gfx1250 DeepSeek-V4-Flash shapes#4804yichiche wants to merge 1 commit into
yichiche wants to merge 1 commit into
Conversation
DeepSeek-V4-Flash (hidden 4096) issues bf16 A16W16 GEMMs with
N in {64, 256, 512, 1024, 2048} at K=4096. None of those shapes had a
gfx1250 entry, so get_GEMM_A16W16_config() fell through to the `torch`
default, where rocBLAS has no good gfx1250 kernel: the measured cost is
flat in M (~21 us for N=64, ~178 us for N=256 from M=2 all the way to
M=8192), i.e. a degenerate kernel pick rather than real work.
Add the tuned rows (libtype=triton, cu_num=96) plus the shape list they
were tuned from. Rows are appended, so the existing gfx950 block keeps
its order and the diff stays additive; lookup is by key, not position.
Note the pre-existing gfx1250 rows in model_configs/dsv4_bf16_tuned_gemm.csv
are cu_num=256 with us/tflops/bw all zero, so they never match a 96-CU
gfx1250 part -- these new rows do not collide with them.
Measured on gfx1250 (96 CU), 120 shapes, output bitwise-identical to
F.linear on every shape:
GPU kernel time geomean 6.82x faster (min 2.07x, 0 regressions)
eager wall clock geomean 0.51x (Triton pays ~90 us/call of host-side
launch overhead vs ~21 us for torch, which dominates
the small shapes; CUDA-graph-captured decode does not
pay it)
Contributor
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
|
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.
Summary
N ∈ {64, 256, 512, 1024, 2048}atK = 4096, bf16 in / bf16 out.torchdefault, where rocBLAS picks a degenerate kernel (cost flat in M).F.linearon every shape.Motivation
get_GEMM_A16W16_config()looks up(gfx, cu_num, M, N, K, bias, dtype, outdtype, scaleAB, bpreshuffle). DeepSeek-V4-Flash (hidden_size4096) issues bf16 GEMMs withN ∈ {64, 256, 512, 1024, 2048}atK = 4096, and none of those had a gfx1250 row, so every one of them hit thetorchdefault.That default is pathological on gfx1250 — the measured cost barely depends on M, which is the signature of a bad kernel pick rather than real work:
N=64, K=4096torchN=256, K=4096torchAn
N=256GEMM costs ~178 us whether it is 2 rows or 8192 rows.Modifications
aiter/configs/bf16_untuned_gemm.csv: +330 rows — the shape list handed to the tuner (5 N values x 66 M values).aiter/configs/bf16_tuned_gemm.csv: +120 tuned rows (gfx1250,cu_num=96,libtype=triton).Rows are appended, so the existing gfx950 block keeps its current order and the diff is purely additive (450 insertions, 0 deletions). Lookup is by dict key, so file position carries no meaning.
Two notes for reviewers:
model_configs/dsv4_bf16_tuned_gemm.csvarecu_num=256withus/tflops/bwall zero, so they never match a 96-CU gfx1250 part. The new rows arecu_num=96and do not collide with them —python3 -m unittest op_tests.tuning_tests.test_config_shape_collisionpasses (12/12), including thebf16_tuned_gemmfamily merge.triton_gemm()ignoressolidx/kernelNameand letsaiter.ops.triton.gemm.basic.gemm_a16w16choose (it selects the gluon backend on this arch), so those columns are carried as0/auto.Accuracy
Every one of the 120 shapes was checked against
F.linearon a call outside the timing loop: all 120 are bitwise identical (torch.equalis True; worst relative error 0.00e+00). This is a dispatch change between two implementations of the same bf16 GEMM, so no accuracy movement is expected and none was observed.Model-level accuracy (GSM8K) has not been run.
Benchmarking
Unit benchmark on gfx1250 (96 CU), all 120 tuned shapes. Both arms go through the real
tgemm.mmdispatcher and differ only by whether this PR's rows are in the config file (before →torch, after →triton).Metric is GPU kernel time from
aiter.test_common.run_perftest(torch profiler device time, arguments rotated to defeat L2 reuse).Overall (120 shapes)
Representative shapes
Checklist
op_tests/tuning_tests/test_config_shape_collisionpasses (12/12)F.linearon all 120 shapesmodel_configs/*bf16_tuned_gemm*.csvRelated
The same box also needs #4791 (
fix(tuned_gemm): gate skinny GEMM default to archs with a real kernel) for shapes that are still untuned on gfx1250 — without it the skinny fallback selects anassert(false)stub. That fix is independent of this PR and does not overlap.