From 1cecff7c197062dafd8d0f08580bcb2a1f972bd9 Mon Sep 17 00:00:00 2001 From: Dmitry Prudnikov Date: Wed, 10 Jun 2026 05:18:34 +0300 Subject: [PATCH] perf(encode): 4-byte gate before HC chain common_prefix_len MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lazy/HC matcher ran a full SIMD common_prefix_len on every chain candidate. The existing speculative tail gate only fires once a best match exists; on dict-primed chains over low-match (random) input best stays None, so every candidate paid the wider vector load+count+tzcnt even though almost none reach the match floor. compress-dict small-10k-random lazy was 9.4x C (no-dict is 1.18x parity) — the dict primes the chains, random input walks them finding nothing. Add the donor MEM_read32 gate: HC_MIN_MATCH_LEN == 4, so a first-4-byte mismatch can never reach the floor, reject on a scalar compare. Falls through to the full count when either side lacks a 4-byte lookahead, so the accepted match set is byte-identical (197 cross-validation + hc + dict tests). --- zstd/src/encoding/hc/mod.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/zstd/src/encoding/hc/mod.rs b/zstd/src/encoding/hc/mod.rs index 572238d63..6163ac2ac 100644 --- a/zstd/src/encoding/hc/mod.rs +++ b/zstd/src/encoding/hc/mod.rs @@ -353,7 +353,22 @@ impl HcMatcher { } } - if !skip { + // Cheap 4-byte equality gate before the wider SIMD count + // (donor `MEM_read32` gate in `ZSTD_HcFindBestMatch`). + // `HC_MIN_MATCH_LEN == 4`, so a first-4-byte mismatch can never + // reach the match floor — reject without the vector + // load+count+tzcnt. On dict-primed chains over low-match + // (random) input, where `best` stays `None` so the speculative + // tail gate above never fires, this rejects the bulk of chain + // candidates on a scalar compare instead of a full + // `common_prefix_len`. Falls through to the full count when + // either side lacks a 4-byte lookahead (the count handles short + // tails), so the accepted set is byte-identical. + let four_byte_ok = candidate_idx + 4 > history_tail + || current_idx + 4 > history_tail + || concat[candidate_idx..candidate_idx + 4] + == concat[current_idx..current_idx + 4]; + if !skip && four_byte_ok { let match_len = common_prefix_len(&concat[candidate_idx..], &concat[current_idx..]); if match_len >= HC_MIN_MATCH_LEN {