Skip to content

Commit b3e372c

Browse files
authored
Merge pull request #2717 from binhdvo/bootcamp
Proactively skip huffman compression based on sampling where non-comp…
2 parents d90bc0e + dc5b693 commit b3e372c

File tree

5 files changed

+46
-16
lines changed

5 files changed

+46
-16
lines changed

lib/common/huf.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,13 @@ typedef enum {
206206
* Same as HUF_compress4X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
207207
* If it uses hufTable it does not modify hufTable or repeat.
208208
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
209-
* If preferRepeat then the old table will always be used if valid. */
209+
* If preferRepeat then the old table will always be used if valid.
210+
* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
210211
size_t HUF_compress4X_repeat(void* dst, size_t dstSize,
211212
const void* src, size_t srcSize,
212213
unsigned maxSymbolValue, unsigned tableLog,
213214
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
214-
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
215+
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible);
215216

216217
/** HUF_buildCTable_wksp() :
217218
* 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
311312
* Same as HUF_compress1X_wksp(), but considers using hufTable if *repeat != HUF_repeat_none.
312313
* If it uses hufTable it does not modify hufTable or repeat.
313314
* If it doesn't, it sets *repeat = HUF_repeat_none, and it sets hufTable to the table used.
314-
* If preferRepeat then the old table will always be used if valid. */
315+
* If preferRepeat then the old table will always be used if valid.
316+
* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
315317
size_t HUF_compress1X_repeat(void* dst, size_t dstSize,
316318
const void* src, size_t srcSize,
317319
unsigned maxSymbolValue, unsigned tableLog,
318320
void* workSpace, size_t wkspSize, /**< `workSpace` must be aligned on 4-bytes boundaries, `wkspSize` must be >= HUF_WORKSPACE_SIZE */
319-
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2);
321+
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible);
320322

321323
size_t HUF_decompress1X1 (void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); /* single-symbol decoder */
322324
#ifndef HUF_FORCE_DECOMPRESS_X1

lib/compress/huf_compress.c

+27-7
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,9 @@ typedef struct {
758758
} wksps;
759759
} HUF_compress_tables_t;
760760

761+
#define SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE 4096
762+
#define SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO 10 /* Must be >= 2 */
763+
761764
/* HUF_compress_internal() :
762765
* `workSpace_align4` must be aligned on 4-bytes boundaries,
763766
* 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,
768771
HUF_nbStreams_e nbStreams,
769772
void* workSpace_align4, size_t wkspSize,
770773
HUF_CElt* oldHufTable, HUF_repeat* repeat, int preferRepeat,
771-
const int bmi2)
774+
const int bmi2, unsigned suspectUncompressible)
772775
{
773776
HUF_compress_tables_t* const table = (HUF_compress_tables_t*)workSpace_align4;
774777
BYTE* const ostart = (BYTE*)dst;
@@ -795,6 +798,21 @@ HUF_compress_internal (void* dst, size_t dstSize,
795798
nbStreams, oldHufTable, bmi2);
796799
}
797800

801+
/* If uncompressible data is suspected, do a smaller sampling first */
802+
DEBUG_STATIC_ASSERT(SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO >= 2);
803+
if (suspectUncompressible && srcSize >= (SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE * SUSPECT_INCOMPRESSIBLE_SAMPLE_RATIO)) {
804+
size_t largestTotal = 0;
805+
{ unsigned maxSymbolValueBegin = maxSymbolValue;
806+
CHECK_V_F(largestBegin, HIST_count_simple (table->count, &maxSymbolValueBegin, (const BYTE*)src, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) );
807+
largestTotal += largestBegin;
808+
}
809+
{ unsigned maxSymbolValueEnd = maxSymbolValue;
810+
CHECK_V_F(largestEnd, HIST_count_simple (table->count, &maxSymbolValueEnd, (const BYTE*)src + srcSize - SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE, SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) );
811+
largestTotal += largestEnd;
812+
}
813+
if (largestTotal <= ((2 * SUSPECT_INCOMPRESSIBLE_SAMPLE_SIZE) >> 7)+4) return 0; /* heuristic : probably not compressible enough */
814+
}
815+
798816
/* Scan input and build symbol stats */
799817
{ CHECK_V_F(largest, HIST_count_wksp (table->count, &maxSymbolValue, (const BYTE*)src, srcSize, workSpace_align4, wkspSize) );
800818
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,
860878
return HUF_compress_internal(dst, dstSize, src, srcSize,
861879
maxSymbolValue, huffLog, HUF_singleStream,
862880
workSpace, wkspSize,
863-
NULL, NULL, 0, 0 /*bmi2*/);
881+
NULL, NULL, 0, 0 /*bmi2*/, 0);
864882
}
865883

866884
size_t HUF_compress1X_repeat (void* dst, size_t dstSize,
867885
const void* src, size_t srcSize,
868886
unsigned maxSymbolValue, unsigned huffLog,
869887
void* workSpace, size_t wkspSize,
870-
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
888+
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat,
889+
int bmi2, unsigned suspectUncompressible)
871890
{
872891
return HUF_compress_internal(dst, dstSize, src, srcSize,
873892
maxSymbolValue, huffLog, HUF_singleStream,
874893
workSpace, wkspSize, hufTable,
875-
repeat, preferRepeat, bmi2);
894+
repeat, preferRepeat, bmi2, suspectUncompressible);
876895
}
877896

878897
/* HUF_compress4X_repeat():
@@ -886,22 +905,23 @@ size_t HUF_compress4X_wksp (void* dst, size_t dstSize,
886905
return HUF_compress_internal(dst, dstSize, src, srcSize,
887906
maxSymbolValue, huffLog, HUF_fourStreams,
888907
workSpace, wkspSize,
889-
NULL, NULL, 0, 0 /*bmi2*/);
908+
NULL, NULL, 0, 0 /*bmi2*/, 0);
890909
}
891910

892911
/* HUF_compress4X_repeat():
893912
* compress input using 4 streams.
913+
* consider skipping quickly
894914
* re-use an existing huffman compression table */
895915
size_t HUF_compress4X_repeat (void* dst, size_t dstSize,
896916
const void* src, size_t srcSize,
897917
unsigned maxSymbolValue, unsigned huffLog,
898918
void* workSpace, size_t wkspSize,
899-
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2)
919+
HUF_CElt* hufTable, HUF_repeat* repeat, int preferRepeat, int bmi2, unsigned suspectUncompressible)
900920
{
901921
return HUF_compress_internal(dst, dstSize, src, srcSize,
902922
maxSymbolValue, huffLog, HUF_fourStreams,
903923
workSpace, wkspSize,
904-
hufTable, repeat, preferRepeat, bmi2);
924+
hufTable, repeat, preferRepeat, bmi2, suspectUncompressible);
905925
}
906926

907927
#ifndef ZSTD_NO_UNUSED_FUNCTIONS

lib/compress/zstd_compress.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -2557,6 +2557,7 @@ ZSTD_buildSequencesStatistics(seqStore_t* seqStorePtr, size_t nbSeq,
25572557
* compresses both literals and sequences
25582558
* Returns compressed size of block, or a zstd error.
25592559
*/
2560+
#define SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO 20
25602561
MEM_STATIC size_t
25612562
ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
25622563
const ZSTD_entropyCTables_t* prevEntropy,
@@ -2591,6 +2592,10 @@ ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
25912592

25922593
/* Compress literals */
25932594
{ const BYTE* const literals = seqStorePtr->litStart;
2595+
size_t const numSequences = seqStorePtr->sequences - seqStorePtr->sequencesStart;
2596+
size_t const numLiterals = seqStorePtr->lit - seqStorePtr->litStart;
2597+
/* Base suspicion of uncompressibility on ratio of literals to sequences */
2598+
unsigned const suspectUncompressible = (numSequences == 0) || (numLiterals / numSequences >= SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO);
25942599
size_t const litSize = (size_t)(seqStorePtr->lit - literals);
25952600
size_t const cSize = ZSTD_compressLiterals(
25962601
&prevEntropy->huf, &nextEntropy->huf,
@@ -2599,7 +2604,7 @@ ZSTD_entropyCompressSeqStore_internal(seqStore_t* seqStorePtr,
25992604
op, dstCapacity,
26002605
literals, litSize,
26012606
entropyWorkspace, entropyWkspSize,
2602-
bmi2);
2607+
bmi2, suspectUncompressible);
26032608
FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed");
26042609
assert(cSize <= dstCapacity);
26052610
op += cSize;

lib/compress/zstd_compress_literals.c

+4-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
7373
void* dst, size_t dstCapacity,
7474
const void* src, size_t srcSize,
7575
void* entropyWorkspace, size_t entropyWorkspaceSize,
76-
const int bmi2)
76+
const int bmi2,
77+
unsigned suspectUncompressible)
7778
{
7879
size_t const minGain = ZSTD_minGain(srcSize, strategy);
7980
size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
@@ -105,11 +106,11 @@ size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
105106
HUF_compress1X_repeat(
106107
ostart+lhSize, dstCapacity-lhSize, src, srcSize,
107108
HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
108-
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) :
109+
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2, suspectUncompressible) :
109110
HUF_compress4X_repeat(
110111
ostart+lhSize, dstCapacity-lhSize, src, srcSize,
111112
HUF_SYMBOLVALUE_MAX, HUF_TABLELOG_DEFAULT, entropyWorkspace, entropyWorkspaceSize,
112-
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
113+
(HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2, suspectUncompressible);
113114
if (repeat != HUF_repeat_none) {
114115
/* reused the existing table */
115116
DEBUGLOG(5, "Reusing previous huffman table");

lib/compress/zstd_compress_literals.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src,
1818

1919
size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize);
2020

21+
/* If suspectUncompressible then some sampling checks will be run to potentially skip huffman coding */
2122
size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
2223
ZSTD_hufCTables_t* nextHuf,
2324
ZSTD_strategy strategy, int disableLiteralCompression,
2425
void* dst, size_t dstCapacity,
2526
const void* src, size_t srcSize,
2627
void* entropyWorkspace, size_t entropyWorkspaceSize,
27-
const int bmi2);
28+
const int bmi2,
29+
unsigned suspectUncompressible);
2830

2931
#endif /* ZSTD_COMPRESS_LITERALS_H */

0 commit comments

Comments
 (0)