Use a better best_len in the lazy search. PiperOrigin-RevId: 988596790
diff --git a/c/enc/backward_references_opt_inc.h b/c/enc/backward_references_opt_inc.h index b9a14eb..149b43a 100644 --- a/c/enc/backward_references_opt_inc.h +++ b/c/enc/backward_references_opt_inc.h
@@ -132,8 +132,12 @@ for (;; --max_length) { const score_t cost_diff_lazy = 175; HasherSearchResult sr2; - sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ? - BROTLI_MIN(size_t, sr.len - 1, max_length) : 0; + sr2.len = + params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH + ? BROTLI_MIN(size_t, sr.len - 1, max_length) + : BROTLI_MIN(size_t, + MinimumBetterLength(sr.score + cost_diff_lazy - 1), + max_length); sr2.len_code_delta = 0; sr2.distance = 0; sr2.score = kMinScore; @@ -206,6 +210,13 @@ range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t, range_start, position + sr.len - (sr.distance << 2))); } + /* The next search is at position + sr.len (the one-ahead in the + prefetch helper covers only the cur_ix + 1 successor): prefetch its + dictionary heads[] line before the StoreRange loop. */ + if (ENABLE_COMPOUND_DICTIONARY) { + PrefetchCompoundDictionaryHeadsOpt(¶ms->dictionary.compound, + ringbuffer, ringbuffer_mask, position + sr.len); + } FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start, range_end); }
diff --git a/c/enc/hash.h b/c/enc/hash.h index dc16d47..35addc8 100644 --- a/c/enc/hash.h +++ b/c/enc/hash.h
@@ -126,6 +126,13 @@ BROTLI_DISTANCE_BIT_PENALTY * Log2FloorNonZero(backward_reference_offset); } +/* Returns the minimum length of a backward reference that will improve on the + provided score. We conservatively assume that the match will be a last + distance match, the best case scenario for the next match.*/ +static BROTLI_INLINE size_t MinimumBetterLength(score_t score) { + return (score - (BROTLI_SCORE_BASE + 15)) / BROTLI_LITERAL_BYTE_SCORE; +} + static BROTLI_INLINE score_t BackwardReferenceScoreUsingLastDistance( size_t copy_length) { return BROTLI_LITERAL_BYTE_SCORE * (score_t)copy_length + @@ -774,6 +781,36 @@ PREFETCH_L1(chain); probes[d].chain = chain; probes[d].item = (head == 0xFFFF) ? 1 : 0; + + /* One-ahead for the heads[] line of the next probe: the next search is + at cur_ix + 1 (the lazy search, or the next position after a miss), + whose hash covers bytes cur_ix+1.. -- the same 8-byte load shifted by + one byte (hash_mask spans at most 56 bits for this to be exact; a + mismatch would only waste the prefetch). The heads[key] load above + misses L1 ~94% of the time (mostly L3 fills). */ + { + const uint64_t h1 = + ((bytes >> 8) & view->hash_mask) * kPreparedDictionaryHashMul64Long; + PREFETCH_L1(&view->heads[(uint32_t)(h1 >> view->hash_shift)]); + } + } +} + +/* The heads[] half of PrefetchCompoundDictionaryMatchOpt: hash the position + and prefetch its heads[] line, with no dependent items[] load. Used at the + commit site, where the successor position is known but the probe state for + it would not survive the intervening StoreRange. */ +static BROTLI_INLINE void PrefetchCompoundDictionaryHeadsOpt( + const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data, + const size_t ring_buffer_mask, const size_t cur_ix) { + const uint64_t bytes = + BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix & ring_buffer_mask]); + size_t d; + for (d = 0; d < addon->num_chunks; ++d) { + const PreparedDictionaryView* view = &addon->chunk_views[d]; + const uint64_t h = + (bytes & view->hash_mask) * kPreparedDictionaryHashMul64Long; + PREFETCH_L1(&view->heads[(uint32_t)(h >> view->hash_shift)]); } }
diff --git a/c/enc/hash_longest_match_simd_opt_inc.h b/c/enc/hash_longest_match_simd_opt_inc.h index df9aa66..6985a5d 100644 --- a/c/enc/hash_longest_match_simd_opt_inc.h +++ b/c/enc/hash_longest_match_simd_opt_inc.h
@@ -156,7 +156,12 @@ /* Don't accept a short copy from far away. */ score_t min_score = out->score; score_t best_score = out->score; - size_t best_len = out->len; + /* If we're still searching the static dictionary, we have to do the full + search to determine if we should check the static dictionary. */ + size_t best_len = + self->common_->dict_num_matches < (self->common_->dict_num_lookups >> 7) + ? out->len + : 0; size_t i; /* Precalculate the hash key and prefetch the bucket. */ const uint32_t hash = @@ -170,6 +175,9 @@ out->len = 0; out->len_code_delta = 0; + if (best_len < 1) { + best_len = 1; + } /* Try last distance first. */ for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { const size_t backward = (size_t)distance_cache[i]; @@ -186,7 +194,8 @@ break; } if (prev_ix + best_len > ring_buffer_mask || - data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { + BrotliUnalignedRead16(&data[cur_ix_masked + best_len - 1]) != + BrotliUnalignedRead16(&data[prev_ix + best_len - 1])) { continue; } {