Skip to content

keccak: benchmark ARM64 backends directly - #30

Draft
yperbasis wants to merge 4 commits into
masterfrom
review/arm64-backend-benchmark
Draft

yperbasis wants to merge 4 commits into
masterfrom
review/arm64-backend-benchmark

Conversation

@yperbasis

Copy link
Copy Markdown
Member

Summary

  • add an ARM64 benchmark that compares the SHA3 assembly and runtime fallback through the same streaming API
  • use Reset, Write, and Read with reusable output for both backends
  • avoid forcing SHA3 instructions when runtime detection did not select them

Why

Instruction availability does not prove that a backend is faster on every ARM core. This benchmark makes the dispatch choice measurable on Apple Silicon and Linux ARM64 systems. When SHA3 is unavailable, it reports the fallback only and never executes unsupported instructions.

This is a benchmark-only addition, so TDD is not applicable.

Benchmark

Apple M2 Max, Go 1.25.7, median of five 300 ms runs:

size       SHA3 assembly    x/crypto fallback
32 B          153.8 ns           352.5 ns
128 B         165.3 ns           351.3 ns
1 KiB        1182 ns             2678 ns
500 KiB       527.7 us           1.253 ms

Both paths report zero allocations with this call shape. The main value of the benchmark is running the same comparison on other ARM64 processors before changing dispatch policy.

Verification

  • go test ./...
  • go test -race ./...
  • go test -tags purego ./...
  • go vet ./...
  • go test -run '^$' -bench '^BenchmarkARM64Backends$' -benchmem -benchtime=300ms -count=5 ./...
  • go mod tidy -diff
  • golangci-lint run (twice)

Comment thread keccak_arm64_bench_test.go Outdated
Comment thread keccak_arm64_bench_test.go Outdated
Comment thread keccak_arm64_bench_test.go Outdated
Comment thread keccak_arm64_bench_test.go Outdated
Comment thread keccak_arm64_bench_test.go Outdated
Move the A/B into keccak_asm_test.go so amd64 runs it too, reuse
benchSizes/benchName so the names line up with the rest of the suite, and
gate the assembly arm on a new immutable hasASM probe instead of the
useASM flag this benchmark mutates. The recorded digest is now compared
across the two backends rather than only written.
`-bench BenchmarkBackends/ASM` ran one arm, so the cross-arm compare had
nothing to compare and reported success on a corrupted digest.
@AskAlexSharov

Copy link
Copy Markdown
Contributor

Found

A -bench filter selecting one arm silently disabled the digest cross-check. backendDigests[size] was only compared when the other arm had already populated it in the same process, so any filter running one arm turned the check into a plain store.

Reproduced by injecting a one-bit corruption into sponge.Read:

  • -bench BenchmarkBackends → FAIL on all six sizes. Good.
  • -bench BenchmarkBackends/ASM → PASS, exit 0, six timing lines, corruption unreported.

Fixed

Each arm is now compared against an x/crypto reference computed per size, so there is no cross-arm state and no filter can disable it — the map is gone too. 72b4bfc

Verified: with the same corruption, -bench BenchmarkBackends/ASM alone now fails.

Verified clean

hasASM is correct on every build — package-level var init runs after x/sys/cpu is initialized and before this package's init(); go vet clean on amd64/arm64/386/riscv64/windows/purego, and the test binary compiles for GOARCH=386. The useASM restore works: probing it from a benchmark ordered after BenchmarkBackends shows it back at its original value.

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.

2 participants