Skip to content

DeroStorm 1.5.5 - The GPU stops waiting

Choose a tag to compare

@Notoriousjoshyb Notoriousjoshyb released this 30 Aug 20:34
· 9 commits to main since this release

The GPU stops waiting. A batch pipeline so the card is never idle between launches, and a scatter that writes coalesced instead of a word at a time — 119,463 H/s on an RTX 5080 against 100,640, and 153.9 – 154.7 KH/s with the CPU mining beside it.

The card was waiting for a CPU

Taking two CPU mining threads away made the GPU faster, which should not happen: the threads and the card share nothing but a job. With every logical CPU busy the GPU ran at 106,429 H/s against 111,247 with the CPU idle, and the run-to-run spread went from 1% to 4.5%.

It is not the clocks — nvidia-smi reports 2,865 MHz either way at the same temperature. It is not the kernels — profiled with nsys, suffix_kernel takes 227 ms a batch whether the CPU is idle or saturated. The card was idle between batches, waiting for the one host thread that enqueues the next one to get a scheduler slot behind sixteen pinned mining threads that never yield.

The miner now keeps a second batch queued behind the running one, so the card starts it the instant the first ends and the host's wake-up happens with a whole batch of slack. Both batches ride one stream and share the same scratch; all the second slot costs is a few hundred bytes.

nonces per batch before after
32,768 (default) 106,429 H/s 112,548 H/s +5.7%
4,096 55,504 H/s 72,728 H/s +31%
1,024 17,740 H/s 31,604 H/s +78%

The gap is a fixed cost per batch, so it is a rounding error against a batch that takes 290 ms and it is most of the time against one that takes 30 — which is why --gpu-batch, sold as a job-latency knob, was quietly also a throughput one. It is not any more: with the pipeline the GPU rate no longer depends on what the CPU is doing at all.

The scatter was writing a word at a time

Placing the sorted positions gave a whole descriptor — a run of ~5.7 positions — to one thread, which copied it one word at a time. Neighbouring threads wrote addresses ~23 bytes apart and read arena slots with no relation to each other, so a warp's 32 words cost ~28 memory transactions where 4 would do. It was 26.5% of the suffix kernel, the largest single phase in it.

Driving the loop by output position fixes the writes completely — output position q always lands at sa[q], so a warp writes 32 consecutive words. Finding which descriptor owns q is done by walking descriptors rather than output tiles: a window of 256 descriptors is read once, coalesced, into shared memory, and the ~1,460 output positions it covers are written from it.

suffix ms
before 140.9
one thread per output position 136.7
two barriers a tile, not three 135.1
by descriptor window, not output tile 129.9

Both merges lose their gather loop as well — the positions are already where they want them. suffix_kernel is 226.4 → 207.2 ms a batch, and the run-to-run spread fell from ±5% to ±0.3%.

Headline

1.5.5 1.5.0
RTX 5080, --bench 119,463 H/s 100,640 +18.7%
CPU + GPU, real mining path 153.9 – 154.7 KH/s 130.4 – 131.8 +17.6%

Hashes are bit-identical to the CPU. gpu/hash_parallel_test.exe matches all 512 reference vectors, and the miner still re-verifies the device against the CPU before it will submit anything.

What did not work

With the scatter fixed the column walk is the largest phase again, and most of it is threads doing nothing: the walk's slowest thread takes 1.98× the average, so a perfectly balanced walk would cost half of what this one does. Two ways to collect that were built, measured and thrown away — cutting the runs shorter is four times slower at every cap, and splitting the columns unevenly landed within noise of the flat split across five threshold settings. Both are written up in gpu/desc.cuh and the README so nobody tries them blind. BR_BITS, DESC_CHUNKS, DESC_MERGE_WIDE, DESC_CMP_WORDS and DESC_SPLIT were all re-swept and all stand.

The CPU row of the headline table reads 32,640 H/s against 34,293 at 1.5.0. Nothing on that path got slower — it is this machine on this day, and it is left as measured rather than carried forward from a better one.

Checksums (SHA-256)

c786dca2467323b71e211a218488296576d5e4cc5dcbe912ad2ebb32f9656a41  derostorm-1.5.5-windows-amd64.zip
a4ee77fef21ec8d6e1e7910a23a45ab6481900a979cd651d6f53c167667b9086  derostorm-1.5.5-linux-amd64.zip
999b37b9b09551f8ae3a1c0be2d8279c3f61bbe98a412717bc506a6c65339d13  derostorm-1.5.5-linux-arm64.zip
75bd9859b080e5d7bdd6a44935dff5600e9e14acea3738224eed804527d10fd3  derostorm-1.5.5-macos-amd64.zip
b22893f3752ef469b431ea1011ef1b69489a3ae58ac6c966661274f4e7d92030  derostorm-1.5.5-macos-arm64.zip