engine-cuda: loop-structured mining_loop kernel, opt-in via MINER_CUDA_KERNEL=loop #29
Reference in New Issue
Block a user
Delete Branch "perf/loop-kernel"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
First step of the rewrite in quantus/miner#27, as a gated path so the deployed kernel is untouched.
What it adds. A second entry point
mining_loopin the same fatbin. It shares every arithmetic primitive withmining_main; the per-nonce body is one template used by both. Its round loops are rolled with the round constants fetched from constant memory by index (the shape of the fastest closed kernel), with its own launch-bound knobs (LAIR_LOOP_TPB,LAIR_LOOP_MINBLOCKS,LAIR_LOOP_INT_PAIR).MINER_CUDA_KERNEL=loopselects it at run time, defaults the block size to 512, and reports kernel idcuda-loopon the per-device metrics; unset keepsmining_mainand thecudaid the deploy validate asserts. No default changes: sm_120mining_mainis still 21,120 instructions at 110 registers, byte for byte.Measured, beast, three interleaved rounds, parity 500/500 on both kernels:
Shapes tried for the loop kernel: 192 registers (one block per SM) 1976, clocks up to 2600 MHz because the card is underfilled; 80 registers 2005 with 424 B of spill; 64 registers 373 to 532 with 716 to 872 B of spill; two internal rounds per iteration 1976 against one at 2105; 256- and 128-thread blocks below 512. On sm_86/89 the loop kernel compiles to 88 registers with no spill where the unrolled one spills 8 bytes; benjy and quadbrat numbers to follow in a comment.
What this says about #27. The loop structure by itself does not lower this arithmetic's register footprint the way the quanpool kernel's is: 64 registers is only reachable with heavy spill. Its loop bodies are 778 / 254 / 789 instructions (external-initial, internal, external-terminal) against their 741 / 199 / 662, so the internal round's diagonal multiply-add is where the instructions are. One attempt at that, folding the whole 64-bit row sum into the first partial product with a carry-out the way their SASS does, measured worse (unrolled 2208 -> 2172, loop internal body 254 -> 268) and was reverted: ptxas does not turn that PTX into their instruction sequence. Next steps happen behind this switch: the round arithmetic as one carry chain with 32-bit halves throughout, screened by the loop body's static count before any bench.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ue5ZZm1Hiv5zPnucykKKuF
benjy and quadbrat, same binary, three interleaved rounds, parity 200/200 on the loop kernel on each:
On the 4090 the 88-register no-spill build runs at a higher clock and wins. So the loop kernel is the better default for benjy today; the switch is per host in the deploy matrix (
MINER_CUDA_KERNEL=loopin its environment,kernel: cuda-loopfor validate), a follow-up once this merges.Second commit (
12bd36a) adds the per-host switch to the deploy matrix:cuda_kernelis rendered into miner.env asMINER_CUDA_KERNEL,kernelstays the id validate asserts. benjy runsloop/cuda-loopon the measurement above; quadbrat and beast stayunrolled/cuda. The earlier bench-workflow failure on this PR (run 67) was the harness refusing a card my own A/B was occupying at that minute, not a build problem.quantus-bench
12bd36aee2on benjy.hanzalova.internaltotal median: 718.48 MH/s (batch 1000000, 5 x 30s, engine gpu-cuda)
--- resume miner ---
active