Skip to content

refactor(checksums): one owner for the SIMD batch input cap - #7787

Merged
oferchen merged 2 commits into
masterfrom
refactor/simd-max-input-size-one-owner
Sep 9, 2026
Merged

refactor(checksums): one owner for the SIMD batch input cap#7787
oferchen merged 2 commits into
masterfrom
refactor/simd-max-input-size-one-owner

Conversation

@oferchen

@oferchen oferchen commented Sep 9, 2026

Copy link
Copy Markdown
Owner

The 1 MiB per-input cap that decides whether a SIMD batch backend hashes
in-lane or bails to the scalar digest was written out twelve times across
crates/checksums/src/simd_batch/ — eleven named const MAX_INPUT_SIZE
declarations plus one bare literal at md4/simd/avx512.rs:59
(if max_len > 1024 * 1024) that a grep for the constant name cannot see.

There is now one owner in simd_batch/mod.rs, cfg-gated to the three
architectures that have SIMD backends, consumed by all twelve former sites.

Why the bound exists

Stated in the doc comment, because it was nowhere before: every backend pads
each lane into a freshly allocated 64-byte-block multiple, so the transient
allocation is bounded by lanes x cap — 16 MiB on the widest, AVX-512 16-lane
path.

Upstream has no multi-buffer MD4/MD5 at all (its only checksum SIMD is
get_checksum1, the Adler rolling sum), so there is no upstream counterpart to
mirror and the doc says so rather than inventing a citation. The one 1 MiB
constant in upstream's SIMD source, simd-checksum-x86_64.cpp:512 BLOCK_LEN, is
a benchmark-harness buffer and unrelated.

The bound was untested

Mutating both live aarch64 copies on the base tree killed 0 of 1158 tests.
Two tests now cover it:

  • cap_bounds_the_worst_case_padded_allocation — pins the value against the
    allocation reasoning that justifies it (whole 64-byte blocks; 16-lane worst
    case), so a change to the value has to confront why.
  • digests_agree_with_scalar_on_both_sides_of_the_cap — at MAX_INPUT_SIZE and
    MAX_INPUT_SIZE + 1, MD4 and MD5 batch digests must equal the scalar
    reference. This is what makes a shared owner safe: a backend reading a
    different bound than the scalar oracle assumes would still have to agree here.

Codegen neutrality

Proven past the test suite: LLVM IR diff is 18659 lines both sides, 22 differing
— the module ID and core::panic::Location line numbers shifting by exactly 3,
the three deleted lines per file.

Gates

rustfmt 3430 files clean (whole-tree checker), clippy
-p checksums --all-targets --all-features clean, nextest 1160/1160 (1158
before plus the 2 new).

Host limitation, stated rather than implied: aarch64-apple-darwin executes only
the NEON path. SSE2/SSSE3/SSE4.1/AVX2/AVX-512 are type-checked but not run
locally, and wasm32 is not compiled — CI covers those.

Eleven SIMD backends each declared their own `MAX_INPUT_SIZE`, and the
MD4 AVX-512 path carried the same bound as a bare `1024 * 1024` literal
with no name at all. All twelve sites held the identical value, so this
was latent duplication rather than a live divergence, but nothing kept
them in step.

Collapse them onto a single `simd_batch::MAX_INPUT_SIZE` consumed by
every MD4 and MD5 backend, so a per-backend value can no longer be
written. The bound caps the transient padding allocation each backend
makes (lanes x cap, 16 MiB on the AVX-512 path); batches above it fall
back to the scalar digest. It has no upstream counterpart - upstream
rsync has no multi-buffer MD4/MD5 - so the value is documented as an
oc-side allocation-tuning choice.

Add tests pinning the value against its allocation invariants and
checking MD4/MD5 batch digests against the scalar reference on both
sides of the cap. The bound had no test before this.

No behaviour change: every backend reads the value it read previously.
@oferchen
oferchen enabled auto-merge (squash) September 9, 2026 12:04
@oferchen
oferchen merged commit 3a7b38f into master Sep 9, 2026
72 of 76 checks passed
@oferchen
oferchen deleted the refactor/simd-max-input-size-one-owner branch September 9, 2026 15:44
oferchen added a commit that referenced this pull request Sep 9, 2026
The measurement-gate note's "Three that look mirrored and are not" section
landed as #7779 and went stale within a day: all three entries have since
been fixed, and one of them cited a file that is being deleted.

Each closure verified in the tree, not taken from a changelog:

- hash table floor/growth -> #7790. `TAG_TABLE_SIZE` now exists at exactly
  one site (`crates/matching/src/index/mod.rs:68`) and its own doc says the
  growth role "belongs to CompactLookup", which grows on upstream's
  `(count/8) * 10 + 11` rule. The entry's second cited site,
  `optimized_search.rs:12`, is dropped: that module is dead and its removal
  is in flight, and the live constant was never the growth-bearing one.

- `MAX_XATTR_DIGEST_LEN` literal -> #7786. Now
  `<Md5 as OutputSizeUser>::OutputSize::USIZE` with
  `const _: () = assert!(MAX_XATTR_DIGEST_LEN == 16)` beneath it
  (`crates/protocol/src/xattr/mod.rs:76,81`), so a digest change cannot
  silently move a wire length.

- `MAX_INPUT_SIZE` copies -> #7787. One definition at
  `crates/checksums/src/simd_batch/mod.rs:46`; every backend imports it.
  The entry said nine copies; the sweep found twelve sites, eleven constants
  plus one bare literal no grep for the name could reach. The count is
  corrected rather than left flattering.

The section is kept rather than deleted: the lesson it teaches (value
equality is not provenance) is the reason the gate exists, and each fix is
evidence the reading was right. The upstream anchors are unchanged except
`match.c:86-88` -> `match.c:84-88`, matching the range the code itself
cites for the same rule.

Also drops the deleted module from the zsync design note's file list and
corrects that entry's crate directory (`crates/match/` -> `crates/matching/`).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant