Repository navigation
Conversation
amax_kernel gave each thread a single 32-byte load and then retired the whole CTA through a reduction and an atomic, so it was latency-bound well under half of DRAM bandwidth. Replace it with a persistent kernel: a grid sized to fill the GPU once strides over the tensor issuing four independent 32-byte loads per lane per iteration, and every CTA commits once. 16-bit inputs fold with packed abs-max on SM 8.9+. Elements before the first and after the last 32-byte boundary are read one at a time, so any alignment and size is served by the same kernel. The maximum of |x| is exact and order-independent, so results are bit-identical to the old kernel. This is the first pass of every NVFP4 quantize and also serves FP8 current scaling. Signed-off-by: Teddy Do <tdophung@nvidia.com>
Add a register-resident BF16 -> NVFP4 1D quantize kernel and dispatch to it ahead of quantize_transpose_tuned_1D for every request it supports: rowwise or rowwise + columnwise output, round-to-nearest or stochastic rounding, E4M3 or UE5M3 scales, with or without the global amaxes and the noop flag. Row- scaled NVFP4, fast math, GEMM-swizzled scales, the columnwise-RHT path and tensors past the kernel's grid limit keep using tuned_1D. No specialization stages the input through shared memory or TMA. The rowwise-only one streams each 16-element block from one 32-byte load; the fused one reads every row twice, once per direction, with the second read served by L2, and stages only the transposed output. The per-block coefficient depends only on the block's scale byte, so its IEEE divide is computed once per CTA into a table. The scale arithmetic is TE's own, so round-to-nearest output is byte-identical to tuned_1D. Stochastic rounding draws Philox once per output block, with a subsequence built from the block's coordinates and direction. Each draw is exactly what curanddx returns for the same key and counter, and the round count follows NVTE_BUILD_NUM_PHILOX_ROUNDS; builds with fewer than 3 rounds keep tuned_1D for stochastic rounding. The random bits for a given seed differ from tuned_1D's, whose stream is keyed by thread id. The tiling was tuned on B200. Its tuning constants are gathered in TunedConfig, and the occupancy queries the launch heuristics use are cached per device. Add a rowwise_only parameter to the NVFP4 cast test, which before only ever requested both directions, and test_cast_nvfp4_sr_streams.cu, which checks the generator against curanddx, that every block gets its own subsequence, and that the rowwise and columnwise draws are independent. Signed-off-by: Teddy Do <tdophung@nvidia.com>
This branch has not been deployed
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
Applies to NVFP4 1D quantization the optimization #3459 made for MXFP8 cast-only quantization: load the input straight from global memory into registers (G2R) instead of staging it through shared memory with TMA. The new kernel serves BF16 input for rowwise and rowwise + columnwise output, with round-to-nearest or stochastic rounding and E4M3 or UE5M3 scales. Requests it does not cover keep using
quantize_transpose_tuned_1D: row-scaled NVFP4, fast math, GEMM-swizzled scales, the columnwise RHT path, and tensors past the kernel's grid limit.The CuTeDSL counterpart of this kernel is a separate draft PR, #3809.
Points for discussion:
tuned_1D's, whose stream is keyed by thread id. SR output stays unbiased and statistically equivalent, but it is not bitwise reproducible against main. Round-to-nearest output is byte-identical to main.Type of change
Changes
quantize_transpose_nvfp4_register_1D.cuh: a register-resident BF16 -> NVFP4 1D quantize kernel, dispatched ahead ofquantize_transpose_tuned_1Dfor every request it supports.nvfp4_block_philox.cuh: per-block Philox for stochastic rounding. The number of rounds followsNVTE_BUILD_NUM_PHILOX_ROUNDS; builds with fewer than 3 rounds keeptuned_1Dfor stochastic rounding.recipe/current_scaling.cu: the amax kernel becomes persistent. Each lane keeps four 32-byte loads in flight, 16-bit inputs use packed abs-max on SM 8.9+, and any alignment is supported.util/ptx.cuh,util/ptx_arch_spec.cuh: new PTX helpers.rowwise_onlyparameter fortest_cast_nvfp4_transpose.cu, which previously always requested both directions.test_cast_nvfp4_sr_streams.cu, which checks three things: the generator matches curanddx, every block gets its own subsequence, and the rowwise and columnwise draws are independent.Results (GB200, ncu kernel time, BF16 randn, E4M3 scales, cold L2)
Speedup over main. Shapes run from 1024x1024 to 32768x16384, and the larger speedups are at the smaller shapes.
Testing
test_operatorwith--gtest_filter='OperatorTest/FusedCastTransposeNVFP4*:OperatorTestUE5M3/FusedCastTransposeNVFP4*:*StochasticRoundingStreams*': 198/198 passed.Checklist: