Repository navigation
Conversation
c-blosc 1.x only provides SSE2/AVX2 shuffle kernels. On aarch64 its dispatcher always selects blosc_internal_(un)shuffle_generic, a scalar byte-by-byte loop that dominates Blosc runtime on ARM. On aarch64, compile a drop-in replacement for c-blosc's shuffle-generic.c that implements those two symbols with NEON kernels (copied from c-blosc2) for type sizes 2, 4, 8 and 16, falling back to the scalar loop otherwise. The c-blosc submodule is left untouched and the output is byte-identical. Controlled by a new `neon` meson option (default: auto). Assisted-by: ClaudeCode:claude-opus-5-5
2e138e2 to
5c34a8d
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #864 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 27 27
Lines 914 914
=========================================
Hits 914 914 🚀 New features to boost your workflow:
|
Resolve the docs/release.md conflict with the 0.17.1 release notes: keep the NEON entry under Unreleased above the new 0.17.1 section. Assisted-by: ClaudeCode:claude-opus-5-5
|
I really think we should see if c-blosc2 already does everything we need. It can now read and write blosc1 data: and they already have neon code: |
|
i was under the impression that blosc2 would not write data that a blosc1 reader could decode. if that's wrong, then blosc2 looks like a great idea |
|
I measured #864 against the c-blosc2 backend I propose in #879, since c-blosc2 builds its own NEON shuffle on aarch64. The short version: c-blosc2 is not uniformly faster than c-blosc 1.x with this patch. #864 recovers most of the NEON speedup for the default backend, and in several cases it is faster than c-blosc2, especially on encode. Single thread (
(Bold is the fastest of the three.)
Caveats: one machine, my own synthetic data (cumulative sums, chosen so that shuffle matters, with Drafted with Claude Code. |
🤖 AI text below 🤖
Summary
c-blosc 1.x only ships SSE2/AVX2 shuffle kernels. On aarch64 (Apple Silicon, AWS Graviton, …) its dispatcher always falls back to
blosc_internal_(un)shuffle_generic, a scalar byte-by-byte loop. That loop dominates Blosc runtime on ARM: with shuffle disabled, the same build decodes lz4 at ~17 GB/s, but with shuffle enabled it decodes at ~2.5 GB/s.This PR adds
src/numcodecs/_blosc_neon/shuffle-generic-neon.c. On aarch64, meson compiles it instead of c-blosc'sshuffle-generic.c. It defines the same two symbols:blosc/shuffle-neon.c(BSD-3, attributed in the header).The
c-bloscsubmodule is not modified, and c-blosc's dispatcher (shuffle.c) is unchanged. A newneonmeson option (defaultauto) controls this. Bitshuffle is unchanged, since c-blosc2 also found its NEON bitshuffle no faster than scalar.Compatibility
The output is byte-identical to the scalar build. The agent compared SHA-256 hashes of the compressed output from both builds over 1,452 combinations: type sizes 1–32 including odd sizes, 11 buffer lengths, 3 block sizes, shuffle and bitshuffle, lz4 and blosclz. The hashes matched and every case round-tripped. The existing backwards-compatibility fixtures also decode correctly.
Benchmarks
Apple M5, Python 3.14, single thread (
use_threads = False),Blosc(cname, clevel=5, shuffle=SHUFFLE), MB/s of uncompressed data. The numbers were stable to within ~1% across two runs.Testing
test_shuffle_roundtrip_typesizes. It round-trips across type sizes, lengths that aren't multiples of the vector width, and block sizes, to cover the scalar tail._M_ARM64as well as__ARM_NEON.Notes for reviewers
🤖 Generated with Claude Code