Add Tools/binasciibench/binasciibench.py benchmark for measuring base64
encoding/decoding throughput.
Optimize base64 encoding/decoding by eliminating loop-carried dependencies.
Key changes:
- Add base64_encode_trio() and base64_decode_quad() helper functions
that process complete groups independently
- Add base64_encode_fast() and base64_decode_fast() wrappers
- Update b2a_base64 and a2b_base64 to use fast path for complete groups
Performance gains (encode/decode speedup vs main, PGO builds):
64 bytes 64K 1M
Zen2: 1.1x/1.6x 1.6x/2.4x 1.4x/2.4x
Zen4: 1.2x/1.7x 1.6x/3.0x 1.5x/3.0x
M4: 1.3x/1.9x 2.3x/2.8x 2.4x/2.9x
RPi5-32: 1.4x/1.4x 2.4x/2.0x 2.0x/1.9x
Additional SIMD implementations (NEON, AVX-512 VBMI) can achieve
+50% to +1500% further gains and are planned for follow-on work.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
gpshead
changed the title
Optimize base64 encode and decode for an easy 2-3x performance win
gh-124951: Optimize base64 encode and decode for an easy 2-3x performance win [no SIMD required]
Open
gpshead
changed the title
gh-124951: Optimize base64 encode and decode for an easy 2-3x performance win [no SIMD required]
gh-124951: Optimize base64 encode and decode for an easy 2-3x speedup [no SIMD required]
gpshead
changed the title
gh-124951: Optimize base64 encode and decode for an easy 2-3x speedup [no SIMD required]
gh-124951: Optimize base64 encode & decode for an easy 2-3x speedup [no SIMD]
MSVC doesn't support forward declarations of arrays without explicit size. Move the table definition before the inline functions that use it, eliminating the need for a forward declaration. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add Py_ALIGNED(64) to both lookup tables to ensure each fits within a single L1 cache line, reducing potential cache misses during encoding/decoding loops. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded '=' characters with the BASE64_PAD macro for consistency with the rest of the codebase. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Merged
Merged
Address review feedback from serhiy-storchaka: the fast path was doing two checks per group - an explicit PAD comparison and the invalid char check in base64_decode_quad(). Change PAD's table entry from 0 to 64 so the existing (v0|v1|v2|v3)&0xc0 check catches it, eliminating 4 comparisons per group. The slow path is unaffected since it checks for PAD character before the table lookup. Decode is ~16% faster at 64K (1.62 GB/s → 1.88 GB/s). Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Suggested by serhiy-storchaka: replace index math (in + i*3, out + i*4) with pointer increments. Encode is ~7% faster at 64K (2.11 → 2.25 GB/s). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
thunder-coding pushed a commit to thunder-coding/cpython that referenced this pull request
Feb 15, 2026…edup [no SIMD] (pythonGH-143262) Optimize base64 encoding/decoding by eliminating loop-carried dependencies. Key changes: - Add `base64_encode_trio()` and `base64_decode_quad()` helper functions that process complete groups independently - Add `base64_encode_fast()` and `base64_decode_fast()` wrappers - Update `b2a_base64` and `a2b_base64` to use fast path for complete groups Performance gains (encode/decode speedup vs main, PGO builds): ``` 64 bytes 64K 1M Zen2: 1.2x/1.8x 1.7x/2.8x 1.5x/2.8x Zen4: 1.2x/1.7x 1.6x/3.0x 1.5x/3.0x [old data, likely faster] M4: 1.3x/1.9x 2.3x/2.8x 2.4x/2.9x [old data, likely faster] RPi5-32: 1.2x/1.2x 2.4x/2.4x 2.0x/2.1x ``` Based on my exploratory work done in python/cpython@ main...gpshead:cpython:claude/vectorize-base64-c-S7Hku See PR and issue for further thoughts on sometimes MUCH faster SIMD vectorized versions of this.