perf: parallelize DEEP quotient assembly#9
Merged
Conversation
Replaces the per-shift serial loop in ComputeDeepQuotient with a row-chunked parallel pass that fuses C_s materialisation, denominator inversion, and the DEEP quotient add into a single sweep: deepQuotient[x] += (v_s - Σ_k scales_k · cols_k[x]) / (z_s - ω^x) Three transformations make this fan-out possible: 1. The serial alpha-power chain (alphaAcc *= pr.alpha across columns and shifts) is unrolled up front into a per-column scales slice on each shift bundle, so per-row work has no cross-column dependency. 2. Constant (len-1) columns are folded into a single constContrib term per bundle so the per-row loop only touches real-width columns. 3. Denominators (z_s - ω^x) for the chunk are inverted via ext.BatchInvertE4 (one inversion + 3·chunkLen ext mul, instead of chunkLen ext inversions). The previous DeepQuotientExt helper is no longer reached from the prover and DeepQuotientExt itself becomes dead — kept as it's still exported. Drive-by: ω^shift now uses Element.Exp (binary exponentiation) instead of an O(shift) manual multiply loop. Numbers on the synth shapes (32 cores, KoalaBear + Poseidon2 + blowup 4 + 4 queries), median of 3 runs, applied on top of the step-1 and step-2 PRs: shape (cells) step-1+2 +step-3 speedup tall (2^20 rows × 24) 2.05 s 1.36 s 1.51× wide (2^14 rows × 1536) 0.288 s 0.285 s ~1.01× The wide shape was never DEEP-bound (8% of step-1+2 wall); the win shows up where DEEP assembly dominates. DEEP phase share on tall: 47% → 20%. vs Plonky3 (same shapes, same primitives): shape Plonky3 loom (step-1+2) loom (step-1+2+3) tall 1.56 s 2.05 s 1.36 s (1.15× faster than P3) wide 0.40 s 0.288 s 0.285 s (1.40× faster than P3) prover/bench_deep_quotient_test.go adds BenchmarkProveWide and BenchmarkProveTall so the wide- and tall-shape improvements stay visible in `go test -bench` without depending on the bench/synth command from PR #7. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR parallelizes DEEP quotient assembly in the prover by replacing serial per-shift accumulation with bundled, row-chunked processing and batched denominator inversion. It fits into the ongoing prover parallelization work by targeting the remaining DEEP quotient hot path.
Changes:
- Replaces serial DEEP quotient column accumulation with
deepQuotientBundlepreparation plus parallelaccumulateDeepQuotient. - Uses
BatchInvertE4per row chunk to reduce extension-field inversion cost. - Adds synthetic tall/wide prover benchmarks for tracking performance.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
prover/prover.go |
Reworks DEEP quotient assembly into precomputed bundles and parallel row accumulation. |
prover/bench_deep_quotient_test.go |
Adds synthetic prover benchmarks for tall and wide trace shapes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
3 tasks
ThomasPiellard
approved these changes
May 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Step 3 of the prover parallelisation series flagged in the bench report. After step 1 (#7) and step 2 (#8),
deep-quotient+fri-commitwas the largest remaining serial chunk on the tall shape (~47% of prove wall, ~960 ms of 2.05 s). This PR replaces the per-shift serial column accumulation with a single row-chunked parallel sweep that fuses C_s materialisation, denominator inversion, and the DEEP quotient add:Three transformations make the fan-out clean:
alphaAcc *= pr.alphachain across columns and shifts is unrolled up front into a per-columnscalesslice on each shift bundle, so the per-row loop has no cross-column data dependency.constContribterm per bundle so the per-row loop only iterates real-width columns.(z_s - ω^x)for the chunk are inverted viaext.BatchInvertE4— one inversion + 3·chunkLen ext muls per chunk, instead of chunkLen ext inversions.Drive-by:
ω^shiftnow usesElement.Exp(binary exponentiation) instead of the O(shift) manual mul loop.Numbers
Median of 3 synth runs (32 cores, KoalaBear + Poseidon2 + blowup 4 + 4 queries), measured on top of step-1 + step-2:
DEEP phase share on tall drops from 47% → 20%. Wide was never DEEP-bound (8% of step-1+2 wall) — the win shows where DEEP assembly actually dominates.
vs Plonky3
Same shapes / same primitives:
loom now beats Plonky3 on both apples-to-apples shapes. (Baseline on main was P3 9.6× ahead on tall, 3.8× on wide.)
Test plan
go test ./...— all greengo test -race ./prover/— no racesgo vet ./...— only pre-existingcopylockswarningsVerify(...)is exercised end-to-end by every existing prover test, so any algebraic mismatch in the rewrite would surface thereprover/BenchmarkProveTallandBenchmarkProveWideadded so the improvement remains visible ingo test -bench(no dependency on thebench/synthcommand from perf: parallelize LDE / coset-FFT / Merkle pipeline #7)🤖 Generated with Claude Code
Note
Medium Risk
Rewrites core DEEP quotient computation in the prove path; invalid algebra would break proofs, though the change is intended to be equivalent to the prior DeepQuotientExt flow.
Overview
Parallelizes DEEP quotient assembly in
ComputeDeepQuotientby replacing per-shift construction of fullC_scolumns pluspoly.DeepQuotientExtwith shift bundles (deepQuotientBundle) and a singleaccumulateDeepQuotientpass that adds ((v_s - \sum_k \text{scale}_k \cdot \text{col}_k[x]) / (z_s - \omega^x)) row-wise.The serial
alphafolding chain is precomputed into per-columnscales; length-1 columns fold intoconstContribso row work skips constants. Row ranges run underparallel.Execute, withBatchInvertE4on chunk denominators andω^shiftviaElement.Expinstead of repeated multiplies.Adds
BenchmarkProveWide/BenchmarkProveTall(synthetic AIR viabuildSynthProveInputs) to track wide vs tall prove shapes ingo test -bench.Reviewed by Cursor Bugbot for commit 7bbb828. Bugbot is set up for automated code reviews on this repo. Configure here.