feat(bp): BP decoder memory-layout, scheduling, and OSD truncation optimizations (2.2x-5.25x) - #294
Merged
Merged
Conversation
…te posterior update
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.
- Implements matrix width truncation in OSD Gaussian Elimination (bounded by factor * num_detectors). - Substantially improves e2e BP-OSD CPU decoding speed (up to 32% faster) without degrading LER. - Exposes `osd_truncation_factor` configuration in BPParams with a safe, optimized default of 1.2. - Wires CLI parameter `--osd-truncation-factor` to bp_main.cc and adds PyBind11 bindings. - Updates benchmark scripts to measure and test the optimization.
The -mavx512f/-mavx512bw/-mavx512dq flags were introduced alongside the explicit AVX-512 intrinsics in c900f95. That commit was reverted in 85f8c44, but the revert did not touch .bazelrc, leaving the flags applied to every Linux build target repo-wide. This caused all binaries (including non-BP targets such as tesseract_tests, common_tests and the Python tests) to abort with SIGILL / 'Illegal instruction' on any CPU without AVX-512, which is the case for the GitHub Actions ubuntu-latest runners. Vectorization is still handled portably: //src:OPT_COPTS selects -march=native for normal builds and -march=x86-64 for portable wheels, and the serial min-sum kernel relies on '#pragma GCC ivdep' auto-vectorization.
Fixes clang-format --dry-run --Werror violations in bp_params.h,
bp.pybind.h, bp_serial_min_sum.test.cc, osd_post_processor.{h,cc},
tesseract_bp_decoder.cc and bp_main.cc. Formatting-only, no behavior change.
main wrapped the shared helpers in an outer 'tesseract_decoder' namespace. The BP sources live in a top-level 'namespace bp' and therefore no longer resolved these names after merging main: - tesseract_bp_decoder.cc: common::merge_indistinguishable_errors - bp_main.cc: parallel_for_shots_in_order - bp.pybind.h / bp_sinter_compat.pybind.h: parse_py_object Fully qualify the call sites (and add 'using namespace tesseract_decoder;' to bp_main.cc, matching tesseract_main.cc and simplex_main.cc).
error_correlations.test.cc calls prepare_two_component_dem(), which is defined in multi_pass/dem_decomposition.cc, but the CMake target only linked the 'error_correlations' library. This produced an undefined reference at link time and broke 'cmake --build .' entirely. The Bazel target //src:error_correlations_tests already declares the dependency correctly, which is why CI (Bazel-only) did not catch it.
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
Performance and robustness work on the
Tesseract-BPdecoder. By re-architecting BP state into a contiguous 1D interleaved memory layout, switching to horizontal layered serial scheduling, adding stochastic check-node schedule permutations, and introducing OSD matrix column truncation, the decoder achieves a 2.2x–5.25x end-to-end throughput speedup with no degradation in logical error rate.This branch has also been synced with
mainand carries the fixes required to keep both the Bazel and CMake builds green.1. BP engine optimizations
Flat interleaved 1D array layout (
bab6616)posteriors_flat[v * 16 + b], interleavingBP_BATCH_SIZE = 16shot streams side by side.Horizontal layered serial scheduling (
b71c8fa)Stochastic check-node permutation (
eac413a)--random-schedule.OSD matrix column truncation (
3e01a32)min(num_errors, num_detectors * osd_truncation_factor)columns, sorted by posterior reliability, instead of materializing all--osd-truncation-factorCLI flag andBPParams.osd_truncation_factorbinding; default1.2,0.0disables.CLI telemetry + benchmark harness (
565ae1f)--threads Npreviously reported summed CPU thread time as wall-clock; now reports true elapsed duration.devtools/benchmark.shcovering Surface (Reverted during review
c900f95, reverted in85f8c44). Explicit_mm512_*intrinsics were benchmarked at only ~2–4% over#pragma GCC ivdepauto-vectorization in optimized builds — not worth the readability cost.2. Build and integration fixes
fix(build): removed leftover global AVX-512 copts from.bazelrc.c900f95added-mavx512f/-mavx512bw/-mavx512dqtobuild:linux; the revert in85f8c44did not undo it. This applied AVX-512 codegen to every Linux target repo-wide, so all binaries — including unrelated ones liketesseract_tests,common_tests, and the Python tests — aborted withSIGILLon any CPU without AVX-512, which is the case for GitHub Actions runners. Vectorization remains portable via//src:OPT_COPTS(-march=native, or-march=x86-64for portable wheels).fix(bp): qualified symbols moved into thetesseract_decodernamespace.After syncing
main, the BP sources (top-levelnamespace bp) no longer resolvedcommon::merge_indistinguishable_errors,parallel_for_shots_in_order, orparse_py_object. Call sites are now fully qualified, andbp_main.ccgainedusing namespace tesseract_decoder;to matchtesseract_main.cc/simplex_main.cc.fix(cmake): linkeddem_decompositionintoerror_correlations_test.error_correlations.test.cccallsprepare_two_component_dem(), defined inmulti_pass/dem_decomposition.cc, but the CMake target linked onlyerror_correlations— an undefined reference that brokecmake --build .outright. The Bazel target already declared the dep, which is why Bazel-only CI never caught it.style:clang-formatapplied to the BP sources.3. Benchmark results
48-vCPU Intel Xeon, 100,000 Monte Carlo shots per configuration.
serial-batchedserial-batchedserial-batchedserial-batchedserial-batchedserial-batchedserial-batched + OSD-0serial-batched + OSD-1serial-batched + OSD-0serial-batched + OSD-0serial-batched + OSD-0OSD truncation, isolated
LER is unaffected; at 1.20 it is marginally better, since excluding extremely low-probability variables keeps OSD out of obscure high-weight equivalence classes.
4. Verification
bazel test --jobs=1 src/...SIGILL)cmake --build . --parallel 1 && ctestclang-format --dry-run --WerrormainAll GitHub CI checks green, including
build (ubuntu-latest)— the job that was previously crashing withSIGILL.5. Out of scope / follow-ups
std::sortover allstd::nth_element+ prefix sort, since truncation discards the tail anyway (~10x fewer comparisons at