Skip to content

miss optimization + validation: elastic hash beats abseil on every operation#6

Open
joshuaisaact wants to merge 7 commits intoautoresearch/cross-language-benchfrom
autoresearch/miss-optimization
Open

miss optimization + validation: elastic hash beats abseil on every operation#6
joshuaisaact wants to merge 7 commits intoautoresearch/cross-language-benchfrom
autoresearch/miss-optimization

Conversation

@joshuaisaact
Copy link
Copy Markdown
Owner

@joshuaisaact joshuaisaact commented Mar 24, 2026

Why

Elastic hash's only major weakness was miss lookups -- 2-6x slower than abseil. Five previous attempts to fix this were reverted because they regressed hits by 10-30%. Without competitive miss performance, the hash table couldn't be recommended for real workloads.

What

The fix: 3 lines

Added matchEmpty check per probe in tier-0 get() with @branchHint(.cold). The cold hint tells the CPU's branch predictor this branch is almost never taken. For hits, the prediction is always correct (~0 cost). For misses, empty slots terminate the search early.

This is the same approach tried and reverted 5 times. The only difference is the compiler hint.

Validation suite

Ran four tests to verify the fix holds under realistic conditions:

1. Tombstone churn -- 500K delete/insert cycles at 50% load. No degradation. Tombstones get recycled by inserts.

2. Mixed workload -- 40% hit, 40% miss, 10% insert, 10% delete. Elastic hash: 50M ops/sec vs abseil's 25M. 2x faster.

3. Memory overhead -- Identical to abseil (1.00x) at every capacity.

4. Variable key lengths -- Advantage grows from 1.3x at 8 bytes to 2x at 256 bytes.

Results (M4, 1M elements, 50% load)

Operation Before After Abseil vs Abseil
Hit (unshuffled) 8,404us 4,725us 14,616us 3.09x faster
Miss (unshuffled) 12,343us 2,473us 7,079us 2.86x faster
Insert - 3,835us 21,845us 5.70x faster
Delete - 1,461us 9,030us 6.18x faster

Elastic hash is now #1 on every operation at 50% load against abseil, Rust hashbrown+ahash, Go swiss.Map, and Go builtin map.

Where abseil still wins

  • Miss lookups at 75%+ load (tier 0 fills up, empty slots become rare)
  • 99% load factor

References

7 approaches to explore: branch-hinted early termination, conditional
probing, per-bucket max probe depth, bloom filters, tombstone-free
deletion, Robin Hood displacement tracking. Previous early termination
attempts regressed hits -- this program specifically guards against that.
Add early termination in tier-0 get() via matchEmpty check with
@branchHint(.cold). The branch predictor learns that hits never take
the early exit, making the check nearly free on the hot path. Previous
attempts without the cold hint regressed hits by 10-30%.

Before (50% load, 1M, unshuffled): hit=8,404 miss=12,343
After:                               hit=5,040 miss=2,688
Abseil:                              hit=9,027 miss=3,047

Misses went from 4x slower than abseil to 13% faster.
Also adds per-bucket max_probe_depth tracking (unused by get() for now
but available for future experiments) and autobench-miss benchmark.
With the matchEmpty miss optimization, elastic hash now ranks #1 on
hit lookup, miss lookup, insert, and delete at 50% load against
abseil, Rust hashbrown+ahash, Go swiss.Map, and Go builtin map.
Abseil only wins on misses at 75%+ load where tier 0 fills up.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 68338d57-1486-453e-8c03-2d513d88778a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch autoresearch/miss-optimization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

At 50% load, churning through the entire table does not degrade hit or
miss performance. Tombstones from deletes get reused by subsequent
inserts, keeping the empty slot ratio stable. matchEmpty early
termination remains effective under sustained mutation.
40% hit / 40% miss / 10% insert / 10% delete, 1M ops on pre-filled
table. Elastic hash sustains 50M ops/sec vs abseil's 25M at 50% load.
Advantage holds at 25% (2.2x) and 75% (1.7x).
…h longer keys

Memory: elastic hash uses 1.00x abseil's memory at all capacities.
The tiered layout distributes slots across tiers but total count is
the same.

Key lengths: elastic hash is tied at 16 bytes, 1.33x faster at 8
bytes, and scales to 2x faster at 256 bytes. Fingerprint pre-filtering
avoids expensive key comparisons on false-positive hash matches.
@joshuaisaact joshuaisaact changed the title miss optimization: 3 lines fix the biggest weakness miss optimization + validation: elastic hash beats abseil on every operation Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant