> Blake3 and SHA-3’s dead-last performance is a bit surprising to me.
Me too :) BLAKE2s was the fastest cryptographic hash for short inputs in these benchmarks, and BLAKE3 should be strictly faster than BLAKE2s, since in this short-input regime it's just the ~same compression function with fewer rounds. I haven't done much benchmarking on AMD CPUs myself, but https://bench.cr.yp.to/results-hash.html has results from an AMD Ryzen 7 7700 that match what I expect. Python's hashlib is going to get BLAKE2s from OpenSSL, so my guess is that the problem might be something about how the BLAKE3 Python module was compiled? It could also be that that module constructs some unnecessary objects or something like that, which doesn't matter for long inputs but which starts to dominate the runtime for tiny ones?
I just took another quick look at my Rust code and Python's C code. It looks like they try to avoid allocating/acquiring a Mutex in the short case. I wonder if that could be part of the problem. Allocating a Rust Mutex should be ~free on Linux, but acquiring it will be a SeqCst compare-exchange...
Edit: My code avoids acquiring the Mutex in the initial constructor and only takes it in update(). Are you using update() in your benchmark? If you tweak it to avoid update, does it affect the numbers?
input bytes: b'hello world'
average SHA-256 iteration time: 284 ns
average SHA-512 iteration time: 470 ns
average BLAKE2s iteration time: 231 ns
average BLAKE3 iteration time: 355 ns
For comparison, in short-input Rust benchmarks on the same machine, one block of BLAKE2s (SSE41) is 77 ns and one block of BLAKE3 (AVX512VL) is 43 ns. So whatever's happening here, I think it's dominated by Python overhead.
5 comments
[ 2.4 ms ] story [ 24.2 ms ] threadMe too :) BLAKE2s was the fastest cryptographic hash for short inputs in these benchmarks, and BLAKE3 should be strictly faster than BLAKE2s, since in this short-input regime it's just the ~same compression function with fewer rounds. I haven't done much benchmarking on AMD CPUs myself, but https://bench.cr.yp.to/results-hash.html has results from an AMD Ryzen 7 7700 that match what I expect. Python's hashlib is going to get BLAKE2s from OpenSSL, so my guess is that the problem might be something about how the BLAKE3 Python module was compiled? It could also be that that module constructs some unnecessary objects or something like that, which doesn't matter for long inputs but which starts to dominate the runtime for tiny ones?
The blake3-py library uses PyO3 to bind the official Rust implementation, so I wonder perhaps if PyO3 is adding some overhead.
Sounds like I have some more testing to do.
Edit: My code avoids acquiring the Mutex in the initial constructor and only takes it in update(). Are you using update() in your benchmark? If you tweak it to avoid update, does it affect the numbers?