merge: main (post-#826) into feat/logup-acc-current-row — compose deep-composition fuse+hoist with g·z pruning#840
Merged
MauroToscano merged 3 commits intoJul 16, 2026
Conversation
…T) (#800) * fix(math-cuda): robust CUDA version handling for cuda builds Two driver-independence fixes so `--features cuda` builds AND runs on the team's GPU hardware without CUDARC_CUDA_VERSION env or a hand-picked toolkit. 1. cudarc symbol floor. Pin cudarc's CUDA version to `cuda-12080` in crypto/math-cuda/Cargo.toml (was `cuda-version-from-build-system` + `fallback-latest`). Auto-detect bound the newest symbol set the build toolkit knew (e.g. CUDA 13.1 -> cuDevSmResourceSplit, gated behind cuda-13010/13020), which cudarc eagerly resolves at init and panics on a driver that predates it (580.x = CUDA 13.0 max). Our cudarc surface is all CUDA-11-era, so the 12.8 symbol set (a strict subset every >=12.8 driver exports) resolves cleanly everywhere. Replaces the per-script sed pin; drops it from scripts/gpu_test.sh and adjusts the compat shim in scripts/bench_abba.sh (still rewrites pre-pin baseline shas). 2. PTX ISA version. AOT-compile kernels to native cubin (SASS) via `nvcc --cubin -arch=sm_XX` instead of `--ptx`, loaded through `Ptx::from_binary` (cuModuleLoadData). A cubin carries pre-compiled SASS for a real arch, so the driver loads it regardless of the toolkit's PTX ISA version -- no CUDA_ERROR_UNSUPPORTED_PTX_VERSION and no silent CPU fallback when the toolkit is newer than the driver. Build+run are co-located and the arch is detected from nvidia-smi, so the arch always matches; a too-old toolkit now fails loudly at nvcc build time. CPU-only and nvcc-less stub builds unaffected (empty cubin stub). README "GPU Tests" updated. * fix(math-cuda): review fixes — warn on cubin load failure + bench pin no-op - backend(): warn once when GPU init fails, so a cubin arch mismatch (AOT cubins are arch-specific) doesn't silently disable the GPU with no signal. Stale ptx->cubin comment fixed. - bench_abba.sh: warn when CUDARC_PIN can't apply (post-pin sha, anchor gone) instead of silently no-opping. * fix(math-cuda,scripts): review fixes — warn on sm_89 arch fallback + bench_abba_gpu pin guard/restore + cubin comment * refactor(scripts): shared ABBA bench lib + README GPU driver floor bench_abba.sh and bench_abba_gpu.sh carried near-verbatim copies of the prove-time parsing, the CUDARC_PIN compat sed, and the paired-stats python — a stats fix applied to one would silently leave the other reporting different numbers for the same pairs. scripts/lib/bench_abba_common.sh now holds all three; the GPU bench gains the full analysis (exact Wilcoxon, stability diagnostics, verdicts) it previously lacked. README: state the cuda-12080 pin's driver floor (CUDA >= 12.8 / 570+) and that older drivers abort at CUDA init rather than CPU-fallback. * chore(scripts): drop unused bench_abba_gpu.sh No automation calls it (the GPU bench CI runs bench_abba.sh), and its whole premise — the rigorous ABBA paired-t + Wilcoxon method — is overkill for the question it wrapped: a GPU-on-vs-off delta is 10-40%, which two runs and your eyes resolve. The ABBA machinery earns its keep only for the ~1% effects (bench_abba.sh's PR-vs-baseline deltas), so one bench script is enough. * fix(math-cuda): hard-fail arch detection instead of guessing sm_89 A cubin is arch-locked, so when nvcc is present but no GPU arch can be detected there is no safe default — the old sm_89 fallback produced a binary that loads on exactly one GPU model (Ada) and silently CPU-falls-back on every other, including lower-arch cards like the 3090 (sm_86, which an sm_89 cubin can't even run — cubins aren't backward-compatible). Panic with an actionable message (set CUDARC_NVCC_ARCH or build on the target host) instead. Only reachable with nvcc present + no visible GPU + no override; nvcc-absent hosts take the empty-stub path and never hit this, so CPU-only CI is unaffected. * chore(scripts): move ABBA bench cleanup to its own PR (#812) The bench-tooling dedup + bench_abba_gpu.sh removal are split into #812 so this PR is purely the cuda build-robustness changes (which want a GPU test run), leaving the trivial script cleanup free to merge independently.
…FRI points (#826) * perf(stark): fuse and hoist deep-composition reconstruction for both FRI points reconstruct_deep_composition_poly_evaluation walked the OOD table and trace-term coefficients, and inverted denominators, independently for the regular and symmetric evaluation points, then recomputed the point-invariant OOD/gamma sums from scratch on every one of the ~80 FRI queries per proof. Rewriting coeff*(base-ood)*denom as denom*(coeff*base - coeff*ood) isolates the point-independent coeff*ood term (identical between the two points) from coeff*base, so both points can share the OOD walk and a single batch-inverse. The point-invariant ood_row_sum/z_pow/h_sum_zpow sums are now computed once per proof in compute_query_invariant_deep_terms instead of once per query. Multi-query recursion profile: 1,325,335,927 -> 916,824,543 cycles (-30.8%); step 3 (FRI) 635,418,644 -> 233,869,693 cycles (-63.2%). * fmt --------- Co-authored-by: Diego K <43053772+diegokingston@users.noreply.github.com>
Composes #826's deep-composition fuse+hoist with this branch's g·z OOD pruning in crypto/stark/src/verifier.rs (union resolution, replayed via rerere from the pre-merge dry run): the QueryInvariantDeepTerms hoist reads the reconstructed full OOD grid, and next rows iterate only the transition-window columns in both the hoisted and per-query sums. Exact because pruned positions have zero coefficient and zero grid value. All guards from both sides preserved; no new panic paths. Everything else from main merged clean.
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.
Why a textual merge was impossible
Main (via #826) and this branch both rewrote
reconstruct_deep_composition_poly_evaluations_for_all_queriesandreconstruct_deep_composition_poly_evaluationincrypto/stark/src/verifier.rs. The conflict is semantic, not just textual: #826's newcompute_query_invariant_deep_termshoist readsproof.trace_ood_evaluations()as the full OOD grid, but after this branch's g·z pruning that field carries only the current-row block — taking either side verbatim would either drop the fuse+hoist or compute the DEEP trace term over a truncated grid.Union resolution
compute_query_invariant_deep_termsnow takes the reconstructed full gridood_full(fromcrate::ood::reconstruct_ood_full, zeros at pruned next-row positions) plusnext_row_cols/step_size; the hoistedood_row_sumsums all columns for current rows and only the transition-window columns for next rows. The grid width is stored inQueryInvariantDeepTermsso the pair function no longer reads the proof.reconstruct_deep_composition_poly_evaluation_pair(regular + symmetric together, shared z·gᵏ walk, single batch inverse per pair, F×E base-field multiplications) keeps perf(stark): fuse and hoist deep-composition reconstruction for both FRI points #826's per-row column loop for rows belowstep_sizeand iterates onlynext_row_cols(one column in production) for rows at or above it — this branch's per-query pruning saving landed inside perf(stark): fuse and hoist deep-composition reconstruction for both FRI points #826's structure, replacing the old branch-per-cell skip.next_row_cols: &[usize]replacesnext_row_flags: &[bool]end to end in verifier.rs;ood.rs's public API is unchanged.num_base != num_base_symand OOD-width checks,number_of_partsequality for both openings, and both batch-inverse rejections. No new panic paths reachable from a malformed proof, and no allocations beyond what the two PRs individually did.Exactness: pruned next-row positions have a zero DEEP coefficient (
build_pruned_trace_term_coeffs) and a zero value in the reconstructed grid, so restricting both the hoistedcoeff·oodsum and the per-querycoeff·basesum to the window columns is bit-exact with the unpruned computation.This composes #826's measured −20.3% verifier win with this branch's per-query g·z pruning saving — neither is lost.
Validation
cargo test --release -p stark: 195 passed, 0 failed (includes the g·z pruning + soundness tests and perf(stark): fuse and hoist deep-composition reconstruction for both FRI points #826-side small-trace/r4-denoms tests).make lint(fmt + all four clippy passes incl. cuda-gated): exit 0.merge/deep-fuse-hoist-x-gz-pruning(a91ef36).