Add ASKL Map#4
Conversation
|
Thanks for doing this work! I'm working on getting it to compile now. Then I can run the benchmarks and share the results with you. Currently, I get quite a few errors and warnings that fall into the following categories:
Verstable is also causing an error due to a conflict between a macro it defines ( I'll modify ASKL to fix each of these issues - hopefully it will compile then. As for the hash function, these benchmarks try to level the playing field by forcing each library to use the same hash function (FNV-1a in the case of strings) and the same maximum load factor (0.875). That's because they started life as a tool to evaluate hash table designs and only later took a turn toward also trying to evaluate hash table libraries (there's a tension in the project's goals here). FNV-1a is not a fast hash function, so askl_map should have quite an advantage if it is allowed to use its default. What I'd like to do here is to run the benchmarks once with askl_map conforming to those requirements and again with each library using its defaults. Then you can review both results. I'm not sure how I'll handling merging the PR. Maybe it would be best for me to merge it into a new branch? The issue here is that I wasn't planning to update the 2024 write-up (which would take a lot of work) anytime soon, and the write-up points to the repo as its source code. |
|
I finally found some time to run the benchmarks. I included ASKL's map, Verstable, khash, khashl, and the two maps from M*LIB, which - besides khashl - are the hash tables that I test in 2024 and that also appeared in your own benchmarks. Most of these hash tables are the versions that were current in 2024 (i.e. I haven't updated them to the most recent versions). I also accidentally included boost::unordered_flat_map instead of Abseil. But Boost was the top performer in 2024, so it's a good yardstick. I used the shim you provided, unmodified. Originally I planned to run the benchmarks once with all hash tables - including ASKL - using the same hash functions (Murmur3 mixer for integers and FNV-1a for strings) and again with all hash tables using their default hash functions, as I explained earlier. However, I didn't end up doing that for reasons that will become clear below. Instead, I tested with all tables except ASKL using Murmer3 mixer/FNV-1a and ASKL using its defaults. This means that ASKL should have an advantage here because neither the Murmer3 mixer or FNV-1a are fast hash functions. Note that khashl - or at least the version I tested (from sometime in 2025, if I recall correctly) - doesn't provide an iteration API, so for that test it does nothing. That's why it looks like it's much faster than the other tables for iteration. In actuality, Boost has the fastest iteration here, followed by Verstable. Here's the results I get (GCC 12.1 via MinGW, -O3, AMD Ryzen 7 5800H, 16 GB RAM): askl_200_000_keys.html
Unfortunately, ASKL doesn't seem to be performing very well in these benchmarks, overall. That's why I didn't bother modifying it to use the slower hash functions, like the other tables, or to see how it competes with the other tables when they are allowed to use their (presumably faster) defaults. In those cases, I'd expect ASKL to do a little bit worse than shown here. These results are rather different from the results you got in your own benchmarks, where ASKL was much more competitive. That could be due, in part, to the datatypes and functionality tested. In the string key benchmarks for insert, replace, look up existing, and look up nonexisting, ASKL isn't actually doing too badly here. One oddity I noticed was a big spike in the 32-bit integer key, 32-bit value: Time to replace 1,000 existing keys with N keys in the table/200,00-keys benchmark at around 110,000 keys. I actually repeated that benchmark three times just to make sure the spike wasn't due to some background system activity. |
|
Thank you very much for sharing these results, this is super interesting because on my machine the results are quite different, look at this 200.000 keys run :
Full run: Compiled with: g++ -I. -std=c++20 -O2 -flto=auto -DNDEBUG -Wall -Wpedantic main.cpp So now I wonder if I'm doing something that's cheap on ARM64 but costly on x86_64. If you have the time, I would be very grateful if you tried to run my python/hyperfine benchmark on your machine, so we can see if the difference is arch-related. I'm also gonna try to run both benchmarks on a x86_64 box on my side. |
|
OK, I did some digging and I think the bad performance may be related to MinGW's pthread implementation. If I'm correct, compiling with -DHAS_ATOMICS should significantly improve performance. I identified the reason for the weird spike, I need to add a specific code path for the "upsert" function map_set so it avoids triggering a resize when the key already exists. |


Hi Jackson,
Thanks again for the feedback on Reddit!
This PR adds an
askl_mapshim with the following quirks:I think the MinGW compile issues you pointed out should be fixed, but if you have a chance to try it on your setup I'd be grateful if you could confirm it.
Happy to improve the shim if you see some correctness/fairness issues.