Compare commits

..
57 Commits
Author SHA1 Message Date
Yann Collet 42e9bed1ea Merge pull request #70 from Cyan4973/dev
Dev
2015-11-09 12:50:27 +01:00
Yann Collet 7ccff59cb3 fold fast stats 2015-11-09 12:07:44 +01:00
Yann Collet 6d2c9e6c62 generic param table 2015-11-09 11:39:48 +01:00
Yann Collet 4baee50728 fix bug 2015-11-09 03:19:33 +01:00
Yann Collet d1ade5a61d fix 32-bits mode 2015-11-08 15:49:20 +01:00
Yann Collet e9eba608c2 simplified bt 2015-11-08 15:08:03 +01:00
Yann Collet d61ddd03ec pg display CL-compatible params 2015-11-08 14:45:38 +01:00
Yann Collet 4c7aae3a36 fuzzer tests more HC levels 2015-11-08 14:24:59 +01:00
Yann Collet 31d00ba4b3 fix bt bug 2015-11-08 14:11:29 +01:00
Yann Collet 72a8e751f4 level tuning 2015-11-07 22:24:46 +01:00
Yann Collet f48e35c206 minor bt improvements 2015-11-07 01:13:31 +01:00
Yann Collet a81d9ac42d minor bt CSpeed 2015-11-06 19:03:59 +01:00
Yann Collet 628065cf98 revert 2015-11-06 18:44:54 +01:00
Yann Collet 9b8e453713 minor CRatio improvement 2015-11-06 18:28:02 +01:00
Yann Collet 47cfa9a985 minor CRatio improvement 2015-11-06 17:13:46 +01:00
Yann Collet eb283710dd minor greedy CRatio improvement 2015-11-06 16:33:11 +01:00
Yann Collet fc2afcfa64 small Cspeed increase 2015-11-06 15:40:14 +01:00
Yann Collet 863ff3be4d Merge pull request #67 from Cyan4973/dev
Dev
2015-11-06 14:29:04 +01:00
Yann Collet acd222c82e update readme 2015-11-06 12:39:39 +01:00
Yann Collet 444873f494 minor greedy mod 2015-11-06 11:48:56 +01:00
Yann Collet 805a52a773 fixed asan warning 2015-11-06 10:52:17 +01:00
Yann Collet 8ad12ec343 level tuning 2015-11-06 10:19:00 +01:00
Yann Collet f12c1304a8 integrate fast mode 2015-11-05 18:16:59 +01:00
Yann Collet 1f44b3f778 added fast mode 2015-11-05 17:32:18 +01:00
Yann Collet 47b68908b2 rename lazy2 2015-11-05 15:14:17 +01:00
Yann Collet 9036105b62 simplified source 2015-11-05 15:03:12 +01:00
Yann Collet 5106a76dc9 merged strats 2015-11-05 15:00:24 +01:00
Yann Collet 43ae161fe9 level tuning 2015-11-05 11:58:02 +01:00
Yann Collet 9876e1e1f5 Merge pull request #65 from Cyan4973/dev
Dev
2015-11-05 02:42:59 +01:00
Yann Collet 92309cb37e level tuning 2015-11-05 00:48:37 +01:00
Yann Collet 3137d1a059 fix fuzzer32 litCSize limit condition 2015-11-04 23:36:36 +01:00
Yann Collet 50c5cdb44c fixed issues reported by Maciej Adamczyk 2015-11-04 20:35:33 +01:00
Yann Collet 3e3582719c Fixed issue #62, reported by @luben 2015-11-04 18:19:39 +01:00
Yann Collet 2c7ac7c055 fix bench on /dev/null 2015-11-04 17:52:18 +01:00
Yann Collet e8455f51ea fix clang warning 2015-11-04 17:41:20 +01:00
Yann Collet b241e9deb7 small compression improvement 2015-11-04 13:57:24 +01:00
Yann Collet 59d7063fbc fix and level tuning 2015-11-04 12:05:27 +01:00
Yann Collet 96b9f0ba4d btlazy2 2015-11-04 03:52:54 +01:00
Yann Collet 293d0cc261 fixed Visual warning 2015-11-03 13:10:25 +01:00
Yann Collet cdc2b2f758 fixed clang warning 2015-11-03 10:52:14 +01:00
Yann Collet 588d1e5fa0 Fixed asan issue reported by Maciej Adamczyk 2015-11-03 10:48:42 +01:00
Yann Collet 050efba81b level tuning 2015-11-03 09:49:30 +01:00
Yann Collet 3564487614 lazydeep 2015-11-02 16:14:46 +01:00
Yann Collet 43194f918d Merge pull request #61 from Cyan4973/dev
v0.3.2
2015-11-02 12:46:42 +01:00
Yann Collet ee34cdf33d Added Silesia corpus link 2015-11-02 12:45:31 +01:00
Yann Collet 7671f393be v0.3.2 2015-11-02 12:17:39 +01:00
cyan 154c25a6df fix Visual Studio projects in 32-bits release mode 2015-11-02 11:43:27 +01:00
Yann Collet 4e049bca8c Fixed Visual Studio issue #60, reported by @mailagentrus 2015-11-02 11:09:54 +01:00
Yann Collet da8557e6dc Merge pull request #59 from Cyan4973/dev
Dev
2015-11-02 03:19:38 +01:00
Yann Collet 81ec15d234 Merge pull request #58 from Cyan4973/Cyan4973-patch-1
Update README.md
2015-11-02 02:45:41 +01:00
Yann Collet 8d8d59e959 Update README.md 2015-11-02 02:44:43 +01:00
Yann Collet 66d22b803b v0.3.1 2015-11-02 02:36:10 +01:00
Yann Collet 33331bf613 Merge pull request #57 from Cyan4973/dev
Dev
2015-11-02 02:29:05 +01:00
Yann Collet 56e1092cb0 level tuning 2015-11-02 01:02:43 +01:00
Yann Collet 21f96934c3 fixed config counter 2015-11-01 14:32:59 +01:00
Yann Collet 9b11b46f8a Fixed speed regression 2015-11-01 12:40:22 +01:00
Yann Collet be2010ea1b lazy strategy 2015-10-31 12:57:14 +01:00
19 changed files with 818 additions and 251 deletions
+1 -1
View File
@@ -32,7 +32,7 @@
# ################################################################
# Version number
export VERSION := 0.3.0
export VERSION := 0.3.5
PRGDIR = programs
ZSTDDIR = lib
+15
View File
@@ -1,3 +1,18 @@
v0.3.5
minor generic compression improvements
v0.3.4
Faster fast cLevels
v0.3.3
Small compression ratio improvement
v0.3.2
Fixed Visual Studio
v0.3.1 :
Small compression ratio improvement
v0.3
HC mode : compression levels 2-26
+13 -17
View File
@@ -7,42 +7,38 @@ It is provided as a BSD-license package, hosted on Github.
|master | [![Build Status](https://travis-ci.org/Cyan4973/zstd.svg?branch=master)](https://travis-ci.org/Cyan4973/zstd) |
|dev | [![Build Status](https://travis-ci.org/Cyan4973/zstd.svg?branch=dev)](https://travis-ci.org/Cyan4973/zstd) |
For a taste of its performance, here are a few benchmark numbers from a number of compression codecs suitable for real-time. The test was completed on a Core i7-5600U @ 2.6 GHz, using [fsbench 0.14.3](http://encode.ru/threads/1371-Filesystem-benchmark?p=34029&viewfull=1#post34029), an open-source benchmark program by m^2.
For a taste of its performance, here are a few benchmark numbers from a number of compression codecs suitable for real-time. The test was completed on a Core i7-5600U @ 2.6 GHz, using m^2's [fsbench 0.14.3](http://encode.ru/threads/1371-Filesystem-benchmark?p=34029&viewfull=1#post34029) compiled with gcc 4.8.4, on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia).
|Name | Ratio | C.speed | D.speed |
|-----------------|-------|--------:|--------:|
| | | MB/s | MB/s |
| **zstd 0.3** |**2.858**|**280**| **670** |
| [zlib 1.2.8] -1 | 2.730 | 70 | 300 |
| [zlib] 1.2.8 -1 | 2.730 | 70 | 300 |
| QuickLZ 1.5.1b6 | 2.237 | 370 | 415 |
| LZO 2.06 | 2.106 | 400 | 580 |
| [LZ4] r131 | 2.101 | 450 | 2100 |
| Snappy 1.1.0 | 2.091 | 330 | 1100 |
| LZF 3.6 | 2.077 | 200 | 560 |
[zlib 1.2.8]:http://www.zlib.net/
[zlib]:http://www.zlib.net/
[LZ4]:http://www.lz4.org/
Zstd can also offer stronger compression ratio at the cost of compression speed, but preserving its decompression speed. In the following test, a few compressors suitable for this scenario are selected (they offer very asymetric performance, useful when compression time has little importance). The test was completed on a Core i7-5600U @ 2.6 GHz, using [benchmark 0.6.1](http://encode.ru/threads/1266-In-memory-benchmark-with-fastest-LZSS-(QuickLZ-Snappy)-compressors?p=45217&viewfull=1#post45217), an open-source benchmark program by inikep.
Zstd can also offer stronger compression ratio at the cost of compression speed. Speed / Ratio trade-off is configurable by small increment, to fit different situations. Note however that decompression speed is preserved and remain roughly the same at all settings, a property shared by most LZ compression algorithms, such as [zlib]. The following test is run on a Core i7-3930K CPU @ 4.5GHz, using [lzbench], an open-source in-memory benchmark by inikep compiled with gcc 5.2.1, on the [Silesia compression corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia).
|Name | Ratio | C.speed | D.speed |
|-----------------|-------|--------:|--------:|
| | | MB/s | MB/s |
| brotli -9 | 3.729 | 4 | 340 |
| **zstd 0.3 -9** |**3.447**|**30** | **640** |
| [zlib 1.2.8] -9 | 3.133 | 10 | 300 |
| LZO 2.06 -999 | 2.790 | 1 | 560 |
| [LZ4] r131 -9 | 2.720 | 25 | 2100 |
[lzbench]:https://github.com/inikep/lzbench
[lzma]:http://www.7-zip.org/
Compression Speed vs Ratio | Decompression Speed
---------------------------|--------------------
![Compression Speed vs Ratio](images/CSpeed.png "Compression Speed vs Ratio") | ![Decompression Speed](images/DSpeed.png "Decompression Speed")
Zstd compression speed is highly configurable, by small increment, to fit different situations. Its memory requirement can also be configured to fit into low-memory hardware configurations, or servers handling multiple connections/contexts in parallel.
Zstd entropy stage is provided by [Huff0 and FSE, from Finite State Entrop library](https://github.com/Cyan4973/FiniteStateEntropy).
Zstd entropy stage is provided by [Huff0 and FSE, from Finite State Entropy library](https://github.com/Cyan4973/FiniteStateEntropy).
Zstd has not yet reached "stable" status. Specifically, it doesn't guarantee yet that its current compressed format will remain stable and supported in future versions. It may still change to adapt further optimizations still being investigated. That being said, the library is now pretty robust, able to withstand hazards situations, including invalid input. The library reliability has been tested using [Fuzz Testing](https://en.wikipedia.org/wiki/Fuzz_testing), with both [internal tools](programs/fuzzer.c) and [external ones](http://lcamtuf.coredump.cx/afl). Therefore, it's now safe to test Zstandard even within production environments.
Its memory requirement can be configured to fit into low-memory hardware configurations, or servers handling multiple connections/contexts in parallel.
"Stable Format" is projected sometimes early 2016.
Zstd has not yet reached "stable format" status. It doesn't guarantee yet that its current compressed format will remain stable and supported in future versions. During this period, it can still change to adapt new optimizations still being investigated. "Stable Format" is projected sometimes early 2016.
That being said, the library is now fairly robust, able to withstand hazards situations, including invalid inputs. The library reliability has been tested using [Fuzz Testing](https://en.wikipedia.org/wiki/Fuzz_testing), with both [internal tools](programs/fuzzer.c) and [external ones](http://lcamtuf.coredump.cx/afl). Therefore, it seems now safe to test Zstandard even within production environments.
### Branch Policy
The "dev" branch is the one where all contributions will be merged before reaching "master". If you plan to propose a patch, please commit into the "dev" branch or its own feature branch. Direct commit to "master" are not permitted.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

+21 -11
View File
@@ -362,7 +362,7 @@ size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U3
U16 min = 0;
for (n=maxNbBits; n>0; n--)
{
valPerRank[n] = min; // get starting value within each rank
valPerRank[n] = min; /* get starting value within each rank */
min += nbPerRank[n];
min >>= 1;
}
@@ -1027,18 +1027,23 @@ size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize)
U32 nextRankVal = 0;
U32 w, consumed;
const int rescale = (memLog-tableLog) - 1; /* tableLog <= memLog */
U32* rankVal0 = rankVal[0];
for (w=1; w<=maxW; w++)
{
U32 current = nextRankVal;
nextRankVal += rankStats[w] << (w+rescale);
rankVal[0][w] = current;
rankVal0[w] = current;
}
for (consumed = minBits; consumed <= memLog - minBits; consumed++)
{
U32* rankValPtr = rankVal[consumed];
for (w = 1; w <= maxW; w++)
{
rankValPtr[w] = rankVal0[w] >> consumed;
}
}
for (consumed=minBits; consumed <= memLog-minBits; consumed++)
for (w=1; w<=maxW; w++)
rankVal[consumed][w] = rankVal[0][w] >> consumed;
}
HUF_fillDTableX4(dt, memLog,
sortedSymbol, sizeOfSort,
rankStart0, rankVal, maxW,
@@ -1394,18 +1399,23 @@ size_t HUF_readDTableX6 (U32* DTable, const void* src, size_t srcSize)
U32 nextRankVal = 0;
U32 w, consumed;
const int rescale = (memLog-tableLog) - 1; /* tableLog <= memLog */
U32* rankVal0 = rankVal[0];
for (w=1; w<=maxW; w++)
{
U32 current = nextRankVal;
nextRankVal += rankStats[w] << (w+rescale);
rankVal[0][w] = current;
rankVal0[w] = current;
}
for (consumed = minBits; consumed <= memLog - minBits; consumed++)
{
U32* rankValPtr = rankVal[consumed];
for (w = 1; w <= maxW; w++)
{
rankValPtr[w] = rankVal0[w] >> consumed;
}
}
for (consumed=minBits; consumed <= memLog-minBits; consumed++)
for (w=1; w<=maxW; w++)
rankVal[consumed][w] = rankVal[0][w] >> consumed;
}
/* fill tables */
{
HUF_DDescX6* DDescription = (HUF_DDescX6*)(DTable+1);
+6 -7
View File
@@ -120,14 +120,11 @@
#define GB *(1U<<30)
#define BLOCKSIZE (128 KB) /* define, for static allocation */
#define MIN_SEQUENCES_SIZE (2 /*seqNb*/ + 2 /*dumps*/ + 3 /*seqTables*/ + 1 /*bitStream*/)
#define MIN_CBLOCK_SIZE (3 /*litCSize*/ + MIN_SEQUENCES_SIZE)
#define IS_RAW BIT0
#define IS_RLE BIT1
static const U32 g_maxDistance = 4 * BLOCKSIZE;
static const U32 g_maxLimit = 1 GB;
static const U32 g_searchStrength = 8;
#define WORKPLACESIZE (BLOCKSIZE*3)
#define MINMATCH 4
@@ -526,8 +523,6 @@ static U32 ZSTD_hashPtr(const void* p) { return ( (MEM_read64(p) * prime7bytes
//static U32 ZSTD_hashPtr(const void* p) { return ( (*(U32*)p * KNUTH) >> (32-HASH_LOG)); }
static void ZSTD_addPtr(U32* table, const BYTE* p, const BYTE* start) { table[ZSTD_hashPtr(p)] = (U32)(p-start); }
static const BYTE* ZSTD_updateMatch(U32* table, const BYTE* p, const BYTE* start)
{
U32 h = ZSTD_hashPtr(p);
@@ -542,6 +537,8 @@ static int ZSTD_checkMatch(const BYTE* match, const BYTE* ip)
return MEM_read32(match) == MEM_read32(ip);
}
static void ZSTD_addPtr(U32* table, const BYTE* p, const BYTE* start) { table[ZSTD_hashPtr(p)] = (U32)(p-start); }
static size_t ZSTD_compressBlock(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
{
@@ -570,7 +567,7 @@ static size_t ZSTD_compressBlock(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, c
ZSTD_resetSeqStore(seqStorePtr);
/* Main Search Loop */
while (ip <= ilimit)
while (ip < ilimit) /* < instead of <=, because unconditionnal ZSTD_addPtr(ip+1) */
{
const BYTE* match = ZSTD_updateMatch(HashTable, ip, base);
@@ -591,7 +588,8 @@ static size_t ZSTD_compressBlock(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, c
ZSTD_addPtr(HashTable, ip+1, base);
ip += matchLength + MINMATCH;
anchor = ip;
if (ip <= ilimit) ZSTD_addPtr(HashTable, ip-2, base);
if (ip < ilimit) /* same test as loop, for speed */
ZSTD_addPtr(HashTable, ip-2, base);
}
}
@@ -920,6 +918,7 @@ size_t ZSTD_decodeLiteralsBlock(void* ctx,
{
if (litSize > srcSize-3) return ERROR(corruption_detected);
memcpy(dctx->litBuffer, istart, litSize);
dctx->litPtr = dctx->litBuffer;
dctx->litBufSize = BLOCKSIZE+8;
dctx->litSize = litSize;
return litSize+3;
+1 -1
View File
@@ -48,7 +48,7 @@ extern "C" {
***************************************/
#define ZSTD_VERSION_MAJOR 0 /* for breaking interface changes */
#define ZSTD_VERSION_MINOR 3 /* for new (non-breaking) interface capabilities */
#define ZSTD_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */
#define ZSTD_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */
#define ZSTD_VERSION_NUMBER (ZSTD_VERSION_MAJOR *100*100 + ZSTD_VERSION_MINOR *100 + ZSTD_VERSION_RELEASE)
unsigned ZSTD_versionNumber (void);
+11 -2
View File
@@ -49,6 +49,8 @@ extern "C" {
****************************************/
static size_t ZSTD_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; }
#define MIN(a,b) ((a)<(b) ? (a) : (b))
static unsigned ZSTD_highbit(U32 val)
{
# if defined(_MSC_VER) /* Visual */
@@ -152,7 +154,7 @@ MEM_STATIC size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pI
return (size_t)(pIn - pStart);
}
if (MEM_32bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
return (size_t)(pIn - pStart);
@@ -169,7 +171,9 @@ static void ZSTD_wildcopy(void* dst, const void* src, size_t length)
const BYTE* ip = (const BYTE*)src;
BYTE* op = (BYTE*)dst;
BYTE* const oend = op + length;
do COPY8(op, ip) while (op < oend);
do
COPY8(op, ip)
while (op < oend);
}
@@ -202,6 +206,8 @@ typedef struct {
void ZSTD_resetSeqStore(seqStore_t* ssPtr);
static const U32 g_searchStrength = 8;
#define REPCODE_STARTVALUE 4
#define MLbits 7
#define LLbits 6
@@ -210,6 +216,9 @@ void ZSTD_resetSeqStore(seqStore_t* ssPtr);
#define MaxLL ((1<<LLbits) - 1)
#define MaxOff 31
#define MIN_SEQUENCES_SIZE (2 /*seqNb*/ + 2 /*dumps*/ + 3 /*seqTables*/ + 1 /*bitStream*/)
#define MIN_CBLOCK_SIZE (3 /*litCSize*/ + MIN_SEQUENCES_SIZE)
/** ZSTD_storeSeq
Store a sequence (literal length, literals, offset code and match length) into seqStore_t
@offsetCode : distance to match, or 0 == repCode
+583 -86
View File
@@ -91,7 +91,7 @@ struct ZSTD_HC_CCtx_s
seqStore_t seqStore; /* sequences storage ptrs */
U32* hashTable;
U32* chainTable;
U32* contentTable;
};
@@ -107,24 +107,46 @@ size_t ZSTD_HC_freeCCtx(ZSTD_HC_CCtx* cctx)
return 0;
}
/** ZSTD_HC_validateParams
correct params value to remain within authorized range
optimize for srcSize if srcSize > 0 */
void ZSTD_HC_validateParams(ZSTD_HC_parameters* params, size_t srcSize)
{
const U32 btPlus = (params->strategy == ZSTD_HC_btlazy2);
/* validate params */
if (params->windowLog > ZSTD_HC_WINDOWLOG_MAX) params->windowLog = ZSTD_HC_WINDOWLOG_MAX;
if (params->windowLog < ZSTD_HC_WINDOWLOG_MIN) params->windowLog = ZSTD_HC_WINDOWLOG_MIN;
/* correct params, to use less memory */
if (srcSize > 0)
{
U32 srcLog = ZSTD_highbit((U32)srcSize-1) + 1;
if (params->windowLog > srcLog) params->windowLog = srcLog;
}
if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_HC_CONTENTLOG_MAX */
if (params->contentLog < ZSTD_HC_CONTENTLOG_MIN) params->contentLog = ZSTD_HC_CONTENTLOG_MIN;
if (params->hashLog > ZSTD_HC_HASHLOG_MAX) params->hashLog = ZSTD_HC_HASHLOG_MAX;
if (params->hashLog < ZSTD_HC_HASHLOG_MIN) params->hashLog = ZSTD_HC_HASHLOG_MIN;
if (params->searchLog > ZSTD_HC_SEARCHLOG_MAX) params->searchLog = ZSTD_HC_SEARCHLOG_MAX;
if (params->searchLog < ZSTD_HC_SEARCHLOG_MIN) params->searchLog = ZSTD_HC_SEARCHLOG_MIN;
if (params->searchLength> ZSTD_HC_SEARCHLENGTH_MAX) params->searchLength = ZSTD_HC_SEARCHLENGTH_MAX;
if (params->searchLength< ZSTD_HC_SEARCHLENGTH_MIN) params->searchLength = ZSTD_HC_SEARCHLENGTH_MIN;
if ((U32)params->strategy>(U32)ZSTD_HC_btlazy2) params->strategy = ZSTD_HC_btlazy2;
}
static size_t ZSTD_HC_resetCCtx_advanced (ZSTD_HC_CCtx* zc,
ZSTD_HC_parameters params)
{
/* validate params */
if (params.windowLog > ZSTD_HC_WINDOWLOG_MAX) params.windowLog = ZSTD_HC_WINDOWLOG_MAX;
if (params.windowLog < ZSTD_HC_WINDOWLOG_MIN) params.windowLog = ZSTD_HC_WINDOWLOG_MIN;
if (params.chainLog > params.windowLog) params.chainLog = params.windowLog; /* <= ZSTD_HC_CHAINLOG_MAX */
if (params.chainLog < ZSTD_HC_CHAINLOG_MIN) params.chainLog = ZSTD_HC_CHAINLOG_MIN;
if (params.hashLog > ZSTD_HC_HASHLOG_MAX) params.hashLog = ZSTD_HC_HASHLOG_MAX;
if (params.hashLog < ZSTD_HC_HASHLOG_MIN) params.hashLog = ZSTD_HC_HASHLOG_MIN;
if (params.searchLog > ZSTD_HC_SEARCHLOG_MAX) params.searchLog = ZSTD_HC_SEARCHLOG_MAX;
if (params.searchLog < ZSTD_HC_SEARCHLOG_MIN) params.searchLog = ZSTD_HC_SEARCHLOG_MIN;
if (params.searchLength> ZSTD_HC_SEARCHLENGTH_MAX) params.searchLength = ZSTD_HC_SEARCHLENGTH_MAX;
if (params.searchLength< ZSTD_HC_SEARCHLENGTH_MIN) params.searchLength = ZSTD_HC_SEARCHLENGTH_MIN;
ZSTD_HC_validateParams(&params, 0);
/* reserve table memory */
{
const size_t tableSpace = ((1 << params.chainLog) + (1 << params.hashLog)) * sizeof(U32);
const U32 contentLog = params.strategy == ZSTD_HC_fast ? 1 : params.contentLog;
const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog)) * sizeof(U32);
const size_t neededSpace = tableSpace + WORKPLACESIZE;
if (zc->workSpaceSize < neededSpace)
{
@@ -133,13 +155,13 @@ static size_t ZSTD_HC_resetCCtx_advanced (ZSTD_HC_CCtx* zc,
zc->workSpace = malloc(neededSpace);
if (zc->workSpace == NULL) return ERROR(memory_allocation);
}
zc->hashTable = (U32*)zc->workSpace;
zc->chainTable = zc->hashTable + ((size_t)1 << params.hashLog);
zc->seqStore.buffer = (void*) (zc->chainTable + ((size_t)1 << params.chainLog));
memset(zc->hashTable, 0, tableSpace );
memset(zc->workSpace, 0, tableSpace );
zc->hashTable = (U32*)(zc->workSpace);
zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog);
zc->seqStore.buffer = (void*) (zc->contentTable + ((size_t)1 << contentLog));
}
zc->nextToUpdate = 0;
zc->nextToUpdate = 1;
zc->end = NULL;
zc->base = NULL;
zc->dictBase = NULL;
@@ -173,30 +195,326 @@ static const U64 prime6bytes = 227718039650203ULL;
static size_t ZSTD_HC_hash6(U64 u, U32 h) { return (size_t)((u * prime6bytes) << (64-48) >> (64-h)) ; }
static size_t ZSTD_HC_hash6Ptr(const void* p, U32 h) { return ZSTD_HC_hash6(MEM_read64(p), h); }
static size_t ZSTD_HC_hashPtr(const void* p, U32 h, U32 mls)
static const U64 prime7bytes = 58295818150454627ULL;
static size_t ZSTD_HC_hash7(U64 u, U32 h) { return (size_t)((u * prime7bytes) << (64-56) >> (64-h)) ; }
static size_t ZSTD_HC_hash7Ptr(const void* p, U32 h) { return ZSTD_HC_hash7(MEM_read64(p), h); }
static size_t ZSTD_HC_hashPtr(const void* p, U32 hBits, U32 mls)
{
switch(mls)
{
default:
case 4: return ZSTD_HC_hash4Ptr(p,h);
case 5: return ZSTD_HC_hash5Ptr(p,h);
case 6: return ZSTD_HC_hash6Ptr(p,h);
case 4: return ZSTD_HC_hash4Ptr(p, hBits);
case 5: return ZSTD_HC_hash5Ptr(p, hBits);
case 6: return ZSTD_HC_hash6Ptr(p, hBits);
case 7: return ZSTD_HC_hash7Ptr(p, hBits);
}
}
#define NEXT_IN_CHAIN(d) chainTable[(d) & chainMask] /* flexible, CHAINSIZE dependent */
/* *************************************
* Fast Scan
***************************************/
FORCE_INLINE
size_t ZSTD_HC_compressBlock_fast_generic(ZSTD_HC_CCtx* ctx,
void* dst, size_t maxDstSize,
const void* src, size_t srcSize,
const U32 mls)
{
U32* hashTable = ctx->hashTable;
const U32 hBits = ctx->params.hashLog;
seqStore_t* seqStorePtr = &(ctx->seqStore);
const BYTE* const base = ctx->base;
const size_t maxDist = ((size_t)1 << ctx->params.windowLog);
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
const BYTE* const lowest = (size_t)(istart-base) > maxDist ? istart-maxDist : base;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
size_t offset_2=4, offset_1=4;
/* init */
if (ip == base)
{
hashTable[ZSTD_HC_hashPtr(base+1, hBits, mls)] = 1;
hashTable[ZSTD_HC_hashPtr(base+2, hBits, mls)] = 2;
hashTable[ZSTD_HC_hashPtr(base+3, hBits, mls)] = 3;
ip = base+4;
}
ZSTD_resetSeqStore(seqStorePtr);
/* Main Search Loop */
while (ip < ilimit) /* < instead of <=, because unconditionnal ZSTD_addPtr(ip+1) */
{
const size_t h = ZSTD_HC_hashPtr(ip, hBits, mls);
const BYTE* match = base + hashTable[h];
hashTable[h] = (U32)(ip-base);
if (MEM_read32(ip-offset_2) == MEM_read32(ip)) match = ip-offset_2;
if ( (match < lowest) ||
(MEM_read32(match) != MEM_read32(ip)) )
{ ip += ((ip-anchor) >> g_searchStrength) + 1; offset_2 = offset_1; continue; }
while ((ip>anchor) && (match>base) && (ip[-1] == match[-1])) { ip--; match--; } /* catch up */
{
size_t litLength = ip-anchor;
size_t matchLength = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
size_t offsetCode = ip-match;
if (offsetCode == offset_2) offsetCode = 0;
offset_2 = offset_1;
offset_1 = ip-match;
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offsetCode, matchLength);
/* Fill Table */
hashTable[ZSTD_HC_hashPtr(ip+1, hBits, mls)] = (U32)(ip+1-base);
ip += matchLength + MINMATCH;
anchor = ip;
if (ip < ilimit) /* same test as loop, for speed */
hashTable[ZSTD_HC_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
}
}
/* Last Literals */
{
size_t lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
/* Finale compression stage */
return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
seqStorePtr, srcSize);
}
size_t ZSTD_HC_compressBlock_fast(ZSTD_HC_CCtx* ctx,
void* dst, size_t maxDstSize,
const void* src, size_t srcSize)
{
const U32 mls = ctx->params.searchLength;
switch(mls)
{
default:
case 4 :
return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 4);
case 5 :
return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 5);
case 6 :
return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 6);
case 7 :
return ZSTD_HC_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 7);
}
}
/* *************************************
* HC Compression
* Binary Tree search
***************************************/
/** ZSTD_HC_insertBt1 : add one ptr to tree
@ip : assumed <= iend-8 */
static U32 ZSTD_HC_insertBt1(ZSTD_HC_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares)
{
U32* const hashTable = zc->hashTable;
const U32 hashLog = zc->params.hashLog;
const size_t h = ZSTD_HC_hashPtr(ip, hashLog, mls);
U32* const bt = zc->contentTable;
const U32 btLog = zc->params.contentLog - 1;
const U32 btMask= (1 << btLog) - 1;
U32 matchIndex = hashTable[h];
size_t commonLengthSmaller=0, commonLengthLarger=0;
const BYTE* const base = zc->base;
const BYTE* match = base + matchIndex;
U32 current = (U32)(ip-base);
const U32 btLow = btMask >= current ? 0 : current - btMask;
U32* smallerPtr = bt + 2*(current&btMask);
U32* largerPtr = bt + 2*(current&btMask) + 1;
U32 dummy32; /* to be nullified at the end */
const U32 windowSize = 1 << zc->params.windowLog;
const U32 windowLow = windowSize >= current ? 0 : current - windowSize;
if ((current-matchIndex == 1) /* RLE */
&& MEM_read64(match) == MEM_read64(ip))
{
size_t rleLength = ZSTD_count(ip+sizeof(size_t), match+sizeof(size_t), iend) + sizeof(size_t);
return (U32)(rleLength - mls);
}
hashTable[h] = (U32)(ip - base); /* Update Hash Table */
while (nbCompares-- && (matchIndex > windowLow))
{
U32* nextPtr = bt + 2*(matchIndex & btMask);
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
match = base + matchIndex;
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
break; /* just drop , to guarantee consistency (miss a bit of compression; if someone knows better, please tell) */
if (match[matchLength] < ip[matchLength])
{
/* match is smaller than current */
*smallerPtr = matchIndex; /* update smaller idx */
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
}
else
{
/* match is larger than current */
*largerPtr = matchIndex;
commonLengthLarger = matchLength;
if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
largerPtr = nextPtr;
matchIndex = nextPtr[0];
}
}
*smallerPtr = *largerPtr = 0;
return 1;
}
FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
size_t ZSTD_HC_insertBtAndFindBestMatch (
ZSTD_HC_CCtx* zc,
const BYTE* const ip, const BYTE* const iend,
size_t* offsetPtr,
U32 nbCompares, const U32 mls)
{
U32* const hashTable = zc->hashTable;
const U32 hashLog = zc->params.hashLog;
const size_t h = ZSTD_HC_hashPtr(ip, hashLog, mls);
U32* const bt = zc->contentTable;
const U32 btLog = zc->params.contentLog - 1;
const U32 btMask= (1 << btLog) - 1;
U32 matchIndex = hashTable[h];
size_t commonLengthSmaller=0, commonLengthLarger=0;
const BYTE* const base = zc->base;
const U32 current = (U32)(ip-base);
const U32 btLow = btMask >= current ? 0 : current - btMask;
const U32 windowSize = 1 << zc->params.windowLog;
const U32 windowLow = windowSize >= current ? 0 : current - windowSize;
U32* smallerPtr = bt + 2*(current&btMask);
U32* largerPtr = bt + 2*(current&btMask) + 1;
size_t bestLength = 0;
U32 dummy32; /* to be nullified at the end */
hashTable[h] = (U32)(ip-base); /* Update Hash Table */
while (nbCompares-- && (matchIndex > windowLow))
{
U32* nextPtr = bt + 2*(matchIndex & btMask);
const BYTE* match = base + matchIndex;
size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
if (matchLength > bestLength)
{
if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
bestLength = matchLength, *offsetPtr = current - matchIndex;
if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
break; /* just drop, to guarantee consistency (miss a little bit of compression) */
}
if (match[matchLength] < ip[matchLength])
{
/* match is smaller than current */
*smallerPtr = matchIndex; /* update smaller idx */
commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
if (matchIndex <= btLow) smallerPtr=&dummy32; /* beyond tree size, stop the search */
matchIndex = (matchIndex <= btLow) ? windowLow : nextPtr[1];
}
else
{
/* match is larger than current */
*largerPtr = matchIndex;
commonLengthLarger = matchLength;
largerPtr = nextPtr;
if (matchIndex <= btLow) largerPtr=&dummy32; /* beyond tree size, stop the search */
matchIndex = (matchIndex <= btLow) ? windowLow : nextPtr[0];
}
}
*smallerPtr = *largerPtr = 0;
zc->nextToUpdate = current+1; /* current has been inserted */
return bestLength;
}
static const BYTE* ZSTD_HC_updateTree(ZSTD_HC_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
{
const BYTE* const base = zc->base;
const U32 target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
//size_t dummy;
for( ; idx < target ; )
idx += ZSTD_HC_insertBt1(zc, base+idx, mls, iend, nbCompares);
//ZSTD_HC_insertBtAndFindBestMatch(zc, base+idx, iend, &dummy, nbCompares, mls);
zc->nextToUpdate = idx;
return base + idx;
}
/** Tree updater, providing best match */
FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
size_t ZSTD_HC_BtFindBestMatch (
ZSTD_HC_CCtx* zc,
const BYTE* const ip, const BYTE* const iLimit,
size_t* offsetPtr,
const U32 maxNbAttempts, const U32 mls)
{
const BYTE* nextToUpdate = ZSTD_HC_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
if (nextToUpdate > ip)
{
/* RLE data */
*offsetPtr = 1;
return ZSTD_count(ip, ip-1, iLimit);
}
return ZSTD_HC_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls);
}
FORCE_INLINE size_t ZSTD_HC_BtFindBestMatch_selectMLS (
ZSTD_HC_CCtx* zc, /* Index table will be updated */
const BYTE* ip, const BYTE* const iLimit,
size_t* offsetPtr,
const U32 maxNbAttempts, const U32 matchLengthSearch)
{
switch(matchLengthSearch)
{
default :
case 4 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
case 5 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
case 6 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
}
}
/* ***********************
* Hash Chain
*************************/
#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
/* Update chains up to ip (excluded) */
static void ZSTD_HC_insert (ZSTD_HC_CCtx* zc, const BYTE* ip, U32 mls)
static U32 ZSTD_HC_insertAndFindFirstIndex (ZSTD_HC_CCtx* zc, const BYTE* ip, U32 mls)
{
U32* const hashTable = zc->hashTable;
const U32 hashLog = zc->params.hashLog;
U32* const chainTable = zc->chainTable;
const U32 chainMask = (1 << zc->params.chainLog) - 1;
U32* const chainTable = zc->contentTable;
const U32 chainMask = (1 << zc->params.contentLog) - 1;
const BYTE* const base = zc->base;
const U32 target = (U32)(ip - base);
U32 idx = zc->nextToUpdate;
@@ -204,26 +522,25 @@ static void ZSTD_HC_insert (ZSTD_HC_CCtx* zc, const BYTE* ip, U32 mls)
while(idx < target)
{
size_t h = ZSTD_HC_hashPtr(base+idx, hashLog, mls);
NEXT_IN_CHAIN(idx) = hashTable[h];
NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
hashTable[h] = idx;
idx++;
}
zc->nextToUpdate = target;
return hashTable[ZSTD_HC_hashPtr(ip, hashLog, mls)];
}
FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
size_t ZSTD_HC_insertAndFindBestMatch (
size_t ZSTD_HC_HcFindBestMatch (
ZSTD_HC_CCtx* zc, /* Index table will be updated */
const BYTE* ip, const BYTE* const iLimit,
const BYTE** matchpos,
const BYTE* const ip, const BYTE* const iLimit,
size_t* offsetPtr,
const U32 maxNbAttempts, const U32 matchLengthSearch)
{
U32* const hashTable = zc->hashTable;
const U32 hashLog = zc->params.hashLog;
U32* const chainTable = zc->chainTable;
const U32 chainSize = (1 << zc->params.chainLog);
U32* const chainTable = zc->contentTable;
const U32 chainSize = (1 << zc->params.contentLog);
const U32 chainMask = chainSize-1;
const BYTE* const base = zc->base;
const BYTE* const dictBase = zc->dictBase;
@@ -236,26 +553,29 @@ size_t ZSTD_HC_insertAndFindBestMatch (
size_t ml=0;
/* HC4 match finder */
ZSTD_HC_insert(zc, ip, matchLengthSearch);
matchIndex = hashTable[ZSTD_HC_hashPtr(ip, hashLog, matchLengthSearch)];
matchIndex = ZSTD_HC_insertAndFindFirstIndex (zc, ip, matchLengthSearch);
while ((matchIndex>=lowLimit) && (nbAttempts))
while ((matchIndex>lowLimit) && (nbAttempts))
{
nbAttempts--;
if (matchIndex >= dictLimit)
{
match = base + matchIndex;
if (*(match+ml) == *(ip+ml)
&& (MEM_read32(match) == MEM_read32(ip)))
if (match[ml] == ip[ml]) /* potentially better */
{
const size_t mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
if (mlt > ml) { ml = mlt; *matchpos = match; if (ip+ml >= iLimit) break; }
const size_t mlt = ZSTD_count(ip, match, iLimit);
if (mlt > ml)
//if (((int)(4*mlt) - (int)ZSTD_highbit((U32)(ip-match)+1)) > ((int)(4*ml) - (int)ZSTD_highbit((U32)((*offsetPtr)+1))))
{
ml = mlt; *offsetPtr = ip-match;
if (ip+mlt >= iLimit) break;
}
}
}
else
{
match = dictBase + matchIndex;
if (MEM_read32(match) == MEM_read32(ip))
if (MEM_read32(match) == MEM_read32(ip)) /* beware of end of dict */
{
size_t mlt;
const BYTE* vLimit = ip + (dictLimit - matchIndex);
@@ -263,35 +583,189 @@ size_t ZSTD_HC_insertAndFindBestMatch (
mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
if ((ip+mlt == vLimit) && (vLimit < iLimit))
mlt += ZSTD_count(ip+mlt, base+dictLimit, iLimit);
if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */
if (mlt > ml) { ml = mlt; *offsetPtr = (ip-base) - matchIndex; }
}
}
if (base + matchIndex <= ip - chainSize) break;
matchIndex = NEXT_IN_CHAIN(matchIndex);
matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
}
return ml;
}
static size_t ZSTD_HC_insertAndFindBestMatch_selectMLS (
FORCE_INLINE size_t ZSTD_HC_HcFindBestMatch_selectMLS (
ZSTD_HC_CCtx* zc, /* Index table will be updated */
const BYTE* ip, const BYTE* const iLimit,
const BYTE** matchpos,
size_t* offsetPtr,
const U32 maxNbAttempts, const U32 matchLengthSearch)
{
switch(matchLengthSearch)
{
default :
case 4 : return ZSTD_HC_insertAndFindBestMatch(zc, ip, iLimit, matchpos, maxNbAttempts, 4);
case 5 : return ZSTD_HC_insertAndFindBestMatch(zc, ip, iLimit, matchpos, maxNbAttempts, 5);
case 6 : return ZSTD_HC_insertAndFindBestMatch(zc, ip, iLimit, matchpos, maxNbAttempts, 6);
case 4 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
case 5 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
case 6 : return ZSTD_HC_HcFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
}
}
static size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
/* common lazy function, to be inlined */
FORCE_INLINE
size_t ZSTD_HC_compressBlock_lazy_generic(ZSTD_HC_CCtx* ctx,
void* dst, size_t maxDstSize, const void* src, size_t srcSize,
const U32 searchMethod, const U32 deep) /* 0 : hc; 1 : bt */
{
seqStore_t* seqStorePtr = &(ctx->seqStore);
const BYTE* const istart = (const BYTE*)src;
const BYTE* ip = istart;
const BYTE* anchor = istart;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
const U32 maxSearches = 1 << ctx->params.searchLog;
const U32 mls = ctx->params.searchLength;
typedef size_t (*searchMax_f)(ZSTD_HC_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
size_t* offsetPtr,
U32 maxNbAttempts, U32 matchLengthSearch);
searchMax_f searchMax = searchMethod ? ZSTD_HC_BtFindBestMatch_selectMLS : ZSTD_HC_HcFindBestMatch_selectMLS;
/* init */
ZSTD_resetSeqStore(seqStorePtr);
if (((ip-ctx->base) - ctx->dictLimit) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
/* Match Loop */
while (ip <= ilimit)
{
size_t matchLength;
size_t offset=999999;
const BYTE* start;
/* try to find a first match */
if (MEM_read32(ip) == MEM_read32(ip - offset_2))
{
/* repcode : we take it*/
size_t offtmp = offset_2;
size_t litLength = ip - anchor;
matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
offset_2 = offset_1;
offset_1 = offtmp;
ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
ip += matchLength+MINMATCH;
anchor = ip;
continue;
}
offset_2 = offset_1;
matchLength = searchMax(ctx, ip, iend, &offset, maxSearches, mls);
if (matchLength < MINMATCH)
{
ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
continue;
}
/* let's try to find a better solution */
start = ip;
while (ip<ilimit)
{
ip ++;
if (MEM_read32(ip) == MEM_read32(ip - offset_1))
{
size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
int gain2 = (int)(ml2 * 3);
int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
if ((ml2 >= MINMATCH) && (gain2 > gain1))
matchLength = ml2, offset = 0, start = ip;
}
{
size_t offset2=999999;
size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
int gain2 = (int)(ml2*(3+deep) - ZSTD_highbit((U32)offset2+1)); /* raw approx */
int gain1 = (int)(matchLength*(3+deep) - ZSTD_highbit((U32)offset+1) + (3+deep));
if ((ml2 >= MINMATCH) && (gain2 > gain1))
{
matchLength = ml2, offset = offset2, start = ip;
continue; /* search a better one */
}
}
/* let's find an even better one */
if (deep && (ip<ilimit))
{
ip ++;
if (MEM_read32(ip) == MEM_read32(ip - offset_1))
{
size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
int gain2 = (int)(ml2 * 4);
int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
if ((ml2 >= MINMATCH) && (gain2 > gain1))
matchLength = ml2, offset = 0, start = ip;
}
{
size_t offset2=999999;
size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
if ((ml2 >= MINMATCH) && (gain2 > gain1))
{
matchLength = ml2, offset = offset2, start = ip;
continue;
}
}
}
break; /* nothing found : store previous solution */
}
/* catch up */
if (offset)
{
while ((start>anchor) && (start>ctx->base+offset) && (start[-1] == start[-1-offset]))
{ start--; matchLength++; }
}
/* store sequence */
{
size_t litLength = start - anchor;
if (offset) offset_1 = offset;
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
anchor = ip = start + matchLength;
}
}
/* Last Literals */
{
size_t lastLLSize = iend - anchor;
memcpy(seqStorePtr->lit, anchor, lastLLSize);
seqStorePtr->lit += lastLLSize;
}
/* Final compression stage */
return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
seqStorePtr, srcSize);
}
size_t ZSTD_HC_compressBlock_btlazy2(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
{
return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 1, 1);
}
size_t ZSTD_HC_compressBlock_lazy2(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
{
return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1);
}
size_t ZSTD_HC_compressBlock_lazy(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
{
return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0);
}
size_t ZSTD_HC_compressBlock_greedy(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
{
seqStore_t* seqStorePtr = &(ctx->seqStore);
const BYTE* const istart = (const BYTE*)src;
@@ -299,7 +773,6 @@ static size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstS
const BYTE* anchor = istart;
const BYTE* const iend = istart + srcSize;
const BYTE* const ilimit = iend - 8;
const BYTE* match = istart;
size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
const U32 maxSearches = 1 << ctx->params.searchLog;
@@ -342,12 +815,18 @@ static size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstS
/* search */
{
size_t matchLength = ZSTD_HC_insertAndFindBestMatch_selectMLS(ctx, ip, iend, &match, maxSearches, mls);
if (!matchLength) { ip++; continue; }
size_t offset=999999;
size_t matchLength = ZSTD_HC_HcFindBestMatch_selectMLS(ctx, ip, iend, &offset, maxSearches, mls);
if (matchLength < MINMATCH)
{
ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
continue;
}
while ((ip>anchor) && (ip-offset>ctx->base) && (ip[-1] == ip[-1-offset])) { ip--; matchLength++; } /* catch up */
/* store sequence */
{
size_t litLength = ip-anchor;
offset_1 = ip-match;
offset_1 = offset;
ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset_1, matchLength-MINMATCH);
ip += matchLength;
anchor = ip;
@@ -364,23 +843,59 @@ static size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstS
/* Final compression stage */
return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
seqStorePtr, srcSize);
}
typedef size_t (*ZSTD_HC_blockCompressor) (ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
static ZSTD_HC_blockCompressor ZSTD_HC_selectBlockCompressor(ZSTD_HC_strategy strat)
{
switch(strat)
{
default :
case ZSTD_HC_fast:
return ZSTD_HC_compressBlock_fast;
case ZSTD_HC_greedy:
return ZSTD_HC_compressBlock_greedy;
case ZSTD_HC_lazy:
return ZSTD_HC_compressBlock_lazy;
case ZSTD_HC_lazy2:
return ZSTD_HC_compressBlock_lazy2;
case ZSTD_HC_btlazy2:
return ZSTD_HC_compressBlock_btlazy2;
}
}
size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
{
ZSTD_HC_blockCompressor blockCompressor = ZSTD_HC_selectBlockCompressor(ctx->params.strategy);
return blockCompressor(ctx, dst, maxDstSize, src, srcSize);
}
static size_t ZSTD_HC_compress_generic (ZSTD_HC_CCtx* ctxPtr,
void* dst, size_t maxDstSize,
const void* src, size_t srcSize)
{
static const size_t blockSize = 128 KB;
size_t blockSize = BLOCKSIZE;
size_t remaining = srcSize;
const BYTE* ip = (const BYTE*)src;
BYTE* const ostart = (BYTE*)dst;
BYTE* op = ostart;
BYTE* const oend = op + maxDstSize;
const ZSTD_HC_blockCompressor blockCompressor = ZSTD_HC_selectBlockCompressor(ctxPtr->params.strategy);
while (remaining > blockSize)
while (remaining)
{
size_t cSize = ZSTD_HC_compressBlock(ctxPtr, op+3, oend-op, ip, blockSize);
size_t cSize;
if (maxDstSize < 3 + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
if (remaining < blockSize) blockSize = remaining;
cSize = blockCompressor(ctxPtr, op+3, maxDstSize-3, ip, blockSize);
if (ZSTD_isError(cSize)) return cSize;
if (cSize == 0)
{
@@ -396,30 +911,9 @@ static size_t ZSTD_HC_compress_generic (ZSTD_HC_CCtx* ctxPtr,
}
remaining -= blockSize;
maxDstSize -= cSize;
ip += blockSize;
op += cSize;
if (ZSTD_isError(cSize)) return cSize;
}
/* last block */
{
size_t cSize = ZSTD_HC_compressBlock(ctxPtr, op+3, oend-op, ip, remaining);
if (cSize == 0)
{
cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, remaining); /* block is not compressible */
}
else
{
op[0] = (BYTE)(cSize>>16);
op[1] = (BYTE)(cSize>>8);
op[2] = (BYTE)cSize;
op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
cSize += 3;
}
op += cSize;
if (ZSTD_isError(cSize)) return cSize;
}
return op-ostart;
@@ -436,7 +930,7 @@ size_t ZSTD_HC_compressContinue (ZSTD_HC_CCtx* ctxPtr,
if (ip != ctxPtr->end)
{
if (ctxPtr->end != NULL)
ZSTD_HC_resetCCtx_advanced(ctxPtr, ctxPtr->params); /* just reset, but no need to re-alloc */
ZSTD_HC_resetCCtx_advanced(ctxPtr, ctxPtr->params);
ctxPtr->base = ip;
}
@@ -492,9 +986,12 @@ size_t ZSTD_HC_compress_advanced (ZSTD_HC_CCtx* ctx,
size_t oSize;
/* correct params, to use less memory */
U32 srcLog = ZSTD_highbit((U32)srcSize-1) + 1;
if (params.windowLog > srcLog) params.windowLog = srcLog;
if (params.chainLog > srcLog) params.chainLog = srcLog;
{
U32 srcLog = ZSTD_highbit((U32)srcSize-1) + 1;
U32 contentBtPlus = (ctx->params.strategy == ZSTD_HC_btlazy2);
if (params.windowLog > srcLog) params.windowLog = srcLog;
if (params.contentLog > srcLog+contentBtPlus) params.contentLog = srcLog+contentBtPlus;
}
/* Header */
oSize = ZSTD_HC_compressBegin_advanced(ctx, dst, maxDstSize, params);
@@ -504,7 +1001,7 @@ size_t ZSTD_HC_compress_advanced (ZSTD_HC_CCtx* ctx,
/* body (compression) */
ctx->base = (const BYTE*)src;
op += ZSTD_HC_compress_generic (ctx, op, maxDstSize, src, srcSize);
oSize = ZSTD_HC_compress_generic (ctx, op, maxDstSize, src, srcSize);
if(ZSTD_isError(oSize)) return oSize;
op += oSize;
maxDstSize -= oSize;
+39 -35
View File
@@ -45,25 +45,29 @@ extern "C" {
/* *************************************
* Types
***************************************/
/** from faster to stronger */
typedef enum { ZSTD_HC_fast, ZSTD_HC_greedy, ZSTD_HC_lazy, ZSTD_HC_lazy2, ZSTD_HC_btlazy2 } ZSTD_HC_strategy;
typedef struct
{
U32 windowLog; /* largest match distance : impact decompression buffer size */
U32 chainLog; /* full search distance : larger == more compression, slower, more memory*/
U32 contentLog; /* full search segment : larger == more compression, slower, more memory (useless for fast) */
U32 hashLog; /* dispatch table : larger == more memory, faster*/
U32 searchLog; /* nb of searches : larger == more compression, slower*/
U32 searchLength; /* size of matches : larger == faster decompression */
ZSTD_HC_strategy strategy;
} ZSTD_HC_parameters;
/* parameters boundaries */
#define ZSTD_HC_WINDOWLOG_MAX 26
#define ZSTD_HC_WINDOWLOG_MIN 18
#define ZSTD_HC_CHAINLOG_MAX ZSTD_HC_WINDOWLOG_MAX
#define ZSTD_HC_CHAINLOG_MIN 4
#define ZSTD_HC_CONTENTLOG_MAX (ZSTD_HC_WINDOWLOG_MAX+1)
#define ZSTD_HC_CONTENTLOG_MIN 4
#define ZSTD_HC_HASHLOG_MAX 28
#define ZSTD_HC_HASHLOG_MIN 4
#define ZSTD_HC_SEARCHLOG_MAX (ZSTD_HC_CHAINLOG_MAX-1)
#define ZSTD_HC_SEARCHLOG_MAX (ZSTD_HC_CONTENTLOG_MAX-1)
#define ZSTD_HC_SEARCHLOG_MIN 1
#define ZSTD_HC_SEARCHLENGTH_MAX 6
#define ZSTD_HC_SEARCHLENGTH_MAX 7
#define ZSTD_HC_SEARCHLENGTH_MIN 4
@@ -71,12 +75,17 @@ typedef struct
* Advanced function
***************************************/
/** ZSTD_HC_compress_advanced
* Same as ZSTD_HC_compressCCtx(), but can fine-tune each compression parameter */
* Same as ZSTD_HC_compressCCtx(), with fine-tune control of each compression parameter */
size_t ZSTD_HC_compress_advanced (ZSTD_HC_CCtx* ctx,
void* dst, size_t maxDstSize,
const void* src, size_t srcSize,
ZSTD_HC_parameters params);
/** ZSTD_HC_validateParams
correct params value to remain within authorized range
optimize for srcSize if srcSize > 0 */
void ZSTD_HC_validateParams(ZSTD_HC_parameters* params, size_t srcSize);
/* *************************************
* Streaming functions
@@ -89,38 +98,33 @@ size_t ZSTD_HC_compressEnd(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize);
/* *************************************
* Pre-defined compression levels
***************************************/
#define ZSTD_HC_MAX_CLEVEL 26
#define ZSTD_HC_MAX_CLEVEL 20
static const ZSTD_HC_parameters ZSTD_HC_defaultParameters[ZSTD_HC_MAX_CLEVEL+1] = {
/* W, C, H, S */
{ 18, 12, 14, 1, 4 }, /* level 0 - never used */
{ 18, 12, 14, 1, 4 }, /* level 1 - in fact redirected towards zstd fast */
{ 18, 12, 15, 2, 4 }, /* level 2 */
{ 19, 14, 16, 3, 4 }, /* level 3 */
{ 20, 15, 17, 4, 5 }, /* level 4 */
{ 20, 17, 19, 4, 5 }, /* level 5 */
{ 20, 19, 19, 4, 5 }, /* level 6 */
{ 20, 19, 19, 5, 5 }, /* level 7 */
{ 20, 20, 20, 5, 5 }, /* level 8 */
{ 20, 20, 20, 6, 5 }, /* level 9 */
{ 21, 21, 20, 5, 5 }, /* level 10 */
{ 22, 21, 22, 6, 5 }, /* level 11 */
{ 23, 21, 22, 6, 5 }, /* level 12 */
{ 23, 21, 22, 7, 5 }, /* level 13 */
{ 22, 22, 23, 7, 5 }, /* level 14 */
{ 22, 22, 23, 7, 5 }, /* level 15 */
{ 22, 22, 23, 8, 5 }, /* level 16 */
{ 22, 22, 23, 8, 5 }, /* level 17 */
{ 22, 22, 23, 9, 5 }, /* level 18 */
{ 22, 22, 23, 9, 5 }, /* level 19 */
{ 23, 23, 23, 9, 5 }, /* level 20 */
{ 23, 23, 23, 9, 5 }, /* level 21 */
{ 23, 23, 23, 10, 5 }, /* level 22 */
{ 23, 23, 23, 10, 5 }, /* level 23 */
{ 23, 23, 23, 11, 5 }, /* level 24 */
{ 23, 23, 23, 12, 5 }, /* level 25 */
{ 23, 23, 23, 13, 5 }, /* level 26 */ /* ZSTD_HC_MAX_CLEVEL */
/* W, C, H, S, L, strat */
{ 18, 12, 12, 1, 4, ZSTD_HC_fast }, /* level 0 - never used */
{ 18, 14, 14, 1, 7, ZSTD_HC_fast }, /* level 1 - in fact redirected towards zstd fast */
{ 19, 15, 16, 1, 6, ZSTD_HC_fast }, /* level 2 */
{ 20, 18, 20, 1, 6, ZSTD_HC_fast }, /* level 3 */
{ 21, 19, 21, 1, 6, ZSTD_HC_fast }, /* level 4 */
{ 20, 13, 18, 5, 5, ZSTD_HC_greedy }, /* level 5 */
{ 20, 17, 19, 3, 5, ZSTD_HC_greedy }, /* level 6 */
{ 21, 17, 20, 3, 5, ZSTD_HC_lazy }, /* level 7 */
{ 21, 19, 20, 3, 5, ZSTD_HC_lazy }, /* level 8 */
{ 21, 20, 20, 3, 5, ZSTD_HC_lazy2 }, /* level 9 */
{ 21, 19, 20, 4, 5, ZSTD_HC_lazy2 }, /* level 10 */
{ 22, 20, 22, 4, 5, ZSTD_HC_lazy2 }, /* level 11 */
{ 22, 20, 22, 5, 5, ZSTD_HC_lazy2 }, /* level 12 */
{ 22, 21, 22, 5, 5, ZSTD_HC_lazy2 }, /* level 13 */
{ 22, 22, 23, 5, 5, ZSTD_HC_lazy2 }, /* level 14 */
{ 23, 23, 23, 5, 5, ZSTD_HC_lazy2 }, /* level 15 */
{ 23, 21, 22, 5, 5, ZSTD_HC_btlazy2 }, /* level 16 */
{ 23, 24, 23, 4, 5, ZSTD_HC_btlazy2 }, /* level 17 */
{ 25, 24, 23, 5, 5, ZSTD_HC_btlazy2 }, /* level 18 */
{ 25, 26, 23, 5, 5, ZSTD_HC_btlazy2 }, /* level 19 */
{ 26, 27, 24, 6, 5, ZSTD_HC_btlazy2 }, /* level 20 */
};
#if defined (__cplusplus)
}
#endif
+1 -1
View File
@@ -30,7 +30,7 @@
# fullbench32: Same as fullbench, but forced to compile in 32-bits mode
# ##########################################################################
VERSION?= 0.3.0
VERSION?= 0.3.5
DESTDIR?=
PREFIX ?= /usr/local
+4 -4
View File
@@ -83,7 +83,7 @@
#define MB *(1 <<20)
#define GB *(1U<<30)
#define MAX_MEM (2 GB - 64 MB)
static const size_t maxMemory = sizeof(size_t)==4 ? (2 GB - 64 MB) : (size_t)(1ULL << ((sizeof(size_t)*8)-31));
#define DEFAULT_CHUNKSIZE (4 MB)
static U32 g_compressibilityDefault = 50;
@@ -237,11 +237,11 @@ static size_t local_compress_fast (void* dst, size_t maxDstSize, const void* src
return ZSTD_compress(dst, maxDstSize, src, srcSize);
}
#define MIN(a,b) (a<b ? a : b)
#define MIN(a,b) ((a)<(b) ? (a) : (b))
static int BMK_benchMem(void* srcBuffer, size_t srcSize, const char* fileName, int cLevel)
{
const size_t blockSize = g_blockSize ? g_blockSize : srcSize;
const size_t blockSize = (g_blockSize ? g_blockSize : srcSize) + (!srcSize); /* avoid div by 0 */
const U32 nbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize);
blockParam_t* const blockTable = (blockParam_t*) malloc(nbBlocks * sizeof(blockParam_t));
const size_t maxCompressedSize = (size_t)nbBlocks * ZSTD_compressBound(blockSize);
@@ -401,7 +401,7 @@ static size_t BMK_findMaxMem(U64 requiredMem)
requiredMem = (((requiredMem >> 26) + 1) << 26);
requiredMem += 2 * step;
if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
if (requiredMem > maxMemory) requiredMem = maxMemory;
while (!testmem)
{
+9 -11
View File
@@ -297,7 +297,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit
{
size_t sampleSize, sampleStart;
size_t cSize, dSize, dSupSize;
U32 sampleSizeLog, buffNb;
U32 sampleSizeLog, buffNb, cLevelMod;
U64 crcOrig, crcDest;
int cLevel;
@@ -329,13 +329,11 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit
crcOrig = XXH64(srcBuffer + sampleStart, sampleSize, 0);
/* HC compression test */
cLevel = (FUZ_rand(&lseed) & 3) + 2;
#define MAX(a,b) ((a)>(b)?(a):(b))
cLevelMod = MAX(1, 38 - (int)(MAX(9, sampleSizeLog) * 2)); /* use high compression levels with small samples, for speed */
cLevel = (FUZ_rand(&lseed) % cLevelMod) +1;
cSize = ZSTD_HC_compressCCtx(hcctx, cBuffer, cBufferSize, srcBuffer + sampleStart, sampleSize, cLevel);
CHECK(ZSTD_isError(cSize), "ZSTD_compress failed");
/* compression test */
cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, srcBuffer + sampleStart, sampleSize);
CHECK(ZSTD_isError(cSize), "ZSTD_compress failed");
CHECK(ZSTD_isError(cSize), "ZSTD_HC_compressCCtx failed");
/* compression failure test : too small dest buffer */
if (cSize > 3)
@@ -346,16 +344,16 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit
static const U32 endMark = 0x4DC2B1A9;
U32 endCheck;
memcpy(dstBuffer+tooSmallSize, &endMark, 4);
errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, srcBuffer + sampleStart, sampleSize);
CHECK(!ZSTD_isError(errorCode), "ZSTD_compress should have failed ! (buffer too small)");
errorCode = ZSTD_HC_compressCCtx(hcctx, dstBuffer, tooSmallSize, srcBuffer + sampleStart, sampleSize, cLevel);
CHECK(!ZSTD_isError(errorCode), "ZSTD_HC_compressCCtx should have failed ! (buffer too small : %u < %u)", (U32)tooSmallSize, (U32)cSize);
memcpy(&endCheck, dstBuffer+tooSmallSize, 4);
CHECK(endCheck != endMark, "ZSTD_compress : dst buffer overflow");
CHECK(endCheck != endMark, "ZSTD_HC_compressCCtx : dst buffer overflow");
}
/* successfull decompression tests*/
dSupSize = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1;
dSize = ZSTD_decompress(dstBuffer, sampleSize + dSupSize, cBuffer, cSize);
CHECK(dSize != sampleSize, "ZSTD_decompress failed (%s)", ZSTD_getErrorName(dSize));
CHECK(dSize != sampleSize, "ZSTD_decompress failed (%s) (srcSize : %u ; cSize : %u)", ZSTD_getErrorName(dSize), (U32)sampleSize, (U32)cSize);
crcDest = XXH64(dstBuffer, sampleSize, 0);
CHECK(crcOrig != crcDest, "dstBuffer corrupted (pos %u / %u)", (U32)findDiff(srcBuffer+sampleStart, dstBuffer, sampleSize), (U32)sampleSize);
+101 -63
View File
@@ -122,7 +122,8 @@ static U32 g_rand = 1;
static U32 g_singleRun = 0;
static U32 g_target = 0;
static U32 g_noSeed = 0;
static ZSTD_HC_parameters g_params = { 0, 0, 0, 0, 0 };
static const ZSTD_HC_parameters* g_seedParams = ZSTD_HC_defaultParameters;
static ZSTD_HC_parameters g_params = { 0, 0, 0, 0, 0, ZSTD_HC_greedy };
void BMK_SetNbIterations(int nbLoops)
{
@@ -279,13 +280,16 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
void* const compressedBuffer = malloc(maxCompressedSize);
void* const resultBuffer = malloc(srcSize);
U32 Wlog = params.windowLog;
U32 Clog = params.chainLog;
U32 Clog = params.contentLog;
U32 Hlog = params.hashLog;
U32 Slog = params.searchLog;
U32 Slength = params.searchLength;
ZSTD_HC_strategy strat = params.strategy;
char name[30] = { 0 };
U64 crcOrig;
/* Memory allocation & restrictions */
snprintf(name, 30, "Sw%02uc%02uh%02us%02ul%1ut%1u", Wlog, Clog, Hlog, Slog, Slength, strat);
if (!compressedBuffer || !resultBuffer || !blockTable)
{
DISPLAY("\nError: not enough memory!\n");
@@ -344,7 +348,7 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
if (totalTime > g_maxParamTime) break;
/* Compression */
DISPLAY("%1u-W%02uC%02uH%02uS%02uL%02u : %9u ->\r", loopNb, Wlog, Clog, Hlog, Slog, Slength, (U32)srcSize);
DISPLAY("\r%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
memset(compressedBuffer, 0xE5, maxCompressedSize);
nbLoops = 0;
@@ -367,8 +371,9 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
cSize += blockTable[blockNb].cSize;
if ((double)milliTime < fastestC*nbLoops) fastestC = (double)milliTime / nbLoops;
ratio = (double)srcSize / (double)cSize;
DISPLAY("%1u-W%02uC%02uH%02uS%02uL%02u : %9u ->", loopNb, Wlog, Clog, Hlog, Slog, Slength, (U32)srcSize);
DISPLAY(" %9u (%4.3f),%7.1f MB/s\r", (U32)cSize, ratio, (double)srcSize / fastestC / 1000.);
DISPLAY("\r");
DISPLAY("%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
DISPLAY(" %9u (%4.3f),%7.1f MB/s", (U32)cSize, ratio, (double)srcSize / fastestC / 1000.);
resultPtr->cSize = cSize;
resultPtr->cSpeed = (U32)((double)srcSize / fastestC);
@@ -389,9 +394,10 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
milliTime = BMK_GetMilliSpan(milliTime);
if ((double)milliTime < fastestD*nbLoops) fastestD = (double)milliTime / nbLoops;
DISPLAY("%1u-W%02uC%02uH%02uS%02uL%02u : %9u -> ", loopNb, Wlog, Clog, Hlog, Slog, Slength, (U32)srcSize);
DISPLAY("\r");
DISPLAY("%1u-%s : %9u -> ", loopNb, name, (U32)srcSize);
DISPLAY("%9u (%4.3f),%7.1f MB/s, ", (U32)cSize, ratio, (double)srcSize / fastestC / 1000.);
DISPLAY("%7.1f MB/s\r", (double)srcSize / fastestD / 1000.);
DISPLAY("%7.1f MB/s", (double)srcSize / fastestD / 1000.);
resultPtr->dSpeed = (U32)((double)srcSize / fastestD);
/* CRC Checking */
@@ -416,18 +422,27 @@ static size_t BMK_benchParam(BMK_result_t* resultPtr,
}
/* End cleaning */
DISPLAY("\r");
free(compressedBuffer);
free(resultBuffer);
return 0;
}
const char* g_stratName[] = { "ZSTD_HC_fast ",
"ZSTD_HC_greedy ",
"ZSTD_HC_lazy ",
"ZSTD_HC_lazy2 ",
"ZSTD_HC_btlazy2" };
static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_HC_parameters params, size_t srcSize)
{
DISPLAY("\r%79s\r", "");
fprintf(f," {%3u,%3u,%3u,%3u,%3u }, ", params.windowLog, params.chainLog, params.hashLog, params.searchLog, params.searchLength);
fprintf(f," {%3u,%3u,%3u,%3u,%3u, %s }, ",
params.windowLog, params.contentLog, params.hashLog, params.searchLog, params.searchLength,
g_stratName[(U32)(params.strategy)]);
fprintf(f,
"/* level %2u */ /* R:%5.3f at %5.1f MB/s - %5.1f MB/s */ \n",
"/* level %2u */ /* R:%5.3f at %5.1f MB/s - %5.1f MB/s */\n",
cLevel, (double)srcSize / result.cSize, (double)result.cSpeed / 1000., (double)result.dSpeed / 1000.);
}
@@ -446,7 +461,7 @@ static void BMK_printWinners2(FILE* f, const winnerInfo_t* winners, size_t srcSi
fprintf(f, "\n /* Selected configurations : */ \n");
fprintf(f, "#define ZSTD_HC_MAX_CLEVEL %2u \n", ZSTD_HC_MAX_CLEVEL);
fprintf(f, "static const ZSTD_HC_parameters ZSTD_HC_defaultParameters[ZSTD_HC_MAX_CLEVEL+1] = {\n");
fprintf(f, " /* W, C, H, S, L */ \n");
fprintf(f, " /* W, C, H, S, L, strat */ \n");
for (cLevel=0; cLevel <= ZSTD_HC_MAX_CLEVEL; cLevel++)
BMK_printWinner(f, cLevel, winners[cLevel].result, winners[cLevel].params, srcSize);
@@ -472,7 +487,7 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_HC_parameters params,
BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params);
for (cLevel = 2; cLevel <= ZSTD_HC_MAX_CLEVEL; cLevel++)
for (cLevel = 1; cLevel <= ZSTD_HC_MAX_CLEVEL; cLevel++)
{
if (testResult.cSpeed < g_cSpeedTarget[cLevel])
continue; /* not fast enough for this level */
@@ -486,7 +501,7 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_HC_parameters params,
continue;
}
if ((double)testResult.cSize <= ((double)winners[cLevel].result.cSize * (1. + (0.01 / cLevel))) )
if ((double)testResult.cSize <= ((double)winners[cLevel].result.cSize * (1. + (0.02 / cLevel))) )
{
/* Validate solution is "good enough" */
double W_ratio = (double)srcSize / testResult.cSize;
@@ -498,8 +513,10 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_HC_parameters params,
double W_DMemUsed_note = W_ratioNote * ( 40 + 9*cLevel) - log((double)W_DMemUsed);
double O_DMemUsed_note = O_ratioNote * ( 40 + 9*cLevel) - log((double)O_DMemUsed);
size_t W_CMemUsed = (1 << params.windowLog) + 4 * (1 << params.hashLog) + 4 * (1 << params.chainLog);
size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + 4 * (1 << winners[cLevel].params.hashLog) + 4 * (1 << winners[cLevel].params.chainLog);
size_t W_CMemUsed = (1 << params.windowLog) + 4 * (1 << params.hashLog) +
((params.strategy==ZSTD_HC_fast) ? 0 : 4 * (1 << params.contentLog));
size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + 4 * (1 << winners[cLevel].params.hashLog) +
((winners[cLevel].params.strategy==ZSTD_HC_fast) ? 0 : 4 * (1 << winners[cLevel].params.contentLog));
double W_CMemUsed_note = W_ratioNote * ( 50 + 13*cLevel) - log((double)W_CMemUsed);
double O_CMemUsed_note = O_ratioNote * ( 50 + 13*cLevel) - log((double)O_CMemUsed);
@@ -562,26 +579,35 @@ static int BMK_seed(winnerInfo_t* winners, const ZSTD_HC_parameters params,
return better;
}
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
static BYTE g_alreadyTested[ZSTD_HC_WINDOWLOG_MAX+1-ZSTD_HC_WINDOWLOG_MIN]
[ZSTD_HC_CHAINLOG_MAX+1-ZSTD_HC_CHAINLOG_MIN]
[ZSTD_HC_HASHLOG_MAX+1-ZSTD_HC_HASHLOG_MIN]
[ZSTD_HC_SEARCHLOG_MAX+1-ZSTD_HC_SEARCHLOG_MIN] = {}; /* init to zero */
/* nullified useless params, to ensure count stats */
static ZSTD_HC_parameters* sanitizeParams(ZSTD_HC_parameters params)
{
g_params = params;
if (params.strategy == ZSTD_HC_fast)
{
g_params.contentLog = 0;
g_params.searchLog = 0;
}
return &g_params;
}
#define PARAMTABLELOG 25
#define PARAMTABLESIZE (1<<PARAMTABLELOG)
#define PARAMTABLEMASK (PARAMTABLESIZE-1)
static BYTE g_alreadyTested[PARAMTABLESIZE] = {0}; /* init to zero */
#define NB_TESTS_PLAYED(p) \
g_alreadyTested[p.windowLog-ZSTD_HC_WINDOWLOG_MIN] \
[p.chainLog-ZSTD_HC_CHAINLOG_MIN] \
[p.hashLog-ZSTD_HC_HASHLOG_MIN] \
[p.searchLog-ZSTD_HC_SEARCHLOG_MIN]
g_alreadyTested[(XXH64(sanitizeParams(p), sizeof(p), 0) >> 3) & PARAMTABLEMASK]
#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
static void playAround(FILE* f, winnerInfo_t* winners,
ZSTD_HC_parameters params,
const void* srcBuffer, size_t srcSize,
ZSTD_HC_CCtx* ctx)
{
const U32 srcLog = BMK_highbit((U32)( (g_blockSize ? g_blockSize : srcSize) -1))+1;
int nbVariations = 0;
const int startTime = BMK_GetMilliStart();
@@ -593,13 +619,13 @@ static void playAround(FILE* f, winnerInfo_t* winners,
for (; nbChanges; nbChanges--)
{
const U32 changeID = FUZ_rand(&g_rand) % 9;
const U32 changeID = FUZ_rand(&g_rand) % 12;
switch(changeID)
{
case 0:
p.chainLog++; break;
p.contentLog++; break;
case 1:
p.chainLog--; break;
p.contentLog--; break;
case 2:
p.hashLog++; break;
case 3:
@@ -616,24 +642,23 @@ static void playAround(FILE* f, winnerInfo_t* winners,
p.searchLength++; break;
case 9:
p.searchLength--; break;
case 10:
p.strategy = (ZSTD_HC_strategy)(((U32)p.strategy)+1); break;
case 11:
p.strategy = (ZSTD_HC_strategy)(((U32)p.strategy)-1); break;
}
}
/* validate new conf */
if (p.windowLog > srcLog) continue;
if (p.windowLog > ZSTD_HC_WINDOWLOG_MAX) continue;
if (p.windowLog < MAX(ZSTD_HC_WINDOWLOG_MIN, p.chainLog)) continue;
if (p.chainLog > p.windowLog) continue;
if (p.chainLog < ZSTD_HC_CHAINLOG_MIN) continue;
if (p.hashLog > ZSTD_HC_HASHLOG_MAX) continue;
if (p.hashLog < ZSTD_HC_HASHLOG_MIN) continue;
if (p.searchLog > p.chainLog) continue;
if (p.searchLog < ZSTD_HC_SEARCHLOG_MIN) continue;
if (p.searchLength > ZSTD_HC_SEARCHLENGTH_MAX) continue;
if (p.searchLength < ZSTD_HC_SEARCHLENGTH_MIN) continue;
{
ZSTD_HC_parameters saved = p;
ZSTD_HC_validateParams(&p, g_blockSize ? g_blockSize : srcSize);
if (memcmp(&p, &saved, sizeof(p))) continue; /* p was invalid */
}
/* exclude faster if already played params */
if (FUZ_rand(&g_rand) & ((1 << NB_TESTS_PLAYED(p))-1)) continue;
if (FUZ_rand(&g_rand) & ((1 << NB_TESTS_PLAYED(p))-1))
continue;
/* test */
NB_TESTS_PLAYED(p)++;
@@ -652,16 +677,17 @@ static void BMK_selectRandomStart(
const void* srcBuffer, size_t srcSize,
ZSTD_HC_CCtx* ctx)
{
U32 id = (FUZ_rand(&g_rand) % ZSTD_HC_MAX_CLEVEL) + 1;
if ((id<2) || (winners[id].params.windowLog==0))
U32 id = (FUZ_rand(&g_rand) % (ZSTD_HC_MAX_CLEVEL+1));
if ((id==0) || (winners[id].params.windowLog==0))
{
/* totally random entry */
ZSTD_HC_parameters p;
p.chainLog = FUZ_rand(&g_rand) % (ZSTD_HC_CHAINLOG_MAX+1 - ZSTD_HC_CHAINLOG_MIN) + ZSTD_HC_CHAINLOG_MIN;
p.contentLog = FUZ_rand(&g_rand) % (ZSTD_HC_CONTENTLOG_MAX+1 - ZSTD_HC_CONTENTLOG_MIN) + ZSTD_HC_CONTENTLOG_MIN;
p.hashLog = FUZ_rand(&g_rand) % (ZSTD_HC_HASHLOG_MAX+1 - ZSTD_HC_HASHLOG_MIN) + ZSTD_HC_HASHLOG_MIN;
p.searchLog = FUZ_rand(&g_rand) % (ZSTD_HC_SEARCHLOG_MAX+1 - ZSTD_HC_SEARCHLOG_MIN) + ZSTD_HC_SEARCHLOG_MIN;
p.windowLog = FUZ_rand(&g_rand) % (ZSTD_HC_WINDOWLOG_MAX+1 - ZSTD_HC_WINDOWLOG_MIN) + ZSTD_HC_WINDOWLOG_MIN;
p.searchLength=FUZ_rand(&g_rand) % (ZSTD_HC_SEARCHLENGTH_MAX+1 - ZSTD_HC_SEARCHLENGTH_MIN) + ZSTD_HC_SEARCHLENGTH_MIN;
p.strategy = (ZSTD_HC_strategy) (FUZ_rand(&g_rand) % (ZSTD_HC_btlazy2+1));
playAround(f, winners, p, srcBuffer, srcSize, ctx);
}
else
@@ -669,8 +695,6 @@ static void BMK_selectRandomStart(
}
static const ZSTD_HC_parameters* g_seedParams = ZSTD_HC_defaultParameters;
static void BMK_benchMem(void* srcBuffer, size_t srcSize)
{
ZSTD_HC_CCtx* ctx = ZSTD_HC_createCCtx();
@@ -684,6 +708,7 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize)
if (g_singleRun)
{
BMK_result_t testResult;
ZSTD_HC_validateParams(&g_params, g_blockSize ? g_blockSize : srcSize);
BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, g_params);
DISPLAY("\n");
return;
@@ -695,32 +720,35 @@ static void BMK_benchMem(void* srcBuffer, size_t srcSize)
if (f==NULL) { DISPLAY("error opening %s \n", rfName); exit(1); }
if (g_target)
g_cSpeedTarget[2] = g_target * 1000;
g_cSpeedTarget[1] = g_target * 1000;
else
{
/* baseline config for level 2 */
/* baseline config for level 1 */
BMK_result_t testResult;
params = g_seedParams[2];
params.windowLog = MIN(srcLog, params.windowLog);
params.chainLog = MIN(params.windowLog, params.chainLog);
params.searchLog = MIN(params.chainLog, params.searchLog);
params.windowLog = MIN(srcLog, 18);
params.hashLog = 14;
params.contentLog = 1;
params.searchLog = 1;
params.searchLength = 7;
params.strategy = ZSTD_HC_fast;
BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params);
g_cSpeedTarget[2] = (testResult.cSpeed * 15) >> 4;
g_cSpeedTarget[1] = (testResult.cSpeed * 15) >> 4;
}
/* establish speed objectives (relative to level 2) */
for (i=3; i<=ZSTD_HC_MAX_CLEVEL; i++)
g_cSpeedTarget[i] = (g_cSpeedTarget[i-1] * 13) >> 4;
/* establish speed objectives (relative to level 1) */
for (i=2; i<=ZSTD_HC_MAX_CLEVEL; i++)
g_cSpeedTarget[i] = (g_cSpeedTarget[i-1] * 25) >> 5;
/* populate initial solution */
{
const int maxSeeds = g_noSeed ? 2 : ZSTD_HC_MAX_CLEVEL;
for (i=2; i<=maxSeeds; i++)
const int maxSeeds = g_noSeed ? 1 : ZSTD_HC_MAX_CLEVEL;
for (i=1; i<=maxSeeds; i++)
{
const U32 btPlus = (params.strategy == ZSTD_HC_btlazy2);
params = g_seedParams[i];
params.windowLog = MIN(srcLog, params.windowLog);
params.chainLog = MIN(params.windowLog, params.chainLog);
params.searchLog = MIN(params.chainLog, params.searchLog);
params.contentLog = MIN(params.windowLog+btPlus, params.contentLog);
params.searchLog = MIN(params.contentLog, params.searchLog);
BMK_seed(winners, params, srcBuffer, srcSize, ctx);
}
}
@@ -938,10 +966,10 @@ int main(int argc, char** argv)
g_params.windowLog *= 10, g_params.windowLog += *argument++ - '0';
continue;
case 'c':
g_params.chainLog = 0;
g_params.contentLog = 0;
argument++;
while ((*argument>= '0') && (*argument<='9'))
g_params.chainLog *= 10, g_params.chainLog += *argument++ - '0';
g_params.contentLog *= 10, g_params.contentLog += *argument++ - '0';
continue;
case 'h':
g_params.hashLog = 0;
@@ -955,19 +983,28 @@ int main(int argc, char** argv)
while ((*argument>= '0') && (*argument<='9'))
g_params.searchLog *= 10, g_params.searchLog += *argument++ - '0';
continue;
case 'l':
case 'l': /* search length */
g_params.searchLength = 0;
argument++;
while ((*argument>= '0') && (*argument<='9'))
g_params.searchLength *= 10, g_params.searchLength += *argument++ - '0';
continue;
case 't': /* strategy */
g_params.strategy = (ZSTD_HC_strategy)0;
argument++;
while ((*argument>= '0') && (*argument<='9'))
{
g_params.strategy = (ZSTD_HC_strategy)((U32)g_params.strategy *10);
g_params.strategy = (ZSTD_HC_strategy)((U32)g_params.strategy + *argument++ - '0');
}
continue;
case 'L':
{
int cLevel = 0;
argument++;
while ((*argument>= '0') && (*argument<='9'))
cLevel *= 10, cLevel += *argument++ - '0';
if (cLevel < 2) cLevel = 2;
if (cLevel < 1) cLevel = 1;
if (cLevel > ZSTD_HC_MAX_CLEVEL) cLevel = ZSTD_HC_MAX_CLEVEL;
g_params = g_seedParams[cLevel];
continue;
@@ -978,7 +1015,7 @@ int main(int argc, char** argv)
}
break;
/* target level2 speed objective, in MB/s */
/* target level1 speed objective, in MB/s */
case 'T':
argument++;
g_target = 0;
@@ -1000,6 +1037,7 @@ int main(int argc, char** argv)
if (*argument=='K') g_blockSize<<=10, argument++; /* allows using KB notation */
if (*argument=='M') g_blockSize<<=20, argument++;
if (*argument=='B') argument++;
DISPLAY("using %u KB block size \n", g_blockSize>>10);
}
break;
+10 -9
View File
@@ -70,7 +70,7 @@
**************************************/
#define COMPRESSOR_NAME "zstd command line interface"
#ifndef ZSTD_VERSION
# define ZSTD_VERSION "v0.0.1"
# define ZSTD_VERSION "v0.3.5"
#endif
#define AUTHOR "Yann Collet"
#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s (%s) ***\n", COMPRESSOR_NAME, (int)(sizeof(void*)*8), ZSTD_VERSION, AUTHOR, __DATE__
@@ -178,7 +178,7 @@ int main(int argc, char** argv)
const char* inFileName = NULL;
const char* outFileName = NULL;
char* dynNameSpace = NULL;
char extension[] = ZSTD_EXTENSION;
const char extension[] = ZSTD_EXTENSION;
displayOut = stderr;
/* Pick out basename component. Don't rely on stdlib because of conflicting behavior. */
@@ -351,16 +351,17 @@ int main(int argc, char** argv)
}
/* decompression to file (automatic name will work only if input filename has correct format extension) */
{
size_t outl;
size_t inl = strlen(inFileName);
dynNameSpace = (char*)calloc(1,inl+1);
size_t filenameSize = strlen(inFileName);
if (strcmp(inFileName + (filenameSize-4), extension))
{
DISPLAYLEVEL(1, "unknown suffix - cannot determine destination filename\n");
return badusage(programName);
}
dynNameSpace = (char*)calloc(1,filenameSize+1);
if (dynNameSpace==NULL) { DISPLAY("not enough memory\n"); exit(1); }
outFileName = dynNameSpace;
strcpy(dynNameSpace, inFileName);
outl = inl;
if (inl>4)
while ((outl >= inl-4) && (inFileName[outl] == extension[outl-inl+4])) dynNameSpace[outl--]=0;
if (outl != inl-5) { DISPLAYLEVEL(1, "Cannot determine an output filename\n"); return badusage(programName); }
dynNameSpace[filenameSize-4]=0;
DISPLAYLEVEL(2, "Decoding file %s \n", outFileName);
}
}
+1 -1
View File
@@ -78,7 +78,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);</IncludePath>
<IncludePath>$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);</IncludePath>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+1 -1
View File
@@ -78,7 +78,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);</IncludePath>
<IncludePath>$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);</IncludePath>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+1 -1
View File
@@ -109,7 +109,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);</IncludePath>
<IncludePath>$(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);</IncludePath>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">