zstd: speed up better encoder hashing, primes in registers on arm64 - #1230
lizthegrey wants to merge 4 commits into
Conversation
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review. 📝 WalkthroughWalkthroughThe better encoder and dictionary encoder use explicit-prime hash helpers for long and short hashes. Prime selection depends on the target architecture. Tests compare the new helpers with ChangesBetter encoder hashing
Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~20 minutes Change: Refactor Suggested reviewers: Merge Risk: ⚪ Minimal · up to No issue identified in the reviewed hash and encoder changes prevents merging after normal checks. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
arm64 rebuilds each 64-bit hash prime with MOVD+3xMOVK per use. Load them once per Encode so they stay in registers; other arches keep constants. Also compute the index-loop bound once and store the short table first so cv1 dies early, removing per-iteration spills. Output is unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ec7323a to
f3a9104
Compare
Rename betterPrimesInRegs to hashPrimesInRegs, in hash_regs_arm64.go and hash_regs_other.go, so other encoders can use the same switch. No code generation change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Nice! I am focused on getting a release out, so perf PRs will have less priority for a while. |
Quite alright, and yeah, that would explain why #1212 has been sitting a while, but no rush, I maintain my own branch of cherrypicked fixes for Honeycomb internal use. |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Replace the two build-tagged files with a constant in hash.go. No code generation change. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
and go compiler issue opened: golang/go#81755 -- but it'll only fix it in 1.28 and newer (if it's even accepted upstream), so we need to carry the workaround. |
Speeds up
SpeedBetterCompressionencoding: +6–8% on arm64 and +3% on amd64, with byte-identical output.The motivating workload is a compress-and-upload service on arm64 (Graviton) that encodes 4 MiB frames with a 4 MiB window at
SpeedBetterCompression.Changes
betterFastEncoderandbetterFastEncoderDicthash every position with two 64-bit multiplicative primes.MOVD+ 3×MOVK) to build, and the compiler rebuilds it on every use, including on every index-loop iteration.betterHashPrimes()now loads both primes once perEncodefrom a package var, so they stay in registers.betterHashPrimes()returns the constants. amd64 builds a prime in oneMOVQ $imm64, and keeping both live across the main loop spills. The choice is a single constant,hashPrimesInRegs = runtime.GOARCH == "arm64"inhash.go, and the compiler removes the unused branch.for end := s - 1; index0 < end; index0 += 2), and the short-table store now comes before the long-table update. Together these remove per-iteration spills on amd64.Why output is unchanged
betterHashL/betterHashScompute exactly whathashLencomputes for these table sizes. A new table test checks them againsthashLenon edge-case and random inputs.Benchmarks
The corpora are 32 MiB decompressed prefixes of your real corpora. Each is encoded as 4 MiB
EncodeAllframes with a 4 MiB window, CRC on and concurrency 1. Each result is 10 interleaved master/PR rounds on one pinned core, compared withbenchstat. Figures areSpeedBetterCompressionMB/s vs master;~means not significant.All non-
~cells are p<0.05. On Zen 3 (5600X) the geomean is +4.4% with no regressions, but that box is shared, so its per-corpus spread is wide.Follow-up
hashPrimesInRegsis named for reuse: the default-level encoder (enc_dfast.go) hashes with the same two primes, so it gets the same treatment in one commit on top of this branch,honeycombio:lizf.zstd-dfast-hash-primes: diff on top of this PR (combined diff vs master). Output is byte-identical to master. At the default level it's +4.4% on Graviton2, +2.1% on Graviton3, +1.9% on Graviton4 and flat on Sapphire Rapids (benchstat, same corpora and setup as above). I can open it as a follow-up PR once this one lands, or push it onto this PR if you'd rather review both together.🤖 Generated with Claude Code
Summary by CodeRabbit