Skip to content

Add measured Python batch APIs - #56

Merged
mrecachinas merged 11 commits into
mainfrom
perf/python-batch-apis
Aug 3, 2026
Merged

Add measured Python batch APIs#56
mrecachinas merged 11 commits into
mainfrom
perf/python-batch-apis

Conversation

@mrecachinas

@mrecachinas mrecachinas commented Aug 2, 2026

Copy link
Copy Markdown
Owner

What

Adds additive Python batch APIs that amortize PyO3/FFI overhead across pairwise distance calculations and multi-query catalog scans. Results can be returned as Python lists, packed byte strings, or written into caller-provided buffers.

The batch core is implemented in safe Rust and reuses the existing SIMD and Rayon scan machinery. Prepared catalogs were evaluated but intentionally omitted because their measured advantage did not meet the 10% acceptance gate.

Advances the Python/FFI portion of #51.

Performance

Three-run medians on an Apple M4 Max, comparing the existing Python loop with the new batch transports:

Workload Python loop Batch list Packed _into
100 x 16B 15.53 us 598 ns (25.9x) 281 ns (55.3x) 208 ns (74.5x)
1,000 x 16B 153.49 us 4.51 us (34.1x) 1.55 us (99.3x) 1.25 us (123.1x)
10,000 x 16B 1.50 ms 44.10 us (34.0x) 14.77 us (101.5x) 11.72 us (128.0x)
100 x 32B 16.02 us 834 ns (19.2x) 511 ns (31.4x) 433 ns (37.0x)
10,000 x 32B 1.53 ms 67.01 us (22.8x) 37.86 us (40.4x) 34.77 us (44.0x)

Additional scan results:

  • first_many: 11.03 us to 752 ns (14.7x)
  • Dense all packed: 30.39 us to 3.14 us (9.7x)
  • Dense all _into: 30.39 us to 2.06 us (14.8x)
  • best_many: 77.50 us to 66.57 us (1.16x)

The writable-output soundness fix was measured against the previous detached implementation on the same machine. Pairwise _into ranged from -1.3% to +2.7%, and dense all_into was 3.3% faster, all within noise.

The earlier CI report showing 3-8x regressions was caused by benchmarking base and PR on separate GitHub-hosted machines with different x86 SIMD feature sets. CI now benchmarks both revisions sequentially on the same runner; the corrected comparison reports all 104 existing benchmarks within noise.

Safety

The implementation reduced the initial batch change from 20 added unsafe occurrences to a net increase of two; src/batch.rs contains no unsafe code. Buffer sizes, formats, contiguity, arithmetic overflow, and input/output overlap are validated.

Python writable buffer exports stabilize storage but do not provide exclusive mutation access. Writable _into APIs therefore keep the GIL for the complete write on standard CPython. On free-threaded Python they raise ValueError and direct callers to the corresponding packed API, which retains detached computation without borrowing caller-owned writable memory.

Testing

  • cargo test --no-default-features - 92 unit and 2 doc tests
  • python -m pytest -q test/test_batch.py - 40 passed, 1 free-threaded-only test skipped
  • Full Python suite - 224 passed, 4 skipped
  • ruff check test/test_batch.py
  • ruff format --check test/test_batch.py
  • cargo fmt --check
  • CI green on Python 3.10-3.14 across Linux, macOS, and Windows
  • Same-runner benchmark comparison: 104 benchmarks within noise

Amortize Python FFI overhead with pairwise, multi-query, packed, and writable-buffer APIs while preserving existing semantics and guarding unsafe buffer access.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
Use safe chunks_exact iteration in pairwise batches. Three-run medians stayed within 1.4% of the raw-pointer baseline across measured workloads.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
Replace raw unaligned writes into Rust-owned Python bytes with safe chunk copies. Three-run medians were unchanged or up to 1.7% faster.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
Let the exact-size chunks iterator collect pairwise distances directly, removing manual pointer initialization and set_len. Three-run medians stayed within 0.8% or improved up to 3.8%.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
Serialize distances through exact-sized output chunks instead of raw unaligned pointers. Three-run medians stayed within 0.4% of baseline across all measured sizes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
Use one pinned Py_buffer guard for readonly and writable exports, removing duplicated FFI unsafe code. Three-run into benchmarks stayed within 0.9% of the prior implementation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
Keep unsafe pointer dereferencing at the actual slice construction sites while exposing the inert raw pointer through a safe accessor. Three-run into benchmarks stayed within 0.7%.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
Keep each pair of buffer-to-slice conversions inside one documented unsafe boundary without changing generated work.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown

📊 Benchmark Comparison Results

✅ All benchmarks within noise

104 benchmarks compared, no significant changes detected.

Legend: ✅ Faster (>5%) · ⚠️ Slower (5-30%) · ❌ Regression (>30%) · 🆕 New · 🗑️ Removed

Run both revisions sequentially on the same GitHub-hosted machine so runtime SIMD dispatch and host variability cannot create false regression reports.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
Keep the GIL while writing caller-owned buffers and reject writable _into APIs on free-threaded Python, where buffer exports do not guarantee exclusive access. Packed APIs remain available for detached computation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 01071e57-12fd-4f42-bc67-e2b274d0b007
@mrecachinas
mrecachinas marked this pull request as ready for review August 3, 2026 01:45
@mrecachinas
mrecachinas merged commit 316826c into main Aug 3, 2026
22 checks passed
@mrecachinas
mrecachinas deleted the perf/python-batch-apis branch August 3, 2026 02:17
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