deflate_compress: use lazy2 compressor for levels 8-9

Instead of switching directly from the lazy compressor at level 7 to the
near-optimal compressor at level 8, use the lazy2 compressor at levels
8-9 and don't switch to near-optimal until level 10.

This avoids poor compression ratio and bad performance (both
significantly worse than level 7, and significantly worse than zlib) at
levels 8-9 on data where the near-optimal compressor doesn't do well
until the parameters are cranked up.

On data where the near-optimal compressor *does* do well, this change
worsens the compression ratio of levels 8-9, but also speeds them up a
lot, thus positioning them similarly vs. zlib as the lower levels (i.e.
much faster and slightly stronger, rather than slightly faster and much
stronger).  The difference between levels 9 and 10 is increased, but
that's perhaps the least bad place to have a discontinuity.

Resolves https://github.com/ebiggers/libdeflate/issues/85
This commit is contained in:
Eric Biggers 2021-12-31 16:04:49 -06:00
parent 1b3eaf2f13
commit f7d3a70d4c

View File

@ -33,9 +33,10 @@
/* /*
* By default, the near-optimal parsing algorithm is enabled at compression * By default, the near-optimal parsing algorithm is enabled at compression
* level 8 and above. The near-optimal parsing algorithm produces a compression * level 10 and above. The near-optimal parsing algorithm produces a
* ratio significantly better than the greedy and lazy algorithms implemented * compression ratio significantly better than the greedy and lazy algorithms
* here, and also the algorithm used by zlib at level 9. However, it is slow. * implemented here, and also the algorithm used by zlib at level 9. However,
* it is slow.
*/ */
#define SUPPORT_NEAR_OPTIMAL_PARSING 1 #define SUPPORT_NEAR_OPTIMAL_PARSING 1
@ -2789,7 +2790,7 @@ libdeflate_alloc_compressor(int compression_level)
return NULL; return NULL;
#if SUPPORT_NEAR_OPTIMAL_PARSING #if SUPPORT_NEAR_OPTIMAL_PARSING
if (compression_level >= 8) if (compression_level >= 10)
size += sizeof(c->p.n); size += sizeof(c->p.n);
else if (compression_level >= 1) else if (compression_level >= 1)
size += sizeof(c->p.g); size += sizeof(c->p.g);
@ -2849,19 +2850,20 @@ libdeflate_alloc_compressor(int compression_level)
c->max_search_depth = 100; c->max_search_depth = 100;
c->nice_match_length = 130; c->nice_match_length = 130;
break; break;
#if SUPPORT_NEAR_OPTIMAL_PARSING
case 8: case 8:
c->impl = deflate_compress_near_optimal; c->impl = deflate_compress_lazy2;
c->max_search_depth = 12; c->max_search_depth = 300;
c->nice_match_length = 20; c->nice_match_length = DEFLATE_MAX_MATCH_LEN;
c->p.n.num_optim_passes = 1;
break; break;
case 9: case 9:
c->impl = deflate_compress_near_optimal; #if !SUPPORT_NEAR_OPTIMAL_PARSING
c->max_search_depth = 16; default:
c->nice_match_length = 26; #endif
c->p.n.num_optim_passes = 2; c->impl = deflate_compress_lazy2;
c->max_search_depth = 600;
c->nice_match_length = DEFLATE_MAX_MATCH_LEN;
break; break;
#if SUPPORT_NEAR_OPTIMAL_PARSING
case 10: case 10:
c->impl = deflate_compress_near_optimal; c->impl = deflate_compress_near_optimal;
c->max_search_depth = 30; c->max_search_depth = 30;
@ -2874,24 +2876,14 @@ libdeflate_alloc_compressor(int compression_level)
c->nice_match_length = 80; c->nice_match_length = 80;
c->p.n.num_optim_passes = 3; c->p.n.num_optim_passes = 3;
break; break;
case 12:
default: default:
c->impl = deflate_compress_near_optimal; c->impl = deflate_compress_near_optimal;
c->max_search_depth = 100; c->max_search_depth = 100;
c->nice_match_length = 133; c->nice_match_length = 133;
c->p.n.num_optim_passes = 4; c->p.n.num_optim_passes = 4;
break; break;
#else #endif /* SUPPORT_NEAR_OPTIMAL_PARSING */
case 8:
c->impl = deflate_compress_lazy;
c->max_search_depth = 150;
c->nice_match_length = 200;
break;
default:
c->impl = deflate_compress_lazy;
c->max_search_depth = 200;
c->nice_match_length = DEFLATE_MAX_MATCH_LEN;
break;
#endif
} }
deflate_init_offset_slot_fast(c); deflate_init_offset_slot_fast(c);