Skip to content

perf: parallelize DEEP quotient assembly#9

Merged
ThomasPiellard merged 2 commits into
mainfrom
perf/parallel-deep-quotient
May 28, 2026
Merged

perf: parallelize DEEP quotient assembly#9
ThomasPiellard merged 2 commits into
mainfrom
perf/parallel-deep-quotient

Conversation

@gbotrel

@gbotrel gbotrel commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Step 3 of the prover parallelisation series flagged in the bench report. After step 1 (#7) and step 2 (#8), deep-quotient+fri-commit was 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:

deepQuotient[x] += (v_s - Σ_k scales_k · cols_k[x]) / (z_s - ω^x)

Three transformations make the fan-out clean:

  1. The serial alphaAcc *= pr.alpha chain across columns and shifts is unrolled up front into a per-column scales slice on each shift bundle, so the per-row loop has no cross-column data dependency.
  2. Constant (len-1) columns are folded into a single constContrib term per bundle so the per-row loop only iterates real-width columns.
  3. Denominators (z_s - ω^x) for the chunk are inverted via ext.BatchInvertE4 — one inversion + 3·chunkLen ext muls per chunk, instead of chunkLen ext inversions.

Drive-by: ω^shift now uses Element.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:

shape step 1+2 + this PR speedup
tall (2²⁰ × 24) 2.05 s 1.36 s 1.51×
wide (2¹⁴ × 1536) 0.288 s 0.285 s ~1×

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:

shape Plonky3 loom (step 1+2+3) gap
tall 1.56 s 1.36 s loom 1.15× faster
wide 0.40 s 0.285 s loom 1.40× faster

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 green
  • go test -race ./prover/ — no races
  • go vet ./... — only pre-existing copylocks warnings
  • Verifier-side Verify(...) is exercised end-to-end by every existing prover test, so any algebraic mismatch in the rewrite would surface there
  • prover/BenchmarkProveTall and BenchmarkProveWide added so the improvement remains visible in go test -bench (no dependency on the bench/synth command 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 ComputeDeepQuotient by replacing per-shift construction of full C_s columns plus poly.DeepQuotientExt with shift bundles (deepQuotientBundle) and a single accumulateDeepQuotient pass that adds ((v_s - \sum_k \text{scale}_k \cdot \text{col}_k[x]) / (z_s - \omega^x)) row-wise.

The serial alpha folding chain is precomputed into per-column scales; length-1 columns fold into constContrib so row work skips constants. Row ranges run under parallel.Execute, with BatchInvertE4 on chunk denominators and ω^shift via Element.Exp instead of repeated multiplies.

Adds BenchmarkProveWide / BenchmarkProveTall (synthetic AIR via buildSynthProveInputs) to track wide vs tall prove shapes in go test -bench.

Reviewed by Cursor Bugbot for commit 7bbb828. Bugbot is set up for automated code reviews on this repo. Configure here.

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>
Copilot AI review requested due to automatic review settings May 27, 2026 20:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 deepQuotientBundle preparation plus parallel accumulateDeepQuotient.
  • Uses BatchInvertE4 per 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.

@ThomasPiellard ThomasPiellard merged commit 1f6d805 into main May 28, 2026
1 check passed
@ThomasPiellard ThomasPiellard deleted the perf/parallel-deep-quotient branch May 28, 2026 14:36
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.

3 participants