Skip to content

Add Cholesky factorization benchmark (bench_potrf_compact) - #28

Merged
ivan-pi merged 3 commits into
mainfrom
claude/potrf-spd-benchmark-pru6pz
Aug 7, 2026
Merged

Add Cholesky factorization benchmark (bench_potrf_compact)#28
ivan-pi merged 3 commits into
mainfrom
claude/potrf-spd-benchmark-pru6pz

Conversation

@ivan-pi

@ivan-pi ivan-pi commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

This PR adds a comprehensive throughput benchmark for the batched Cholesky factorization (cqr_mkl_dpotrf_compact), mirroring the existing QR factorization benchmark (bench_geqrf_compact). The benchmark compares three implementations: the project's compact SIMD kernel, Intel MKL's compact kernel, and conventional per-matrix LAPACK, over pools of small symmetric positive-definite (SPD) matrices.

Key Changes

  • New benchmark executable (bench_potrf_compact):

    • Factors pools of SPD matrices in column-major lower triangle form (A = L L^T)
    • Compares cqr_mkl_dpotrf_compact vs mkl_dpotrf_compact vs per-matrix LAPACKE_dpotrf
    • Reports throughput in GFLOP/s and matrices/second with geometric-mean speedup
    • Validates correctness by comparing compact factors elementwise against per-matrix LAPACK (leveraging the uniqueness of the SPD Cholesky factor)
  • Benchmark features:

    • Pre-packs the matrix pool once; only the factorization is timed (untimed restore between passes)
    • Uses OpenMP outer loop parallelization over groups of V interleaved matrices (the intended usage pattern)
    • Supports optional --size-sweep=nmin:nmax[:stride] for cqr-only throughput scans
    • Supports optional --simdlen=2|4|8 to force narrower interleave widths than the host default
    • Default size list deliberately includes non-multiple-of-V sizes (30, 45, 60, 105, 168) to expose SIMD remainder handling
  • Integration testing:

    • Added CTest integration test (bench_potrf_compact_integration) with 33 matrices and 1 rep
    • Doubles as an accuracy gate: compact factorization must match LAPACK to machine precision
  • Build integration:

    • CMakeLists.txt target wired to link against cqr_mkl_ext and MKL::Compact
    • OpenMP support when available
  • Documentation:

    • Design document updated with section 9 (Benchmark) describing the methodology
    • README.md updated with usage instructions and build recommendations
    • PLANS.md updated to mark the benchmark as complete

Implementation Details

  • Uses aligned memory allocation (64 B alignment) for both the dense pool and compact buffers to avoid cache-line splits
  • SPD test matrices are generated with diagonal dominance (A_ii = 2n) rather than expensive M^T M products
  • Unlike geqrf, potrf requires no workspace, so no per-thread work arrays are needed
  • Timing uses std::chrono::steady_clock with best-of-multiple-passes methodology
  • Relative error is computed as the maximum elementwise difference in the lower triangle, scaled by the factor's L1 norm

https://claude.ai/code/session_01GKgcv8eoffP2gWrED44KqH

claude added 3 commits August 6, 2026 13:37
Add the potrf analogue of bench_geqrf_compact: a throughput benchmark of
the batched Cholesky factorization on symmetric positive-definite matrices,
comparing three implementations of the same ?potrf math --

  cqr-compact  cqr_mkl_dpotrf_compact  (this project's batched SIMD kernel)
  mkl-compact  mkl_dpotrf_compact      (Intel MKL's batched compact kernel)
  per-matrix   LAPACKE_dpotrf          (conventional one-matrix-at-a-time)

over pools of small SPD matrices across the target size range, on the tuned
column-major lower path (A = L L^T). It reports per-size throughput
(matrices/s, GFLOP/s from the n^3/3 + n^2/2 + n/6 Cholesky flop count) and a
geometric-mean speedup, and -- since the SPD factor is unique -- gates the
compact factor elementwise against LAPACKE_dpotrf, so it doubles as an
integration test. Unlike geqrf, potrf needs no workspace, so there is no
lwork query and no per-thread work array. The SPD pool uses the cheap
diagonally dominant A_ii = 2n form (SPD without an O(n^3) M^T M). The
--size-sweep and --simdlen flags mirror bench_geqrf_compact.

Wire it into CMakeLists.txt as the bench_potrf_compact target plus a small
CTest integration run (33 1, exercising a padded final group). Document it
in the README (Examples bullets/table, CTest list), flip the potrf
benchmark note in PLANS.md from Deferred to Benchmarked, and add a
section 9 (Benchmark) to the potrf design doc mirroring geqrf's.

Verified: full ctest suite passes on both GCC and Clang (12/12), the
accuracy gate holds at machine precision, and a -march=native run shows the
expected story -- the compact path beats per-matrix LAPACK and is
competitive with mkl_dpotrf_compact on the small-size range, LAPACK's
blocked algorithm crossing ahead only at larger orders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKgcv8eoffP2gWrED44KqH
Per the project's convention to stop documenting benchmarks in the routine
design documents, consolidate all benchmark documentation into a single
examples/BENCHMARKS.md next to the programs it describes.

- Add examples/BENCHMARKS.md documenting all three benchmarks
  (bench_geqrf_compact, bench_potrf_compact, bench_qr_compact): what each
  measures, the three-way comparison, how to run them, the -march=native
  fairness caveat, the OpenMP outer loop, the optional --size-sweep/--simdlen
  flags, how to read the output, and the CTest integration gating.
- Remove the "9. Benchmark" section from both the geqrf and potrf design docs
  (it was the last section in each), replacing it with a one-line pointer to
  examples/BENCHMARKS.md.
- Fix every stale "section 9" cross-reference: the two benchmark source-file
  header comments, both PLANS.md "Benchmarked" bullets, and the CMakeLists.txt
  target comments now point to examples/BENCHMARKS.md.
- Link the new doc from the root README's Examples section.

No functional change: the benchmarks build and their CTest integration runs
still pass on GCC (bench_qr/geqrf/potrf_compact_integration, 3/3).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKgcv8eoffP2gWrED44KqH
Address review feedback on the benchmark work:

- Deduplicate the two compact-format helpers that were copied across the
  benchmark files. compact_format_name (3 copies) and format_for_vlen (2
  copies) now live once in cqr::detail (cqr_mkl_ext.h), next to their sibling
  vlen_for_format; the benchmarks pull them in with using-declarations.
  format_for_vlen is now the type-correct inverse of vlen_for_format
  (templated on the scalar type, keyed on v*sizeof(T) register bytes) instead
  of a double-only mapping; call sites pass <double>. Behavior is unchanged
  for the double benchmarks.

- Drop the two "documented in examples/BENCHMARKS.md" pointer lines from the
  geqrf and potrf design docs, per the convention to keep benchmark docs out
  of the design documents entirely.

- Trim examples/BENCHMARKS.md (148 -> 108 lines): fold the per-benchmark
  three-way lists into the overview table, state the shared "pack once, time
  only the factorization" methodology once, and drop the standalone Threading
  section.

Verified: full ctest passes on both GCC and Clang (12/12), including the three
benchmark integration runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKgcv8eoffP2gWrED44KqH
@ivan-pi
ivan-pi merged commit b0a2607 into main Aug 7, 2026
2 of 6 checks passed
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.

2 participants