[llvm] [DenseMap] Store occupancy in a packed used-bit array (PR #201281)
Alexis Engelke via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 3 01:49:53 PDT 2026
https://github.com/aengelke commented:
I think the code changes look largely good.
- Pro: This removes the need for getEmptyKey()
- Pro: iteration and find if missed is faster
- Con: insertion and lookup (hit) executes more instructions for small key-value pairs
- Con: rather large code size increase, which (I expect) substantially contributes to the max-rss increase
- Con: it makes the operations that should, ideally be less used (iteration) cheaper at the cost of (ideally) more frequently used operations (insert, find-hit)
I measured sqlite -O0g (+0.42% on c-t-t) on a Zen 4 AMD machine (hyperfine interleaved with perf stat -r10; built with clang 23 from Monday):
```
Benchmark 1: ./clang-main ...
Time (mean ± σ): 768.0 ms ± 2.7 ms [User: 709.2 ms, System: 58.4 ms]
Range (min … max): 763.7 ms … 772.3 ms 10 runs
766,881,875 task-clock # 0.992 CPUs utilized ( +- 0.12% )
6 context-switches # 7.824 /sec ( +- 11.39% )
0 cpu-migrations # 0.000 /sec
17,363 page-faults # 22.641 K/sec ( +- 0.02% )
3,400,146,015 instructions # 1.61 insn per cycle
# 0.24 stalled cycles per insn ( +- 0.02% )
2,108,737,113 cycles # 2.750 GHz ( +- 0.12% )
828,287,269 stalled-cycles-frontend # 39.28% frontend cycles idle ( +- 0.24% )
640,473,796 branches # 835.166 M/sec ( +- 0.02% )
19,282,271 branch-misses # 3.01% of all branches ( +- 0.23% )
0.773348 +- 0.000894 seconds time elapsed ( +- 0.12% )
Benchmark 2: ./clang-dmub ...
Time (mean ± σ): 766.2 ms ± 1.5 ms [User: 705.2 ms, System: 60.7 ms]
Range (min … max): 764.2 ms … 768.5 ms 10 runs
762,892,904 task-clock # 0.991 CPUs utilized ( +- 0.10% )
8 context-switches # 10.486 /sec ( +- 7.47% )
0 cpu-migrations # 0.000 /sec
17,519 page-faults # 22.964 K/sec ( +- 0.03% )
3,415,991,033 instructions # 1.63 insn per cycle
# 0.24 stalled cycles per insn ( +- 0.02% )
2,097,698,394 cycles # 2.750 GHz ( +- 0.10% )
817,560,241 stalled-cycles-frontend # 38.97% frontend cycles idle ( +- 0.15% )
632,956,100 branches # 829.679 M/sec ( +- 0.02% )
18,645,270 branch-misses # 2.95% of all branches ( +- 0.19% )
0.769438 +- 0.000747 seconds time elapsed ( +- 0.10% )
```
I also compiled sqlite -O3g (not run on c-t-t) with similar results:
```
Time (mean ± σ): 9.465 s ± 0.019 s [User: 9.318 s, System: 0.144 s]
Range (min … max): 9.438 s … 9.503 s 10 runs
39,121,269,386 instructions # 1.51 insn per cycle
# 0.24 stalled cycles per insn ( +- 0.00% )
25,938,149,301 cycles # 2.750 GHz ( +- 0.03% )
7,834,529,243 branches # 830.568 M/sec ( +- 0.00% )
321,152,958 branch-misses # 4.10% of all branches ( +- 0.04% )
Time (mean ± σ): 9.343 s ± 0.011 s [User: 9.198 s, System: 0.141 s]
Range (min … max): 9.326 s … 9.359 s 10 runs
39,178,375,169 instructions # 1.53 insn per cycle
# 0.24 stalled cycles per insn ( +- 0.01% )
25,665,077,467 cycles # 2.750 GHz ( +- 0.09% )
7,657,498,371 branches # 820.440 M/sec ( +- 0.01% )
311,128,182 branch-misses # 4.06% of all branches ( +- 0.05% )
```
So at least on this machine, the number of instructions is misleading and this is actually faster. This only leaves the file-size ~= max-rss regression (and therefore also more page faults etc.). Given that we currently don't really care about this (I think we should do more here, but whatever), I don't think this is too important.
I'm mildly opposed to a DensePtrMap. This provides only slight (if any) advantages, but makes it more difficult to choose. I think, if beneficial, DenseMap should automatically use some heuristic to determine this instead of placing the burden of choice on our devs, which might not even be aware of the subtle performance differences.
https://github.com/llvm/llvm-project/pull/201281
More information about the llvm-commits
mailing list