Skip to content

Add SIMD window to key digest search - #32

Merged
hadashiA merged 1 commit into
mainfrom
claude/simd-digest-search
Aug 16, 2026
Merged

Add SIMD window to key digest search#32
hadashiA merged 1 commit into
mainfrom
claude/simd-digest-search

Conversation

@hadashiA

@hadashiA hadashiA commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Note

Stacked on #31 (struct key comparer specialization) — review the last commit only. Retarget to main after #31 merges.

Summary

Replaces the tail of the digest binary search with a branch-free SIMD count. The classic binary search carries one hard-to-predict branch per level; this change runs the branchy search only down to a 32-element window and finishes with a Vector128 count of digests below the probe (DigestSearch.LowerBound), then resolves the run of equal digests with full key comparisons.

Two details worth reviewing:

  • Anchored window, no sentinels. The 32-wide window is anchored at [max-32, max): it always stays inside the digest array, and any element below min it covers is < keyDigest by the binary-search invariant, so counting it keeps the result exact.
  • Gated on DigestSearch.IsAccelerated. The lower-bound restructure only pays off together with the SIMD window — losing the classic search's early digest-equality exit costs more than the restructure alone gains (measured: 16.4 → 22.3 µs on point lookups with the SIMD path disabled). netstandard2.1 (Unity) and non-SIMD hardware therefore keep the existing mixed digest binary search unchanged.

Benchmark

The existing RandomKeys benchmark re-seeds its LCG every op, so the same 1000-key sequence repeats and the branch predictor gradually memorizes its branch history — it no longer models unpredictable access. This PR adds a RandomKeys_NoRepeat variant that carries the seed across ops (genuinely non-repeating), which is the closest model of real random access; the measured 86 µs vs 30 µs against the repeating variant on identical code shows how much the predictor was learning.

M4 / .NET 10, ShortRun, paired runs (machine noise ±2-3 µs; worth re-verifying with the usual solo-run protocol):

Benchmark before after
FindByKey (fixed key) 16.4 µs 17.0 µs
FindByKey_RandomKeys (repeating 1000-key sequence) 30.0–31.5 µs 32.0–33.8 µs
FindByKey_RandomKeys_NoRepeat (non-repeating) 86.0 µs 66.9 µs (-22%)

The trade: ~+2-4% on fully-predictable access patterns, -22% on unpredictable ones. Real workloads (keys driven by app logic) sit closer to the NoRepeat end than to a repeating 1000-key loop.

Tests: 79/79 pass, including new coverage for digest-collision runs (ascii keys sharing an 8-byte prefix) and >32-entry nodes on the SIMD path (KeyDigestSearchTest). No file-format change; netstandard2.1 byte-for-byte identical behavior.

🤖 Generated with Claude Code

Base automatically changed from claude/readonly-db-optimization-19c03f to main August 16, 2026 05:34
@hadashiA
hadashiA merged commit 5ac5e30 into main Aug 16, 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