Comprehensive C++ Hashmap Benchmarks (2022)
46 points by klaussilveira 6 days ago | 14 comments

spacechild1 4 hours ago
Note that this benchmark does not include boost::unordered_flat_map. This is an open addressing variant of boost::unordered_map which has only been released in December 2022.

I wanted to mention this because boost::unordered_flat_map and boost::unordered_flat_set are among the fastest open addressing hash containers in C++ land. Internally, they use lots of cool SIMD tricks. If anyone is interested in the details, here's a nice blog post by the developer: https://bannalia.blogspot.com/2022/11/inside-boostunorderedf...

reply
loeg 3 hours ago
The F14/Abseil maps are included and use cute SIMD tricks, FWIW (discussed by the blogspot author).
reply
jandrewrogers 3 hours ago
Benchmarks are fine but they will only be loosely correlated with the measured performance for any specific use case.

There is still substantial performance to be gained by creating bespoke hashmap designs at every point of use in code. The high dimensionality of the algorithm optimization space makes it improbable that any specific hashmap algorithm implementation will optimally capture the characteristics of a use case or set of use cases. The variance can be relatively high.

It isn't uncommon to find several independent hashmap designs inside performance-engineered code bases. The sensitivity to small details makes it difficult to build excellent hashmap abstractions with broad scope.

reply
anematode 3 hours ago
Definitely. As an extreme but fun example... in one project I had a massive hash map (~700 GB or so) that was concurrently read to/written from by 256 threads. The entries themselves were only 16 bytes and so I could use atomic cmpxchg, but the problem I hit was that even with 1GB huge pages, I was running out of dTLB entries. So I assigned each thread to a subregion of the hash table, then used channels between each pair of threads to handle the reads and writes (and restructured the program a bit to allow this). Since the dTLB budget is per core, this allowed me to get essentially 0 dTLB misses, and ultimately sped up the program by ~2x
reply
senderista 52 minutes ago
The "delegation pattern" for datastructures:

https://timharris.uk/papers/2013-opodis.pdf

reply
anematode 50 minutes ago
ah! I thought I was being original :)
reply
jeffbee 3 hours ago
It's also the case that performance of a hashmap, or anything, in a small-scale benchmark may not reflect the performance in a large system that does things other than manage maps. There are side effects like how many icache lines are visited during a map operation. These don't hurt microbenchmarks but they can matter in real systems. It may not be completely pointless to microbenchmark a data structure but it can be ultimately misleading.
reply
menaerus 15 minutes ago
Totally. It's funny how many people do not actually realize this and get stuck in cargo-cult mindset forever, no matter the years of experience.
reply
hermitcrab 4 hours ago
Would be interested to hear how the Qt QHash compares.

https://doc.qt.io/qt-6/qhash.html

reply
rurban 4 hours ago
Still using linked lists as std::unordered_map. So it won't fly, but keeps ptr stability.
reply
hermitcrab 3 hours ago
Didn't all the QList<> linked lists become QVector<> is Qt 6?
reply
rurban 4 hours ago
Not really comprehesive. Doesn't include my favorite https://github.com/greg7mdp/parallel-hashmap which adds thread-safety to performance.
reply
aw1621107 4 hours ago
For what it's worth, there's this bit from the parallel-hashmap readme:

> We encourage phmap users to switch to gtl if possible. gtl provides the same functionality as this repository, but requires C++20 or above.

And the benchmarks do include gtl.

reply
rurban 3 hours ago
Thanks, didn't knew that.
reply