Skip to content

Use a fast fixed hasher for the .NET-style set index (1.3x, same output) - #179

Merged
wormeyman merged 1 commit into
mainfrom
rust-native/fast-index-hasher
Oct 21, 2026
Merged

wormeyman merged 1 commit into
mainfrom
rust-native/fast-index-hasher

Conversation

@wormeyman

Copy link
Copy Markdown
Collaborator

This is the first same-output speed change of the Rust-native phase (#138). The planner is 1.3x faster, and every plan stays byte for byte the same.

The change

NetHashSet and NetDictionary in rust/dotnet-compat copy .NET's HashSet and Dictionary. Each keeps its entries in an array, in the order .NET would enumerate them, plus a std HashMap from key to entry index for lookups. That index used std's default hasher: SipHash, with a new random seed for every map. SipHash is built to resist hash flooding, and it is slow on small keys like a grid location.

The index is only ever looked up. It is never enumerated, because enumeration order comes from the entry array. So its hash function cannot change any output. This PR swaps it for FxHash's rotate-xor-multiply mix, the one rustc uses, in a new dotnet_compat::FastHasher (about 60 lines, no new crate). It has no seed, so maps also behave the same from run to run.

Hash flooding doesn't apply here. The keys come from the user's own blueprint, and the planner runs in their own browser.

Why this first

I profiled with samply at 2 kHz on the first 93 big-list fields (13.7 s of planning, including the five slowest). A* was 67% of all samples. The SipHash index of the .NET-style sets was about 14%: contains_key was 9.9% on its own, most of it A*'s goals.contains().

Results

cargo run --release -p bench on tealc (8 cores, Linux). Each run is compared with --baseline to a run of main on the same machine:

list main this PR speed-up geometric mean per field responses
small, 5 runs 1,417 ms 1,077 ms 1.32x 1.33x all 61 identical
big, 1 run 58.0 s 44.7 s 1.30x 1.35x all 1,147 identical

The WASM module also gets smaller: 961,191 bytes to 911,892 (-5.1%), and 243.9 KB to 234.9 KB with brotli. That is probably the SipHash and random-seed code dropping out. A main build made locally is exactly the size of the live module, so the comparison is fair.

Checks run

  • cargo fmt, cargo clippy --all-targets -- -D warnings: clean
  • cargo test --all-targets: 194 passed, 7 ignored. The 2 new tests check that the hasher is fixed, that a 40 x 40 block of grid cells has no collisions, and that a partial last word is hashed.
  • cargo test --release -p snapshots -p contract -- --include-ignored: 37 passed, covering all 2,748 snapshots and the scoreboard
  • cargo build --workspace --target wasm32-unknown-unknown: OK

Merging deploys the site, with the same plans and a smaller, faster planner. I'll run the 61-blueprint live check after the deploy.

🤖 Generated with Claude Code

https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH

…asher

The key-to-entry index behind the .NET HashSet and Dictionary copies
used std's default SipHash with a random seed. It is only looked up,
never enumerated (enumeration order comes from the entry array), so its
hash cannot change any output. Swap it for FxHash's rotate-xor-multiply
mix, with no seed.

Same output: bench --baseline reports every response identical on the
small list (61) and the big list (1,147), and the snapshot gate passes.
On tealc the small list goes 1,417 -> 1,077 ms (1.32x) and the big list
58.0 -> 44.7 s (1.30x). The WASM module shrinks from 961,191 to 911,892
bytes (243.9 -> 234.9 KB brotli).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PTSQFMEdmByebgkoa9RiqH
@coderabbitai

coderabbitai Bot commented Oct 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 23 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 02af43a7-b463-42ab-b577-aa5f2d71c774
📥 Commits

Reviewing files that changed from the base of the PR and between 1ecbd46 and 2beab78.

📒 Files selected for processing: 3
  • rust/dotnet-compat/src/fast_hash.rs
  • rust/dotnet-compat/src/hash_table.rs
  • rust/dotnet-compat/src/lib.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@wormeyman
wormeyman merged commit e4daf9b into main Oct 21, 2026
4 checks passed
@wormeyman
wormeyman deleted the rust-native/fast-index-hasher branch October 21, 2026 17:00
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