Skip to content

shuffle: conformance test, GOMAXPROCS-aware fan-out, fork-join cleanup#787

Merged
pk910 merged 2 commits into
masterfrom
qu0b/shuffle-worker-pool
Jul 8, 2026
Merged

shuffle: conformance test, GOMAXPROCS-aware fan-out, fork-join cleanup#787
pk910 merged 2 commits into
masterfrom
qu0b/shuffle-worker-pool

Conversation

@qu0b

@qu0b qu0b commented Jul 3, 2026

Copy link
Copy Markdown
Member

Follow-up on #782, targeting pk910/statetransition-performance.

What's included

  • Spec-conformance test for computeShuffledList against the per-index computeShuffledIndex reference, across sizes spanning the 4096 parallelization threshold (0–20,000). Passes under -race. Also adds a mainnet-scale (1M indices) benchmark. The package previously had no tests for the shuffle.
  • runtime.GOMAXPROCS(0) instead of runtime.NumCPU() for the worker fan-out: NumCPU reports host cores and ignores container CPU quotas and user-set GOMAXPROCS, so the old code oversubscribes in quota'd containers.
  • Fork-join cleanup: wg.Go (Go 1.25+) and a start-stepped chunk loop replace the manual Add/Done + bounds-clamping dance. Removed the dead var _ = binary.LittleEndian guard.

What's deliberately NOT included

A persistent channel-fed worker pool (spawn goroutines once, signal each of the 90 rounds over channels) was implemented and benchmarked as an alternative to per-round goroutine spawning. On the real workload it measured 2–4% slower in every interleaved run pair (mean 147.2 ms vs 142.5 ms per 1M-index shuffle, 16 threads):

spawn-per-round (kept) persistent pool (rejected)
mean 142.5 ms 147.2 ms

The serial source-hash phase between rounds parks the pool workers, and waking 16 parked goroutines via sequential channel sends costs more than spawning fresh ones (the runtime hands new goroutines straight to idle Ps and recycles stacks). A synthetic benchmark without the inter-round serial phase shows the opposite (~10% pool win), which is why this needed measuring on the real code path. Documented in a comment on shuffleRound so it isn't re-attempted.

Benchmark on this branch matches the base branch: ~122–129 ms per full shuffle (AMD 7840U, 8C/16T), ~6.3× over serial.

- Add a spec-conformance test checking computeShuffledList against the
  per-index computeShuffledIndex reference across sizes spanning the
  parallelization threshold, plus a mainnet-scale benchmark.
- Size the worker fan-out by runtime.GOMAXPROCS(0) instead of NumCPU so
  container CPU quotas and user overrides are respected.
- Use wg.Go and a start-stepped chunk loop; drop the dead unused-import
  guard.

A persistent channel-fed worker pool (spawn once, signal per round) was
also evaluated: it measured 2-4% slower than per-round goroutine spawns
because workers park during the serial source-hash phase between rounds
and channel wakeups cost more than fresh spawns. Documented in a comment
on shuffleRound.
Base automatically changed from pk910/statetransition-performance to master July 8, 2026 10:06
@pk910 pk910 enabled auto-merge July 8, 2026 10:09
@pk910 pk910 merged commit 2419a4d into master Jul 8, 2026
5 checks passed
@pk910 pk910 deleted the qu0b/shuffle-worker-pool branch July 8, 2026 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants