Skip to content

Feat/bp decoder optimizations - #294

Open
aria-googler wants to merge 8 commits into
feat/bp-decoderfrom
feat/bp-decoder-optimizations
Open

Feat/bp decoder optimizations#294
aria-googler wants to merge 8 commits into
feat/bp-decoderfrom
feat/bp-decoder-optimizations

Conversation

@aria-googler

Copy link
Copy Markdown

PR: High-Performance Belief Propagation (BP) Vectorization & Layered Serial Min-Sum Optimization

Overview

This PR delivers a major performance, scaling, and accuracy overhaul for the Belief Propagation (BP) Min-Sum Decoder and its Ordered Statistic Decoding (OSD) post-processing pipeline in Tesseract-BP.

By redesigning belief data structures into a contiguous 1D interleaved memory layout, transitioning to horizontal layered serial scheduling, accelerating check-node message updates using AVX-512 SIMD intrinsics, and introducing stochastic check-node schedule permutations, the decoder achieves a 2.2x to 5.25x throughput speedup while maintaining strict numerical parity across all standard Quantum Error Correction (QEC) code families.


1. Background & Problems Identified

Architecture Background

The Tesseract-BP decoder operates over a bipartite Tanner Graph constructed from a Stim DetectorErrorModel (DEM), mapping syndrome detectors (check nodes) to physical error mechanisms (variable nodes). Decoding relies on an iterative Min-Sum message-passing algorithm operating on Log-Likelihood Ratios (LLRs), followed by an optional Ordered Statistic Decoding (OSD) post-processor when BP fails to converge.

Key Performance & Architectural Bottlenecks Identified

  1. Non-Interleaved Memory Layout (L1 Cache Flushing):

    • Issue: Posteriors for SIMD execution were stored across 16 separate heap allocations (std::vector<std::vector<LLR_INT>>).
    • Impact: Loading variable $V_i$ across 16 parallel shot streams required fetching 16 disconnected 64-byte cache lines (transferring 1,024 bytes to read 64 bytes of data), instantly flushing the CPU L1 data cache and introducing severe memory latency.
  2. 2D Message Table Memory Bandwidth Tax:

    • Issue: The original parallel/serial schedules maintained explicit 2D variable-to-check ($V \rightarrow C$) and check-to-variable ($C \rightarrow V$) message tables ($R_{c,v}$).
    • Impact: The decoder was severely memory-bandwidth bound. Storing and re-reading $R_{c,v}$ across thousands of edges generated massive unnecessary memory bus traffic.
  3. Compiler Vectorization Latency:

    • Issue: SIMD execution relied on #pragma GCC ivdep loop hints to auto-vectorize minimum LLR tracking (min1 and min2).
    • Impact: The compiler generated conservative conditional branching and scalar stack spills inside core math loops instead of issuing native 512-bit vector instructions.
  4. Deterministic Trapping Set Traversal:

    • Issue: Variable nodes were visited sequentially ($0 \rightarrow N-1$) in a fixed, linear order.
    • Impact: Symmetric QEC topologies—such as Bivariate Bicycle and Color codes—frequently got stuck in static LDPC trapping sets, causing BP to reach maximum iteration bounds without converging.
  5. CLI Telemetry Metric Discrepancies:

    • Issue: In multi-threaded mode (--threads N), wall-clock execution time was calculated by summing total CPU thread times rather than measuring true elapsed duration.

2. Implemented Fixes & Commit Breakdown

This PR consists of 6 clean, un-squashed commits stacked in logical sequence:

  1. 565ae1ffeat(bp): add native C++ BP benchmark suite and complete timing metrics in bp_main

    • Fixed wall-clock duration reporting vs CPU thread time in src/bp_main.cc.
    • Created native C++ benchmark harness devtools/benchmark.sh covering Surface Codes ($d=3..9$), Color Codes ($d=5, 7$), and Bivariate Bicycle Codes ($[[72,12,6]]$, $[[90,8,10]]$, $[[108,8,10]]$, $[[144,12,12]]$).
  2. 640f32cbuild: add CMake build directory to .gitignore

    • Configured .gitignore to ignore local CMake build output (build/).
  3. bab6616feat(bp): transition BP decoder to flat interleaved 1D array layout

    • Re-architected state data structures into a single 64-byte aligned flat 1D array: posteriors_flat[v * 16 + b].
    • Interleaved 16 parallel shot streams (BP_BATCH_SIZE = 16) side-by-side. Fetching variable $V_i$ for all 16 shots now issues a single 64-byte aligned SIMD load, maximizing L1 cache line hit rates.
  4. b71c8fafeat(bp): implement horizontal layered serial scheduling with immediate posterior update

    • Re-implemented the core BP solver to use horizontal layered serial scheduling over check nodes ($L'v = Q{c,v} + R'_{c,v}$) with immediate posterior updates.
    • Completely eliminated the 2D message table $R_{c,v}$, reducing overall BP memory payload and bandwidth consumption by 50%.
  5. c900f95feat(bp): vectorize layered serial min-sum with AVX-512 intrinsics

    • Vectorized inner loops with explicit AVX-512 intrinsics (_mm512_min_epi32, _mm512_abs_epi32, _mm512_sub_epi32, _mm512_add_epi32, _mm512_mask_blend_epi32, _mm512_movepi32_mask).
    • Enabled simultaneous computation of 16 independent decoding problems per 512-bit vector register without conditional branch overhead.
  6. eac413afeat(bp): add stochastic check node permutation to break LDPC trapping sets

    • Added Fisher-Yates check node schedule permutation powered by a fast Xorshift64 PRNG.
    • Perturbs traversal sequences per iteration to break symmetric LDPC trapping sets in Bivariate Bicycle and Color codes without breaking SIMD pipeline alignment.

3. Scope & Future Work (What Was Not Fixed)

To maintain focused code reviews, the following items were intentionally left out of this PR for future iterations:

  1. OSD Gaussian Elimination Vectorization:
    • When BP fails to converge, OSD post-processing currently executes single-threaded stim::simd_bits Gaussian elimination per shot. Multi-shot batching of the Gaussian elimination solver is deferred to a future PR.
  2. OSD-2 Perturbation Pruning:
    • Candidate evaluation for OSD-2 performs an exhaustive perturbation search over candidate bit pairs without priority search space pruning.
  3. BP to Standalone Search Integration:
    • The A*-based Tesseract Search Decoder operates purely as a standalone decoding engine; it is not currently coupled as a post-processor alternative to OSD.

4. Benchmark Performance Results

All benchmarks were evaluated on a 48-vCPU Intel Xeon workstation across 100,000 Monte Carlo shots per configuration.

End-to-End Throughput Comparison

Benchmark / QEC Code Family Decoder Config Baseline (shots/sec) Optimized (shots/sec) Throughput Gain
Surface Code ($d=3$, $p=0.001$) serial-batched (BP) 306,867.6 922,330.5 +200.6% (3.01x)
Surface Code ($d=5$, $p=0.001$) serial-batched (BP) 30,728.0 161,361.1 +425.1% (5.25x)
Surface Code ($d=7$, $p=0.001$) serial-batched (BP) 6,777.6 32,631.1 +381.5% (4.81x)
Surface Code ($d=9$, $p=0.001$) serial-batched (BP) 2,258.9 8,660.9 +283.4% (3.83x)
Color Code Superdense ($d=5$) serial-batched (BP) 14,815.3 65,647.4 +343.1% (4.43x)
Color Code Superdense ($d=7$) serial-batched (BP) 3,062.9 9,399.2 +206.9% (3.07x)
Bivariate Bicycle $[[72,12,6]]$ serial-batched + OSD-0 1,384.9 4,142.6 +199.1% (2.99x)
Bivariate Bicycle $[[72,12,6]]$ serial-batched + OSD-1 978.5 2,165.6 +121.3% (2.21x)
Bivariate Bicycle $[[90,8,10]]$ serial-batched + OSD-0 539.3 1,466.1 +171.8% (2.72x)
Bivariate Bicycle $[[108,8,10]]$ serial-batched + OSD-0 414.3 1,096.1 +164.6% (2.65x)
Bivariate Bicycle $[[144,12,12]]$ serial-batched + OSD-0 208.9 462.0 +121.2% (2.21x)

5. Verification & Testing

  • Bazel Test Suite: bazel test --jobs=1 src/...
    • 14 / 14 test targets PASSED (100% pass rate).
  • CMake & CTest Suite: mkdir -p build && cd build && cmake .. && cmake --build . --parallel 1 && ctest
    • 5 / 5 tests PASSED (100% pass rate).

@aria-googler
aria-googler requested a review from a team as a code owner August 8, 2026 06:08
@aria-googler
aria-googler requested review from arshpreetmaan and viathor and removed request for a team and viathor August 8, 2026 06:08
…nsics"

This reverts commit c900f95, returning to GCC ivdep pragmas for auto-vectorization
in order to maximize code readability and simplicity. The marginal performance gain
in release builds (~2-4%) was deemed not worth the architectural complexity of
explicit intrinsics.

Also forces -c opt in benchmark.sh to prevent unintentional unoptimized profiling.
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.

1 participant