Add runtime-selected 16-lane SHA-256 backend for Merkle hashing - #4157
Add runtime-selected 16-lane SHA-256 backend for Merkle hashing#4157masih wants to merge 1 commit into
Conversation
Adds sei-tendermint/crypto/tmhash with a default crypto/sha256 backend and a 16-lane AVX-512 kernel built under goexperiment.simd, and routes merkle.HashFromByteSlices through level-batched hashing when a multi-lane backend is active. Output is byte-identical to the recursive tree.
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
The latest Buf updates on your PR. Results from workflow Buf / buf (pull_request).
|
LtHash default vs SIMD (
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## masih/1789147125-lthash-simd-backend #4157 +/- ##
========================================================================
- Coverage 65.48% 65.41% -0.07%
========================================================================
Files 2090 2082 -8
Lines 157791 157360 -431
========================================================================
- Hits 103325 102944 -381
+ Misses 54325 54275 -50
Partials 141 141
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
tmhash / merkle default vs SIMD (
|
LtHash default vs SIMD (
|
tmhash / merkle default vs SIMD (
|
Stacked on #4151. Tendermint's Merkle hashing (
merkle.HashFromByteSlices: tx hashes, part sets, commit signatures, results, validator sets) hashes every leaf and every tree level as independent SHA-256 calls, which is the batch shape a multi-lane kernel wants, butcrypto/sha256already uses single-lane SHA-NI so the achievable win is smaller than the LtHash case and had to be measured rather than assumed.This adds
sei-tendermint/crypto/tmhashwith the same runtime-selected backend pattern as the LtHash PR:SumBatch(prefix, msgs, out)is served by a default backend (a reusedsha256.New(), always compiled) or, underGOEXPERIMENT=simdon a CPU with AVX-512F/VBMI/VBMI2, by a generated 16-lanearchsimd.Uint32x16SHA-256 kernel that loads, prefixes, pads and transposes sixteen messages in-register (VPERMB / VPERMT2D) and falls back to scalar for remainders and mixed lengths.SEI_TMHASH_BACKEND=defaultpins the portable path.HashFromByteSliceskeeps its signature and, when a multi-lane backend is active and there are at least sixteen leaves, builds the tree level by level, pairing adjacent nodes and carrying an odd trailing node up, which yields exactly the RFC 6962getSplitPointshape; a differential test checks totals 1 to 70 against the recursive implementation and the tmhash tests check every backend againstcrypto/sha256across block and padding boundaries.Two Go 1.27 findings surfaced while benchmarking and are handled here. The compiler never emits
VZEROUPPERafterarchsimdcode, so the SHA-NI scalar path that followed ran several times slower with dirty ZMM state; the SIMD backend now calls a one-instruction assemblyvzeroupperbefore handing off. Separately, withGOEXPERIMENT=simdon an AVX-512 machine the runtime's async preemption restores all 32 ZMM registers withoutVZEROUPPER, which made the pinned-default merkle benchmark 2 to 4x slower and noisy in the same binary; the CI job therefore takes the default column from a plain build and the SIMD column from the experiment build. That second effect is worth keeping in mind for any decision to ship aGOEXPERIMENT=simdbinary, since it affects all legacy-SSE code in the process, not just this package.Local numbers on an Intel Xeon Platinum 8559C (benchstat, n=8): the 16-lane kernel is 2.0x faster than SHA-NI on 1024 inner nodes (124 µs to 61 µs), 1.6x on 256-byte leaves and 1.3x on 1 KiB leaves, and the whole tree for 1024 x 32-byte leaves goes from 223 µs to 122 µs. This is a per-block cost of a few thousand hashes, so the wall-clock effect on a node is modest; the PR mainly shows the shape of the consensus-side integration. The
SIMD hash backendsworkflow runs both packages' tests with and without the experiment and posts the benchstat table as a job summary and PR comment.Tests:
go test -race ./crypto/tmhash ./crypto/merklewith and withoutGOEXPERIMENT=simd, golangci-lint under both builds,make fmtcheck, and the benchmarks above.