Repository navigation
hip exl3: the input rotation and trellis linear for decode rows, under the kernel contract - #3314
Open
Shoestring-dev wants to merge 1 commit into
Open
Shoestring-dev wants to merge 1 commit into
Shoestring-dev wants to merge 1 commit into
Conversation
…r the kernel contract A new HIP group, exl3/exl3.hip: tf_exl3_rot_in (x * suh rotated by 128 and rounded to fp16, CUDA's rot_in arithmetic) and tf_exl3_linear at 2, 3, 4, 5, 6 and 8 bits (mul1) on 4 and 8 waves, the HIP side of what deepseek_v41's CUDA path calls tensorfold_exl3_linear_v4.rot_in and .linear. A row's sums are v_dot2_f32_f16 chains whose bits do not depend on the rows sharing its launch; the waves' sums and the output rotation follow CUDA's finish. Nothing launches them outside their tests yet. Kernel tests: the decoded weights against exl3_format bit for bit at every width, both wave counts and both trellis layouts; a row's bits alone, in any window and in passes of 16; rot_in by its fp32 steps from fp32, fp16 and bf16 rows. Contract: rot_in and the linear at each width against float64 (the linear's gate 4 exact), one control each, and gate-5 records from ROCm 10.1's hipcc.
Owner
|
Thanks @Shoestring-dev. The launch geometry, trellis placement, stable row sums and FP32 barrier before the input's FP16 conversion hold up on review; the portable launch and record checks pass. Your gfx1151 runs cover the new operators and both controls. The full contract's existing
|
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.
What this changes
A new HIP kernel group,
exl3/exl3.hip, adds the HIP side of the single EXL3 projection thatdeepseek_v41's CUDA path calls astensorfold_exl3_linear_v4.rot_inand.linear(exl3_block/linear.cu). It serves the LM head (5120 to 129,280, fp32 logits), Engram'swkv(6144 to 25,600) and the indexer'swk(512 to 128):tf_exl3_rot_in: x times suh, rotated by 128 and rounded to fp16 once. These are CUDA'srot_inoperations in its order: the fp32 product,fwht128's butterflies, then the scale.tf_exl3_linear_k{4,6,8,10,12,16}_w{4,8}: the trellis linear at 2, 3, 4, 5, 6 and 8 bits (mul1, the codebook CUDA launches) on 4 and 8 waves a block.v_dot2_f32_f16chains in a fixed order, so a row's bits do not depend on the rows that share its launch (1 to 16 rows a pass, any number of passes).finish.planwithout a K split. CUDA's emitter refuses a split on this path, so the kernel has none, and it has no bias, because no caller passes one.launches/exl3.zig, with the shapes they refuse (fits,widthIndex) and the wave count (waves) host-tested there.Nothing launches these outside their tests yet. Every HIP build compiles and embeds one more code object: 379 KB and about 3.9 s of hipcc on gfx1151 (the draft group is 39 KB and 0.7 s).
Only the K sums run in another order than CUDA's
mma.m16n8k16. The rotations and the epilogue are CUDA's operations in CUDA's order, so the outputs are held to float64 (below), not to CUDA's bits. The end-to-end token gate against CUDA's serial path stays where #2065 put it: in the TP=2 pull request.deepseek_v41HIP kernel pull request, after the TCP Kind (fabric/tp: a TCP Kind for hosts without RDMA #2718, merged) and its HIP device side (fabric/tp: HIP device side of the TCP Kind #2961). Next come the prompt path (unpackand the prompt tiles, registered bit-equal to this linear, so that prompt rows equal decode rows), then the grouped dense projections and the experts.mainat 93d77e5. One commit, 6750d98. It merges clean onmain222f038, 59 commits later.gh pr list), and withgit merge-treeon each one that shares a code file.launches.zig,kernel_tests.zig,contract_main.zig,hip_records*.zig).zig/build/hip.zig.docs/kernel-contract.md, where this adds a paragraph.Checks on this head
main93d77e5. The suite and the limits ran on this head. The GPU runs used binaries built from a tree identical to this head exceptdocs/kernel-contract.md.python3 tools/pr_check.py --base 93d77e5dareports 0 errors, lean 341 on the base and 341 on this head, 0 new. Its one advisory warning is the Unreleased line, which you write. No comment is past 120 columns, trailing comments included.hip_records.ziggains the file on an existing line and stays at 600 lines.zig build test test-golden -Dhip=truewith ROCm 10.1's hipcc on Linux x86_64 (CPU only): 754 of 754 steps, 10,043 of 10,122 tests pass, 79 skip, exit 0. Onmain93d77e5: 754 of 754 steps, 10,041 of 10,120 tests pass, 79 skip. Both runs print the same 25failed commandlines for passing steps that wrote to stderr.zig build hip-host-test -Dhip=trueon macOS (M4 Pro): 79 of 79 pass. One new host test covers the launches' refusals, the wave counts and the LDS size; a planted fault in it fails it by name.zig build hip-kernel-teston gfx1151: 220 passed, 6 skipped, 0 failed, against 216 passed, 6 skipped, 0 failed onmain93d77e5 (another host of the same model and runtime). The three new tests:core/exl3_format.zig'sunpackdoes, bit for bit. The input is the identity, so each output row is a weight row through the output rotation, and the host repeats the kernel's fp32 butterflies. This runs at 4 waves on the checkpoint's tile layout and at 8 waves on the strips layout.caps.zig'sdot2_signed_zero), so random weights against a zero-padded identity cannot be bit-exact there.rot_in's fp16 rows equal the host's fp32 steps rounded once, from fp32, fp16 and bf16 rows: 391,680 roundings, so a 1-ulp fp32 error shows. Replayed on the host with the test's own inputs, a 1-ulp error in the scale (a division by sqrt(128) for the product) moves 22 of the fp16 outputs, one rounding of x * suh * scale in place of two moves 29, and fp16 products move 168,635. Without the kernel'sopaque()guard, ROCm 10.1's hipcc fuses that product and its fp16 conversion intov_fma_mixlo_f16/v_fma_mixhi_f16(one rounding); with it,v_mul_f32thenv_cvt_f16_f32, as on CUDA.rot_individing by sqrt(128) instead of multiplying by its fp32 scale (a 1-ulp fp32 error): only the rot_in test fails (an fp16 output is 14274 where 14273, one ulp).rot_inwithout itsopaque()guard (one rounding): only the rot_in test fails (15453 where 15454, one ulp).rot_inrounding its products to fp16 before the butterflies: only the rot_in test fails (42438 where 42418).zig fmt --check build.zig zigandgit diff --check: clean.Receipt
n/a for inference: nothing calls these kernels yet. For the same reason there are no token hashes; the pull request that wires
deepseek_v41's HIP lane carries them, and the checkpoint needs TP=2 across two boxes.main's HIP records hold.kernel_tests/exl3.zigand the contract.Kernel contract
zig/tests/hip/contract_exl3.zig). None replaces a kernel, so each is held to float64:tf_exl3_rot_in, bf16 rows to fp16: within float64's bound at depth 8 (the product and seven butterflies). Gate 4 follows CUDA'srot_group, inputs to 64: fp32 is not exact on 128-term rotations, so it proves fp16's miss alone.tf_exl3_linearat each of the six widths, fp32 out (the head's), and at 4 bits with bf16 out. Each registration's shapes reach both of its kernels:wkin windows of 16 and 64 rows and at one row (4 waves);wkvat 4 rows (8 waves);fmt.rotatescales each term first and leaves up to 5e-9 there, which the exact-sum bound would count against the kernel's exact zeros.tf_exl3_rot_inreads the next block's suh: red at gate 3 (at 64 x 512 x 128, output 0 is 2,447 times its bound).tf_exl3_linearreads its input rows one row late: red at gate 3 (at 16 x 128 x 512, output 0 is 235 times its bound).hip-kernel-contracton gfx1151 at 6750d98:SUMMARY gfx1151 169 kernels: 169 pass gates 1-4, 0 fail, 2 known findings; 44 controls: 44 red as planted, 0 missed; 1 limit problems; gates 444983 ms, limits 2447 ms. The exit status is 1, from the one limit problem.main93d77e5 on another host of the same model and runtime:SUMMARY gfx1151 161 kernels: 161 pass gates 1-4, 0 fail, 2 known findings; 42 controls: 42 red as planted, 0 missed; 1 limit problems; gates 429664 ms, limits 2425 ms. The same limit problem:tf_moe_combine_gate, launched at 256 threads where the runtime allows 1,024.rot_in: 256 non-finite and 3840 finite outputs match float64's classes. Its 7 shapes are within float64's bound, worst 0.993 of it. Gate 4: fp16 sums would miss 250x and bf16 912x.main's take 429.7 s and 438.4 s on two other hosts of the same model and runtime to the gates.reference_threads, asaffine.zigdoes, in each output's K order. They are bit-identical to the one-thread reference on the shapes I compared.hip-kernel-contract-limitswith ROCm 10.1's hipcc (no GPU), at 6750d98: all 52 new lines (13 launches on 4 chips) readrecord current. The run reportsFAIL kernel-contract-limits: 3 problems, the same 3 asmain93d77e5:tf_moe_combine_gate's records are stale on gfx1030, gfx1100 and gfx1151.The linears use 205 to 227 VGPRs, 43 to 46 SGPRs, no scratch, 2 to 16 KiB of static LDS, and at most 32 KiB of dynamic LDS (the waves' sums for 8 rows).
rot_inuses 16 VGPRs and no LDS.The records are in
hip_records_exl3.zig, andhip_records_families.zig's count test lists them. TheRECORDlines, in the order gfx1030, gfx1100, gfx1151, gfx1201:Known limits
Checklist
"draft": false, a resumed prompt equals a fresh one, and concurrent equals solo. (No served path changes.)