perf: whole-grid batches, early reject on element 0, precomputed nonce direction (+2.9% on beast) #26
Reference in New Issue
Block a user
Delete Branch "perf/scheduling"
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?
The scheduling leads left after #23, each measured with three interleaved rounds and parity on every host (quantus/miner#3).
Batches of whole grids (host). The CLI's 1M-nonce batch filled a 5090 eleven waves deep with a half-empty tail wave and paid the launch gap every 1M hashes. Batches are now rounded up to a multiple of the grid (SMs x threads per SM), two grids per batch by default so each thread loops over two nonces: beast +1.6% for one grid, +0.4% more for two; benjy +0.5% for the second grid; quadbrat neutral. A batch is ~10 ms on every card, so a job switch discards ~0.1% of a block interval.
MINER_CUDA_BATCH_ALIGN=0restores the CLI batch,MINER_CUDA_BATCH_WAVESsets the minimum grids per batch.LAIR_EARLY_REJECT(kernel). The second permutation stops before its last external linear layer; output 0 alone (the hash's top 64 bits) is computed and compared with the target's top words, and only the ~2^-47 of nonces that survive pay for the other eleven outputs and the canonicalisation. +0.6%.LAIR_NONCE_DIR(host + kernel). The host computes the state after the first external layer and round constant for the batch's first nonce (first_layer_after_absorb, in canonical arithmetic, with a unit test that the matrix column the kernel assumes is[1,1,3,2,2,2,6,4,1,1,3,2]). The kernel derives each nonce's state as that base plus a scalar (the byte-swapped low limb difference) times that column viagf_mul_add, twelve fused multiply-adds instead of the absorb and full layer. Nonces past a carry out of the low limb take the old path. +0.25% on beast, +0.6% on the 4090 and 3060. The uniform block grows from 224 to 320 bytes.Tried and rejected: 512-thread blocks (-0.4%; the
LAIR_TPB/MINER_CUDA_THREADS_PER_BLOCKknob stays for experiments), a smaller grid viaMINER_CUDA_THREADS_PER_SM=16384(-0.6%), a larger one at 65536 (within noise of two waves), and the whole x^7 S-box as one PTX block, which compiles to byte-identical SASS (noted in a comment ongf_sbox).Measured, final tree vs the deployed #23 build:
Parity: 2000/2000 on beast with the final build, 500/500 and 300/300 on the intermediate builds on beast, benjy and quadbrat. Static: sm_120 21,120 instructions, 110 registers, no spill; sm_86/89 22,968 instructions, 80 registers with an 8-byte spill that did not show on hardware.
Where this leaves the gap to the pool binary: instruction parity, ~6% of cycles per nonce on the 5090 that the profiler attributes to scheduling and the power envelope. No further scalar lever is known; the voltage/frequency curve is the remaining host-side one.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Ue5ZZm1Hiv5zPnucykKKuF
quantus-bench
2e6fce162eon benjy.hanzalova.internaltotal median: 709.92 MH/s (batch 1000000, 5 x 30s, engine gpu-cuda)
--- resume miner ---
active