mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 08:36:02 -10:00
rdeflate: the lazy parser skips the match finder on an empty chain
rd_insert() hands back the chain head it just linked for a position, and the greedy parser (levels 1-3) already used it to skip the match search when there is no earlier occurrence. The lazy parser - levels 4-9, which includes the level-6 screenshot encoder - threw it away and called rd_longest_match() at every position, which reloaded the head from prev[] and returned 0 when it was empty. On noisy input that is about half of all positions: a full call, register saves and the struct loads of the prologue, to learn there was nothing to do. Both parsers now pass the head in and only call when a chain exists; rd_longest_match() starts its walk from it instead of re-reading prev[]. An empty chain returned 0 with no side effects before, so the parse - and the stream - are unchanged. Compressed output is byte-identical to before over the level 0-9 x input chunking x six-input matrix, zlib-wrapped and raw, also under ASan/UBSan; rzip, rpng, archive and encodings sample tests pass; builds C89 without new warnings and for aarch64. screenshot_io_bench, 3840x2160 BGR24 PNG: noise instructions -10.3% (10.37 G -> 9.30 G), best 393 -> 380 ms, median about -4%; gradient unchanged.
This commit is contained in:
1 parent
e67ddc9a8a
commit
7b44ddac58
1 file changed
+20
-14
@@ -2587,8 +2587,12 @@ static INLINE uint32_t rd_insert_end(uint32_t stop, uint32_t end)
|
||||
return stop < lim ? stop : lim;
|
||||
}
|
||||
|
||||
/* `first` is the chain head rd_insert() returned for `pos` - the
|
||||
* previous occurrence, zero-based - which the caller has already found
|
||||
* to exist; an empty chain never gets here. */
|
||||
static INLINE uint32_t rd_longest_match(struct rdeflate *s, uint32_t pos,
|
||||
uint32_t max_len, uint32_t best_start, uint32_t *dist_out)
|
||||
int32_t first, uint32_t max_len, uint32_t best_start,
|
||||
uint32_t *dist_out)
|
||||
{
|
||||
int chain;
|
||||
uint32_t limit;
|
||||
@@ -2597,13 +2601,10 @@ static INLINE uint32_t rd_longest_match(struct rdeflate *s, uint32_t pos,
|
||||
const uint8_t *scan = win + pos;
|
||||
uint32_t best_len = best_start; /* only a longer match is interesting */
|
||||
uint32_t best_dist = 0;
|
||||
/* The caller has already inserted `pos`; begin at the previous
|
||||
* occurrence recorded in prev[]. Chain links are stored as
|
||||
* position+1 with 0 for "empty" (see rd_insert), so `cur` is
|
||||
* one-based throughout this walk and `cpos` is the position. */
|
||||
int32_t cur = s->prev[pos & RD_WMASK];
|
||||
if (cur == 0)
|
||||
return 0;
|
||||
/* Chain links are stored as position+1 with 0 for "empty" (see
|
||||
* rd_insert), so `cur` is one-based throughout this walk and `cpos`
|
||||
* is the position. */
|
||||
int32_t cur = first + 1;
|
||||
|
||||
{
|
||||
const int32_t *prev = s->prev; /* hoisted: avoids repeated struct load */
|
||||
@@ -2892,8 +2893,9 @@ static void rd_parse(struct rdeflate *s)
|
||||
{
|
||||
/* insert returns the previous head of this hash chain; only
|
||||
* bother searching when the chain is non-empty. */
|
||||
if (rd_insert(s, s->pos) >= 0)
|
||||
mlen = rd_longest_match(s, s->pos, max_len,
|
||||
int32_t first = rd_insert(s, s->pos);
|
||||
if (first >= 0)
|
||||
mlen = rd_longest_match(s, s->pos, first, max_len,
|
||||
(uint32_t)(RD_MIN_MATCH - 1), &mdist);
|
||||
}
|
||||
if (mlen >= RD_MIN_MATCH)
|
||||
@@ -2939,12 +2941,16 @@ static void rd_parse(struct rdeflate *s)
|
||||
/* insert the current position into the hash chain and find a match */
|
||||
if (max_len >= RD_MIN_MATCH)
|
||||
{
|
||||
rd_insert(s, s->pos);
|
||||
/* An empty chain - about half of all positions on noisy
|
||||
* input - has nothing to search, so the match finder is not
|
||||
* entered for it; it would only have returned 0. */
|
||||
int32_t first = rd_insert(s, s->pos);
|
||||
/* When a match is pending from the previous byte, only a strictly
|
||||
* longer match here matters -- start the search bar at prev_len. */
|
||||
mlen = rd_longest_match(s, s->pos, max_len,
|
||||
s->have_prev ? s->prev_len : (uint32_t)(RD_MIN_MATCH - 1),
|
||||
&mdist);
|
||||
if (first >= 0)
|
||||
mlen = rd_longest_match(s, s->pos, first, max_len,
|
||||
s->have_prev ? s->prev_len : (uint32_t)(RD_MIN_MATCH - 1),
|
||||
&mdist);
|
||||
}
|
||||
|
||||
if (s->have_prev)
|
||||
|
||||
Reference in new issue
Block a user