These are benchmarks of how the different Rust hashing algorithm implementations compare. In particular, they are using the Hasher interface, which may not be optimal for all algorithms. Implementation quality may also vary.
Numbers are generated from a MacBook Pro (x64 OSX) with a 2.8 GHz Intel Core i7 (Haswell) and 16GB of RAM. This is unfortunately quite important, as even different cpu revisions by the same manufacturer (e.g. Haswell vs Sandy Bridge) can produce significantly different results for these functions. As always, bench your workload on your hardware for best results.
Variance bars excluded because this dang charting library was absolutely freaking out with them. Note also that both axes are on a log-scale, so small vertical differences may actually represent a large difference.
The hash functions on display are:
SipHash 2-4 (sip): This is the state-of-the-art for hashing that is completely resistant against even theoretical hash flooding DDOS attacks when paired with a random seed. While most applications probably do not require this, it's important for some usecases (for instance, many webservers can be completely locked up by POST requests with colliding keys). Since this is a relatively obscure attack, but quite costly when applicable, we believe that it's important to default to such a hash function. As such, this is the default hasher used by Rust's HashMap, but it can be overloaded. Sip's performance is overall mediocre but consistent. As such, it's not an awful default.
Performance could be gained by moving to SipHash 2-3, which has slightly inferior cryptographic properties, but is sufficient for preventing flooding.
Fowler-Noll-Vo (fnv): A hash function with excellent distribution, but no particular cryptographic properties. FNV is the best at small inputs, but does terribly on large inputs. Since small inputs are much more common, it's the Rust community's most popular override for SipHash where security doesn't matter. The Rust compiler itself uses this function.
xxHash (xx): Like fnv, a hash function with good distribution, but no crypto. It's our best performer for large inputs, and performs strongly on small ones.
FarmHash (farm): Another decent distribution, but no crypto. This algorithm is intended to perform excellently on all sizes of input, but is massively pessimized by Rust's streaming hashing architecture, as it's designed to process the input in one shot, forcing the entire input to be buffered in a growable array. In order for it to compete, Rust needs to adopt a solution that allows the top-level type in a hashing to identify whether it can be hashed in a one-shot manner, for a specialized result. However this can lead to confusing or inconsistent results, particularly if hashing derivation is done incorrectly.
Horner (horner): A universal hash function without the full cryptographic strength of SipHash. It defends against all hash flooding attacks that have been demonstrated in practice, but is theoretically vulnerable to a timing attack if the attacker is allowed to continuously query against maps with the same seed. It's unclear how practical this attack is under ideal conditions for the attacker, but for most situations this hasher is likely sufficient. Performance is roughly on-par with xxHash.
btree is not a hash function at all, but rather feeding the same inputs into Rust's BTreeMap, which is based on comparisons instead of hashing. This serves as a baseline, as well as a demonstration of how ordered data structures can completely stomp unordered data structures under particular workloads, even when not used for their ordering properties. btreenew is an experimental rewrite of std's btree that is kicking its butt.