@@ -195,24 +195,24 @@ These numbers show the pure computation time using Rust's ``criterion`` benchmar
195195================================================ ===========
196196Name Mean (ns)
197197================================================ ===========
198- hex_string (NEON) [16 chars] 2.4
199- hex_string (NEON) [64 chars] 8.3
200- hex_string (NEON) [128 chars] 16.2
201- hex_string (NEON) [254 chars] 30.2
202- bytes (native) [8 bytes] 1.7
203- bytes (native) [32 bytes] 2.4
204- bytes (native) [64 bytes] 3.2
205- bytes (native) [127 bytes] 8.4
206- bytes_within_dist [127 bytes] 2.4
207- array first [512×16, at start] 6.6
208- array first [512×16, at end] 1,397.0
209- array best [512×16, exact at start] 8 .3
210- array best [512×16, exact at end] 1,599.2
211- array all [512×16] 1,610.1
212- array best [16384×64, match at mid] 71,121 .0
213- array all [16384×64, match at mid] 79,365 .0
214- array best [100000×128, parallel] 50,996 .0
215- array all [100000×128, parallel] 144,800 .0
198+ hex_string (NEON) [16 chars] 1.6
199+ hex_string (NEON) [64 chars] 5.4
200+ hex_string (NEON) [128 chars] 10.5
201+ hex_string (NEON) [254 chars] 19.7
202+ bytes (native) [8 bytes] 1.1
203+ bytes (native) [32 bytes] 1.5
204+ bytes (native) [64 bytes] 2.1
205+ bytes (native) [127 bytes] 5.5
206+ bytes_within_dist [127 bytes] 1.6
207+ array first [512×16, at start] 1.9
208+ array first [512×16, at end] 402.4
209+ array best [512×16, exact at start] 3 .3
210+ array best [512×16, exact at end] 526.4
211+ array all [512×16] 449.0
212+ array best [16384×64, match at mid] 10,986 .0
213+ array all [16384×64, match at mid] 20,350 .0
214+ array best [100000×128, parallel] 46,547 .0
215+ array all [100000×128, parallel] 99,266 .0
216216================================================ ===========
217217
218218On AArch64, LLVM's auto-vectorized native byte loop is faster than the
@@ -229,35 +229,53 @@ These numbers include Python wrapper and function-call overhead using
229229====================================================== ===========
230230Name Mean (ns)
231231====================================================== ===========
232- hamming_distance_string [3 chars, same] 56.3
233- hamming_distance_string [3 chars, diff] 105.8
234- hamming_distance_string [64 chars, diff] 60.0
235- hamming_distance_string [1024 chars, diff] 177.1
236- hamming_distance_bytes [3 bytes, same] 51.7
237- hamming_distance_bytes [3 bytes, diff] 51.8
238- hamming_distance_bytes [64 bytes, diff] 51.9
239- hamming_distance_bytes [1024 bytes, diff] 68.9
240- check_hexstrings_within_dist [1000 chars] 56.4
241- check_bytes_within_dist [16 bytes] 52.5
242- check_bytes_within_dist [64 bytes] 51.8
243- check_bytes_within_dist [127 bytes] 52.8
244- first_within_dist [512×16, at start] 58.5
245- first_within_dist [512×16, mid] 771.4
246- first_within_dist [512×16, at end] 1,475.1
247- first_within_dist [16384×64, at start] 160.3
248- first_within_dist [16384×64, mid] 23,031.5
249- first_within_dist [16384×64, at end] 45,801.2
250- best_within_dist [512×16, at start] 75.3
251- best_within_dist [512×16, at end] 1,703.5
252- best_within_dist [16384×64, mid] 93,212.8
253- all_within_dist [512×16, at start] 1,735.5
254- all_within_dist [512×16, at end] 1,747.3
255- all_within_dist [16384×64, mid] 93,056.3
232+ hamming_distance_string [3 chars, same] 37.1
233+ hamming_distance_string [3 chars, diff] 70.7
234+ hamming_distance_string [64 chars, diff] 39.8
235+ hamming_distance_string [1024 chars, diff] 116.4
236+ hamming_distance_bytes [3 bytes, same] 33.4
237+ hamming_distance_bytes [3 bytes, diff] 39.9
238+ hamming_distance_bytes [64 bytes, diff] 33.9
239+ hamming_distance_bytes [1024 bytes, diff] 44.6
240+ hamming_distance_bytes [64-byte bytearray] 50.6
241+ hamming_distance_bytes [64-byte memoryview] 51.5
242+ check_hexstrings_within_dist [1000 chars] 37.3
243+ check_bytes_within_dist [16 bytes] 34.3
244+ check_bytes_within_dist [64 bytes] 33.7
245+ check_bytes_within_dist [127 bytes] 34.7
246+ first_within_dist [512×16, at start] 35.6
247+ first_within_dist [512×16, mid] 240.7
248+ first_within_dist [512×16, at end] 440.5
249+ first_within_dist [16384×64, at start] 74.2
250+ first_within_dist [16384×64, mid] 14,319.4
251+ first_within_dist [16384×64, at end] 28,619.9
252+ best_within_dist [512×16, at start] 47.0
253+ best_within_dist [512×16, at end] 584.3
254+ best_within_dist [16384×64, mid] 32,031.4
255+ all_within_dist [512×16, at start] 530.4
256+ all_within_dist [512×16, at end] 537.5
257+ all_within_dist [16384×64, mid] 30,725.4
256258====================================================== ===========
257259
258- For small inputs, Python call and wrapper overhead dominates (roughly 40–55 ns
259- on this machine). For large inputs
260+ For random inputs, the direct APIs also avoid the temporary big integers used
261+ by an equivalent standard-library implementation:
262+
263+ ================ =============== ============== ========
264+ Input hexhamming (ns) stdlib (ns) Speedup
265+ ================ =============== ============== ========
266+ bytes [16] 33.5 158.3 4.72×
267+ bytes [64] 37.4 233.1 6.24×
268+ bytes [1024] 53.2 2,029.0 38.17×
269+ hex [16 chars] 37.2 126.3 3.39×
270+ hex [64 chars] 39.7 200.2 5.05×
271+ hex [1024 chars] 116.5 1,708.1 14.66×
272+ ================ =============== ============== ========
273+
274+ For small exact ``str `` and ``bytes `` inputs, Python call and wrapper overhead
275+ dominates (roughly 30–40 ns on this machine). For large inputs
260276(1024+ chars, 16384-element arrays), computation dominates and Python overhead
261- is negligible. Array APIs transparently parallelize with Rayon once the input
262- exceeds ~64 KiB; the ``first `` variant additionally short-circuits on the first
263- hit, so a match near the start is much faster than one near the end.
277+ is negligible. Byte operations release the GIL at 16 KiB, while immutable
278+ strings use a zero-copy detached path from 4 KiB. Array wrappers release the GIL
279+ at 64 KiB and parallelize with Rayon at 5 MiB; the ``first `` variant additionally
280+ short-circuits on the first hit, so a match near the start is much faster than
281+ one near the end.
0 commit comments