perf(rsema1d): precompute coefficient logarithms for RLC computation - #1005
Open
citizen-stig wants to merge 3 commits into
Open
perf(rsema1d): precompute coefficient logarithms for RLC computation#1005citizen-stig wants to merge 3 commits into
citizen-stig wants to merge 3 commits into
Conversation
citizen-stig
marked this pull request as ready for review
September 2, 2026 14:37
citizen-stig
requested review from
mcrakhman and
vgonkivs
and removed request for
a team and
vgonkivs
September 2, 2026 14:37
mcrakhman
approved these changes
Sep 2, 2026
compute_rlc multiplied every 2-byte symbol of a row by a GF(2^128)
coefficient through GF128::scalar_mul, which for each of the 8 limbs looked
up log(symbol), log(limb) and exp(sum): 24 dependent table loads per
symbol, with log(symbol) recomputed 8 times. It was 51% of a single-core
encode of a 128 MiB blob and the largest CPU consumer once parity encoding
is parallel.
RlcCoefficients holds the coefficients together with the logarithm of
every limb (256 KiB for 32 KiB rows), computed once per blob. Per symbol
the work is now one log lookup plus one exp lookup per limb. ExtendedData
builds the table once for all K rows and VerificationContext caches it
alongside the coefficients. compute_rlc(row, coeffs) keeps its signature
and builds a table per call. Results are identical: a test compares against
the previous scalar_mul formulation on random rows with zero symbols and
zero limbs, and the Go cross-implementation vectors (254 cases including
K=4096/N=12288) pass.
criterion, target-cpu=native, Ryzen 9 3950X:
verification/128MB_k4096_n12288 (one row) 305 us -> 133 us
verification/8MB_k4096_n12288 20.7 us -> 9.7 us
encode_in_place/128MB_k4096_n12288 821 ms -> 763 ms
(32 threads; the RLC pass itself went 79 ms -> 30 ms, the rest is the
still single-threaded parity encoder on main)
single core RLC pass over a 128 MiB blob 1.26 s -> 0.44 s (probe)
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VPtihoV1GJ9VcNkd7oMRUf
citizen-stig
force-pushed
the
perf/rsema1d-rlc-precomputed-logs
branch
from
September 2, 2026 14:55
245fa38 to
e3c6f12
Compare
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.
compute_rlcmultiplied every 2-byte symbol of a row by a GF(2^128) coefficient throughGF128::scalar_mul, which for each of the 8 limbs looked up: 1.log(symbol), 2. log(limb) and 3. exp(sum): 24 dependent table loads per symbol, with log(symbol) recomputed 8 times.It was 51% of a single-core encode of a 128 MiB blob and the largest CPU consumer once parity encoding is parallel.
Encoding and context-based verification precompute the GF(2^16) logarithm of each coefficient limb. For a 32 KiB row, this lookup table uses 256 KiB.
ExtendedDatabuilds it once for all rows, andVerificationContextcaches it after the first successful verification. The original coefficients are not retained.The public
compute_rlc(row, coeffs)function keeps its existing signature and direct multiplication path. This avoids building a lookup table for one-off calls and remains efficient for sparse or zero-filled rows.Simplified explanation:
Tests compare the optimized path with the direct implementation using random rows, zero symbols, zero coefficient limbs, and exponent wraparound. All 254 Go compatibility vectors, including K=4096/N=12288 cases, also pass.