Hello, I just read about Swiss Table map is used by Rust, Golang and Zig. While C++ uses linked list. So I am curious about the performance of all of them, then I benchmarked them
The full benchmark code can be found here GitHub - fuji-184/HashMap-Benchmark · GitHub
The benchmark uses Assembly X86 RDTSCP instruction to make all languages use the same timer not STD time
Edit : Previously I used RDTSC. I just found it does not wait all previous instructions are done, but it runs out of order, good for speed but not good for timing execution speed like benchmark, because there will operarions that are not counted. I changed to the version that waits all previous instructions finish, aka RDTSXP. I also updated the result below and code in the github
To reproduce the benchmark :
- Clone the repo
chmod +x ./run.sh./run.sh
The bash script is abstraction to compile all in release mode then run all of them
You can also compile and run by your own if you find any better compile flags
The result is supprising. Because the STD HashMap is slower
Here is the result for 1000000 items
=== 1. COMPILING ===
[+] Compiling C++ with Clang...
[+] Compiling C++ Abseil Swiss Table with Clang...
[+] Compiling Rust...
[+] Compiling Rust Rustc_Hash library...
[+] Compiling Rust Ahash library...
[+] Compiling Rust Hashbrown library...
[+] Compiling Zig...
[+] Compiling Go...
=== 2. RUNNING BENCHMARKS ===
-----------------------------------
C++ (std::unordered_map via Clang)
-----------------------------------
N: 1,000,000
Get: 499,999,500,000
Insert: 346,769,016 cycles
Get Hit: 16,441,728 cycles
Get Miss: 18,854,272 cycles
Update: 17,794,388 cycles
Delete: 91,483,570 cycles
-----------------------------------
C++ (absl::flat_hash_map via Clang)
-----------------------------------
N: 1,000,000
Get: 499,999,500,000
Insert: 617,524,586 cycles
Get Hit: 180,881,470 cycles
Get Miss: 46,403,484 cycles
Update: 391,016,774 cycles
Delete: 388,502,294 cycles
-----------------------------------
Rust (std::collections::HashMap)
-----------------------------------
N: 1000000
Get: 499999500000
Insert: 508.799.908 cycles
Get Hit: 480.473.190 cycles
Get Miss: 93.977.088 cycles
Update: 628.344.672 cycles
Delete: 745.041.942 cycles
-----------------------------------
Rust (rustc_hash::FxHashMap)
-----------------------------------
N: 1000000
Get: 499999500000
Insert: 401.385.032 cycles
Get Hit: 129.132.822 cycles
Get Miss: 14.771.436 cycles
Update: 376.373.640 cycles
Delete: 397.623.422 cycles
-----------------------------------
Rust (ahash::AHashMap)
-----------------------------------
N: 1000000 Get: 499999500000
Insert: 416.307.314 cycles
Get Hit: 102.810.244 cycles
Get Miss: 36.378.782 cycles
Update: 358.037.282 cycles
Delete: 358.654.686 cycles
-----------------------------------
Rust (hashbrown::HashMap;) -----------------------------------
N: 1000000
Get: 499999500000
Insert: 406.681.224 cycles
Get Hit: 125.862.512 cycles
Get Miss: 27.706.644 cycles
Update: 354.708.998 cycles
Delete: 299.873.148 cycles
-----------------------------------
Zig (std::AutoHashMap)
-----------------------------------
N: 1000000
Get: 499999500000
Insert: 449.253.678 cycles
Get Hit: 195.605.874 cycles
Get Miss: 76.549.814 cycles
Update: 282.018.606 cycles
Delete: 167.909.892 cycles
-----------------------------------
Go (map[int]int)
-----------------------------------
N: 1000000
Get: 499999500000
Insert: 1.348.740.788 cycles
Get Hit: 366.265.524 cycles
Get Miss: 459.286.064 cycles
Update: 416.440.874 cycles
Delete: 431.979.628 cycles
=== Done ===
Anyone know why?
Also if there is error in my benchmark code, please don't hestitate to correct it
If the benchmark is valid, we may need to find why and how to improve the performance