Tune SM103 fused 4-bit GEMM SIMT dispatch - #2054
Open
heiheiha798 wants to merge 3 commits into
Open
Conversation
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
M <= 5shapes from three up to, but not including, four output-tile waves.M >= 6shapes, and on every non-SM103 architecture.--build-root, supports native or official-wheel-compatible CUDA targets, and records interleaved CUDA-event samples as JSONL.Fork issue: heiheiha798#3
Problem and design
The internal dispatch in
csrc/gemm_4bit.cuhad no SM103-specific SIMT/MMA calibration. Direct forced-path measurements on a 148-SM B300 show a stable, dtype-independent SIMT region for public fused tall-KM=4,5calls at the start of the third output-tile wave. Later-wave validation found a mixed result at exactly four waves and a clear MMA win at eight waves, so the final predicate is deliberately bounded:This changes no kernel math, public API, Python top-level dispatch, wheel target, dependency, or non-SM103 branch. At four and later waves the candidate retains the upstream MMA decision. The benchmark's forced-path edits exist only in temporary source trees and do not ship as an API.
B300 performance
Native-SM103 calibration used baseline job 4821 at
95f9af309d4d5793847169c39288dcd3fcbdf564and candidate job 4829 atdc7eff3e7cfc2adc61874c82d494da897f09ae9f. It covered the 148/296/444-block boundaries, real projection controls,M=3..8, and FP16/BF16. Those native results established the initial three-wave target region.Final job 4851 validated commit
7d9c98730d6d483f43e39d3af140a89498943953using the official CUDA 13 x64 wheel target input75;80;86;89;90;100;120, which CMake expanded to75-real;80-real;86-real;89-real;90-real;100-real;120. Each path used 20 warmups followed by 7 rounds of 100 CUDA-event samples, with variant order rotating for every sample. Values below are p10 / median / p90 milliseconds from job 4851; old path is forced MMA.All seven round-median SIMT/MMA ratios remain below 0.95 for every three-wave target. Across FP16/BF16, the overall ratios are 0.663-0.675 for
M=4and 0.891-0.907 forM=5.The same job directly checks why the upper bound is required:
The final automatic dispatch chooses SIMT at 444/445 blocks and MMA at 592/1184 blocks, with adjacent
M=6controls also on MMA. Automatic median latency matches its selected forced path within 0.11% over all 24 cells. The conservative common upper bound intentionally forgoes the isolatedM=4win at exactly four waves instead of introducing an M-dependent special case.Job 4837, run at the pre-bound commit
187e4e4faa4d62ba060b0e7ec461ec134b8c2d9c, provided the decision-changing compatible-path evidence that led to this upper bound. Job 4834 is only a pre-build wrapper failure caused by passing already-suffixed CMake targets; it produced no benchmark data and is not performance evidence.Reproduce
Run the following inside a one-GPU B300/SM103 Slurm allocation from a clean checkout.
--build-rootmust not already exist.python benchmarking/gemm_4bit_sm103_simt_mma.py \ --output /tmp/bnb-sm103-compatible-range.jsonl \ --build-root /tmp/bnb-sm103-compatible-range-build \ --compute-capability '75;80;86;89;90;100;120' \ --warmup 20 \ --repetitions 100 \ --rounds 7 \ --case wave3_at_tall:28416:32768:4,5,6 \ --case wave3_above_tall:28480:32768:4,5,6 \ --case wave4_tall_k49152:37888:49152:4,5,6 \ --case wave8_tall_k81920:75776:81920:4,5,6 \ --dtype fp16 \ --dtype bf16Omitting
--compute-capabilitybuilds native SM103 by default. The default grid also includes the 148/296/444-block boundaries, 11008x4096 and 14336x4096 projections, and a 128256x4096 vocabulary projection. The CLI requires exactly one visible B300 with CC 10.3 and records complete samples, round medians, p10/p90, correctness, commit, job, GPU, and software metadata. All three builds and the automatic package import are isolated below--build-root; the checkout library is not overwritten.Correctness and checks
Job 4851 identity: NVIDIA B300 SXM6 AC, CC 10.3, 148 SMs, driver 580.126.09, CUDA compiler 13.0.88, PyTorch 2.13.0+cu130, Python 3.12.3.
7d9c98730d6d483f43e39d3af140a89498943953.dc7eff3e7cfc2adc61874c82d494da897f09ae9f; they are regression evidence, not exact-head temporary-library validation. The 5 focused cases exercise the 444-block target wheredc7eff3and the final bounded predicate select the same paths. A rerun is unnecessary because the exact-head public automatic benchmark above directly loads and path-checks the final temporary library and covers every changed and restored boundary.BNB_TEST_DEVICE=cuda pytest -vv tests/test_ops.py -k gemm_4bit_sm103_tall_k_dispatch: 5 passed using thedc7eff3checkout native artifact.BNB_TEST_DEVICE=cuda pytest -q tests/test_ops.py -k 'test_gemm_4bit and not sm103_tall_k_dispatch': 100 passed using thedc7eff3checkout native artifact.BNB_TEST_DEVICE=cuda pytest -q tests/test_functional.py -k matmul_4bit: 1153 passed using thedc7eff3checkout native artifact.BNB_TEST_DEVICE=cuda pytest -q tests/test_autograd.py -k matmul_4bit: 384 passed using thedc7eff3checkout native artifact.tests/test_ops.pycollection: 392 tests collected without a CUDA import/collection failure; the 5 SM103 cases skip as intended.pre-commit run --all-files: all 10 hooks passed at the exact final head.git diff --checkpassed at the exact final head.Raw workspace evidence:
benchmark-evidence/cycle2/slurm-4821-simt-mma.outbenchmark-evidence/cycle2/sm103-simt-mma-job-4821.jsonlbenchmark-evidence/cycle2/slurm-4829-candidate.outbenchmark-evidence/cycle2/sm103-candidate-job-4829.jsonlbenchmark-evidence/cycle2/slurm-4834-compatible-range.out(pre-build failure, not evidence)benchmark-evidence/cycle2/slurm-4837-compatible-range.outbenchmark-evidence/cycle2/sm103-compatible-range-job-4837.jsonlbenchmark-evidence/cycle2/slurm-4851-compatible-range.outbenchmark-evidence/cycle2/sm103-compatible-range-job-4851.jsonlLimits and risk
M=4opportunity unused in order to keep one maintainable, dtype-independent rule with no adjacent regression.dc7eff3checkout native artifact; exact-head binary correctness comes from the path-asserted 24-cell public automatic benchmark, not those pytest counts.Tracking