Add non-TMA MXFP8 cast-only kernels for specialized rowwise-only and row+colwise - #3459
Draft
tdophung wants to merge 1 commit into
Draft
Add non-TMA MXFP8 cast-only kernels for specialized rowwise-only and row+colwise #3459tdophung wants to merge 1 commit into
tdophung wants to merge 1 commit into
Conversation
…sional
The specialized cast-only path currently stages its tile: the rowwise kernel
through shared memory, the bidimensional one through a TMA pipeline. For a
cast with no bias or activation there is nothing to stage for -- the tile is
read once and consumed immediately -- so both can be done entirely in
registers instead.
Adds two kernels under cast/mxfp8/specialized/:
cast_rowwise.cu Two lanes cooperate on each 32-element MX block, a lane's
half being exactly one 256-bit load. No shared memory and
no barrier at all; the tensor is a flat sequence of
independent MX blocks whenever the scale array is packed.
cast_bidim.cu A CTA owns a 32-row band, which is exactly the colwise
block height, so the colwise reduction closes inside the
CTA and the tile drives both passes from registers. Shared
memory is used only for the cross-warp column fold.
Both pick their launch configuration from a documented size-tier table and use
L2 eviction policies plus a software prefetch one resident CTA-wave ahead.
New PTX wrappers in util/ptx.cuh, none of which had a TE equivalent: L2
cache-policy creation, 256/128-bit non-coherent loads and 128/64/8-bit stores
carrying a policy, an L2 prefetch, a packed BF16 reciprocal-scale helper, and
a mul_cvt_4x overload taking two BF16 pairs with independent scales, which the
colwise pass needs since every column pair has its own scale.
Dispatch routes to these kernels for BF16 input with a packed scale layout,
and falls through to the existing kernels otherwise. hasSpec already
establishes cast-only, so no further condition on the fused-op flags is
needed. FP16 input and GEMM-swizzled scale layouts are not yet covered and
remain on the existing path.
Measured on GR10x (CC 10.7, CUDA 13.4), medians of 20 with the clocks warmed:
rowwise, geomean over 12 small shapes 10.949 us -> 9.913 us
rowwise, geomean over 6 standard shapes 19.411 us -> 17.934 us
bidimensional, geomean over 6 shapes 29.595 us -> 25.730 us
The margin narrows as the shapes grow and the kernels become DRAM-bound; at
65536x16384 rowwise reaches 89% of peak DRAM throughput, where little headroom
remains for anyone.
Registers drop from 48 to 24-30 (rowwise) and from 70 to 46-64 (bidimensional),
with occupancy rising correspondingly.
All 1541 MXFP8 tests in tests/cpp/operator pass. qa/format.sh is clean.
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
I think this needs correctness regression coverage before the new kernels become the default dispatch for these shapes.
Could we compare the new path against the existing MXFP8 implementation for at least rowwise and bidimensional scaling, including boundary/alignment cases and a padded rowwise scale stride?
Since the change also introduces new scale arithmetic and PTX helpers, coverage for zero, Inf/NaN and both supported FP8 output formats would be particularly useful. Performance measurements look good, but currently a numerical regression would have no dedicated test catching it.
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.
Description
The specialized cast-only path currently stages its tile: the rowwise kernel through shared memory, the bidimensional one through a TMA pipeline. For a cast with no bias or activation there is nothing to stage for, the tile is read once and consumed immediately, so both can be done entirely in registers instead.
Adds two kernels under
cast/mxfp8/specialized/(NOTE: both of these has been adapted from the winning kernel in Kernel Factory to work in TE, after some suggestions to KF on where I think the bottleneck is)cast_rowwise.cu
Two lanes cooperate on each 32-element scaling block, each lane's half being exactly one 256-bit load. No shared memory and no barrier at all; the tensor is a flat sequence of independent scaling blocks whenever the scale array is packed.
cast_bidim.cu
A CTA owns a 32-row band, which is exactly the colwise block height, so the colwise reduction closes inside the CTA and the tile drives both passes from registers. Shared memory is used only for the cross-warp column fold.
Both pick their launch configuration from a documented size-tier table and use L2 eviction policies plus a software prefetch one resident CTA-wave ahead.
New PTX wrappers in
util/ptx.cuh:Dispatch routes to these kernels for BF16 input with a NON-SWIZZLE scale layout only, and falls through to the existing kernels otherwise. FP16 input and GEMM-swizzled scale layouts are not yet covered.
Measured on GR10x (CC 10.7, CUDA 13.4), medians of 20 with the clocks warmed:
rowwise, geomean over 12 small shapes (up to M_size = 4k) 10.949 us -> 9.913 us
rowwise, geomean over 6 standard shapes (M_size = 16k - 64k) 19.411 us -> 17.934 us
bidimensional, geomean over 6 shapes (M_size 8k - 64k) 29.595 us -> 25.730 us
The margin narrows as the shapes grow and the kernels become DRAM-bound; at 65536x16384 rowwise reaches 89% of peak DRAM throughput based on NCU.
Registers drop from 48 to 24-30 (rowwise) and from 70 to 46-64 (bidimensional), with occupancy rising correspondingly.
Fixes # (issue)
Type of change
Changes
See in description
Checklist: