Repository navigation
cuda: shared device primitives in zig/kernels/cuda/common (#1409, part 1: SASS unchanged) - #1440
Conversation
|
Thanks for starting #1409 with a pure move, and for planting controls that show the comparison can go red. We checked a merge with current main: it is clean, nothing still includes the old paths, Two asks:
A small point: Then we'll run the kernel contract and |
…nged qmm_frag.cuh and glue_math.cuh, already included by 22 and 16 units, move to common/ next to two new headers in namespace tf_common: reduce.cuh (warp_sum and warp_max by xor butterfly 16..1, block_sum_tree and block_max_tree, group_sum8) and vec.cuh (pack8, unpack8). qmm_frag.cuh gains ldmatrix4t, fp4pair and ld_nc. Units drop their own identical copies for using declarations; the train kernels name the block order at their call sites. The Qwen4 generators that read glue_math.cuh's text follow the move. cuobjdump -sass is identical for every function of the 53 images whose units include a changed file (2,880 functions, sm_80/86/89/120/121, base 8c36359). Files in open PRs and files a generator parses keep their copies.
…/ paths, and the units the move edits The move left both pins at the old paths, so test-gradient-serving stopped at FileNotFound. Both now name common/ with the moved files' bytes. The move also edits the include lines of units whose pins matched main: their pins (12 units) and route_rows.cu's approval take the new bytes, so this change adds no pin failure. Main fails the step on its own for 63 other pins (contract_controls.cu first); those are left as they are.
…o revisions Builds every CUDA image whose unit includes a file changed under zig/kernels (the catalog's, and those other build files name, such as h3 and contract_controls), from both trees with their flags for sm_80/86/89/120/121, compares the SASS function by function, and plants two controls (an fp4pair constant and a reversed warp_sum butterfly) that must change functions. --receipt writes each function's digests.
|
Thanks. Pushed
Checks on the head: |
|
Thanks @jschmied for committing the comparison as a tool, and for trying What we checked:
Two asks before we rely on the tool on our side:
Then we'll run the tool ourselves, and the kernel contract and |
…struction's second encoding word
functions() took only instruction lines whose address had four hex digits, so anything from 0x10000 on (past
a function's first 4,096 instructions) was left out of its digest, and it skipped the /* 0x... */ continuation
lines that carry each instruction's second encoding word. It now matches [0-9a-f]{4,} and keeps those lines,
as zig/tests/cuda/oracle/sass_compare.py does. cuda_sass_identity_test.py (python3 -m unittest
cuda_sass_identity_test, from tools/zig) compares a canned dump of two functions that differ only at
0x10000, and only in a second encoding word; both fail before this change.
|
Thanks. Both done, pushed as
Checks on the branch: |
|
Thanks @jschmied, both are done:
On the lone red function: this PR doesn't need an automatic second build, and a follow-up would be welcome. If you add
Next on our side:
|
|
The rebuild follow-up is up as #1532, a draft stacked on this PR: a differing image is rebuilt from both trees one build at a time, a function counts only if it differs again, and a tree whose two builds disagree fails as unstable. |
|
Thanks @jschmied, this is merged. We built every CUDA image for main and for this branch at sm_121 and sm_80 and compared |
…rp_sum, SASS unchanged The three remaining float warp_sum copies (xor butterfly 16..1) give way to common/reduce.cuh through a using declaration, as in ashhart#1440. qwen4_gdn.cu is the checked-in text Gdn.cuda generates from flashnext_gdn.cu (source_test), so both change together. qwen4_gdn_cuda_host.zig, which builds that text for the CPU, now strips the include and the using declaration instead of the deleted function. flashnext_gdn.cu's gradient-serving pin takes the new bytes; flashnext_batch.cu's two pins already differ on main and are left as they are. cuobjdump -sass is identical for every function of the three images (65 functions, sm_80/86/89/120/121) with nvcc 13.0 and 13.2, base prims-1409.
|
Thanks @jschmied: the shared CUDA headers shipped in TensorFold 1.1.9. |
…rp_sum, SASS unchanged The three remaining float warp_sum copies (xor butterfly 16..1) give way to common/reduce.cuh through a using declaration, as in ashhart#1440. qwen4_gdn.cu is the checked-in text Gdn.cuda generates from flashnext_gdn.cu (source_test), so both change together. qwen4_gdn_cuda_host.zig, which builds that text for the CPU, now strips the include and the using declaration instead of the deleted function. flashnext_gdn.cu's gradient-serving pin takes the new bytes; flashnext_batch.cu's two pins already differ on main and are left as they are. cuobjdump -sass is identical for every function of the three images (65 functions, sm_80/86/89/120/121) with nvcc 13.0 and 13.2, base prims-1409.
…rp_sum, SASS unchanged The three remaining float warp_sum copies (xor butterfly 16..1) give way to common/reduce.cuh through a using declaration, as in #1440. qwen4_gdn.cu is the checked-in text Gdn.cuda generates from flashnext_gdn.cu (source_test), so both change together. qwen4_gdn_cuda_host.zig, which builds that text for the CPU, now strips the include and the using declaration instead of the deleted function. flashnext_gdn.cu's gradient-serving pin takes the new bytes; flashnext_batch.cu's two pins already differ on main and are left as they are. cuobjdump -sass is identical for every function of the three images (65 functions, sm_80/86/89/120/121) with nvcc 13.0 and 13.2, base prims-1409.
…_frag.cuh goes, SASS unchanged Step 5 of ashhart#1409. glm_qmm_frag.cuh was a copy of qmm_frag.cuh's device code from before ashhart#1440 (its header names a gen_copies.py that is no longer in the tree): the same namespace qmm_frag, the same cp.async (cp16, cp16z, cp8, cp4, commit, wait), ldmatrix, mma, nibble and swizzle helpers, and fewer of them. common/qmm_frag.cuh is a superset (it adds ld_nc, ldmatrix4t and fp4pair, which glm_mm.cu does not call), so glm_mm.cu, its only user, includes that instead.
…_frag.cuh goes, SASS unchanged Step 5 of #1409. glm_qmm_frag.cuh was a copy of qmm_frag.cuh's device code from before #1440 (its header names a gen_copies.py that is no longer in the tree): the same namespace qmm_frag, the same cp.async (cp16, cp16z, cp8, cp4, commit, wait), ldmatrix, mma, nibble and swizzle helpers, and fewer of them. common/qmm_frag.cuh is a superset (it adds ld_nc, ldmatrix4t and fp4pair, which glm_mm.cu does not call), so glm_mm.cu, its only user, includes that instead.
What
First step of #1409. Pure refactor: no kernel changes its code.
cuobjdump -sassis identical for every function of every image that includes a touched file.Directory. The two headers that were already shared move to
zig/kernels/cuda/common/, the layout the HIP backend already uses (zig/kernels/hip/common/):qmm_frag.cuh(22 includers): cp.async, ldmatrix, bf16 mma, nibble decoding, swizzle. Its first line pointed atzig/tests/cuda/copies.py, which left the tree with the Python engine; it now says what the header holds.glue_math.cuh(16 includers): the exact scalar math with a host twin inglue_math.zig.qwen4_ple_cuda_host.zig(embed path, the include it strips) andhybrid_ple_source.zig(the include it emits).New headers, namespace
tf_common:common/reduce.cuh:warp_sumandwarp_max(xor butterfly, 16 down to 1);block_sum_treeandblock_max_tree(each warp's butterfly, then one more butterfly over the warp results);group_sum8(a thread's 8 values in order, then 8 lanes in a fixed tree).common/vec.cuh:pack8/unpack8, eight bf16 values in one 16-byte word.Added to
qmm_frag.cuh:ldmatrix4t(x4 .trans),fp4pair(e2m1 pair to bf16),ld_nc(16-byte non-allocating global load).Copies removed. Each unit drops its own definition for a
usingdeclaration and keeps its call sites, except the train kernels, whoseblock_sum/block_maxcalls now name the order (block_sum_tree,block_max_tree).warp_sumglue_math.cuh's own copywarp_maxblock_sum_tree/block_max_treetrain_mixers.cuh)pack8/unpack8/group_sum8ldmatrix4twindow_rows.cuh,flashnext_attn.cu)fp4pair,ld_ncqmmf.cu,drama3_fp8.cu67 files, +542 / −483: 65 under
zig/(+274 / −483), plus the SASS tool and its test.Tool.
tools/zig/cuda_sass_identity.py BASE HEADbuilds every catalog image whose unit reaches a file changed between two revisions, from both trees with each tree's flags, and comparescuobjdump -sassfunction by function;--receiptwrites the digests, and two planted controls must go red.tools/zig/cuda_sass_identity_test.pyis its test.Left alone on purpose
prefill_attention.cu,qwen35_attn_tc.cuh,prompt16.cu,nvfp4_experts.cu,fp8_experts.cu,norms.cu.flashnext_gdn.cu,flashnext_batch.cu,flashnext_hc.cu, theqwen4_*units, andflashnext_attn.cu'sblock_sum.h3.cuhas the same order, but itsh3_normdid not compile to the same SASS through a shared function, so it keeps its own.block_sumandblock_max, the double-precision deepseek copies) and the precision-bearing helpers (sigmoid/silu/softplus onexpfvstf_exp,inv_rms). These wait on the nemotron CUDA: RMSNorm rows run on the shared norms and combine (#548, step 1) #1353 rule.bfin some files andrbfin others, andbfmeans widening in others still, so it needs call-site renames. That is a separate PR.Verification
tools/zig/cuda_sass_identity.py db3fd5aba b6ea38468(current main against its merge with this branch), nvcc 13.0.88: every image whose unit includes a changed file, 53 images (the catalog's plush3andcontract_controls) with 2,890 functions, built with the build's flags for sm_80/86/89/120/121. 0 changed, 0 added, 0 removed functions in every image; exit status 0. The digests cover every instruction line at any address width and each instruction's second encoding word. Receipt: one row per image, arch and function with both SHA-256 digests.fp4pairconstant (common/qmm_frag.cuh) changes 52 functions in 1 of the 26 images that include it (qmmf);warp_sumbutterfly (common/reduce.cuh) changes 580 functions in 24 of the 34 images that include it.zig build test -Dnvcc=/usr/local/cuda/bin/nvcc: RC 0, 0 errors.python3 -m unittest cuda_sass_identity_test(fromtools/zig) compares a canned dump of two functions that differ only at address0x10000, and only in a second encoding word. Both cases fail with the tool's first version.Conflicts: #1353 and #1354 delete
nemotron_norms.cu, whose#includeline this PR rewrites. Whichever lands second drops the file; nothing else conflicts with an open PR.Part of #1409.