Merge pull request #3248 from facebook/opt_comments1

[easy] add a few comments to the optimal parser code base for improved clarity
This commit is contained in:
Yann Collet
2022-12-28 18:03:57 -08:00
committed by GitHub
+46 -30
View File
@@ -26,27 +26,35 @@
#if 0 /* approximation at bit level (for tests) */ #if 0 /* approximation at bit level (for tests) */
# define BITCOST_ACCURACY 0 # define BITCOST_ACCURACY 0
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
# define WEIGHT(stat, opt) ((void)opt, ZSTD_bitWeight(stat)) # define WEIGHT(stat, opt) ((void)(opt), ZSTD_bitWeight(stat))
#elif 0 /* fractional bit accuracy (for tests) */ #elif 0 /* fractional bit accuracy (for tests) */
# define BITCOST_ACCURACY 8 # define BITCOST_ACCURACY 8
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
# define WEIGHT(stat,opt) ((void)opt, ZSTD_fracWeight(stat)) # define WEIGHT(stat,opt) ((void)(opt), ZSTD_fracWeight(stat))
#else /* opt==approx, ultra==accurate */ #else /* opt==approx, ultra==accurate */
# define BITCOST_ACCURACY 8 # define BITCOST_ACCURACY 8
# define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY) # define BITCOST_MULTIPLIER (1 << BITCOST_ACCURACY)
# define WEIGHT(stat,opt) (opt ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat)) # define WEIGHT(stat,opt) ((opt) ? ZSTD_fracWeight(stat) : ZSTD_bitWeight(stat))
#endif #endif
/* ZSTD_bitWeight() :
* provide estimated "cost" of a stat in full bits only */
MEM_STATIC U32 ZSTD_bitWeight(U32 stat) MEM_STATIC U32 ZSTD_bitWeight(U32 stat)
{ {
return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER); return (ZSTD_highbit32(stat+1) * BITCOST_MULTIPLIER);
} }
/* ZSTD_fracWeight() :
* provide fractional-bit "cost" of a stat,
* using linear interpolation approximation */
MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat) MEM_STATIC U32 ZSTD_fracWeight(U32 rawStat)
{ {
U32 const stat = rawStat + 1; U32 const stat = rawStat + 1;
U32 const hb = ZSTD_highbit32(stat); U32 const hb = ZSTD_highbit32(stat);
U32 const BWeight = hb * BITCOST_MULTIPLIER; U32 const BWeight = hb * BITCOST_MULTIPLIER;
/* Fweight was meant for "Fractional weight"
* but it's effectively a value between 1 and 2
* using fixed point arithmetic */
U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb; U32 const FWeight = (stat << BITCOST_ACCURACY) >> hb;
U32 const weight = BWeight + FWeight; U32 const weight = BWeight + FWeight;
assert(hb + BITCOST_ACCURACY < 31); assert(hb + BITCOST_ACCURACY < 31);
@@ -91,17 +99,19 @@ static U32 sum_u32(const unsigned table[], size_t nbElts)
static U32 ZSTD_downscaleStats(unsigned* table, U32 lastEltIndex, U32 shift) static U32 ZSTD_downscaleStats(unsigned* table, U32 lastEltIndex, U32 shift)
{ {
U32 s, sum=0; U32 s, sum=0;
DEBUGLOG(5, "ZSTD_downscaleStats (nbElts=%u, shift=%u)", (unsigned)lastEltIndex+1, (unsigned)shift); DEBUGLOG(5, "ZSTD_downscaleStats (nbElts=%u, shift=%u)",
(unsigned)lastEltIndex+1, (unsigned)shift );
assert(shift < 30); assert(shift < 30);
for (s=0; s<lastEltIndex+1; s++) { for (s=0; s<lastEltIndex+1; s++) {
table[s] = 1 + (table[s] >> shift); unsigned newStat = 1 + (table[s] >> shift);
sum += table[s]; sum += newStat;
table[s] = newStat;
} }
return sum; return sum;
} }
/* ZSTD_scaleStats() : /* ZSTD_scaleStats() :
* reduce all elements in table is sum too large * reduce all elt frequencies in table if sum too large
* return the resulting sum of elements */ * return the resulting sum of elements */
static U32 ZSTD_scaleStats(unsigned* table, U32 lastEltIndex, U32 logTarget) static U32 ZSTD_scaleStats(unsigned* table, U32 lastEltIndex, U32 logTarget)
{ {
@@ -129,18 +139,22 @@ ZSTD_rescaleFreqs(optState_t* const optPtr,
DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize); DEBUGLOG(5, "ZSTD_rescaleFreqs (srcSize=%u)", (unsigned)srcSize);
optPtr->priceType = zop_dynamic; optPtr->priceType = zop_dynamic;
if (optPtr->litLengthSum == 0) { /* first block : init */ if (optPtr->litLengthSum == 0) { /* no literals stats collected -> first block assumed -> init */
if (srcSize <= ZSTD_PREDEF_THRESHOLD) { /* heuristic */
DEBUGLOG(5, "(srcSize <= ZSTD_PREDEF_THRESHOLD) => zop_predef"); /* heuristic: use pre-defined stats for too small inputs */
if (srcSize <= ZSTD_PREDEF_THRESHOLD) {
DEBUGLOG(5, "srcSize <= %i : use predefined stats", ZSTD_PREDEF_THRESHOLD);
optPtr->priceType = zop_predef; optPtr->priceType = zop_predef;
} }
assert(optPtr->symbolCosts != NULL); assert(optPtr->symbolCosts != NULL);
if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) { if (optPtr->symbolCosts->huf.repeatMode == HUF_repeat_valid) {
/* huffman table presumed generated by dictionary */
/* huffman stats covering the full value set : table presumed generated by dictionary */
optPtr->priceType = zop_dynamic; optPtr->priceType = zop_dynamic;
if (compressedLiterals) { if (compressedLiterals) {
/* generate literals statistics from huffman table */
unsigned lit; unsigned lit;
assert(optPtr->litFreq != NULL); assert(optPtr->litFreq != NULL);
optPtr->litSum = 0; optPtr->litSum = 0;
@@ -188,10 +202,11 @@ ZSTD_rescaleFreqs(optState_t* const optPtr,
optPtr->offCodeSum += optPtr->offCodeFreq[of]; optPtr->offCodeSum += optPtr->offCodeFreq[of];
} } } }
} else { /* not a dictionary */ } else { /* huf.repeatMode != HUF_repeat_valid => presumed not a dictionary */
assert(optPtr->litFreq != NULL); assert(optPtr->litFreq != NULL);
if (compressedLiterals) { if (compressedLiterals) {
/* base initial cost of literals on direct frequency within src */
unsigned lit = MaxLit; unsigned lit = MaxLit;
HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */ HIST_count_simple(optPtr->litFreq, &lit, src, srcSize); /* use raw first block to init statistics */
optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8); optPtr->litSum = ZSTD_downscaleStats(optPtr->litFreq, MaxLit, 8);
@@ -224,10 +239,9 @@ ZSTD_rescaleFreqs(optState_t* const optPtr,
optPtr->offCodeSum = sum_u32(baseOFCfreqs, MaxOff+1); optPtr->offCodeSum = sum_u32(baseOFCfreqs, MaxOff+1);
} }
} }
} else { /* new block : re-use previous statistics, scaled down */ } else { /* new block : scale down accumulated statistics */
if (compressedLiterals) if (compressedLiterals)
optPtr->litSum = ZSTD_scaleStats(optPtr->litFreq, MaxLit, 12); optPtr->litSum = ZSTD_scaleStats(optPtr->litFreq, MaxLit, 12);
@@ -275,10 +289,11 @@ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optP
assert(litLength <= ZSTD_BLOCKSIZE_MAX); assert(litLength <= ZSTD_BLOCKSIZE_MAX);
if (optPtr->priceType == zop_predef) if (optPtr->priceType == zop_predef)
return WEIGHT(litLength, optLevel); return WEIGHT(litLength, optLevel);
/* We can't compute the litLength price for sizes >= ZSTD_BLOCKSIZE_MAX
* because it isn't representable in the zstd format. So instead just /* ZSTD_LLcode() can't compute litLength price for sizes >= ZSTD_BLOCKSIZE_MAX
* call it 1 bit more than ZSTD_BLOCKSIZE_MAX - 1. In this case the block * because it isn't representable in the zstd format.
* would be all literals. * So instead just pretend it would cost 1 bit more than ZSTD_BLOCKSIZE_MAX - 1.
* In such a case, the block would be all literals.
*/ */
if (litLength == ZSTD_BLOCKSIZE_MAX) if (litLength == ZSTD_BLOCKSIZE_MAX)
return BITCOST_MULTIPLIER + ZSTD_litLengthPrice(ZSTD_BLOCKSIZE_MAX - 1, optPtr, optLevel); return BITCOST_MULTIPLIER + ZSTD_litLengthPrice(ZSTD_BLOCKSIZE_MAX - 1, optPtr, optLevel);
@@ -292,7 +307,7 @@ static U32 ZSTD_litLengthPrice(U32 const litLength, const optState_t* const optP
} }
/* ZSTD_getMatchPrice() : /* ZSTD_getMatchPrice() :
* Provides the cost of the match part (offset + matchLength) of a sequence * Provides the cost of the match part (offset + matchLength) of a sequence.
* Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence. * Must be combined with ZSTD_fullLiteralsCost() to get the full cost of a sequence.
* @offBase : sumtype, representing an offset or a repcode, and using numeric representation of ZSTD_storeSeq() * @offBase : sumtype, representing an offset or a repcode, and using numeric representation of ZSTD_storeSeq()
* @optLevel: when <2, favors small offset for decompression speed (improved cache efficiency) * @optLevel: when <2, favors small offset for decompression speed (improved cache efficiency)
@@ -308,8 +323,9 @@ ZSTD_getMatchPrice(U32 const offBase,
U32 const mlBase = matchLength - MINMATCH; U32 const mlBase = matchLength - MINMATCH;
assert(matchLength >= MINMATCH); assert(matchLength >= MINMATCH);
if (optPtr->priceType == zop_predef) /* fixed scheme, do not use statistics */ if (optPtr->priceType == zop_predef) /* fixed scheme, does not use statistics */
return WEIGHT(mlBase, optLevel) + ((16 + offCode) * BITCOST_MULTIPLIER); return WEIGHT(mlBase, optLevel)
+ ((16 + offCode) * BITCOST_MULTIPLIER); /* emulated offset cost */
/* dynamic statistics */ /* dynamic statistics */
price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel)); price = (offCode * BITCOST_MULTIPLIER) + (optPtr->offCodeSumBasePrice - WEIGHT(optPtr->offCodeFreq[offCode], optLevel));
@@ -347,7 +363,7 @@ static void ZSTD_updateStats(optState_t* const optPtr,
optPtr->litLengthSum++; optPtr->litLengthSum++;
} }
/* offset code : expected to follow storeSeq() numeric representation */ /* offset code : follows storeSeq() numeric representation */
{ U32 const offCode = ZSTD_highbit32(offBase); { U32 const offCode = ZSTD_highbit32(offBase);
assert(offCode <= MaxOff); assert(offCode <= MaxOff);
optPtr->offCodeFreq[offCode]++; optPtr->offCodeFreq[offCode]++;
@@ -1352,7 +1368,7 @@ size_t ZSTD_compressBlock_btopt(
/* ZSTD_initStats_ultra(): /* ZSTD_initStats_ultra():
* make a first compression pass, just to seed stats with more accurate starting values. * make a first compression pass, just to seed stats with more accurate starting values.
* only works on first block, with no dictionary and no ldm. * only works on first block, with no dictionary and no ldm.
* this function cannot error, hence its contract must be respected. * this function cannot error out, its narrow contract must be respected.
*/ */
static void static void
ZSTD_initStats_ultra(ZSTD_matchState_t* ms, ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
@@ -1371,7 +1387,7 @@ ZSTD_initStats_ultra(ZSTD_matchState_t* ms,
ZSTD_compressBlock_opt2(ms, seqStore, tmpRep, src, srcSize, ZSTD_noDict); /* generate stats into ms->opt*/ ZSTD_compressBlock_opt2(ms, seqStore, tmpRep, src, srcSize, ZSTD_noDict); /* generate stats into ms->opt*/
/* invalidate first scan from history */ /* invalidate first scan from history, only keep entropy stats */
ZSTD_resetSeqStore(seqStore); ZSTD_resetSeqStore(seqStore);
ms->window.base -= srcSize; ms->window.base -= srcSize;
ms->window.dictLimit += (U32)srcSize; ms->window.dictLimit += (U32)srcSize;
@@ -1395,20 +1411,20 @@ size_t ZSTD_compressBlock_btultra2(
U32 const curr = (U32)((const BYTE*)src - ms->window.base); U32 const curr = (U32)((const BYTE*)src - ms->window.base);
DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize); DEBUGLOG(5, "ZSTD_compressBlock_btultra2 (srcSize=%zu)", srcSize);
/* 2-pass strategy: /* 2-passes strategy:
* this strategy makes a first pass over first block to collect statistics * this strategy makes a first pass over first block to collect statistics
* and seed next round's statistics with it. * in order to seed next round's statistics with it.
* After 1st pass, function forgets everything, and starts a new block. * After 1st pass, function forgets history, and starts a new block.
* Consequently, this can only work if no data has been previously loaded in tables, * Consequently, this can only work if no data has been previously loaded in tables,
* aka, no dictionary, no prefix, no ldm preprocessing. * aka, no dictionary, no prefix, no ldm preprocessing.
* The compression ratio gain is generally small (~0.5% on first block), * The compression ratio gain is generally small (~0.5% on first block),
* the cost is 2x cpu time on first block. */ ** the cost is 2x cpu time on first block. */
assert(srcSize <= ZSTD_BLOCKSIZE_MAX); assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
if ( (ms->opt.litLengthSum==0) /* first block */ if ( (ms->opt.litLengthSum==0) /* first block */
&& (seqStore->sequences == seqStore->sequencesStart) /* no ldm */ && (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
&& (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */ && (ms->window.dictLimit == ms->window.lowLimit) /* no dictionary */
&& (curr == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */ && (curr == ms->window.dictLimit) /* start of frame, nothing already loaded nor skipped */
&& (srcSize > ZSTD_PREDEF_THRESHOLD) && (srcSize > ZSTD_PREDEF_THRESHOLD) /* input large enough to not employ default stats */
) { ) {
ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize); ZSTD_initStats_ultra(ms, seqStore, rep, src, srcSize);
} }