Proactively skip huffman compression based on sampling where non-compressibility is suspected
This commit is contained in:
+6
-4
@@ -206,12 +206,13 @@ typedef enum {
|
|||||||
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
||||||
* If it uses hufTable it does not modify hufTable or repeat.
|
* If it uses hufTable it does not modify hufTable or repeat.
|
||||||
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
||||||
* If preferRepeat then the old table will always be used if valid. */
|
* If preferRepeat then the old table will always be used if valid.
|
||||||
|
* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
|
||||||
size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
|
size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned tableLog,
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible);
|
||||||
|
|
||||||
/** HUF_buildCTable_wksp() :
|
/** HUF_buildCTable_wksp() :
|
||||||
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
* Same as HUF_buildCTable(), but using externally allocated scratch buffer.
|
||||||
@@ -311,12 +312,13 @@ size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, si
|
|||||||
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
|
||||||
* If it uses hufTable it does not modify hufTable or repeat.
|
* If it uses hufTable it does not modify hufTable or repeat.
|
||||||
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
|
||||||
* If preferRepeat then the old table will always be used if valid. */
|
* If preferRepeat then the old table will always be used if valid.
|
||||||
|
* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
|
||||||
size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
|
size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned tableLog,
|
unsigned maxSymbolValue, unsigned tableLog,
|
||||||
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible);
|
||||||
|
|
||||||
size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
|
size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
|
||||||
#ifndef HUF_FORCE_DECOMPRESS_X1
|
#ifndef HUF_FORCE_DECOMPRESS_X1
|
||||||
|
|||||||
@@ -758,6 +758,9 @@ typedef struct {
|
|||||||
} wksps;
|
} wksps;
|
||||||
} HUF_compress_tables_t;
|
} HUF_compress_tables_t;
|
||||||
|
|
||||||
|
#define SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE 4096
|
||||||
|
#define SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO 10 /* Must be >= 2 */
|
||||||
|
|
||||||
/* HUF_compress_internal() :
|
/* HUF_compress_internal() :
|
||||||
* `workSpace_align4` must be aligned on 4-bytes boundaries,
|
* `workSpace_align4` must be aligned on 4-bytes boundaries,
|
||||||
* and occupies the same space as a table of HUF_WORKSPACE_SIZE_U32 unsigned */
|
* and occupies the same space as a table of HUF_WORKSPACE_SIZE_U32 unsigned */
|
||||||
@@ -768,7 +771,7 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
|||||||
HUF_nbStreams_e nbStreams,
|
HUF_nbStreams_e nbStreams,
|
||||||
void* workSpace_align4, size_t wkspSize,
|
void* workSpace_align4, size_t wkspSize,
|
||||||
HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
|
HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
|
||||||
const int bmi2)
|
const int bmi2, unsigned suspectUncompressible)
|
||||||
{
|
{
|
||||||
HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace_align4;
|
HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace_align4;
|
||||||
BYTE* const ostart = (BYTE*)dst;
|
BYTE* const ostart = (BYTE*)dst;
|
||||||
@@ -795,6 +798,21 @@ HUF_compress_internal (void* dst, size_t dstSize,
|
|||||||
nbStreams, oldHufTable, bmi2);
|
nbStreams, oldHufTable, bmi2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If uncompressible data is suspected, do a smaller sampling first */
|
||||||
|
DEBUG_STATIC_ASSERT(SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO >= 2);
|
||||||
|
if (suspectUncompressible && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) {
|
||||||
|
size_t largestTotal = 0;
|
||||||
|
{ unsigned maxSymbolValueBegin = maxSymbolValue;
|
||||||
|
CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) );
|
||||||
|
largestTotal += largestBegin;
|
||||||
|
}
|
||||||
|
{ unsigned maxSymbolValueEnd = maxSymbolValue;
|
||||||
|
CHECK_V_F(largestEnd, HIST_count_simple (table->count, &maxSymbolValueEnd, (const BYTE*)src + srcSize - SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) );
|
||||||
|
largestTotal += largestEnd;
|
||||||
|
}
|
||||||
|
if (largestTotal <= ((2 * SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) >> 7)+4) return 0; /* heuristic : probably not compressible enough */
|
||||||
|
}
|
||||||
|
|
||||||
/* Scan input and build symbol stats */
|
/* Scan input and build symbol stats */
|
||||||
{ CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace_align4, wkspSize) );
|
{ CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace_align4, wkspSize) );
|
||||||
if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
|
if (largest == srcSize) { *ostart = ((const BYTE*)src)[0]; return 1; } /* single symbol, rle */
|
||||||
@@ -860,19 +878,20 @@ size_t HUF_compress1X_wksp (void* dst, size_t dstSize,
|
|||||||
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
maxSymbolValue, huffLog, HUF_singleStream,
|
maxSymbolValue, huffLog, HUF_singleStream,
|
||||||
workSpace, wkspSize,
|
workSpace, wkspSize,
|
||||||
NULL, NULL, 0, 0 /*bmi2*/);
|
NULL, NULL, 0, 0 /*bmi2*/, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
|
size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat,
|
||||||
|
int bmi2, unsigned suspectUncompressible)
|
||||||
{
|
{
|
||||||
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
maxSymbolValue, huffLog, HUF_singleStream,
|
maxSymbolValue, huffLog, HUF_singleStream,
|
||||||
workSpace, wkspSize, hufTable,
|
workSpace, wkspSize, hufTable,
|
||||||
repeat, preferRepeat, bmi2);
|
repeat, preferRepeat, bmi2, suspectUncompressible);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HUF_compress4X_repeat():
|
/* HUF_compress4X_repeat():
|
||||||
@@ -886,22 +905,23 @@ size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
|
|||||||
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
maxSymbolValue, huffLog, HUF_fourStreams,
|
maxSymbolValue, huffLog, HUF_fourStreams,
|
||||||
workSpace, wkspSize,
|
workSpace, wkspSize,
|
||||||
NULL, NULL, 0, 0 /*bmi2*/);
|
NULL, NULL, 0, 0 /*bmi2*/, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* HUF_compress4X_repeat():
|
/* HUF_compress4X_repeat():
|
||||||
* compress input using 4 streams.
|
* compress input using 4 streams.
|
||||||
|
* consider skipping quickly
|
||||||
* re-use an existing huffman compression table */
|
* re-use an existing huffman compression table */
|
||||||
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
|
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
unsigned maxSymbolValue, unsigned huffLog,
|
unsigned maxSymbolValue, unsigned huffLog,
|
||||||
void* workSpace, size_t wkspSize,
|
void* workSpace, size_t wkspSize,
|
||||||
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
|
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible)
|
||||||
{
|
{
|
||||||
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
return HUF_compress_internal(dst, dstSize, src, srcSize,
|
||||||
maxSymbolValue, huffLog, HUF_fourStreams,
|
maxSymbolValue, huffLog, HUF_fourStreams,
|
||||||
workSpace, wkspSize,
|
workSpace, wkspSize,
|
||||||
hufTable, repeat, preferRepeat, bmi2);
|
hufTable, repeat, preferRepeat, bmi2, suspectUncompressible);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ZSTD_NO_UNUSED_FUNCTIONS
|
#ifndef ZSTD_NO_UNUSED_FUNCTIONS
|
||||||
|
|||||||
@@ -2557,6 +2557,7 @@ ZSTD_buildSequencesStatistics(seqStore_t* seqStorePtr, size_t nbSeq,
|
|||||||
* compresses both literals and sequences
|
* compresses both literals and sequences
|
||||||
* Returns compressed size of block, or a zstd error.
|
* Returns compressed size of block, or a zstd error.
|
||||||
*/
|
*/
|
||||||
|
#define SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO 20
|
||||||
MEM_STATIC size_t
|
MEM_STATIC size_t
|
||||||
ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
|
ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
|
||||||
const ZSTD_entropyCTables_t* prevEntropy,
|
const ZSTD_entropyCTables_t* prevEntropy,
|
||||||
@@ -2591,6 +2592,10 @@ ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
|
|||||||
|
|
||||||
/* Compress literals */
|
/* Compress literals */
|
||||||
{ const BYTE* const literals = seqStorePtr->litStart;
|
{ const BYTE* const literals = seqStorePtr->litStart;
|
||||||
|
size_t const numSequences = seqStorePtr->sequences - seqStorePtr->sequencesStart;
|
||||||
|
size_t const numLiterals = seqStorePtr->lit - seqStorePtr->litStart;
|
||||||
|
/* Base suspicion of uncompressibility on ratio of literals to sequences */
|
||||||
|
unsigned const suspectUncompressible = (numSequences == 0) || (numLiterals / numSequences >= SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO);
|
||||||
size_t const litSize = (size_t)(seqStorePtr->lit - literals);
|
size_t const litSize = (size_t)(seqStorePtr->lit - literals);
|
||||||
size_t const cSize = ZSTD_compressLiterals(
|
size_t const cSize = ZSTD_compressLiterals(
|
||||||
&prevEntropy->huf, &nextEntropy->huf,
|
&prevEntropy->huf, &nextEntropy->huf,
|
||||||
@@ -2599,7 +2604,7 @@ ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
|
|||||||
op, dstCapacity,
|
op, dstCapacity,
|
||||||
literals, litSize,
|
literals, litSize,
|
||||||
entropyWorkspace, entropyWkspSize,
|
entropyWorkspace, entropyWkspSize,
|
||||||
bmi2);
|
bmi2, suspectUncompressible);
|
||||||
FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed");
|
FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed");
|
||||||
assert(cSize <= dstCapacity);
|
assert(cSize <= dstCapacity);
|
||||||
op += cSize;
|
op += cSize;
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
|||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
void* entropyWorkspace, size_t entropyWorkspaceSize,
|
void* entropyWorkspace, size_t entropyWorkspaceSize,
|
||||||
const int bmi2)
|
const int bmi2,
|
||||||
|
unsigned suspectUncompressible)
|
||||||
{
|
{
|
||||||
size_t const minGain = ZSTD_minGain(srcSize, strategy);
|
size_t const minGain = ZSTD_minGain(srcSize, strategy);
|
||||||
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
|
||||||
@@ -105,11 +106,11 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
|||||||
HUF_compress1X_repeat(
|
HUF_compress1X_repeat(
|
||||||
ostart+lhSize, dstCapacity-lhSize, src, srcSize,
|
ostart+lhSize, dstCapacity-lhSize, src, srcSize,
|
||||||
HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
|
HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
|
||||||
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) :
|
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2, suspectUncompressible) :
|
||||||
HUF_compress4X_repeat(
|
HUF_compress4X_repeat(
|
||||||
ostart+lhSize, dstCapacity-lhSize, src, srcSize,
|
ostart+lhSize, dstCapacity-lhSize, src, srcSize,
|
||||||
HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
|
HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
|
||||||
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
|
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2, suspectUncompressible);
|
||||||
if (repeat != HUF_repeat_none) {
|
if (repeat != HUF_repeat_none) {
|
||||||
/* reused the existing table */
|
/* reused the existing table */
|
||||||
DEBUGLOG(5, "Reusing previous huffman table");
|
DEBUGLOG(5, "Reusing previous huffman table");
|
||||||
|
|||||||
@@ -18,12 +18,14 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src,
|
|||||||
|
|
||||||
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
|
||||||
|
|
||||||
|
/* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
|
||||||
size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
|
||||||
ZSTD_hufCTables_t* nextHuf,
|
ZSTD_hufCTables_t* nextHuf,
|
||||||
ZSTD_strategy strategy, int disableLiteralCompression,
|
ZSTD_strategy strategy, int disableLiteralCompression,
|
||||||
void* dst, size_t dstCapacity,
|
void* dst, size_t dstCapacity,
|
||||||
const void* src, size_t srcSize,
|
const void* src, size_t srcSize,
|
||||||
void* entropyWorkspace, size_t entropyWorkspaceSize,
|
void* entropyWorkspace, size_t entropyWorkspaceSize,
|
||||||
const int bmi2);
|
const int bmi2,
|
||||||
|
unsigned suspectUncompressible);
|
||||||
|
|
||||||
#endif /* ZSTD_COMPRESS_LITERALS_H */
|
#endif /* ZSTD_COMPRESS_LITERALS_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user