hashcodecs 1.4.0__tar.gz → 1.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hashcodecs-1.4.2/BENCHMARK.md +165 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/CHANGELOG.md +35 -1
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/CITATION.cff +2 -2
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/Cargo.lock +1 -1
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/Cargo.toml +1 -1
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/PKG-INFO +14 -13
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/README.md +13 -12
- hashcodecs-1.4.2/SAFETY.md +120 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/benches/crossover.rs +9 -5
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/benches/xxhash.rs +7 -1
- hashcodecs-1.4.2/docs/ARCHITECTURE.md +267 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/performance.md +13 -6
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hatch_build.py +1 -1
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/pyproject.toml +10 -10
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/decode/avx2.rs +17 -31
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/decode/sse41.rs +10 -7
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/decode/ssse3.rs +9 -6
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/decode/tables.rs +12 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/tests.rs +93 -10
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64.rs +0 -2
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/arguments.rs +8 -3
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/api.rs +16 -22
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/batch.rs +32 -28
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/configured.rs +70 -9
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/configured_tests.rs +4 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/decode.rs +473 -66
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/encode.rs +101 -66
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/lenient.rs +88 -15
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/policy.rs +49 -4
- hashcodecs-1.4.2/src/bindings/base64/strict.rs +187 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/buffer.rs +264 -18
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/objects.rs +2 -2
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/schema.rs +41 -10
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/xxhash/batch.rs +127 -21
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/dispatch.rs +4 -2
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/tests.rs +74 -21
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/long_inputs.rs +1 -1
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/one_shot.rs +1 -1
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/primitives.rs +2 -2
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/short_inputs.rs +34 -21
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/tests.rs +25 -0
- hashcodecs-1.4.0/BENCHMARK.md +0 -195
- hashcodecs-1.4.0/SAFETY.md +0 -47
- hashcodecs-1.4.0/docs/ARCHITECTURE.md +0 -218
- hashcodecs-1.4.0/src/bindings/base64/strict.rs +0 -274
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/.gitignore +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/LICENSE +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/LICENSE-MIT +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/SECURITY.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/benches/Cargo.toml +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/benches/base64.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/benches/murmur3.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/benches/support/mod.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/build.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/api/base64.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/api/murmur3.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/api/xxh3.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/base64.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/compatibility.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/index.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/murmur3.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/requirements.txt +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/docs/xxh3.md +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/generated/rust/binding_schema.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/generated/rust/murmur3_classes.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/__init__.py +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/__init__.pyi +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/_hashcodecs.pyi +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/base64.py +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/base64.pyi +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/murmur3.py +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/murmur3.pyi +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/py.typed +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/xxhash.py +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/hashcodecs/xxhash.pyi +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/backend.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/alphabet.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/backend.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/decode/aarch64.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/decode/avx512.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/decode/x86_contracts.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/decode.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/encode/aarch64.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/encode/avx2.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/encode/avx512.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/encode/cache.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/encode/ssse3.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/encode.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/error.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/miri_tests.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/output_buffer.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/proofs.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/runtime_dispatch.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/base64/tests/aarch64.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/scan/aarch64.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/scan/scalar.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/scan/x86.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/scan.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64/staging.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/base64.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/compatibility.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/murmur3/callbacks.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/murmur3/digest.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/murmur3/incremental.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/murmur3/methods.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/murmur3.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/runtime.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/xxhash/callbacks.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/xxhash/methods.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings/xxhash.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/bindings.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/lib.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/block_buffer.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/miri_tests.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/primitives.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/proofs.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/x64_128/x86.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/x64_128.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/x86_128/x86.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/x86_128.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/x86_32/x86.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3/x86_32.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/murmur3.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/batch.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/long_inputs/aarch64.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/long_inputs/scalar.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/long_inputs/x86/avx2.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/long_inputs/x86/avx2_batch.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/long_inputs/x86/avx512.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/long_inputs/x86/ssse3.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/long_inputs/x86.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/miri_tests.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/prepared.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash/proofs.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/src/xxhash.rs +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/tools/generate_api_metadata.py +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/tools/install_local_wheel.py +0 -0
- {hashcodecs-1.4.0 → hashcodecs-1.4.2}/tools/verify_sdist.py +0 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Benchmarks
|
|
2
|
+
|
|
3
|
+
Use this reference to compare `hashcodecs` APIs and reproduce the measurements for a change. For the implementation
|
|
4
|
+
behind the results, read [Architecture](docs/ARCHITECTURE.md).
|
|
5
|
+
|
|
6
|
+
## Measurement conditions
|
|
7
|
+
|
|
8
|
+
| Setting | Recorded comparison |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| Host | Windows 10 x64, Intel Core Ultra 7 265K |
|
|
11
|
+
| Execution | One thread, pinned to one logical CPU |
|
|
12
|
+
| Rust | Criterion, 50 samples per case, release optimization |
|
|
13
|
+
| Python timing | Median of 15 samples, calibrated to at least 0.2 seconds per sample |
|
|
14
|
+
| Python | Free-threaded CPython 3.14.6 (`3.14t`), GIL disabled |
|
|
15
|
+
| Python baselines | pybase64 1.5.0, mmh3 5.3.0, xxhash 4.0.1 |
|
|
16
|
+
| Allocation | `mimalloc` for Rust benchmark allocations and Rust allocations in the Python extension |
|
|
17
|
+
| XXH3 C baseline | xxHash 0.8.3 through `xxhash-c-sys`, compiled with AVX2 to match this host's selected backend |
|
|
18
|
+
|
|
19
|
+
Charts report GiB/s (2³⁰ bytes per second). Higher values mean greater throughput. Base64 uses the original binary
|
|
20
|
+
payload size for both encoding and decoding. Batch throughput counts the total payload across items. Default
|
|
21
|
+
Python Base64 comparisons use immutable `bytes` and strict decoding (`validate=True`).
|
|
22
|
+
|
|
23
|
+
Cases that return output include result allocation. Cases with reusable output allocate destinations before timing.
|
|
24
|
+
The harnesses reuse inputs across iterations, so cache residency affects the results. Compare like input types,
|
|
25
|
+
sizes, and output models. These measurements describe this host and workload.
|
|
26
|
+
|
|
27
|
+
The repository's [results.csv](docs/benchmarks/results.csv) supplies the chart values. Focused updates replace the
|
|
28
|
+
affected series and retain the other measurements, so the charts combine results from multiple runs.
|
|
29
|
+
|
|
30
|
+
## Base64 results
|
|
31
|
+
|
|
32
|
+
| API and workload | Charts |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| Rust, standard Base64 and Base64 for URLs | [Rust Base64](docs/benchmarks/base64-rust.svg) |
|
|
35
|
+
| Python, standard Base64 and Base64 for URLs | [Python Base64](docs/benchmarks/base64-python.svg) |
|
|
36
|
+
| Python, reusable `bytearray` output | [Reusable buffers](docs/benchmarks/base64-python-reusable.svg) |
|
|
37
|
+
| Python, MIME whitespace and ignored characters outside the alphabet | [Lenient decoding](docs/benchmarks/base64-python-lenient.svg) |
|
|
38
|
+
| Python, full and sliced immutable views | [Memoryview inputs](docs/benchmarks/base64-python-memoryview.svg) |
|
|
39
|
+
| Python, ASCII `str` decoding | [String inputs](docs/benchmarks/base64-python-str.svg) |
|
|
40
|
+
| Python, mutable `bytearray` input | [Mutable inputs](docs/benchmarks/base64-python-mutable.svg) |
|
|
41
|
+
| Python, batches | [Returned bytes](docs/benchmarks/base64-python-batch.svg), [reusable outputs](docs/benchmarks/base64-python-batch-reusable.svg) |
|
|
42
|
+
| Python, batches of memoryviews | [Memoryview batches](docs/benchmarks/base64-python-batch-memoryview.svg) |
|
|
43
|
+
| Python, batches of 1 MiB items | [Large batches](docs/benchmarks/base64-python-batch-large.svg) |
|
|
44
|
+
|
|
45
|
+
Batch charts use item count on the horizontal axis. Reusable Base64 batches provide one destination per item.
|
|
46
|
+
Lenient cases insert CRLF or `!` after each line of 76 characters.
|
|
47
|
+
|
|
48
|
+
## MurmurHash3 results
|
|
49
|
+
|
|
50
|
+
| API and workload | Charts |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| Rust, x86-32, x86-128, and x64-128 | [Rust MurmurHash3](docs/benchmarks/murmur3-rust.svg) |
|
|
53
|
+
| Python, single calls and incremental hashing | [Python MurmurHash3](docs/benchmarks/murmur3-python.svg) |
|
|
54
|
+
| Python, mutable `bytearray` input | [Mutable inputs](docs/benchmarks/murmur3-python-mutable.svg) |
|
|
55
|
+
|
|
56
|
+
Incremental cases include construction, `update`, and digest creation.
|
|
57
|
+
|
|
58
|
+
## XXH3 results
|
|
59
|
+
|
|
60
|
+
| API and workload | Charts |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| Rust, XXH3-64 and XXH3-128, single calls and batches of 32 items | [Rust XXH3](docs/benchmarks/xxh3-rust.svg) |
|
|
63
|
+
| Rust, batches of two and three items | [Batch remainders](docs/benchmarks/xxh3-rust-batch-remainders.svg) |
|
|
64
|
+
| Python, single calls, list results, and packed output | [Python XXH3](docs/benchmarks/xxh3-python.svg) |
|
|
65
|
+
|
|
66
|
+
Rust allocating batches include allocation of the result vector. Python list batches create one integer per digest.
|
|
67
|
+
Packed batches write digests in little endian order into one reusable `bytearray`. Python batch comparisons use
|
|
68
|
+
32 inputs of equal size by default and compare against the upstream `xxhash` extension.
|
|
69
|
+
|
|
70
|
+
The Python small-input panels cover 16, 17, 33, 65, 97, and 240 bytes. These sizes use scalar formulas; runtime SIMD
|
|
71
|
+
dispatch starts at 241 bytes.
|
|
72
|
+
|
|
73
|
+
## Reproduce a benchmark
|
|
74
|
+
|
|
75
|
+
Run commands from the repository root. Install Rust 1.89 or newer, a C/C++ compiler and linker for your platform,
|
|
76
|
+
and `uv`. Use free-threaded CPython 3.14 for the Python charts. The Python setup below builds and installs the
|
|
77
|
+
current checkout as a CPython wheel through Hatchling.
|
|
78
|
+
|
|
79
|
+
Run the group affected by your change. Reserve a complete run for changes that can affect all groups. Keep
|
|
80
|
+
benchmarks out of CI. The standard harnesses set CPU affinity on Windows and Linux. On other platforms, arrange
|
|
81
|
+
equivalent CPU pinning before collecting comparison results.
|
|
82
|
+
|
|
83
|
+
### Rust
|
|
84
|
+
|
|
85
|
+
Choose the relevant harness:
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
cargo bench --manifest-path benches/Cargo.toml --bench base64
|
|
89
|
+
cargo bench --manifest-path benches/Cargo.toml --bench murmur3
|
|
90
|
+
cargo bench --manifest-path benches/Cargo.toml --bench xxhash
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
To reproduce the Windows XXH3 C baseline, set the compiler flags and rebuild its package before running the harness:
|
|
94
|
+
|
|
95
|
+
```powershell
|
|
96
|
+
$env:CFLAGS = '/O2 /arch:AVX2'
|
|
97
|
+
cargo clean -p xxhash-c-sys
|
|
98
|
+
cargo bench --manifest-path benches/Cargo.toml --bench xxhash
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Use the equivalent AVX2 compiler flag on other platforms. Match the baseline instruction set to the backend under
|
|
102
|
+
comparison. Pass a Criterion name filter after `--` to narrow a run:
|
|
103
|
+
|
|
104
|
+
```sh
|
|
105
|
+
cargo bench --manifest-path benches/Cargo.toml --bench murmur3 -- x64_128/hashcodecs
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Python
|
|
109
|
+
|
|
110
|
+
Prepare the free-threaded interpreter (`3.14t`) and pinned benchmark dependencies. Repeat the wheel installation
|
|
111
|
+
after changing native code or switching interpreters:
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
uv sync --python 3.14t --frozen --group benchmark --no-install-project
|
|
115
|
+
uv run --python 3.14t --frozen --no-sync python tools/install_local_wheel.py
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Choose the relevant script:
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_base64.py
|
|
122
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_base64_batch.py
|
|
123
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_murmur3.py
|
|
124
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_xxhash.py
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The scripts check outputs before timing and print GiB/s. Append a mode from the table to select a workload. Use
|
|
128
|
+
`--help` for the full option list.
|
|
129
|
+
|
|
130
|
+
| Script | Focused modes |
|
|
131
|
+
| --- | --- |
|
|
132
|
+
| `python_base64.py` | `--into`, `--lenient`, `--custom-lenient`, `--bytearray-input`, `--memoryview-input`, `--sliced-memoryview-input`, `--str-input` |
|
|
133
|
+
| `python_base64_batch.py` | `--large`, `--memoryview-input`, `--decode-only`. Select sizes with `--item-sizes` and `--batch-sizes`. |
|
|
134
|
+
| `python_murmur3.py` | `--incremental`, `--bytearray-input` |
|
|
135
|
+
| `python_xxhash.py` | `--one-shot-only`, `--sizes 17 33 65 97 240`, `--batches-only`, `--batch-counts 2 3` |
|
|
136
|
+
|
|
137
|
+
`python_base64.py` accepts one mode per run. Its `--configured` and `--wrapped` modes require CPython 3.15 or newer.
|
|
138
|
+
Use that interpreter for both setup commands and the benchmark. These modes cover configured decoding and
|
|
139
|
+
encoding with newlines after 76 output characters.
|
|
140
|
+
|
|
141
|
+
The four scripts accept `--hashcodecs-only` to skip competitor timing. The Base64 script treats that flag as a
|
|
142
|
+
mode, so run it apart from `--into`, `--lenient`, and the other Base64 modes. All four accept `--samples` and
|
|
143
|
+
`--minimum-sample-seconds`. Keep the defaults for published comparisons. Lower them for local exploration.
|
|
144
|
+
|
|
145
|
+
For call overhead, run `benchmarks/python_calls.py` with the same `uv run` prefix. It reports nanoseconds per call
|
|
146
|
+
and supports `--keywords`, `--thresholds`, and `--buffer-inputs`. Its `--thread-scaling` mode measures aggregate
|
|
147
|
+
throughput without pinning to one CPU. Keep those results separate from the charts above.
|
|
148
|
+
|
|
149
|
+
## Update the charts
|
|
150
|
+
|
|
151
|
+
1. Copy the measured GiB/s values into [results.csv](docs/benchmarks/results.csv). Update the series you measured.
|
|
152
|
+
Retain unmeasured values and leave `gib_per_second` empty for unavailable results.
|
|
153
|
+
2. Keep matching input categories across implementations in each panel. Each row identifies a chart, panel,
|
|
154
|
+
input category, and implementation. Row order controls chart, panel, category, and legend order.
|
|
155
|
+
3. Render the SVG files:
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
uv run --python 3.14t --no-project python benchmarks/render_charts.py
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
4. Review the CSV and SVG diff. A focused update should change the corresponding charts, including any README
|
|
162
|
+
overview that uses those values.
|
|
163
|
+
|
|
164
|
+
The renderer reads the CSV without running benchmarks or changing measurements. Keep temporary tuning sweeps,
|
|
165
|
+
branch comparisons, and profiler output out of this reference.
|
|
@@ -4,6 +4,38 @@ This file records notable user-facing changes to `hashcodecs`. Version 1.0.0 sta
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.4.2] - 2026-09-29
|
|
8
|
+
|
|
9
|
+
### What's Changed
|
|
10
|
+
* perf: Improve AVX2 Base64 decoding throughput by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/125
|
|
11
|
+
* perf: Reduce SSE Base64 decode stores by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/126
|
|
12
|
+
* perf: Reduce Python Base64 ASCII decoding overhead by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/127
|
|
13
|
+
* docs: Clarify benchmarks, architecture, and safety guidance by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/128
|
|
14
|
+
* chore: Refresh all Python benchmarks on free-threaded 3.14 by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/129
|
|
15
|
+
* perf: Reduce Python XXH3 seed conversion overhead by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/130
|
|
16
|
+
* perf: Speed up short XXH3 inputs by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/131
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
**Full Changelog**: https://github.com/kozistr/hashcodecs-rs/compare/v1.4.1...v1.4.2
|
|
20
|
+
|
|
21
|
+
## [1.4.1] - 2026-09-13
|
|
22
|
+
|
|
23
|
+
### What's Changed
|
|
24
|
+
* fix: match CPython Base64 and XXH3 buffer semantics by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/114
|
|
25
|
+
* fix: preserve Base64 callback buffer semantics by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/115
|
|
26
|
+
* fix: preserve CPython Base64 observable behavior by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/116
|
|
27
|
+
* fix: resolve repository type diagnostics by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/117
|
|
28
|
+
* fix: release Base64 input buffers before writing output by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/118
|
|
29
|
+
* refactor: centralize buffer callback policy and clarify finalizers by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/119
|
|
30
|
+
* fix: accelerate custom-alphabet lenient Base64 decoding by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/120
|
|
31
|
+
* fix: reduce XXH3 packed batch detachment overhead by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/121
|
|
32
|
+
* fix: delay MurmurHash3 x64 SIMD dispatch until 512 bytes by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/122
|
|
33
|
+
* fix: restore Python buffer and batch throughput by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/123
|
|
34
|
+
* fix: typo in the performance viz image by @kozistr in https://github.com/kozistr/hashcodecs-rs/pull/124
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
**Full Changelog**: https://github.com/kozistr/hashcodecs-rs/compare/v1.4.0...v1.4.1
|
|
38
|
+
|
|
7
39
|
## [1.4.0] - 2026-09-10
|
|
8
40
|
|
|
9
41
|
### What's Changed
|
|
@@ -193,7 +225,9 @@ This file records notable user-facing changes to `hashcodecs`. Version 1.0.0 sta
|
|
|
193
225
|
- Initial Python and Rust APIs for Base64 and MurmurHash3.
|
|
194
226
|
- Runtime SIMD dispatch and platform-specific CPython wheels.
|
|
195
227
|
|
|
196
|
-
[Unreleased]: https://github.com/kozistr/hashcodecs-rs/compare/v1.4.
|
|
228
|
+
[Unreleased]: https://github.com/kozistr/hashcodecs-rs/compare/v1.4.2...HEAD
|
|
229
|
+
[1.4.2]: https://github.com/kozistr/hashcodecs-rs/compare/v1.4.1...v1.4.2
|
|
230
|
+
[1.4.1]: https://github.com/kozistr/hashcodecs-rs/compare/v1.4.0...v1.4.1
|
|
197
231
|
[1.4.0]: https://github.com/kozistr/hashcodecs-rs/compare/v1.3.0...v1.4.0
|
|
198
232
|
[1.3.0]: https://github.com/kozistr/hashcodecs-rs/compare/v1.2.1...v1.3.0
|
|
199
233
|
[1.2.1]: https://github.com/kozistr/hashcodecs-rs/compare/v1.2.0...v1.2.1
|
|
@@ -5,8 +5,8 @@ authors:
|
|
|
5
5
|
given-names: Hyeongchan
|
|
6
6
|
orcid: https://orcid.org/0000-0002-1729-0580
|
|
7
7
|
title: "hashcodecs: SIMD-accelerated Base64, MurmurHash3, and XXH3 for Python and Rust"
|
|
8
|
-
version: 1.4.
|
|
9
|
-
date-released: 2026-09-
|
|
8
|
+
version: 1.4.2
|
|
9
|
+
date-released: 2026-09-29
|
|
10
10
|
license: "MIT OR Apache-2.0"
|
|
11
11
|
repository-code: "https://github.com/kozistr/hashcodecs-rs"
|
|
12
12
|
url: "https://github.com/kozistr/hashcodecs-rs"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: hashcodecs
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.2
|
|
4
4
|
Summary: SIMD-accelerated Base64, MurmurHash3, and xxHash codecs
|
|
5
5
|
Project-URL: Documentation, https://hashcodecs-rs.readthedocs.io/
|
|
6
6
|
Project-URL: Repository, https://github.com/kozistr/hashcodecs-rs
|
|
@@ -43,7 +43,7 @@ Description-Content-Type: text/markdown
|
|
|
43
43
|
|
|
44
44
|
<p align="center">
|
|
45
45
|
<a href="BENCHMARK.md">
|
|
46
|
-
<img src="docs/benchmarks/performance-at-a-glance.svg" alt="CPython 3.
|
|
46
|
+
<img src="docs/benchmarks/performance-at-a-glance.svg" alt="Free-threaded CPython 3.14.6 standard Base64 encoding and decoding benchmark">
|
|
47
47
|
</a>
|
|
48
48
|
</p>
|
|
49
49
|
|
|
@@ -184,6 +184,7 @@ CPython boundary, and safety invariants.
|
|
|
184
184
|
|
|
185
185
|
Run the suite on Windows 10 x64 with an Intel Core Ultra 7 265K. Pin one logical CPU and run each case in one thread.
|
|
186
186
|
Collect 50 Rust samples and 15 Python samples. Higher throughput wins.
|
|
187
|
+
Use free-threaded CPython 3.14.6 with the GIL disabled for all Python charts.
|
|
187
188
|
|
|
188
189
|
### Base64: Rust
|
|
189
190
|
|
|
@@ -230,12 +231,13 @@ cargo bench --manifest-path benches/Cargo.toml --bench murmur3
|
|
|
230
231
|
cargo bench --manifest-path benches/Cargo.toml --bench xxhash
|
|
231
232
|
cargo bench --manifest-path benches/Cargo.toml --bench crossover
|
|
232
233
|
|
|
233
|
-
uv sync --group benchmark --no-install-project
|
|
234
|
-
uv run --
|
|
235
|
-
uv run --
|
|
236
|
-
uv run --
|
|
237
|
-
uv run --
|
|
238
|
-
uv run --
|
|
234
|
+
uv sync --python 3.14t --frozen --group benchmark --no-install-project
|
|
235
|
+
uv run --python 3.14t --frozen --no-sync python tools/install_local_wheel.py
|
|
236
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_base64.py
|
|
237
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_base64_batch.py
|
|
238
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_calls.py
|
|
239
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_murmur3.py
|
|
240
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_xxhash.py
|
|
239
241
|
```
|
|
240
242
|
|
|
241
243
|
The Python benchmarks expose focused modes such as `--into`, `--lenient`, `--bytearray-input`, `--memoryview-input`,
|
|
@@ -253,11 +255,10 @@ cargo bench --manifest-path benches/Cargo.toml --bench xxhash
|
|
|
253
255
|
|
|
254
256
|
## Performance snapshot
|
|
255
257
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
[benchmark details](BENCHMARK.md) and [raw comparison results](docs/benchmarks/results.csv).
|
|
258
|
+
On the benchmark host with CPython 3.14.6t, `hashcodecs.xxh3_64` processes a 1 MiB input at 80.87 GiB/s. The Base64
|
|
259
|
+
batch API reaches 5.10 GiB/s for encode and 5.03 GiB/s for decode with 256 B items in batches of 64. Each run pins
|
|
260
|
+
one logical CPU and uses 15 samples with a 0.2-second minimum per sample. Read the [benchmark details](BENCHMARK.md)
|
|
261
|
+
and [raw comparison results](docs/benchmarks/results.csv).
|
|
261
262
|
|
|
262
263
|
## Development
|
|
263
264
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
<p align="center">
|
|
14
14
|
<a href="BENCHMARK.md">
|
|
15
|
-
<img src="docs/benchmarks/performance-at-a-glance.svg" alt="CPython 3.
|
|
15
|
+
<img src="docs/benchmarks/performance-at-a-glance.svg" alt="Free-threaded CPython 3.14.6 standard Base64 encoding and decoding benchmark">
|
|
16
16
|
</a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
@@ -153,6 +153,7 @@ CPython boundary, and safety invariants.
|
|
|
153
153
|
|
|
154
154
|
Run the suite on Windows 10 x64 with an Intel Core Ultra 7 265K. Pin one logical CPU and run each case in one thread.
|
|
155
155
|
Collect 50 Rust samples and 15 Python samples. Higher throughput wins.
|
|
156
|
+
Use free-threaded CPython 3.14.6 with the GIL disabled for all Python charts.
|
|
156
157
|
|
|
157
158
|
### Base64: Rust
|
|
158
159
|
|
|
@@ -199,12 +200,13 @@ cargo bench --manifest-path benches/Cargo.toml --bench murmur3
|
|
|
199
200
|
cargo bench --manifest-path benches/Cargo.toml --bench xxhash
|
|
200
201
|
cargo bench --manifest-path benches/Cargo.toml --bench crossover
|
|
201
202
|
|
|
202
|
-
uv sync --group benchmark --no-install-project
|
|
203
|
-
uv run --
|
|
204
|
-
uv run --
|
|
205
|
-
uv run --
|
|
206
|
-
uv run --
|
|
207
|
-
uv run --
|
|
203
|
+
uv sync --python 3.14t --frozen --group benchmark --no-install-project
|
|
204
|
+
uv run --python 3.14t --frozen --no-sync python tools/install_local_wheel.py
|
|
205
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_base64.py
|
|
206
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_base64_batch.py
|
|
207
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_calls.py
|
|
208
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_murmur3.py
|
|
209
|
+
uv run --python 3.14t --frozen --no-sync python benchmarks/python_xxhash.py
|
|
208
210
|
```
|
|
209
211
|
|
|
210
212
|
The Python benchmarks expose focused modes such as `--into`, `--lenient`, `--bytearray-input`, `--memoryview-input`,
|
|
@@ -222,11 +224,10 @@ cargo bench --manifest-path benches/Cargo.toml --bench xxhash
|
|
|
222
224
|
|
|
223
225
|
## Performance snapshot
|
|
224
226
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
[benchmark details](BENCHMARK.md) and [raw comparison results](docs/benchmarks/results.csv).
|
|
227
|
+
On the benchmark host with CPython 3.14.6t, `hashcodecs.xxh3_64` processes a 1 MiB input at 80.87 GiB/s. The Base64
|
|
228
|
+
batch API reaches 5.10 GiB/s for encode and 5.03 GiB/s for decode with 256 B items in batches of 64. Each run pins
|
|
229
|
+
one logical CPU and uses 15 samples with a 0.2-second minimum per sample. Read the [benchmark details](BENCHMARK.md)
|
|
230
|
+
and [raw comparison results](docs/benchmarks/results.csv).
|
|
230
231
|
|
|
231
232
|
## Development
|
|
232
233
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Memory safety verification
|
|
2
|
+
|
|
3
|
+
Use this reference when reviewing changes to unsafe Rust or CPython buffer handling. It identifies the memory
|
|
4
|
+
contracts, the checks that exercise them, and the commands to reproduce those checks. For performance mechanisms,
|
|
5
|
+
see [Architecture](docs/ARCHITECTURE.md).
|
|
6
|
+
|
|
7
|
+
## Required invariants
|
|
8
|
+
|
|
9
|
+
| Boundary | Required contract | Source |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| CPU dispatch | Check the features required by a kernel and its fallback paths before executing SIMD instructions. | [CPU detection](src/backend.rs), [Base64 dispatch](src/base64/backend.rs), [MurmurHash3 dispatch](src/murmur3/dispatch.rs), [XXH3 engine](src/xxhash/long_inputs.rs) |
|
|
12
|
+
| Input loads | Keep scalar word loads, vector loads, and final overlapping stripes within the input allocation. | [MurmurHash3 loads](src/murmur3/primitives.rs), [XXH3 loads](src/xxhash/primitives.rs), [XXH3 schedule](src/xxhash/long_inputs.rs) |
|
|
13
|
+
| Output stores | Check capacity before writing. Overlapping vector stores need space for their full width. Exact outputs must preserve bytes beyond the returned length. | [Base64 store policies](src/base64/decode/x86_contracts.rs), [output initialization](src/base64/output_buffer.rs) |
|
|
14
|
+
| Result initialization | Initialize the returned prefix before exposing uninitialized storage as a result. | [Base64 allocation](src/base64/output_buffer.rs), [XXH3 batch results](src/bindings/xxhash/batch.rs) |
|
|
15
|
+
| Python ownership | Keep owners alive and stabilize inputs before callbacks, overlapping writes, or interpreter detachment can invalidate a borrow. | [Buffer policy](src/bindings/buffer.rs), [Base64 batches](src/bindings/base64/batch.rs) |
|
|
16
|
+
|
|
17
|
+
Exact output bounds do not imply rollback on errors. Reusable Base64 batches retain prior destination writes.
|
|
18
|
+
Packed XXH3 batches validate and stabilize inputs before mutating the destination.
|
|
19
|
+
|
|
20
|
+
## CPython ownership and callbacks
|
|
21
|
+
|
|
22
|
+
The global interpreter lock (GIL) does not prevent callbacks from running on the same thread. Python allocation
|
|
23
|
+
can trigger garbage collection and finalizers that clear an input list or resize a `bytearray`. Argument
|
|
24
|
+
conversion and buffer release can also invoke user code. Bindings must preserve input ownership across these
|
|
25
|
+
operations and copy mutable or overlapping data where the buffer policy requires it.
|
|
26
|
+
|
|
27
|
+
XXH3 list batches finish input reads before allocating Python result containers. They store up to 32 native
|
|
28
|
+
results on the stack and use a vector with fallible allocation for larger batches. Base64 batches retain input
|
|
29
|
+
owners across result allocation. Subprocess tests on CPython 3.10 and 3.11 trigger finalizers during allocation
|
|
30
|
+
and reuse freed storage to check these lifetime rules.
|
|
31
|
+
|
|
32
|
+
Detached packed XXH3 batches retain immutable owners and stage digests in native memory. The path for exact
|
|
33
|
+
`bytes` borrows 64 retained inputs at a time in a stack array. After reattaching, the binding rechecks destination
|
|
34
|
+
capacity under synchronization before writing. The private `PackedDigest` contract requires initialized bytes
|
|
35
|
+
without padding and a representation matching the packed output on hosts that use little endian order. Those
|
|
36
|
+
hosts can copy the staged results in one operation. Other hosts serialize each word.
|
|
37
|
+
|
|
38
|
+
Tests cover source list mutation, output resizing, overlapping buffers, and access to mutable data on CPython
|
|
39
|
+
builds without the GIL. See the [XXH3 binding tests](src/bindings/xxhash/batch.rs),
|
|
40
|
+
[XXH3 Python tests](tests/test_xxhash.py), [Base64 batch tests](tests/test_base64_batch.py), and
|
|
41
|
+
[buffer tests](tests/test_base64_buffers.py).
|
|
42
|
+
|
|
43
|
+
## Verification scope
|
|
44
|
+
|
|
45
|
+
| Check | What it verifies | Limits |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
| Kani | Base64 scalar output bounds, MurmurHash3 and XXH3 word loads, MurmurHash3 scalar block loops, and XXH3 scheduling bounds. | Proofs apply within each harness's assumptions and unwind limits. The XXH3 schedule proof covers 241 through 3,072 bytes. |
|
|
48
|
+
| Miri | Scalar allocation, pointer provenance, exact Base64 outputs, MurmurHash3 incremental state, and XXH3 length classes and batches. | The Miri configuration uses scalar dispatch and does not execute hardware intrinsics. |
|
|
49
|
+
| AddressSanitizer | Invalid memory access in the sanitizer executable, including runtime SIMD paths, exact Base64 outputs, and hash batches. | Exercises inputs in the harness and backends available on the host. |
|
|
50
|
+
| MemorySanitizer | Reads of uninitialized memory in the same executable. | Exercises the instrumented Rust core, including a rebuilt standard library. |
|
|
51
|
+
| libFuzzer | Differential output checks against `base64`, `murmur3`, and `xxhash-rust` under sanitizers. | A timed run samples inputs. XXH3 batches cover one through nine independent buffers with equal or mixed lengths. |
|
|
52
|
+
| Python and Rust binding tests | Callback order, retained owners, alias snapshots, output publication, and thread coordination. | Some cases require a specific CPython version or a build without the GIL. |
|
|
53
|
+
|
|
54
|
+
The Rust Kani, Miri, sanitizer, and fuzz jobs exclude the optional CPython bindings. Binding tests cover that
|
|
55
|
+
boundary. Passing a check establishes its stated coverage, not a proof of all unsafe code.
|
|
56
|
+
|
|
57
|
+
Proof harnesses live in [Base64](src/base64/proofs.rs), [MurmurHash3](src/murmur3/proofs.rs), and
|
|
58
|
+
[XXH3](src/xxhash/proofs.rs). Miri cases live in the corresponding `miri_tests.rs` files.
|
|
59
|
+
The [sanitizer executable](tests/sanitizers.rs), [fuzz targets](fuzz/fuzz_targets), and
|
|
60
|
+
[CI workflow](.github/workflows/ci.yml) define the executed checks.
|
|
61
|
+
[Fuzz dependencies](fuzz/Cargo.toml) record the reference implementations.
|
|
62
|
+
|
|
63
|
+
## Run the Rust checks on Linux
|
|
64
|
+
|
|
65
|
+
Run these commands from the repository root on Linux x86_64 with a C/C++ compiler and linker installed.
|
|
66
|
+
Install nightly Rust with the `rust-src` and `miri` components, plus `cargo-fuzz`. Install
|
|
67
|
+
[Kani](https://model-checking.github.io/kani/install-guide.html) and complete `cargo kani setup` before running proofs.
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
rustup toolchain install nightly --component rust-src --component miri
|
|
71
|
+
cargo install cargo-fuzz --locked
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Run the proofs and scalar interpreter checks:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
cargo kani
|
|
78
|
+
MIRIFLAGS=-Zmiri-strict-provenance \
|
|
79
|
+
cargo +nightly miri test --lib miri_tests
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Run the sanitizer executable with each instrumentation mode:
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
RUSTFLAGS="-Zsanitizer=address" \
|
|
86
|
+
RUSTDOCFLAGS="-Zsanitizer=address" \
|
|
87
|
+
cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu \
|
|
88
|
+
--test sanitizers
|
|
89
|
+
|
|
90
|
+
RUSTFLAGS="-Zsanitizer=memory -Zsanitizer-memory-track-origins" \
|
|
91
|
+
RUSTDOCFLAGS="-Zsanitizer=memory -Zsanitizer-memory-track-origins" \
|
|
92
|
+
cargo +nightly test -Zbuild-std --target x86_64-unknown-linux-gnu \
|
|
93
|
+
--test sanitizers
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Run the bounded fuzz checks used in CI:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
cargo +nightly fuzz run base64 -- -max_total_time=30 -rss_limit_mb=2048
|
|
100
|
+
cargo +nightly fuzz run murmur3 -- -max_total_time=30 -rss_limit_mb=2048
|
|
101
|
+
cargo +nightly fuzz run xxhash -- -max_total_time=30 -rss_limit_mb=2048
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Successful runs exit with status zero and no failed proof, assertion, or sanitizer diagnostic. Preserve any
|
|
105
|
+
failing input or counterexample and reproduce the failure before changing the affected code.
|
|
106
|
+
|
|
107
|
+
## Run the CPython checks
|
|
108
|
+
|
|
109
|
+
Build the current wheel before testing the installed package:
|
|
110
|
+
|
|
111
|
+
```sh
|
|
112
|
+
uv sync --python 3.12 --frozen --no-install-project
|
|
113
|
+
uv run --python 3.12 --frozen --no-sync python tools/install_local_wheel.py
|
|
114
|
+
uv run --python 3.12 --frozen --no-sync pytest tests
|
|
115
|
+
uv run --python 3.12 --frozen --no-sync cargo test --features python
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Repeat the setup and test commands with `3.10` or `3.11` for the finalizer subprocess cases and with `3.15t` for
|
|
119
|
+
cases that require CPython without the GIL. Those tests skip on incompatible interpreters. Check the selected
|
|
120
|
+
interpreter and skipped cases before treating a run as coverage of those behaviors.
|
|
@@ -8,6 +8,7 @@ mod support;
|
|
|
8
8
|
const BASE64_ENCODE_SIZES: [usize; 10] = [15, 16, 31, 32, 47, 48, 51, 52, 103, 104];
|
|
9
9
|
const BASE64_DECODE_SIZES: [usize; 8] = [12, 16, 28, 32, 60, 64, 124, 128];
|
|
10
10
|
const MURMUR_SIZES: [usize; 6] = [15, 16, 31, 32, 255, 256];
|
|
11
|
+
const MURMUR_X64_SIZES: [usize; 12] = [15, 16, 31, 32, 64, 255, 256, 384, 511, 512, 513, 1024];
|
|
11
12
|
|
|
12
13
|
fn data(size: usize) -> Vec<u8> {
|
|
13
14
|
(0..size)
|
|
@@ -41,9 +42,9 @@ fn base64_decode(c: &mut Criterion) {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
macro_rules! murmur_group {
|
|
44
|
-
($criterion:expr, $name:literal, $function:path) => {{
|
|
45
|
+
($criterion:expr, $name:literal, $function:path, $sizes:expr) => {{
|
|
45
46
|
let mut group = $criterion.benchmark_group($name);
|
|
46
|
-
for size in
|
|
47
|
+
for size in $sizes {
|
|
47
48
|
let input = data(size);
|
|
48
49
|
group.throughput(Throughput::Bytes(size as u64));
|
|
49
50
|
group.bench_with_input(BenchmarkId::from_parameter(size), &input, |bench, input| {
|
|
@@ -58,17 +59,20 @@ fn murmur3(c: &mut Criterion) {
|
|
|
58
59
|
murmur_group!(
|
|
59
60
|
c,
|
|
60
61
|
"murmur_x86_32_crossover",
|
|
61
|
-
hashcodecs::murmur3::murmur3_x86_32
|
|
62
|
+
hashcodecs::murmur3::murmur3_x86_32,
|
|
63
|
+
MURMUR_SIZES
|
|
62
64
|
);
|
|
63
65
|
murmur_group!(
|
|
64
66
|
c,
|
|
65
67
|
"murmur_x86_128_crossover",
|
|
66
|
-
hashcodecs::murmur3::murmur3_x86_128
|
|
68
|
+
hashcodecs::murmur3::murmur3_x86_128,
|
|
69
|
+
MURMUR_SIZES
|
|
67
70
|
);
|
|
68
71
|
murmur_group!(
|
|
69
72
|
c,
|
|
70
73
|
"murmur_x64_128_crossover",
|
|
71
|
-
hashcodecs::murmur3::murmur3_x64_128
|
|
74
|
+
hashcodecs::murmur3::murmur3_x64_128,
|
|
75
|
+
MURMUR_X64_SIZES
|
|
72
76
|
);
|
|
73
77
|
}
|
|
74
78
|
|
|
@@ -6,13 +6,19 @@ use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_m
|
|
|
6
6
|
|
|
7
7
|
mod support;
|
|
8
8
|
|
|
9
|
-
const SIZES: [usize;
|
|
9
|
+
const SIZES: [usize; 22] = [
|
|
10
10
|
16,
|
|
11
11
|
17,
|
|
12
12
|
32,
|
|
13
|
+
33,
|
|
13
14
|
64,
|
|
15
|
+
65,
|
|
16
|
+
97,
|
|
14
17
|
128,
|
|
15
18
|
129,
|
|
19
|
+
160,
|
|
20
|
+
192,
|
|
21
|
+
224,
|
|
16
22
|
240,
|
|
17
23
|
241,
|
|
18
24
|
512,
|