Parallelize the two dominant bitwise-histogram sources internally#794
Conversation
The bitwise multiplicity phase ran each source as one atomic collector across a capped par_chunks, so the two dominant sources — the in-walk lookups and MEMW_R (each tens of millions of items) — each pinned a single core while the rest idled, and the in-walk fold ran serially before the parallel region. Split those two sources into ~cap row-range slices and round-robin every unit (whole collectors + the heavy slices) into exactly cap buckets, one 80 MiB histogram each. Peak memory is unchanged (still cap concurrent histograms), but the heavy work is now spread across buckets instead of piled onto one core, and the in-walk fold moved into the parallel region. add_ops/bump/merge form a commutative monoid, so multiplicities are byte-identical (prove+verify pass). PAGE is left whole for now; if it becomes the bottleneck it can be sliced the same way in a follow-up.
Measured on a 16C/32T CPU box (125 GiB RAM), ethrex 5-transferPhase-level (
→ ~10% off the phase (~91 ms), distributions barely overlap, no regression. End-to-end (ABBA, 32 pairs, same box): median −0.27%, mean −0.17%, 95% CI [−0.54%, +0.19%], Wilcoxon p=0.26 — inconclusive end-to-end because the phase is only 2.7% of prove time on CPU. The 91 ms saving / 33.2 s prove = 0.27%, which matches the ABBA median exactly — the two instruments agree, the effect is just small on CPU. Why this still matters: on GPU the FFT/Merkle/LDE move to the device but trace-gen stays CPU work, so the bitwise phase is a much larger share of end-to-end there — the same ~10% phase cut should land around ~1% end-to-end. That's the configuration worth measuring before merging. Cap note: the phase is memory-bandwidth-bound (random writes into 80 MiB histograms) — splitting across 8 buckets recovered ~10%, not ~8×, so raising the Correctness unchanged: full |
baa9e73
into
perf/tracegen-cpu-optimizations
Follow-up to #786's review (efficiency finding #6). Perf-only change — meant to be ABBA'd against
perf/tracegen-cpu-optimizationsbefore merging.Problem
The bitwise multiplicity phase (
p4_bitwise_collect) ran each source as one atomic collector over a cappedpar_chunks. The two dominant sources — the in-walk lookups and MEMW_R, each tens of millions of items — therefore each pinned a single core while the other cores finished their trivial chunks and idled;par_chunksis static/contiguous so rayon can't work-steal into the busy chunk. The in-walk fold also ran serially before the parallel region opened.Change
caprow-range slices (cap = min(threads, 8)).capbuckets, one 80 MiB histogram each, thenpar_iter().map(fold).reduce_with(merge).Peak memory is unchanged (still ≤
capconcurrent histograms — same as the previouspar_chunks(≤8)cap); the heavy work is just spread across buckets instead of piled onto one core.add_ops/bump/mergeform a commutative monoid, so multiplicities are byte-identical regardless of partition.PAGE is left whole for now; if the ABBA shows it's the new bottleneck it can be sliced the same way in a follow-up.
Correctness
cargo test -p lambda-vm-prover --lib: 502 passed (only the 5 known missing rust-guest ELF fixtures fail, at file-read). The prove+verify tests passing is the real check — a wrong multiplicity would unbalance the BITWISE bus and fail verification.make lint,cargo clippy --all-targets,cargo fmt --checkall clean; bothparalleland--no-default-features(serial) paths compile.Expected
Should shrink
p4_bitwise_collectwall time (the MEMW_R slice was ~1–2 s single-core at 10-tx); most visible on GPU where trace-gen is a larger share of prove time. Please ABBA on the CPU and GPU paths before merging — if it doesn't move the needle, it's fine to close.