From 7616e39f3b5618a20d2c8d059f1369283838cbce Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 20 Jan 2022 21:23:48 -0800 Subject: [PATCH 1/9] adding traces to better track processing of literals --- lib/compress/huf_compress.c | 135 ++++++++++++++++++------- lib/compress/zstd_compress.c | 13 +-- lib/compress/zstd_compress_literals.c | 36 +++++-- lib/decompress/zstd_decompress_block.c | 2 +- lib/zstd.h | 4 +- 5 files changed, 135 insertions(+), 55 deletions(-) diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index 2b3d6adc2..e9652058d 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -272,7 +272,7 @@ size_t HUF_readCTable (HUF_CElt* CTable, unsigned* maxSymbolValuePtr, const void U32 HUF_getNbBitsFromCTable(HUF_CElt const* CTable, U32 symbolValue) { - const HUF_CElt* ct = CTable + 1; + const HUF_CElt* const ct = CTable + 1; assert(symbolValue <= HUF_SYMBOLVALUE_MAX); return (U32)HUF_getNbBits(ct[symbolValue]); } @@ -287,53 +287,56 @@ typedef struct nodeElt_s { /** * HUF_setMaxHeight(): - * Enforces maxNbBits on the Huffman tree described in huffNode. + * Try to enforce @targetNbBits on the Huffman tree described in @huffNode. * - * It sets all nodes with nbBits > maxNbBits to be maxNbBits. Then it adjusts - * the tree to so that it is a valid canonical Huffman tree. + * It attempts to convert all nodes with nbBits > @targetNbBits + * to employ @targetNbBits instead. Then it adjusts the tree + * so that it remains a valid canonical Huffman tree. * * @pre The sum of the ranks of each symbol == 2^largestBits, * where largestBits == huffNode[lastNonNull].nbBits. * @post The sum of the ranks of each symbol == 2^largestBits, - * where largestBits is the return value <= maxNbBits. + * where largestBits is the return value (expected <= targetNbBits). * - * @param huffNode The Huffman tree modified in place to enforce maxNbBits. + * @param huffNode The Huffman tree modified in place to enforce targetNbBits. + * It's presumed sorted, from most frequent to rarest symbol. * @param lastNonNull The symbol with the lowest count in the Huffman tree. - * @param maxNbBits The maximum allowed number of bits, which the Huffman tree + * @param targetNbBits The allowed number of bits, which the Huffman tree * may not respect. After this function the Huffman tree will - * respect maxNbBits. - * @return The maximum number of bits of the Huffman tree after adjustment, - * necessarily no more than maxNbBits. + * respect targetNbBits. + * @return The maximum number of bits of the Huffman tree after adjustment. */ -static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) +static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 targetNbBits) { const U32 largestBits = huffNode[lastNonNull].nbBits; - /* early exit : no elt > maxNbBits, so the tree is already valid. */ - if (largestBits <= maxNbBits) return largestBits; + /* early exit : no elt > targetNbBits, so the tree is already valid. */ + if (largestBits <= targetNbBits) return largestBits; + + DEBUGLOG(5, "HUF_setMaxHeight (targetNbBits = %u)", targetNbBits); /* there are several too large elements (at least >= 2) */ { int totalCost = 0; - const U32 baseCost = 1 << (largestBits - maxNbBits); + const U32 baseCost = 1 << (largestBits - targetNbBits); int n = (int)lastNonNull; - /* Adjust any ranks > maxNbBits to maxNbBits. + /* Adjust any ranks > targetNbBits to targetNbBits. * Compute totalCost, which is how far the sum of the ranks is * we are over 2^largestBits after adjust the offending ranks. */ - while (huffNode[n].nbBits > maxNbBits) { + while (huffNode[n].nbBits > targetNbBits) { totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits)); - huffNode[n].nbBits = (BYTE)maxNbBits; + huffNode[n].nbBits = (BYTE)targetNbBits; n--; } - /* n stops at huffNode[n].nbBits <= maxNbBits */ - assert(huffNode[n].nbBits <= maxNbBits); - /* n end at index of smallest symbol using < maxNbBits */ - while (huffNode[n].nbBits == maxNbBits) --n; + /* n stops at huffNode[n].nbBits <= targetNbBits */ + assert(huffNode[n].nbBits <= targetNbBits); + /* n end at index of smallest symbol using < targetNbBits */ + while (huffNode[n].nbBits == targetNbBits) --n; - /* renorm totalCost from 2^largestBits to 2^maxNbBits + /* renorm totalCost from 2^largestBits to 2^targetNbBits * note : totalCost is necessarily a multiple of baseCost */ assert((totalCost & (baseCost - 1)) == 0); - totalCost >>= (largestBits - maxNbBits); + totalCost >>= (largestBits - targetNbBits); assert(totalCost > 0); /* repay normalized cost */ @@ -342,12 +345,12 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) /* Get pos of last (smallest = lowest cum. count) symbol per rank */ ZSTD_memset(rankLast, 0xF0, sizeof(rankLast)); - { U32 currentNbBits = maxNbBits; + { U32 currentNbBits = targetNbBits; int pos; for (pos=n ; pos >= 0; pos--) { if (huffNode[pos].nbBits >= currentNbBits) continue; - currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ - rankLast[maxNbBits-currentNbBits] = (U32)pos; + currentNbBits = huffNode[pos].nbBits; /* < targetNbBits */ + rankLast[targetNbBits-currentNbBits] = (U32)pos; } } while (totalCost > 0) { @@ -394,7 +397,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) rankLast[nBitsToDecrease] = noSymbol; else { rankLast[nBitsToDecrease]--; - if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease) + if (huffNode[rankLast[nBitsToDecrease]].nbBits != targetNbBits-nBitsToDecrease) rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */ } } /* while (totalCost > 0) */ @@ -406,11 +409,11 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) * TODO. */ while (totalCost < 0) { /* Sometimes, cost correction overshoot */ - /* special case : no rank 1 symbol (using maxNbBits-1); - * let's create one from largest rank 0 (using maxNbBits). + /* special case : no rank 1 symbol (using targetNbBits-1); + * let's create one from largest rank 0 (using targetNbBits). */ if (rankLast[1] == noSymbol) { - while (huffNode[n].nbBits == maxNbBits) n--; + while (huffNode[n].nbBits == targetNbBits) n--; huffNode[n+1].nbBits--; assert(n >= 0); rankLast[1] = (U32)(n+1); @@ -424,7 +427,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) } /* repay normalized cost */ } /* there are several too large elements (at least >= 2) */ - return maxNbBits; + return targetNbBits; } typedef struct { @@ -594,6 +597,28 @@ static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSy assert(HUF_isSorted(huffNode, maxSymbolValue1)); } + +size_t showHNodeSymbols(const nodeElt* hnode, size_t size) +{ + size_t u; + for (u=0; uhuffNodeTbl; nodeElt* const huffNode = huffNode0+1; int nonNullRank; + DEBUGLOG(5, "HUF_buildCTable_wksp (alphabet size = %u)", maxSymbolValue+1); + /* safety checks */ if (wkspSize < sizeof(HUF_buildCTable_wksp_tables)) - return ERROR(workSpace_tooSmall); + return ERROR(workSpace_tooSmall); if (maxNbBits == 0) maxNbBits = HUF_TABLELOG_DEFAULT; if (maxSymbolValue > HUF_SYMBOLVALUE_MAX) - return ERROR(maxSymbolValue_tooLarge); + return ERROR(maxSymbolValue_tooLarge); ZSTD_memset(huffNode0, 0, sizeof(huffNodeTable)); /* sort, decreasing order */ HUF_sort(huffNode, count, maxSymbolValue, wksp_tables->rankPosition); + DEBUGLOG(6, "sorted symbols completed (%zu symbols)", showHNodeSymbols(huffNode, maxSymbolValue+1)); (void)showHNodeSymbols; /* build tree */ nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); - /* enforce maxTableLog */ + /* determine and enforce maxTableLog */ maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ @@ -1158,6 +1192,28 @@ static size_t HUF_compressCTable_internal( return (size_t)(op-ostart); } +static size_t showU32(const U32* arr, size_t size) +{ + size_t u; + for (u=0; u= 2); if (suspectUncompressible && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) { size_t largestTotal = 0; + DEBUGLOG(5, "input suspected incompressible : sampling to check"); { unsigned maxSymbolValueBegin = maxSymbolValue; CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) ); largestTotal += largestBegin; @@ -1227,6 +1285,7 @@ HUF_compress_internal (void* dst, size_t dstSize, if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */ if (largest <= (srcSize >> 7)+4) return 0; /* heuristic : probably not compressible enough */ } + DEBUGLOG(6, "histogram detail completed (%zu symbols)", showU32(table->count, maxSymbolValue+1)); (void)showU32; /* Check validity of previous table */ if ( repeat @@ -1248,6 +1307,7 @@ HUF_compress_internal (void* dst, size_t dstSize, &table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp)); CHECK_F(maxBits); huffLog = (U32)maxBits; + DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1)); (void)showCTableBits; } /* Zero unused symbols in CTable, so we can check it for validity */ { @@ -1300,6 +1360,7 @@ size_t HUF_compress1X_repeat (void* dst, size_t dstSize, HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible) { + DEBUGLOG(5, "HUF_compress1X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_singleStream, workSpace, wkspSize, hufTable, @@ -1314,6 +1375,7 @@ size_t HUF_compress4X_wksp (void* dst, size_t dstSize, unsigned maxSymbolValue, unsigned huffLog, void* workSpace, size_t wkspSize) { + DEBUGLOG(5, "HUF_compress4X_wksp (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_fourStreams, workSpace, wkspSize, @@ -1330,6 +1392,7 @@ size_t HUF_compress4X_repeat (void* dst, size_t dstSize, void* workSpace, size_t wkspSize, HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible) { + DEBUGLOG(5, "HUF_compress4X_repeat (srcSize = %zu)", srcSize); return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, HUF_fourStreams, workSpace, wkspSize, diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index c369c84e2..c534eb25e 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -5850,12 +5850,13 @@ ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, return 0; } -/* Returns the number of bytes to move the current read position back by. Only non-zero - * if we ended up splitting a sequence. Otherwise, it may return a ZSTD error if something - * went wrong. +/* Returns the number of bytes to move the current read position back by. + * Only non-zero if we ended up splitting a sequence. + * Otherwise, it may return a ZSTD error if something went wrong. * - * This function will attempt to scan through blockSize bytes represented by the sequences - * in inSeqs, storing any (partial) sequences. + * This function will attempt to scan through blockSize bytes + * represented by the sequences in @inSeqs, + * storing any (partial) sequences. * * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to * avoid splitting a match, or to avoid splitting a match such that it would produce a match @@ -5883,7 +5884,7 @@ ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* } else { dictSize = 0; } - DEBUGLOG(5, "ZSTD_copySequencesToSeqStore: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize); + DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreNoBlockDelim: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize); DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) { diff --git a/lib/compress/zstd_compress_literals.c b/lib/compress/zstd_compress_literals.c index 52b0a8059..0c1acc407 100644 --- a/lib/compress/zstd_compress_literals.c +++ b/lib/compress/zstd_compress_literals.c @@ -36,7 +36,7 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, } ZSTD_memcpy(ostart + flSize, src, srcSize); - DEBUGLOG(5, "Raw literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); + DEBUGLOG(5, "Raw (uncompressed) literals: %u -> %u", (U32)srcSize, (U32)(srcSize + flSize)); return srcSize + flSize; } @@ -67,6 +67,17 @@ size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* return flSize+1; } +static size_t showHexa(const void* src, size_t srcSize) +{ + const BYTE* const ip = (const BYTE*)src; + size_t u; + for (u=0; urepeatMode; - int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; + int const preferRepeat = (strategy < ZSTD_lazy) ? srcSize <= 1024 : 0; + typedef size_t (*huf_compress_f)(void*, size_t, const void*, size_t, unsigned, unsigned, void*, size_t, HUF_CElt*, HUF_repeat*, int, int, unsigned); + huf_compress_f huf_compress; if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; - cLitSize = singleStream ? - HUF_compress1X_repeat( - ostart+lhSize, dstCapacity-lhSize, src, srcSize, - HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize, - (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2, suspectUncompressible) : - HUF_compress4X_repeat( - ostart+lhSize, dstCapacity-lhSize, src, srcSize, - HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize, - (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2, suspectUncompressible); + huf_compress = singleStream ? HUF_compress1X_repeat : HUF_compress4X_repeat; + cLitSize = huf_compress(ostart+lhSize, dstCapacity-lhSize, + src, srcSize, + HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, + entropyWorkspace, entropyWorkspaceSize, + (HUF_CElt*)nextHuf->CTable, + &repeat, preferRepeat, + bmi2, suspectUncompressible); if (repeat != HUF_repeat_none) { /* reused the existing table */ DEBUGLOG(5, "Reusing previous huffman table"); diff --git a/lib/decompress/zstd_decompress_block.c b/lib/decompress/zstd_decompress_block.c index 2e44d30d2..758c7ad99 100644 --- a/lib/decompress/zstd_decompress_block.c +++ b/lib/decompress/zstd_decompress_block.c @@ -1993,7 +1993,7 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, /* Decode literals section */ { size_t const litCSize = ZSTD_decodeLiteralsBlock(dctx, src, srcSize, dst, dstCapacity, streaming); - DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : %u", (U32)litCSize); + DEBUGLOG(5, "ZSTD_decodeLiteralsBlock : cSize=%u, nbLiterals=%zu", (U32)litCSize, dctx->litSize); if (ZSTD_isError(litCSize)) return litCSize; ip += litCSize; srcSize -= litCSize; diff --git a/lib/zstd.h b/lib/zstd.h index 8e90ae5f9..286785053 100644 --- a/lib/zstd.h +++ b/lib/zstd.h @@ -1409,7 +1409,9 @@ ZSTD_generateSequences( ZSTD_CCtx* zc, ZSTDLIB_STATIC_API size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize); /*! ZSTD_compressSequences() : - * Compress an array of ZSTD_Sequence, generated from the original source buffer, into dst. + * Compress an array of ZSTD_Sequence, associted with @src buffer, into dst. + * @src contains the entire input (not just the literals). + * If @srcSize > sum(sequence.length), the remaining bytes are considered all literals * If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) * The entire source is compressed into a single frame. * From 51da2d2ff245be6bcd719ee1f3d4c23225d4e653 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 20 Jan 2022 21:24:33 -0800 Subject: [PATCH 2/9] improved compression of literals in specific corner cases In rare cases, the default huffman depth selector is a bit too harsh, requiring brutal adaptations to the tree, resulting is some loss of compression ratio. This new heuristic avoids the worse cases, favoring compression ratio. As an example, compression of a specific distribution of 771 literals is now improved to 441 bytes, from 601 bytes before. --- lib/compress/huf_compress.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index e9652058d..e61b39f60 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -705,6 +705,18 @@ static void HUF_buildCTableFromTree(HUF_CElt* CTable, nodeElt const* huffNode, i CTable[0] = maxNbBits; } +static size_t +HUF_nbSymbolsTooLarge(const nodeElt* hnodes, U32 maxSymbolValue, U32 maxNbBits) +{ + size_t nbSTL = 0; + int s = (int)maxSymbolValue; + for ( ; s > 0; s-- ) { + if (hnodes[s].nbBits > maxNbBits) nbSTL++; + else break; + } + return nbSTL; +} + size_t HUF_buildCTable_wksp(HUF_CElt* CTable, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize) @@ -733,6 +745,16 @@ HUF_buildCTable_wksp(HUF_CElt* CTable, const unsigned* count, U32 maxSymbolValue nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); /* determine and enforce maxTableLog */ + /* Loosen target when maxNbBits is within limits. + * A harsh rebalancing can be bad for compression ratio + * while a mild one tends to be better */ + while (maxNbBits < HUF_TABLELOG_MAX) { + size_t const nbNodes = HUF_nbSymbolsTooLarge(huffNode, maxSymbolValue, maxNbBits); + #define HUF_NB_NODES_TO_FIX_MAX 8 + if (nbNodes < HUF_NB_NODES_TO_FIX_MAX) /* heuristic */ + break; + maxNbBits++; + } maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ From 4684836f4fbaea1d5416306173306bac56361d83 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 20 Jan 2022 21:59:46 -0800 Subject: [PATCH 3/9] update regression tests minor compression ratio benefits in some cases, no compression ratio regression in the measured scenarios. --- lib/compress/huf_compress.c | 18 +++++++++--------- lib/compress/zstd_compress_literals.c | 2 +- tests/regression/results.csv | 22 +++++++++++----------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index e61b39f60..fee2c0b52 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -598,21 +598,21 @@ static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSy } -size_t showHNodeSymbols(const nodeElt* hnode, size_t size) +static size_t showHNodeSymbols(const nodeElt* hnode, size_t size) { size_t u; for (u=0; u Date: Thu, 20 Jan 2022 22:19:35 -0800 Subject: [PATCH 4/9] proper max limit to 11 --- lib/compress/huf_compress.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index fee2c0b52..d3b597d98 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -745,10 +745,10 @@ HUF_buildCTable_wksp(HUF_CElt* CTable, const unsigned* count, U32 maxSymbolValue nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); /* determine and enforce maxTableLog */ - /* Loosen target when maxNbBits is within limits. + /* Loosen target when maxNbBits is already within limits. * A harsh rebalancing can be bad for compression ratio * while a mild one tends to be better */ - while (maxNbBits < HUF_TABLELOG_MAX) { + while (maxNbBits < HUF_TABLELOG_DEFAULT) { size_t const nbSTL = HUF_nbSymbolsTooLarge(huffNode, maxSymbolValue, maxNbBits); #define HUF_NB_NODES_TO_FIX_MAX 32 if (nbSTL < HUF_NB_NODES_TO_FIX_MAX) /* heuristic */ From e9dd923fa4b87db64ff6c3681194967d5eaaa264 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 21 Jan 2022 16:14:25 -0800 Subject: [PATCH 5/9] only declare debug functions in debug mode --- doc/zstd_manual.html | 4 +- lib/compress/huf_compress.c | 124 ++++++++++++++------------ lib/compress/zstd_compress_internal.h | 8 +- lib/compress/zstd_compress_literals.c | 38 +++++--- lib/compress/zstd_cwksp.h | 2 +- 5 files changed, 100 insertions(+), 76 deletions(-) diff --git a/doc/zstd_manual.html b/doc/zstd_manual.html index 9f73c4c81..6b45e0a99 100644 --- a/doc/zstd_manual.html +++ b/doc/zstd_manual.html @@ -1164,7 +1164,9 @@ size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
ZSTDLIB_STATIC_API size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstSize,
                       const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
                       const void* src, size_t srcSize);
-

Compress an array of ZSTD_Sequence, generated from the original source buffer, into dst. +

Compress an array of ZSTD_Sequence, associted with @src buffer, into dst. + @src contains the entire input (not just the literals). + If @srcSize > sum(sequence.length), the remaining bytes are considered all literals If a dictionary is included, then the cctx should reference the dict. (see: ZSTD_CCtx_refCDict(), ZSTD_CCtx_loadDictionary(), etc.) The entire source is compressed into a single frame. diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index d3b597d98..b533573d1 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -42,13 +42,67 @@ /* ************************************************************** -* Utils +* Required declarations ****************************************************************/ -unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue) +typedef struct nodeElt_s { + U32 count; + U16 parent; + BYTE byte; + BYTE nbBits; +} nodeElt; + + +/* ************************************************************** +* Debug Traces +****************************************************************/ + +#if DEBUGLEVEL >= 2 + +static size_t showU32(const U32* arr, size_t size) { - return FSE_optimalTableLog_internal(maxTableLog, srcSize, maxSymbolValue, 1); + size_t u; + for (u=0; u 1) { assert(bucketStartIdx < maxSymbolValue1); @@ -598,27 +645,6 @@ static void HUF_sort(nodeElt huffNode[], const unsigned count[], U32 const maxSy } -static size_t showHNodeSymbols(const nodeElt* hnode, size_t size) -{ - size_t u; - for (u=0; urankPosition); - DEBUGLOG(6, "sorted symbols completed (%zu symbols)", showHNodeSymbols(huffNode, maxSymbolValue+1)); (void)showHNodeSymbols; + DEBUGLOG(6, "sorted symbols completed (%zu symbols)", showHNodeSymbols(huffNode, maxSymbolValue+1)); /* build tree */ nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); @@ -943,7 +969,7 @@ static size_t HUF_closeCStream(HUF_CStream_t* bitC) { size_t const nbBits = bitC->bitPos[0] & 0xFF; if (bitC->ptr >= bitC->endPtr) return 0; /* overflow detected */ - return (bitC->ptr - bitC->startPtr) + (nbBits > 0); + return (size_t)(bitC->ptr - bitC->startPtr) + (nbBits > 0); } } @@ -1214,28 +1240,12 @@ static size_t HUF_compressCTable_internal( return (size_t)(op-ostart); } -static size_t showU32(const U32* arr, size_t size) + +unsigned HUF_optimalTableLog(unsigned maxTableLog, size_t srcSize, unsigned maxSymbolValue) { - size_t u; - for (u=0; u> 7)+4) return 0; /* heuristic : probably not compressible enough */ } - DEBUGLOG(6, "histogram detail completed (%zu symbols)", showU32(table->count, maxSymbolValue+1)); (void)showU32; + DEBUGLOG(6, "histogram detail completed (%zu symbols)", showU32(table->count, maxSymbolValue+1)); /* Check validity of previous table */ if ( repeat @@ -1329,7 +1339,7 @@ HUF_compress_internal (void* dst, size_t dstSize, &table->wksps.buildCTable_wksp, sizeof(table->wksps.buildCTable_wksp)); CHECK_F(maxBits); huffLog = (U32)maxBits; - DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1)); (void)showCTableBits; + DEBUGLOG(6, "bit distribution completed (%zu symbols)", showCTableBits(table->CTable + 1, maxSymbolValue+1)); } /* Zero unused symbols in CTable, so we can check it for validity */ { diff --git a/lib/compress/zstd_compress_internal.h b/lib/compress/zstd_compress_internal.h index 9fe3affab..e615b10c2 100644 --- a/lib/compress/zstd_compress_internal.h +++ b/lib/compress/zstd_compress_internal.h @@ -713,7 +713,7 @@ static unsigned ZSTD_NbCommonBytes (size_t val) } # endif # elif defined(__GNUC__) && (__GNUC__ >= 4) - return (__builtin_ctzll((U64)val) >> 3); + return (unsigned)(__builtin_ctzll((U64)val) >> 3); # else static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, @@ -736,7 +736,7 @@ static unsigned ZSTD_NbCommonBytes (size_t val) __assume(0); } # elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_ctz((U32)val) >> 3); + return (unsigned)(__builtin_ctz((U32)val) >> 3); # else static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, @@ -761,7 +761,7 @@ static unsigned ZSTD_NbCommonBytes (size_t val) } # endif # elif defined(__GNUC__) && (__GNUC__ >= 4) - return (__builtin_clzll(val) >> 3); + return (unsigned)(__builtin_clzll(val) >> 3); # else unsigned r; const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */ @@ -781,7 +781,7 @@ static unsigned ZSTD_NbCommonBytes (size_t val) __assume(0); } # elif defined(__GNUC__) && (__GNUC__ >= 3) - return (__builtin_clz((U32)val) >> 3); + return (unsigned)(__builtin_clz((U32)val) >> 3); # else unsigned r; if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } diff --git a/lib/compress/zstd_compress_literals.c b/lib/compress/zstd_compress_literals.c index a114b7d15..d6d63278a 100644 --- a/lib/compress/zstd_compress_literals.c +++ b/lib/compress/zstd_compress_literals.c @@ -13,6 +13,29 @@ ***************************************/ #include "zstd_compress_literals.h" + +/* ************************************************************** +* Debug Traces +****************************************************************/ +#if DEBUGLEVEL >= 2 + +static size_t showHexa(const void* src, size_t srcSize) +{ + const BYTE* const ip = (const BYTE*)src; + size_t u; + for (u=0; utableValidEnd >= ws->objectEnd); assert(ws->tableValidEnd <= ws->allocStart); if (ws->tableValidEnd < ws->tableEnd) { - ZSTD_memset(ws->tableValidEnd, 0, (BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd); + ZSTD_memset(ws->tableValidEnd, 0, (size_t)((BYTE*)ws->tableEnd - (BYTE*)ws->tableValidEnd)); } ZSTD_cwksp_mark_tables_clean(ws); } From 32a5d95dcb873044cb6af4921772510e619ac9e7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 21 Jan 2022 16:40:30 -0800 Subject: [PATCH 6/9] moved HufLog to lib/decompress it's only used to size decompression tables --- lib/common/zstd_internal.h | 1 - lib/compress/zstd_compress.c | 12 ++++++------ lib/decompress/zstd_decompress_internal.h | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index e4d36ce09..0594b7fce 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -95,7 +95,6 @@ typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ -#define HufLog 12 typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingType_e; #define LONGNBSEQ 0x7F00 diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index c534eb25e..e80d453e9 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -746,12 +746,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_minMatch : if (value!=0) /* 0 => use default */ BOUNDCHECK(ZSTD_c_minMatch, value); - CCtxParams->cParams.minMatch = value; + CCtxParams->cParams.minMatch = (U32)value; return CCtxParams->cParams.minMatch; case ZSTD_c_targetLength : BOUNDCHECK(ZSTD_c_targetLength, value); - CCtxParams->cParams.targetLength = value; + CCtxParams->cParams.targetLength = (U32)value; return CCtxParams->cParams.targetLength; case ZSTD_c_strategy : @@ -764,12 +764,12 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, /* Content size written in frame header _when known_ (default:1) */ DEBUGLOG(4, "set content size flag = %u", (value!=0)); CCtxParams->fParams.contentSizeFlag = value != 0; - return CCtxParams->fParams.contentSizeFlag; + return (size_t)CCtxParams->fParams.contentSizeFlag; case ZSTD_c_checksumFlag : /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ CCtxParams->fParams.checksumFlag = value != 0; - return CCtxParams->fParams.checksumFlag; + return (size_t)CCtxParams->fParams.checksumFlag; case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); @@ -778,7 +778,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_forceMaxWindow : CCtxParams->forceWindow = (value != 0); - return CCtxParams->forceWindow; + return (size_t)CCtxParams->forceWindow; case ZSTD_c_forceAttachDict : { const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; @@ -3063,7 +3063,7 @@ static size_t ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSi unsigned* const countWksp = (unsigned*)workspace; const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); BYTE* const nodeWksp = countWkspStart + countWkspSize; - const size_t nodeWkspSize = wkspEnd-nodeWksp; + const size_t nodeWkspSize = (size_t)(wkspEnd - nodeWksp); unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; unsigned huffLog = HUF_TABLELOG_DEFAULT; HUF_repeat repeat = prevHuf->repeatMode; diff --git a/lib/decompress/zstd_decompress_internal.h b/lib/decompress/zstd_decompress_internal.h index 2b5a53850..17c7df9d0 100644 --- a/lib/decompress/zstd_decompress_internal.h +++ b/lib/decompress/zstd_decompress_internal.h @@ -75,6 +75,7 @@ static UNUSED_ATTR const U32 ML_base[MaxML+1] = { #define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) #define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) +#define HufLog 12 typedef struct { ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ From 2d154e627a9961b728ee5943076c639b3942bbaa Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 21 Jan 2022 17:03:48 -0800 Subject: [PATCH 7/9] renamed HufLog into ZSTD_HUFFDTABLE_CAPACITY_LOG old name was not descriptive and actually misleading --- lib/decompress/zstd_ddict.c | 2 +- lib/decompress/zstd_decompress.c | 2 +- lib/decompress/zstd_decompress_internal.h | 4 ++-- lib/legacy/zstd_v05.c | 6 +++--- lib/legacy/zstd_v06.c | 6 +++--- lib/legacy/zstd_v07.c | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/decompress/zstd_ddict.c b/lib/decompress/zstd_ddict.c index ce335477b..889764a5e 100644 --- a/lib/decompress/zstd_ddict.c +++ b/lib/decompress/zstd_ddict.c @@ -134,7 +134,7 @@ static size_t ZSTD_initDDict_internal(ZSTD_DDict* ddict, ZSTD_memcpy(internalBuffer, dict, dictSize); } ddict->dictSize = dictSize; - ddict->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + ddict->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ /* parse dictionary content */ FORWARD_IF_ERROR( ZSTD_loadEntropy_intoDDict(ddict, dictContentType) , ""); diff --git a/lib/decompress/zstd_decompress.c b/lib/decompress/zstd_decompress.c index 0031e98cf..44649dd37 100644 --- a/lib/decompress/zstd_decompress.c +++ b/lib/decompress/zstd_decompress.c @@ -1453,7 +1453,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) dctx->prefixStart = NULL; dctx->virtualStart = NULL; dctx->dictEnd = NULL; - dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */ + dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */ dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; dctx->bType = bt_reserved; diff --git a/lib/decompress/zstd_decompress_internal.h b/lib/decompress/zstd_decompress_internal.h index 17c7df9d0..91e9dceb5 100644 --- a/lib/decompress/zstd_decompress_internal.h +++ b/lib/decompress/zstd_decompress_internal.h @@ -75,13 +75,13 @@ static UNUSED_ATTR const U32 ML_base[MaxML+1] = { #define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE (sizeof(S16) * (MaxSeq + 1) + (1u << MaxFSELog) + sizeof(U64)) #define ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32 ((ZSTD_BUILD_FSE_TABLE_WKSP_SIZE + sizeof(U32) - 1) / sizeof(U32)) -#define HufLog 12 +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 typedef struct { ZSTD_seqSymbol LLTable[SEQSYMBOL_TABLE_SIZE(LLFSELog)]; /* Note : Space reserved for FSE Tables */ ZSTD_seqSymbol OFTable[SEQSYMBOL_TABLE_SIZE(OffFSELog)]; /* is also used as temporary workspace while building hufTable during DDict creation */ ZSTD_seqSymbol MLTable[SEQSYMBOL_TABLE_SIZE(MLFSELog)]; /* and therefore must be at least HUF_DECOMPRESS_WORKSPACE_SIZE large */ - HUF_DTable hufTable[HUF_DTABLE_SIZE(HufLog)]; /* can accommodate HUF_decompress4X */ + HUF_DTable hufTable[HUF_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUF_decompress4X */ U32 rep[ZSTD_REP_NUM]; U32 workspace[ZSTD_BUILD_FSE_TABLE_WKSP_SIZE_U32]; } ZSTD_entropyDTables_t; diff --git a/lib/legacy/zstd_v05.c b/lib/legacy/zstd_v05.c index 795dfb410..fbed0a015 100644 --- a/lib/legacy/zstd_v05.c +++ b/lib/legacy/zstd_v05.c @@ -485,7 +485,7 @@ static const size_t ZSTDv05_frameHeaderSize_min = 5; #define FSEv05_ENCODING_DYNAMIC 3 -#define HufLog 12 +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ @@ -2645,7 +2645,7 @@ struct ZSTDv05_DCtx_s FSEv05_DTable LLTable[FSEv05_DTABLE_SIZE_U32(LLFSEv05Log)]; FSEv05_DTable OffTable[FSEv05_DTABLE_SIZE_U32(OffFSEv05Log)]; FSEv05_DTable MLTable[FSEv05_DTABLE_SIZE_U32(MLFSEv05Log)]; - unsigned hufTableX4[HUFv05_DTABLE_SIZE(HufLog)]; + unsigned hufTableX4[HUFv05_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; const void* previousDstEnd; const void* base; const void* vBase; @@ -2673,7 +2673,7 @@ size_t ZSTDv05_decompressBegin(ZSTDv05_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTableX4[0] = HufLog; + dctx->hufTableX4[0] = ZSTD_HUFFDTABLE_CAPACITY_LOG; dctx->flagStaticTables = 0; return 0; } diff --git a/lib/legacy/zstd_v06.c b/lib/legacy/zstd_v06.c index ead213c48..c486ed0ac 100644 --- a/lib/legacy/zstd_v06.c +++ b/lib/legacy/zstd_v06.c @@ -479,7 +479,7 @@ typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ -#define HufLog 12 +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 #define IS_HUF 0 #define IS_PCH 1 @@ -2806,7 +2806,7 @@ struct ZSTDv06_DCtx_s FSEv06_DTable LLTable[FSEv06_DTABLE_SIZE_U32(LLFSELog)]; FSEv06_DTable OffTable[FSEv06_DTABLE_SIZE_U32(OffFSELog)]; FSEv06_DTable MLTable[FSEv06_DTABLE_SIZE_U32(MLFSELog)]; - unsigned hufTableX4[HUFv06_DTABLE_SIZE(HufLog)]; + unsigned hufTableX4[HUFv06_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; const void* previousDstEnd; const void* base; const void* vBase; @@ -2834,7 +2834,7 @@ size_t ZSTDv06_decompressBegin(ZSTDv06_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTableX4[0] = HufLog; + dctx->hufTableX4[0] = ZSTD_HUFFDTABLE_CAPACITY_LOG; dctx->flagRepeatTable = 0; return 0; } diff --git a/lib/legacy/zstd_v07.c b/lib/legacy/zstd_v07.c index 3a0418e52..20d97da5d 100644 --- a/lib/legacy/zstd_v07.c +++ b/lib/legacy/zstd_v07.c @@ -2717,7 +2717,7 @@ typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; #define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ #define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ -#define HufLog 12 +#define ZSTD_HUFFDTABLE_CAPACITY_LOG 12 typedef enum { lbt_huffman, lbt_repeat, lbt_raw, lbt_rle } litBlockType_t; #define LONGNBSEQ 0x7F00 @@ -2931,7 +2931,7 @@ struct ZSTDv07_DCtx_s FSEv07_DTable LLTable[FSEv07_DTABLE_SIZE_U32(LLFSELog)]; FSEv07_DTable OffTable[FSEv07_DTABLE_SIZE_U32(OffFSELog)]; FSEv07_DTable MLTable[FSEv07_DTABLE_SIZE_U32(MLFSELog)]; - HUFv07_DTable hufTable[HUFv07_DTABLE_SIZE(HufLog)]; /* can accommodate HUFv07_decompress4X */ + HUFv07_DTable hufTable[HUFv07_DTABLE_SIZE(ZSTD_HUFFDTABLE_CAPACITY_LOG)]; /* can accommodate HUFv07_decompress4X */ const void* previousDstEnd; const void* base; const void* vBase; @@ -2967,7 +2967,7 @@ size_t ZSTDv07_decompressBegin(ZSTDv07_DCtx* dctx) dctx->base = NULL; dctx->vBase = NULL; dctx->dictEnd = NULL; - dctx->hufTable[0] = (HUFv07_DTable)((HufLog)*0x1000001); + dctx->hufTable[0] = (HUFv07_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); dctx->litEntropy = dctx->fseEntropy = 0; dctx->dictID = 0; { int i; for (i=0; irep[i] = repStartValue[i]; } From a66e8bb437203df68910f9d898dd9434bbf8f08a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 21 Jan 2022 17:13:33 -0800 Subject: [PATCH 8/9] introduced LitHufLog constant which properly represents the maximum bit size of compressed literals (11) as defined in the specification. To be preferred from HUF_TABLELOG_DEFAULT which represents the same value but by accident. Name selected to keep the same convention as existing width definitions, MLFSELog, LLFSELog and OffFSELog. --- lib/common/zstd_internal.h | 7 ++++--- lib/compress/zstd_compress.c | 16 ++++++++-------- lib/compress/zstd_compress_literals.c | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/common/zstd_internal.h b/lib/common/zstd_internal.h index 0594b7fce..ff2c2cd44 100644 --- a/lib/common/zstd_internal.h +++ b/lib/common/zstd_internal.h @@ -102,6 +102,7 @@ typedef enum { set_basic, set_rle, set_compressed, set_repeat } symbolEncodingTy #define MINMATCH 3 #define Litbits 8 +#define LitHufLog 11 #define MaxLit ((1<= 3) /* GCC Intrinsic */ - return __builtin_clz (val) ^ 31; + return (U32)__builtin_clz (val) ^ 31; # elif defined(__ICCARM__) /* IAR Intrinsic */ return 31 - __CLZ(val); # else /* Software version */ @@ -416,7 +417,7 @@ MEM_STATIC unsigned ZSTD_countTrailingZeros(size_t val) } # endif # elif defined(__GNUC__) && (__GNUC__ >= 4) - return __builtin_ctzll((U64)val); + return (unsigned)__builtin_ctzll((U64)val); # else static const int DeBruijnBytePos[64] = { 0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 34, 20, 56, @@ -439,7 +440,7 @@ MEM_STATIC unsigned ZSTD_countTrailingZeros(size_t val) __assume(0); } # elif defined(__GNUC__) && (__GNUC__ >= 3) - return __builtin_ctz((U32)val); + return (unsigned)__builtin_ctz((U32)val); # else static const int DeBruijnBytePos[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index e80d453e9..ed10d8555 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -840,7 +840,7 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_enableDedicatedDictSearch : CCtxParams->enableDedicatedDictSearch = (value!=0); - return CCtxParams->enableDedicatedDictSearch; + return (size_t)CCtxParams->enableDedicatedDictSearch; case ZSTD_c_enableLongDistanceMatching : CCtxParams->ldmParams.enableLdm = (ZSTD_paramSwitch_e)value; @@ -849,38 +849,38 @@ size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, case ZSTD_c_ldmHashLog : if (value!=0) /* 0 ==> auto */ BOUNDCHECK(ZSTD_c_ldmHashLog, value); - CCtxParams->ldmParams.hashLog = value; + CCtxParams->ldmParams.hashLog = (U32)value; return CCtxParams->ldmParams.hashLog; case ZSTD_c_ldmMinMatch : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmMinMatch, value); - CCtxParams->ldmParams.minMatchLength = value; + CCtxParams->ldmParams.minMatchLength = (U32)value; return CCtxParams->ldmParams.minMatchLength; case ZSTD_c_ldmBucketSizeLog : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); - CCtxParams->ldmParams.bucketSizeLog = value; + CCtxParams->ldmParams.bucketSizeLog = (U32)value; return CCtxParams->ldmParams.bucketSizeLog; case ZSTD_c_ldmHashRateLog : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_ldmHashRateLog, value); - CCtxParams->ldmParams.hashRateLog = value; + CCtxParams->ldmParams.hashRateLog = (U32)value; return CCtxParams->ldmParams.hashRateLog; case ZSTD_c_targetCBlockSize : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_targetCBlockSize, value); - CCtxParams->targetCBlockSize = value; + CCtxParams->targetCBlockSize = (U32)value; return CCtxParams->targetCBlockSize; case ZSTD_c_srcSizeHint : if (value!=0) /* 0 ==> default */ BOUNDCHECK(ZSTD_c_srcSizeHint, value); CCtxParams->srcSizeHint = value; - return CCtxParams->srcSizeHint; + return (size_t)CCtxParams->srcSizeHint; case ZSTD_c_stableInBuffer: BOUNDCHECK(ZSTD_c_stableInBuffer, value); @@ -3065,7 +3065,7 @@ static size_t ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSi BYTE* const nodeWksp = countWkspStart + countWkspSize; const size_t nodeWkspSize = (size_t)(wkspEnd - nodeWksp); unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; - unsigned huffLog = HUF_TABLELOG_DEFAULT; + unsigned huffLog = LitHufLog; HUF_repeat repeat = prevHuf->repeatMode; DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize); diff --git a/lib/compress/zstd_compress_literals.c b/lib/compress/zstd_compress_literals.c index d6d63278a..83f911648 100644 --- a/lib/compress/zstd_compress_literals.c +++ b/lib/compress/zstd_compress_literals.c @@ -132,7 +132,7 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, huf_compress = singleStream ? HUF_compress1X_repeat : HUF_compress4X_repeat; cLitSize = huf_compress(ostart+lhSize, dstCapacity-lhSize, src, srcSize, - HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, + HUF_SYMBOLVALUE_MAX, LitHufLog, entropyWorkspace, entropyWorkspaceSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, From 8b46895588c6a199d6fa674752b51dd547f0addf Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 26 Jan 2022 15:22:06 -0800 Subject: [PATCH 9/9] removed new huffman depth heuristic results are now identical to before this PR --- lib/compress/huf_compress.c | 27 ++++----------------------- tests/regression/results.csv | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 34 deletions(-) diff --git a/lib/compress/huf_compress.c b/lib/compress/huf_compress.c index b533573d1..d1b98afdb 100644 --- a/lib/compress/huf_compress.c +++ b/lib/compress/huf_compress.c @@ -143,7 +143,10 @@ typedef struct { S16 norm[HUF_TABLELOG_MAX+1]; } HUF_CompressWeightsWksp; -static size_t HUF_compressWeights(void* dst, size_t dstSize, const void* weightTable, size_t wtSize, void* workspace, size_t workspaceSize) +static size_t +HUF_compressWeights(void* dst, size_t dstSize, + const void* weightTable, size_t wtSize, + void* workspace, size_t workspaceSize) { BYTE* const ostart = (BYTE*) dst; BYTE* op = ostart; @@ -731,18 +734,6 @@ static void HUF_buildCTableFromTree(HUF_CElt* CTable, nodeElt const* huffNode, i CTable[0] = maxNbBits; } -static size_t -HUF_nbSymbolsTooLarge(const nodeElt* hnodes, U32 maxSymbolValue, U32 maxNbBits) -{ - size_t nbSTL = 0; - int s = (int)maxSymbolValue; - for ( ; s > 0; s-- ) { - if (hnodes[s].nbBits > maxNbBits) nbSTL++; - else break; - } - return nbSTL; -} - size_t HUF_buildCTable_wksp(HUF_CElt* CTable, const unsigned* count, U32 maxSymbolValue, U32 maxNbBits, void* workSpace, size_t wkspSize) @@ -771,16 +762,6 @@ HUF_buildCTable_wksp(HUF_CElt* CTable, const unsigned* count, U32 maxSymbolValue nonNullRank = HUF_buildTree(huffNode, maxSymbolValue); /* determine and enforce maxTableLog */ - /* Loosen target when maxNbBits is already within limits. - * A harsh rebalancing can be bad for compression ratio - * while a mild one tends to be better */ - while (maxNbBits < HUF_TABLELOG_DEFAULT) { - size_t const nbSTL = HUF_nbSymbolsTooLarge(huffNode, maxSymbolValue, maxNbBits); - #define HUF_NB_NODES_TO_FIX_MAX 32 - if (nbSTL < HUF_NB_NODES_TO_FIX_MAX) /* heuristic */ - break; - maxNbBits++; - } maxNbBits = HUF_setMaxHeight(huffNode, (U32)nonNullRank, maxNbBits); if (maxNbBits > HUF_TABLELOG_MAX) return ERROR(GENERIC); /* check fit into table */ diff --git a/tests/regression/results.csv b/tests/regression/results.csv index f80da9f4e..3385c5049 100644 --- a/tests/regression/results.csv +++ b/tests/regression/results.csv @@ -51,7 +51,7 @@ silesia, long distance mode, compress silesia, multithreaded, compress cctx, 4842075 silesia, multithreaded long distance mode, compress cctx, 4842075 silesia, small window log, compress cctx, 7082951 -silesia, small hash log, compress cctx, 6525895 +silesia, small hash log, compress cctx, 6526141 silesia, small chain log, compress cctx, 4912197 silesia, explicit params, compress cctx, 4794052 silesia, uncompressed literals, compress cctx, 4842075 @@ -115,7 +115,7 @@ silesia, long distance mode, zstdcli, silesia, multithreaded, zstdcli, 4842123 silesia, multithreaded long distance mode, zstdcli, 4833785 silesia, small window log, zstdcli, 7095048 -silesia, small hash log, zstdcli, 6525943 +silesia, small hash log, zstdcli, 6526189 silesia, small chain log, zstdcli, 4912245 silesia, explicit params, zstdcli, 4795432 silesia, uncompressed literals, zstdcli, 5120614 @@ -141,7 +141,7 @@ silesia.tar, long distance mode, zstdcli, silesia.tar, multithreaded, zstdcli, 4854164 silesia.tar, multithreaded long distance mode, zstdcli, 4845745 silesia.tar, small window log, zstdcli, 7100701 -silesia.tar, small hash log, zstdcli, 6529041 +silesia.tar, small hash log, zstdcli, 6529289 silesia.tar, small chain log, zstdcli, 4917022 silesia.tar, explicit params, zstdcli, 4820713 silesia.tar, uncompressed literals, zstdcli, 5122571 @@ -255,7 +255,7 @@ silesia, long distance mode, advanced silesia, multithreaded, advanced one pass, 4842075 silesia, multithreaded long distance mode, advanced one pass, 4833737 silesia, small window log, advanced one pass, 7095000 -silesia, small hash log, advanced one pass, 6525895 +silesia, small hash log, advanced one pass, 6526141 silesia, small chain log, advanced one pass, 4912197 silesia, explicit params, advanced one pass, 4795432 silesia, uncompressed literals, advanced one pass, 5120566 @@ -289,7 +289,7 @@ silesia.tar, long distance mode, advanced silesia.tar, multithreaded, advanced one pass, 4854160 silesia.tar, multithreaded long distance mode, advanced one pass, 4845741 silesia.tar, small window log, advanced one pass, 7100655 -silesia.tar, small hash log, advanced one pass, 6528983 +silesia.tar, small hash log, advanced one pass, 6529231 silesia.tar, small chain log, advanced one pass, 4917041 silesia.tar, explicit params, advanced one pass, 4806855 silesia.tar, uncompressed literals, advanced one pass, 5122473 @@ -573,7 +573,7 @@ silesia, long distance mode, advanced silesia, multithreaded, advanced one pass small out, 4842075 silesia, multithreaded long distance mode, advanced one pass small out, 4833737 silesia, small window log, advanced one pass small out, 7095000 -silesia, small hash log, advanced one pass small out, 6525895 +silesia, small hash log, advanced one pass small out, 6526141 silesia, small chain log, advanced one pass small out, 4912197 silesia, explicit params, advanced one pass small out, 4795432 silesia, uncompressed literals, advanced one pass small out, 5120566 @@ -607,7 +607,7 @@ silesia.tar, long distance mode, advanced silesia.tar, multithreaded, advanced one pass small out, 4854160 silesia.tar, multithreaded long distance mode, advanced one pass small out, 4845741 silesia.tar, small window log, advanced one pass small out, 7100655 -silesia.tar, small hash log, advanced one pass small out, 6528983 +silesia.tar, small hash log, advanced one pass small out, 6529231 silesia.tar, small chain log, advanced one pass small out, 4917041 silesia.tar, explicit params, advanced one pass small out, 4806855 silesia.tar, uncompressed literals, advanced one pass small out, 5122473 @@ -891,7 +891,7 @@ silesia, long distance mode, advanced silesia, multithreaded, advanced streaming, 4842075 silesia, multithreaded long distance mode, advanced streaming, 4833737 silesia, small window log, advanced streaming, 7111103 -silesia, small hash log, advanced streaming, 6525895 +silesia, small hash log, advanced streaming, 6526141 silesia, small chain log, advanced streaming, 4912197 silesia, explicit params, advanced streaming, 4795452 silesia, uncompressed literals, advanced streaming, 5120566 @@ -925,7 +925,7 @@ silesia.tar, long distance mode, advanced silesia.tar, multithreaded, advanced streaming, 4854160 silesia.tar, multithreaded long distance mode, advanced streaming, 4845741 silesia.tar, small window log, advanced streaming, 7117559 -silesia.tar, small hash log, advanced streaming, 6528986 +silesia.tar, small hash log, advanced streaming, 6529234 silesia.tar, small chain log, advanced streaming, 4917021 silesia.tar, explicit params, advanced streaming, 4806873 silesia.tar, uncompressed literals, advanced streaming, 5127423 @@ -1303,7 +1303,7 @@ silesia, long distance mode, old stre silesia, multithreaded, old streaming advanced, 4842075 silesia, multithreaded long distance mode, old streaming advanced, 4842075 silesia, small window log, old streaming advanced, 7111103 -silesia, small hash log, old streaming advanced, 6525895 +silesia, small hash log, old streaming advanced, 6526141 silesia, small chain log, old streaming advanced, 4912197 silesia, explicit params, old streaming advanced, 4795452 silesia, uncompressed literals, old streaming advanced, 4842075 @@ -1329,7 +1329,7 @@ silesia.tar, long distance mode, old stre silesia.tar, multithreaded, old streaming advanced, 4859271 silesia.tar, multithreaded long distance mode, old streaming advanced, 4859271 silesia.tar, small window log, old streaming advanced, 7117562 -silesia.tar, small hash log, old streaming advanced, 6528986 +silesia.tar, small hash log, old streaming advanced, 6529234 silesia.tar, small chain log, old streaming advanced, 4917021 silesia.tar, explicit params, old streaming advanced, 4806873 silesia.tar, uncompressed literals, old streaming advanced, 4859271