From 8a1d1a6a6c5824af4a6273c083607525a40e765e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 10 Mar 2016 21:02:25 +0100 Subject: [PATCH 01/49] implemented `--ultra` mode protection --- programs/fileio.c | 23 ++++++++++++++--------- programs/fileio.h | 7 ++++--- programs/zstdcli.c | 2 ++ 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 028c7db45..2a7d73d15 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -126,6 +126,7 @@ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } static U32 g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */ +void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; } #define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \ if ((FIO_GetMilliSpan(g_time) > refreshRate) || (g_displayLevel>=4)) \ @@ -142,7 +143,8 @@ static clock_t g_time = 0; ***************************************/ static U32 g_overwrite = 0; void FIO_overwriteMode(void) { g_overwrite=1; } -void FIO_setNotificationLevel(unsigned level) { g_displayLevel=level; } +static U32 g_maxWLog = 23; +void FIO_setMaxWLog(unsigned maxWLog) { g_maxWLog = maxWLog; } /*-************************************* @@ -239,10 +241,10 @@ static FILE* FIO_openDstFile(const char* dstFileName) } -/*!FIO_loadFile -* creates a buffer, pointed by *bufferPtr, -* loads "filename" content into it -* up to MAX_DICT_SIZE bytes +/*! FIO_loadFile() : +* creates a buffer, pointed by *bufferPtr, +* loads `filename` content into it, +* up to MAX_DICT_SIZE bytes */ static size_t FIO_loadFile(void** bufferPtr, const char* fileName) { @@ -274,7 +276,7 @@ static size_t FIO_loadFile(void** bufferPtr, const char* fileName) } -/* ********************************************************************** +/*-********************************************************************** * Compression ************************************************************************/ typedef struct { @@ -321,7 +323,7 @@ static void FIO_freeCResources(cRess_t ress) /*! FIO_compressFilename_internal() : - * same as FIO_compressFilename_extRess(), with ress.desFile already opened + * same as FIO_compressFilename_extRess(), with `ress.desFile` already opened. * @return : 0 : compression completed correctly, * 1 : missing or pb opening srcFileName */ @@ -335,10 +337,13 @@ static int FIO_compressFilename_internal(cRess_t ress, U64 compressedfilesize = 0; size_t dictSize = ress.dictBufferSize; size_t sizeCheck, errorCode; + ZSTD_parameters params; /* init */ filesize = MAX(FIO_getFileSize(srcFileName),dictSize); - errorCode = ZBUFF_compressInit_advanced(ress.ctx, ress.dictBuffer, ress.dictBufferSize, ZSTD_getParams(cLevel, filesize)); + params = ZSTD_getParams(cLevel, filesize); + if (g_maxWLog) if (params.windowLog > g_maxWLog) params.windowLog = g_maxWLog; + errorCode = ZBUFF_compressInit_advanced(ress.ctx, ress.dictBuffer, ress.dictBufferSize, params); if (ZBUFF_isError(errorCode)) EXM_THROW(21, "Error initializing compression : %s", ZBUFF_getErrorName(errorCode)); /* Main compression loop */ @@ -482,7 +487,7 @@ int FIO_compressMultipleFilenames(const char** inFileNamesTable, unsigned nbFile ress.dstFile = stdout; for (u=0; u Date: Fri, 11 Mar 2016 13:41:20 +0100 Subject: [PATCH 02/49] benchmark mode : automated cooling (overheat protection) --- programs/bench.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/programs/bench.c b/programs/bench.c index 1c776c4e6..82e28d405 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -62,6 +62,17 @@ # include /* gettimeofday */ #endif +/* sleep : posix - windows - others */ +#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) +# include +# define BMK_sleep(s) sleep(s) +#elif defined(_WIN32) +# include +# define BMK_sleep(s) Sleep(1000*s) +#else +# define BMK_sleep(s) /* disabled */ +#endif + #include "mem.h" #include "zstd_static.h" #include "xxhash.h" @@ -83,8 +94,10 @@ /* ************************************* * Constants ***************************************/ -#define NBLOOPS 3 -#define TIMELOOP 2500 +#define NBLOOPS 3 +#define TIMELOOP_MS 2500 +#define ACTIVEPERIOD_S 70 +#define COOLPERIOD_S 10 #define KB *(1 <<10) #define MB *(1 <<20) @@ -274,6 +287,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, double fastestC = 100000000., fastestD = 100000000.; double ratio = 0.; U64 crcCheck = 0; + int coolTime = BMK_GetMilliStart(); DISPLAY("\r%79s\r", ""); for (loopNb = 1; loopNb <= nbIterations; loopNb++) { @@ -281,6 +295,13 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, int milliTime; U32 blockNb; + /* overheat protection */ + if (BMK_GetMilliSpan(coolTime) > ACTIVEPERIOD_S*1000) { + DISPLAY("\rcooling down ... \r"); + BMK_sleep(COOLPERIOD_S); + coolTime = BMK_GetMilliStart(); + } + /* Compression */ DISPLAY("%2i-%-17.17s :%10u ->\r", loopNb, displayName, (U32)srcSize); memset(compressedBuffer, 0xE5, maxCompressedSize); @@ -289,7 +310,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, milliTime = BMK_GetMilliStart(); while (BMK_GetMilliStart() == milliTime); milliTime = BMK_GetMilliStart(); - while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { + while (BMK_GetMilliSpan(milliTime) < TIMELOOP_MS) { ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, MAX(dictBufferSize, largestBlockSize))); for (blockNb=0; blockNb Date: Fri, 11 Mar 2016 21:58:04 +0100 Subject: [PATCH 03/49] created ZSTD_frameParams --- lib/zbuff.c | 53 +++++++++++++++++++++++-------------------- lib/zbuff.h | 17 +++++++------- lib/zstd_compress.c | 2 +- lib/zstd_decompress.c | 31 +++++++++++++------------ lib/zstd_internal.h | 4 +--- lib/zstd_static.h | 23 +++++++++++-------- 6 files changed, 69 insertions(+), 61 deletions(-) diff --git a/lib/zbuff.c b/lib/zbuff.c index 4c1eb2cf2..69341df8e 100644 --- a/lib/zbuff.c +++ b/lib/zbuff.c @@ -298,28 +298,29 @@ size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr) } - -/** ************************************************ -* Streaming decompression +/*-*************************************************************************** +* Streaming decompression howto * -* A ZBUFF_DCtx object is required to track streaming operation. +* A ZBUFF_DCtx object is required to track streaming operations. * Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. -* Use ZBUFF_decompressInit() to start a new decompression operation. -* ZBUFF_DCtx objects can be reused multiple times. +* Use ZBUFF_decompressInit() to start a new decompression operation, +* or ZBUFF_decompressInitDictionary() if decompression requires a dictionary. +* Note that ZBUFF_DCtx objects can be re-init multiple times. * * Use ZBUFF_decompressContinue() repetitively to consume your input. -* *srcSizePtr and *maxDstSizePtr can be any size. -* The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr. -* Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input. -* The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst . -* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) -* or 0 when a frame is completely decoded +* *srcSizePtr and *dstCapacityPtr can be any size. +* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. +* Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. +* The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change @dst. +* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency), +* or 0 when a frame is completely decoded, * or an error code, which can be tested using ZBUFF_isError(). * -* Hint : recommended buffer sizes (not compulsory) -* output : 128 KB block size is the internal unit, it ensures it's always possible to write a full block when it's decoded. -* input : just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . -* **************************************************/ +* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize() +* output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded. +* input : ZBUFF_recommendedDInSize == 128KB + 3; +* just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . +* *******************************************************************************/ typedef enum { ZBUFFds_init, ZBUFFds_readHeader, ZBUFFds_loadHeader, ZBUFFds_decodeHeader, ZBUFFds_read, ZBUFFds_load, ZBUFFds_flush } ZBUFF_dStage; @@ -329,7 +330,7 @@ typedef enum { ZBUFFds_init, ZBUFFds_readHeader, ZBUFFds_loadHeader, ZBUFFds_dec #define ZSTD_frameHeaderSize_max 5 /* too magical, should come from reference */ struct ZBUFF_DCtx_s { ZSTD_DCtx* zc; - ZSTD_parameters params; + ZSTD_frameParams fParams; char* inBuff; size_t inBuffSize; size_t inPos; @@ -381,14 +382,16 @@ size_t ZBUFF_decompressInit(ZBUFF_DCtx* zbc) /* *** Decompression *** */ -size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePtr, const void* src, size_t* srcSizePtr) +size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, + void* dst, size_t* dstCapacityPtr, + const void* src, size_t* srcSizePtr) { const char* const istart = (const char*)src; const char* ip = istart; const char* const iend = istart + *srcSizePtr; char* const ostart = (char*)dst; char* op = ostart; - char* const oend = ostart + *maxDstSizePtr; + char* const oend = ostart + *dstCapacityPtr; U32 notDone = 1; while (notDone) { @@ -400,13 +403,13 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt case ZBUFFds_readHeader : /* read header from src */ { - size_t headerSize = ZSTD_getFrameParams(&(zbc->params), src, *srcSizePtr); + size_t headerSize = ZSTD_getFrameParams(&(zbc->fParams), src, *srcSizePtr); if (ZSTD_isError(headerSize)) return headerSize; if (headerSize) { /* not enough input to decode header : tell how many bytes would be necessary */ memcpy(zbc->headerBuffer+zbc->hPos, src, *srcSizePtr); zbc->hPos += *srcSizePtr; - *maxDstSizePtr = 0; + *dstCapacityPtr = 0; zbc->stage = ZBUFFds_loadHeader; return headerSize - zbc->hPos; } @@ -422,11 +425,11 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt src, *srcSizePtr); zbc->hPos += headerSize; ip += headerSize; - headerSize = ZSTD_getFrameParams(&(zbc->params), zbc->headerBuffer, zbc->hPos); + headerSize = ZSTD_getFrameParams(&(zbc->fParams), zbc->headerBuffer, zbc->hPos); if (ZSTD_isError(headerSize)) return headerSize; if (headerSize) { /* not enough input to decode header : tell how many bytes would be necessary */ - *maxDstSizePtr = 0; + *dstCapacityPtr = 0; return headerSize - zbc->hPos; } // zbc->stage = ZBUFFds_decodeHeader; break; /* useless : stage follows */ @@ -435,7 +438,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt case ZBUFFds_decodeHeader: /* apply header to create / resize buffers */ { - size_t neededOutSize = (size_t)1 << zbc->params.windowLog; + size_t neededOutSize = (size_t)1 << zbc->fParams.windowLog; size_t neededInSize = BLOCKSIZE; /* a block is never > BLOCKSIZE */ if (zbc->inBuffSize < neededInSize) { free(zbc->inBuff); @@ -524,7 +527,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, void* dst, size_t* maxDstSizePt } } *srcSizePtr = ip-istart; - *maxDstSizePtr = op-ostart; + *dstCapacityPtr = op-ostart; { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbc->zc); diff --git a/lib/zbuff.h b/lib/zbuff.h index d3275b7df..7a914a4a7 100644 --- a/lib/zbuff.h +++ b/lib/zbuff.h @@ -75,7 +75,7 @@ ZSTDLIB_API size_t ZBUFF_compressFlush(ZBUFF_CCtx* cctx, void* dst, size_t* dstC ZSTDLIB_API size_t ZBUFF_compressEnd(ZBUFF_CCtx* cctx, void* dst, size_t* dstCapacityPtr); /*-************************************************* -* Streaming compression +* Streaming compression - howto * * A ZBUFF_CCtx object is required to track streaming operation. * Use ZBUFF_createCCtx() and ZBUFF_freeCCtx() to create/release resources. @@ -127,26 +127,27 @@ ZSTDLIB_API size_t ZBUFF_decompressContinue(ZBUFF_DCtx* dctx, const void* src, size_t* srcSizePtr); /*-*************************************************************************** -* Streaming decompression +* Streaming decompression howto * * A ZBUFF_DCtx object is required to track streaming operations. * Use ZBUFF_createDCtx() and ZBUFF_freeDCtx() to create/release resources. * Use ZBUFF_decompressInit() to start a new decompression operation, * or ZBUFF_decompressInitDictionary() if decompression requires a dictionary. -* Note that ZBUFF_DCtx objects can be reused multiple times. +* Note that ZBUFF_DCtx objects can be re-init multiple times. * * Use ZBUFF_decompressContinue() repetitively to consume your input. * *srcSizePtr and *dstCapacityPtr can be any size. * The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. * Note that it may not consume the entire input, in which case it's up to the caller to present remaining input again. -* The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change @dst. -* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency) -* or 0 when a frame is completely decoded +* The content of @dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters, or change @dst. +* @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to help latency), +* or 0 when a frame is completely decoded, * or an error code, which can be tested using ZBUFF_isError(). * -* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() / ZBUFF_recommendedDOutSize() +* Hint : recommended buffer sizes (not compulsory) : ZBUFF_recommendedDInSize() and ZBUFF_recommendedDOutSize() * output : ZBUFF_recommendedDOutSize==128 KB block size is the internal unit, it ensures it's always possible to write a full block when decoded. -* input : ZBUFF_recommendedDInSize==128Kb+3; just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . +* input : ZBUFF_recommendedDInSize == 128KB + 3; +* just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . * *******************************************************************************/ diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index fc88eb168..c1ab910bc 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -103,7 +103,7 @@ struct ZSTD_CCtx_s size_t workSpaceSize; size_t blockSize; size_t hbSize; - char headerBuffer[ZSTD_frameHeaderSize_max]; + char headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; seqStore_t seqStore; /* sequences storage ptrs */ U32* hashTable; diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 60136b615..2625f5476 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -136,7 +136,7 @@ struct ZSTD_DCtx_s const void* dictEnd; size_t expected; size_t headerSize; - ZSTD_parameters params; + ZSTD_frameParams fParams; blockType_t bType; /* used in ZSTD_decompressContinue(), to transfer blockType between header decoding and block decoding stages */ ZSTD_dStage stage; U32 flagStaticTables; @@ -144,7 +144,7 @@ struct ZSTD_DCtx_s size_t litBufSize; size_t litSize; BYTE litBuffer[BLOCKSIZE + WILDCOPY_OVERLENGTH]; - BYTE headerBuffer[ZSTD_frameHeaderSize_max]; + BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; }; /* typedef'd to ZSTD_DCtx within "zstd_static.h" */ size_t sizeofDCtx (void) { return sizeof(ZSTD_DCtx); } @@ -159,7 +159,7 @@ size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx) dctx->dictEnd = NULL; dctx->hufTableX4[0] = HufLog; dctx->flagStaticTables = 0; - dctx->params.searchLength = MINMATCH; /* overwritten by frame but forces ZSTD_btopt to MINMATCH in block mode */ + dctx->fParams.mml = MINMATCH; /* overwritten by frame but forces ZSTD_btopt to MINMATCH in block mode */ ZSTD_LOG_BLOCK("%p: ZSTD_decompressBegin searchLength=%d\n", dctx->base, dctx->params.searchLength); return 0; } @@ -286,15 +286,15 @@ static size_t ZSTD_decodeFrameHeader_Part1(ZSTD_DCtx* zc, const void* src, size_ } -size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize) +size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize) { U32 magicNumber; if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_max; magicNumber = MEM_readLE32(src); if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); - memset(params, 0, sizeof(*params)); - params->windowLog = (((const BYTE*)src)[4] & 15) + ZSTD_WINDOWLOG_ABSOLUTEMIN; - params->searchLength = (((const BYTE*)src)[4] & 16) ? MINMATCH-1 : MINMATCH; + memset(fparamsPtr, 0, sizeof(*fparamsPtr)); + fparamsPtr->windowLog = (((const BYTE*)src)[4] & 15) + ZSTD_WINDOWLOG_ABSOLUTEMIN; + fparamsPtr->mml = (((const BYTE*)src)[4] & 16) ? MINMATCH-1 : MINMATCH; if ((((const BYTE*)src)[4] >> 5) != 0) return ERROR(frameParameter_unsupported); /* reserved 3 bits */ return 0; } @@ -308,8 +308,8 @@ static size_t ZSTD_decodeFrameHeader_Part2(ZSTD_DCtx* zc, const void* src, size_ size_t result; if (srcSize != zc->headerSize) return ERROR(srcSize_wrong); - result = ZSTD_getFrameParams(&(zc->params), src, srcSize); - if ((MEM_32bits()) && (zc->params.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits); + result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize); + if ((MEM_32bits()) && (zc->fParams.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits); return result; } @@ -792,7 +792,7 @@ static size_t ZSTD_decompressSequences( const BYTE* const base = (const BYTE*) (dctx->base); const BYTE* const vBase = (const BYTE*) (dctx->vBase); const BYTE* const dictEnd = (const BYTE*) (dctx->dictEnd); - const U32 mls = dctx->params.searchLength; + const U32 mls = dctx->fParams.mml; /* Build Decoding Tables */ errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, @@ -885,9 +885,9 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, } -/*! ZSTD_decompress_continueDCtx -* dctx must have been properly initialized */ -static size_t ZSTD_decompress_continueDCtx(ZSTD_DCtx* dctx, +/*! ZSTD_decompress_continueDCtx() : +* `dctx` must have been properly initialized */ +static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) { @@ -965,7 +965,7 @@ size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* refDC { ZSTD_copyDCtx(dctx, refDCtx); ZSTD_checkContinuity(dctx, dst); - return ZSTD_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize); + return ZSTD_decompressFrame(dctx, dst, maxDstSize, src, srcSize); } @@ -977,7 +977,7 @@ size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, ZSTD_decompressBegin_usingDict(dctx, dict, dictSize); ZSTD_LOG_BLOCK("%p: ZSTD_decompressBegin_usingDict searchLength=%d\n", dctx->base, dctx->params.searchLength); ZSTD_checkContinuity(dctx, dst); - return ZSTD_decompress_continueDCtx(dctx, dst, maxDstSize, src, srcSize); + return ZSTD_decompressFrame(dctx, dst, maxDstSize, src, srcSize); } @@ -986,6 +986,7 @@ size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const return ZSTD_decompress_usingDict(dctx, dst, maxDstSize, src, srcSize, NULL, 0); } + size_t ZSTD_decompress(void* dst, size_t maxDstSize, const void* src, size_t srcSize) { #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE==1) diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index 409e5e57a..d67505caa 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -71,11 +71,9 @@ #define MB *(1 <<20) #define GB *(1U<<30) -#define BLOCKSIZE (128 KB) /* define, for static allocation */ +#define BLOCKSIZE (128 KB) /* define, for static allocation */ static const size_t ZSTD_blockHeaderSize = 3; -static const size_t ZSTD_frameHeaderSize_min = 5; -#define ZSTD_frameHeaderSize_max 5 /* define, for static allocation */ #define BIT7 128 #define BIT6 64 diff --git a/lib/zstd_static.h b/lib/zstd_static.h index 4f23fca98..e3c0dfc45 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -165,13 +165,17 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci You can then reuse ZSTD_CCtx to compress some new frame. */ +typedef struct { U64 frameSize; U32 windowLog; U32 mml; } ZSTD_frameParams; + +#define ZSTD_FRAMEHEADERSIZE_MAX 13 /* for static allocation */ +static const size_t ZSTD_frameHeaderSize_min = 5; +static const size_t ZSTD_frameHeaderSize_max = ZSTD_FRAMEHEADERSIZE_MAX; +ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize); /**< doesn't consume input */ ZSTDLIB_API size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize); ZSTDLIB_API void ZSTD_copyDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx); -ZSTDLIB_API size_t ZSTD_getFrameParams(ZSTD_parameters* params, const void* src, size_t srcSize); - ZSTDLIB_API size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx); ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); @@ -182,15 +186,16 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds Use ZSTD_createDCtx() / ZSTD_freeDCtx() to manage it. A ZSTD_DCtx object can be re-used multiple times. - First typical operation is to retrieve frame parameters, using ZSTD_getFrameParams(). - This operation is independent, and just needs enough input data to properly decode the frame header. - Objective is to retrieve *params.windowlog, to know minimum amount of memory required during decoding. - Result : 0 when successful, it means the ZSTD_parameters structure has been filled. - >0 : means there is not enough data into src. Provides the expected size to successfully decode header. + First optional operation is to retrieve frame parameters, using ZSTD_getFrameParams(). + It requires to read the beginning of compressed frame. + The amount of data to read is variable, from ZSTD_frameHeaderSize_min to ZSTD_frameHeaderSize_max. + If you don't provide enough length, function will return the minimum size it wants to produce a result. + Result : 0 when successful, it means the ZSTD_frameParams structure has been filled. + >0 : means there is not enough data into src. Provides the expected size to successfully decode header. errorCode, which can be tested using ZSTD_isError() - Start decompression, with ZSTD_decompressBegin() or ZSTD_decompressBegin_usingDict() - Alternatively, you can copy a prepared context, using ZSTD_copyDCtx() + Start decompression, with ZSTD_decompressBegin() or ZSTD_decompressBegin_usingDict(). + Alternatively, you can copy a prepared context, using ZSTD_copyDCtx(). Then use ZSTD_nextSrcSizeToDecompress() and ZSTD_decompressContinue() alternatively. ZSTD_nextSrcSizeToDecompress() tells how much bytes to provide as 'srcSize' to ZSTD_decompressContinue(). From 03ea59b17be761523a4e8d6e6748ef0dab74b9b7 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 12 Mar 2016 01:25:40 +0100 Subject: [PATCH 04/49] Decompression can decode frame content size --- lib/zstd_decompress.c | 102 +++++++++++++++++++++++++++--------------- lib/zstd_static.h | 2 +- 2 files changed, 66 insertions(+), 38 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 2625f5476..bfa398d8b 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -94,13 +94,13 @@ typedef struct } blockProperties_t; -/* ******************************************************* +/*_******************************************************* * Memory operations **********************************************************/ static void ZSTD_copy4(void* dst, const void* src) { memcpy(dst, src, 4); } -/* ************************************* +/*-************************************* * Error Management ***************************************/ unsigned ZSTD_versionNumber (void) { return ZSTD_VERSION_NUMBER; } @@ -118,7 +118,7 @@ ZSTD_ErrorCode ZSTD_getError(size_t code) { return ERR_getError(code); } const char* ZSTD_getErrorName(size_t code) { return ERR_getErrorName(code); } -/* ************************************************************* +/*-************************************************************* * Context management ***************************************************************/ typedef enum { ZSTDds_getFrameHeaderSize, ZSTDds_decodeFrameHeader, @@ -185,15 +185,15 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) } -/* ************************************************************* +/*-************************************************************* * Decompression section ***************************************************************/ /* Frame format description Frame Header - [ Block Header - Block ] - Frame End 1) Frame Header - - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_internal.h) - - 1 byte - Window Descriptor + - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h) + - 1 byte - Frame Descriptor 2) Block Header - 3 bytes, starting with a 2-bits descriptor Uncompressed, Compressed, Frame End, unused @@ -203,7 +203,18 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) - 3 bytes, compatible with Block Header */ -/* Block format description + +/* Frame descriptor + + 1 byte, using : + bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h) + bit 4 : minmatch 4(0) or 3(1) + bit 5 : reserved (must be zero) + bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes +*/ + + +/* Compressed Block, format description Block = Literal Section - Sequences Section Prerequisite : size of (compressed) block, maximum size of regenerated data @@ -269,46 +280,63 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) TO DO */ +static const size_t ZSTD_fcs_fieldSize[4] = { 0, 1, 2, 8 }; -/** ZSTD_decodeFrameHeader_Part1() : -* decode the 1st part of the Frame Header, which tells Frame Header size. -* srcSize must be == ZSTD_frameHeaderSize_min. -* @return : the full size of the Frame Header */ -static size_t ZSTD_decodeFrameHeader_Part1(ZSTD_DCtx* zc, const void* src, size_t srcSize) +/** ZSTD_frameHeaderSize() : +* srcSize must be >= ZSTD_frameHeaderSize_min. +* @return : size of the Frame Header */ +static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) { - U32 magicNumber; - if (srcSize != ZSTD_frameHeaderSize_min) - return ERROR(srcSize_wrong); - magicNumber = MEM_readLE32(src); - if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); - zc->headerSize = ZSTD_frameHeaderSize_min; - return zc->headerSize; + U32 fcsId; + if (srcSize < ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); + fcsId = (((const BYTE*)src)[4]) >> 6; + return ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId]; } +/** ZSTD_getFrameParams() : +* decode Frame Header, or provide expected `srcSize`. +* @return : 0, `fparamsPtr` is correctly filled, +* >0, not enough srcSize, provide expected `srcSize`, +* or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize) { - U32 magicNumber; - if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_max; + U32 magicNumber, fcsId; + const BYTE* ip = (const BYTE*)src; + BYTE frameDesc; + + if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_min; magicNumber = MEM_readLE32(src); if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); + + { size_t fhsize = ZSTD_frameHeaderSize(src, srcSize); + if (srcSize < fhsize) return fhsize; } + memset(fparamsPtr, 0, sizeof(*fparamsPtr)); - fparamsPtr->windowLog = (((const BYTE*)src)[4] & 15) + ZSTD_WINDOWLOG_ABSOLUTEMIN; - fparamsPtr->mml = (((const BYTE*)src)[4] & 16) ? MINMATCH-1 : MINMATCH; - if ((((const BYTE*)src)[4] >> 5) != 0) return ERROR(frameParameter_unsupported); /* reserved 3 bits */ + frameDesc = ip[4]; + fparamsPtr->windowLog = (frameDesc & 0xF) + ZSTD_WINDOWLOG_ABSOLUTEMIN; + fparamsPtr->mml = (frameDesc & 0x10) ? MINMATCH-1 : MINMATCH; + if ((frameDesc & 0x20) != 0) return ERROR(frameParameter_unsupported); /* reserved 1 bit */ + fcsId = frameDesc >> 6; + switch(fcsId) + { + default: /* impossible */ + case 0 : fparamsPtr->frameContentSize = 0; break; + case 1 : fparamsPtr->frameContentSize = ip[5]; break; + case 2 : fparamsPtr->frameContentSize = MEM_readLE16(ip+5); break; + case 3 : fparamsPtr->frameContentSize = MEM_readLE64(ip+5); break; + } return 0; } -/** ZSTD_decodeFrameHeader_Part2() : -* decode the full Frame Header. + +/** ZSTD_decodeFrameHeader() : +* decode Frame Header. * srcSize must be the size provided by ZSTD_decodeFrameHeader_Part1(). * @return : 0, or an error code, which can be tested using ZSTD_isError() */ -static size_t ZSTD_decodeFrameHeader_Part2(ZSTD_DCtx* zc, const void* src, size_t srcSize) +static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* zc, const void* src, size_t srcSize) { - size_t result; - if (srcSize != zc->headerSize) - return ERROR(srcSize_wrong); - result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize); + size_t result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize); if ((MEM_32bits()) && (zc->fParams.windowLog > 25)) return ERROR(frameParameter_unsupportedBy32bits); return result; } @@ -901,7 +929,7 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, /* Frame Header */ { - size_t frameHeaderSize; + size_t frameHeaderSize, errorCode; if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) { @@ -910,12 +938,12 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, return ZSTD_decompressLegacy(dst, maxDstSize, src, srcSize, magicNumber); } #endif - frameHeaderSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); + frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); + errorCode = ZSTD_decodeFrameHeader(dctx, src, frameHeaderSize); + if (ZSTD_isError(errorCode)) return errorCode; ip += frameHeaderSize; remainingSize -= frameHeaderSize; - frameHeaderSize = ZSTD_decodeFrameHeader_Part2(dctx, src, frameHeaderSize); - if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; } /* Loop on each block */ @@ -1024,7 +1052,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co { /* get frame header size */ if (srcSize != ZSTD_frameHeaderSize_min) return ERROR(srcSize_wrong); /* impossible */ - dctx->headerSize = ZSTD_decodeFrameHeader_Part1(dctx, src, ZSTD_frameHeaderSize_min); + dctx->headerSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min); if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize; memcpy(dctx->headerBuffer, src, ZSTD_frameHeaderSize_min); if (dctx->headerSize > ZSTD_frameHeaderSize_min) { @@ -1039,7 +1067,7 @@ size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, co /* get frame header */ size_t result; memcpy(dctx->headerBuffer + ZSTD_frameHeaderSize_min, src, dctx->expected); - result = ZSTD_decodeFrameHeader_Part2(dctx, dctx->headerBuffer, dctx->headerSize); + result = ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize); if (ZSTD_isError(result)) return result; dctx->expected = ZSTD_blockHeaderSize; dctx->stage = ZSTDds_decodeBlockHeader; diff --git a/lib/zstd_static.h b/lib/zstd_static.h index e3c0dfc45..f6eb8aa39 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -165,7 +165,7 @@ ZSTDLIB_API size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapaci You can then reuse ZSTD_CCtx to compress some new frame. */ -typedef struct { U64 frameSize; U32 windowLog; U32 mml; } ZSTD_frameParams; +typedef struct { U64 frameContentSize; U32 windowLog; U32 mml; } ZSTD_frameParams; #define ZSTD_FRAMEHEADERSIZE_MAX 13 /* for static allocation */ static const size_t ZSTD_frameHeaderSize_min = 5; From fb7973580ffa12c3cb95c8a0576b1142cf4011e0 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 13 Mar 2016 11:08:40 +0100 Subject: [PATCH 05/49] minor comments update --- lib/zstd_compress.c | 44 +++++++++++++++++++++++++++++++++++++------ lib/zstd_decompress.c | 6 ++++++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index c1ab910bc..469410faf 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -287,7 +287,7 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) } -/*! ZSTD_reduceIndex +/*! ZSTD_reduceIndex() : * rescale indexes to avoid future overflow (indexes are U32) */ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) @@ -308,6 +308,37 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, * Block entropic compression *********************************************************/ +/* Frame format description + Frame Header - [ Block Header - Block ] - Frame End + 1) Frame Header + - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h) + - 1 byte - Frame Descriptor + 2) Block Header + - 3 bytes, starting with a 2-bits descriptor + Uncompressed, Compressed, Frame End, unused + 3) Block + See Block Format Description + 4) Frame End + - 3 bytes, compatible with Block Header +*/ + + +/* Frame descriptor + + 1 byte, using : + bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h) + bit 4 : minmatch 4(0) or 3(1) + bit 5 : reserved (must be zero) + bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes + + Optional : content size (0, 1, 2 or 8 bytes) + 0 : unknown + 1 : 0-255 bytes + 2 : 256 - 65535+256 + 8 : up to 16 exa +*/ + + /* Block format description Block = Literal Section - Sequences Section @@ -2099,10 +2130,10 @@ static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t /* Dictionary format : Magic == ZSTD_DICT_MAGIC (4 bytes) - Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable + HUF_writeCTable(256) Dictionary content */ -/*! ZSTD_loadDictEntropyStats +/*! ZSTD_loadDictEntropyStats() : @return : size read from dictionary */ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize) { @@ -2160,7 +2191,7 @@ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, si } -/*! ZSTD_compressBegin_advanced +/*! ZSTD_compressBegin_advanced() : * @return : 0, or an error code */ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, const void* dict, size_t dictSize, @@ -2173,6 +2204,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, errorCode = ZSTD_resetCCtx_advanced(zc, params); if (ZSTD_isError(errorCode)) return errorCode; + /* Write Frame Header */ MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */ ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN + ((params.searchLength==3)<<4)); zc->hbSize = ZSTD_frameHeaderSize_min; @@ -2195,8 +2227,8 @@ size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel) } -/*! ZSTD_compressEnd -* Write frame epilogue +/*! ZSTD_compressEnd() : +* Write frame epilogue. * @return : nb of bytes written into dst (or an error code) */ size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize) { diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index bfa398d8b..6e595228f 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -211,6 +211,12 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) bit 4 : minmatch 4(0) or 3(1) bit 5 : reserved (must be zero) bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes + + Optional : content size (0, 1, 2 or 8 bytes) + 0 : unknown + 1 : 0-255 bytes + 2 : 256 - 65535+256 + 8 : up to 16 exa */ From 6de382cdbb37f06bbf3b06810311ce9e8bc56e30 Mon Sep 17 00:00:00 2001 From: Chip Turner Date: Sun, 13 Mar 2016 22:24:46 -0700 Subject: [PATCH 06/49] propagate errors when decompressing; also unlink dstfile if we create it but fail to successfully compress or decompress --- programs/fileio.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 028c7db45..25d75b626 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -428,6 +428,10 @@ static int FIO_compressFilename_extRess(cRess_t ress, result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel); + if (result != 0) { + unlink(dstFileName); + } + fclose(ress.srcFile); /* no pb to expect : only reading */ if (fclose(ress.dstFile)) EXM_THROW(28, "Write error : cannot properly close %s", dstFileName); return result; @@ -633,13 +637,17 @@ static int FIO_decompressSrcFile(dRess_t ress, const char* srcFileName) static int FIO_decompressFile_extRess(dRess_t ress, const char* dstFileName, const char* srcFileName) { + int result; ress.dstFile = FIO_openDstFile(dstFileName); if (ress.dstFile==0) return 1; - FIO_decompressSrcFile(ress, srcFileName); + result = FIO_decompressSrcFile(ress, srcFileName); + if (result != 0) { + unlink(dstFileName); + } if (fclose(ress.dstFile)) EXM_THROW(38, "Write error : cannot properly close %s", dstFileName); - return 0; + return result; } From 9da7f865913756d5ee413e48d6636073f13b8a99 Mon Sep 17 00:00:00 2001 From: Chip Turner Date: Mon, 14 Mar 2016 07:44:59 -0700 Subject: [PATCH 07/49] use remove instead of unlink --- programs/fileio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/fileio.c b/programs/fileio.c index 25d75b626..8f26a4c32 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -429,7 +429,7 @@ static int FIO_compressFilename_extRess(cRess_t ress, result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel); if (result != 0) { - unlink(dstFileName); + remove(dstFileName); } fclose(ress.srcFile); /* no pb to expect : only reading */ @@ -643,7 +643,7 @@ static int FIO_decompressFile_extRess(dRess_t ress, result = FIO_decompressSrcFile(ress, srcFileName); if (result != 0) { - unlink(dstFileName); + remove(dstFileName); } if (fclose(ress.dstFile)) EXM_THROW(38, "Write error : cannot properly close %s", dstFileName); From 97406c9b2cb01946f3d2f08d954d28820f1d011a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 14 Mar 2016 17:05:40 +0100 Subject: [PATCH 08/49] Added test to check decompression error return code --- programs/playTests.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/programs/playTests.sh b/programs/playTests.sh index ec625ee84..891ab9d4e 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -36,7 +36,10 @@ $ZSTD --decompress tmpCompressed --stdout > tmpResult $ZSTD -q tmp && die "overwrite check failed!" $ZSTD -q -f tmp $ZSTD -q --force tmp - +$ZSTD -df tmp && die "should have refused : wrong extension" +cp tmp tmp2.zst +$ZSTD -df tmp2.zst && die "should have failed : wrong format" +rm tmp2.zst echo "\n**** frame concatenation **** " From d1b26849e504bc72a2e3b1e9d247be37f9218d7b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 01:24:33 +0100 Subject: [PATCH 09/49] Frame content size supported --- lib/zstd_compress.c | 148 +++++++++++++++++++++++------------------- lib/zstd_decompress.c | 11 ++-- 2 files changed, 85 insertions(+), 74 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 469410faf..b1b106b2b 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -425,11 +425,11 @@ static void ZSTD_reduceIndex (ZSTD_CCtx* zc, FSE_ENCODING_DYNAMIC : read NCount */ -size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize) +size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) { BYTE* const ostart = (BYTE* const)dst; - if (srcSize + ZSTD_blockHeaderSize > maxDstSize) return ERROR(dstSize_tooSmall); + if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall); memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize); /* Build header */ @@ -442,12 +442,12 @@ size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size } -static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize) { BYTE* const ostart = (BYTE* const)dst; const U32 flSize = 1 + (srcSize>31) + (srcSize>4095); - if (srcSize + flSize > maxDstSize) return ERROR(dstSize_tooSmall); + if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall); switch(flSize) { @@ -470,12 +470,12 @@ static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* return srcSize + flSize; } -static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) { BYTE* const ostart = (BYTE* const)dst; U32 flSize = 1 + (srcSize>31) + (srcSize>4095); - (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough */ + (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */ switch(flSize) { @@ -502,7 +502,7 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, - void* dst, size_t maxDstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize) { const size_t minGain = ZSTD_minGain(srcSize); @@ -512,19 +512,19 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, U32 hType = IS_HUF; size_t clitSize; - if (maxDstSize < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ + if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ if (zc->flagStaticTables && (lhSize==3)) { hType = IS_PCH; singleStream = 1; - clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable); + clitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable); } else { - clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12) - : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12); + clitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12) + : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12); } - if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize); - if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize); + if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); /* Build header */ switch(lhSize) @@ -557,7 +557,7 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, #define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, - void* dst, size_t maxDstSize, + void* dst, size_t dstCapacity, size_t srcSize) { const seqStore_t* seqStorePtr = &(zc->seqStore); @@ -577,7 +577,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, BYTE* const offCodeTable = seqStorePtr->offCodeStart; BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - BYTE* const oend = ostart + maxDstSize; + BYTE* const oend = ostart + dstCapacity; const size_t nbSeq = llPtr - llTable; const size_t minGain = ZSTD_minGain(srcSize); const size_t maxCSize = srcSize - minGain; @@ -590,9 +590,9 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, const size_t minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY; if (litSize <= minLitSize) - cSize = ZSTD_noCompressLiterals(op, maxDstSize, op_lit_start, litSize); + cSize = ZSTD_noCompressLiterals(op, dstCapacity, op_lit_start, litSize); else - cSize = ZSTD_compressLiterals(zc, op, maxDstSize, op_lit_start, litSize); + cSize = ZSTD_compressLiterals(zc, op, dstCapacity, op_lit_start, litSize); if (ZSTD_isError(cSize)) return cSize; op += cSize; } @@ -1940,17 +1940,17 @@ static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int } -static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit); if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */ blockCompressor(zc, src, srcSize); - return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize); + return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize); } static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, - void* dst, size_t maxDstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize) { size_t blockSize = zc->blockSize; @@ -1969,7 +1969,7 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, while (remaining) { size_t cSize; - if (maxDstSize < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ + if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ if (remaining < blockSize) blockSize = remaining; if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */ @@ -1978,11 +1978,11 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit; } - cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize); + cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize); if (ZSTD_isError(cSize)) return cSize; if (cSize == 0) { /* block is not compressible */ - cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); + cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize); if (ZSTD_isError(cSize)) return cSize; } else { op[0] = (BYTE)(cSize>>16); @@ -1993,7 +1993,7 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, } remaining -= blockSize; - maxDstSize -= cSize; + dstCapacity -= cSize; ip += blockSize; op += cSize; } @@ -2077,12 +2077,12 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* zc, } -size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong); zc->params.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */ ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.searchLength); - return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0); + return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0); } @@ -2174,20 +2174,20 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize; } - +/** ZSTD_compress_insertDictionary() : +* @return : 0, or an error code */ static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) { - if (dict && (dictSize>4)) { - U32 magic = MEM_readLE32(dict); - size_t eSize; - if (magic != ZSTD_DICT_MAGIC) - return ZSTD_loadDictionaryContent(zc, dict, dictSize); + if ((dict==NULL) || (dictSize<=4)) return 0; - eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4; - if (ZSTD_isError(eSize)) return eSize; - return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize); + /* default : dict is pure content */ + if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize); + + /* known magic number : dict is parsed for entropy stats and content */ + { size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4 /* skip magic */, dictSize-4) + 4; + if (ZSTD_isError(eSize)) return eSize; + return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize); } - return 0; } @@ -2197,27 +2197,42 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, const void* dict, size_t dictSize, ZSTD_parameters params) { - size_t errorCode; - ZSTD_validateParams(¶ms); - errorCode = ZSTD_resetCCtx_advanced(zc, params); - if (ZSTD_isError(errorCode)) return errorCode; + { size_t const errorCode = ZSTD_resetCCtx_advanced(zc, params); + if (ZSTD_isError(errorCode)) return errorCode; } + + /* Write Frame Header into ctx headerBuffer */ + MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); + { + U32 const fcsSize[4] = { 0, 1, 2, 8 }; + U32 const fcsId = (params.srcSize>0) + (params.srcSize>=256) + (params.srcSize>=65536+256); /* 0-3 */ + BYTE fdescriptor = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); /* windowLog : 4 KB - 128 MB */ + fdescriptor |= (BYTE)((params.searchLength==3)<<4); /* mml : 3-4 */ + fdescriptor |= (BYTE)(fcsId << 6); + ((BYTE*)zc->headerBuffer)[4] = fdescriptor; + switch(fcsId) + { + default: /* impossible */ + case 0 : break; + case 1 : ((BYTE*)zc->headerBuffer)[5] = (BYTE)(params.srcSize); break; + case 2 : MEM_writeLE16(((BYTE*)zc->headerBuffer)+5, (U16)(params.srcSize-256)); break; + case 3 : MEM_writeLE64(((BYTE*)zc->headerBuffer)+5, (U64)(params.srcSize)); break; + } + zc->hbSize = ZSTD_frameHeaderSize_min + fcsSize[fcsId]; + } - /* Write Frame Header */ - MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */ - ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN + ((params.searchLength==3)<<4)); - zc->hbSize = ZSTD_frameHeaderSize_min; zc->stage = 0; - return ZSTD_compress_insertDictionary(zc, dict, dictSize); } size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel) { + ZSTD_parameters params = ZSTD_getParams(compressionLevel, dictSize); + params.srcSize = 0; ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel); - return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize))); + return ZSTD_compressBegin_advanced(zc, dict, dictSize, params); } size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel) @@ -2230,7 +2245,7 @@ size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel) /*! ZSTD_compressEnd() : * Write frame epilogue. * @return : nb of bytes written into dst (or an error code) */ -size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize) +size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t dstCapacity) { BYTE* op = (BYTE*)dst; size_t hbSize = 0; @@ -2238,15 +2253,15 @@ size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize) /* empty frame */ if (zc->stage==0) { hbSize = zc->hbSize; - if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall); + if (dstCapacity <= hbSize) return ERROR(dstSize_tooSmall); zc->stage = 1; memcpy(dst, zc->headerBuffer, hbSize); - maxDstSize -= hbSize; + dstCapacity -= hbSize; op += hbSize; } /* frame epilogue */ - if (maxDstSize < 3) return ERROR(dstSize_tooSmall); + if (dstCapacity < 3) return ERROR(dstSize_tooSmall); op[0] = (BYTE)(bt_end << 6); op[1] = 0; op[2] = 0; @@ -2256,16 +2271,16 @@ size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize) size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, - void* dst, size_t maxDstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize) { size_t outSize; size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx); if (ZSTD_isError(errorCode)) return errorCode; - errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize); + errorCode = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize); if (ZSTD_isError(errorCode)) return errorCode; outSize = errorCode; - errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize); + errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, dstCapacity-outSize); if (ZSTD_isError(errorCode)) return errorCode; outSize += errorCode; return outSize; @@ -2273,51 +2288,50 @@ size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* prepare size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, - void* dst, size_t maxDstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict,size_t dictSize, ZSTD_parameters params) { BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - size_t oSize; /* Init */ - oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params); - if(ZSTD_isError(oSize)) return oSize; + { size_t const errorCode = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params); + if(ZSTD_isError(errorCode)) return errorCode; } /* body (compression) */ - oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize); + { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize); if(ZSTD_isError(oSize)) return oSize; op += oSize; - maxDstSize -= oSize; + dstCapacity -= oSize; } /* Close frame */ - oSize = ZSTD_compressEnd(ctx, op, maxDstSize); + { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity); if(ZSTD_isError(oSize)) return oSize; - op += oSize; + op += oSize; } return (op - ostart); } -size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel) +size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel) { ZSTD_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel); - return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize)); + return ZSTD_compress_advanced(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize)); } -size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel) +size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) { ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel); - return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize)); + return ZSTD_compress_advanced(ctx, dst, dstCapacity, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize)); } -size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel) +size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) { size_t result; ZSTD_CCtx ctxBody; memset(&ctxBody, 0, sizeof(ctxBody)); - result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel); + result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */ return result; } diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 6e595228f..736e0a275 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -307,15 +307,13 @@ static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) * or an error code, which can be tested using ZSTD_isError() */ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize) { - U32 magicNumber, fcsId; const BYTE* ip = (const BYTE*)src; BYTE frameDesc; if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_min; - magicNumber = MEM_readLE32(src); - if (magicNumber != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); + if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); - { size_t fhsize = ZSTD_frameHeaderSize(src, srcSize); + { size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize); if (srcSize < fhsize) return fhsize; } memset(fparamsPtr, 0, sizeof(*fparamsPtr)); @@ -323,13 +321,12 @@ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t fparamsPtr->windowLog = (frameDesc & 0xF) + ZSTD_WINDOWLOG_ABSOLUTEMIN; fparamsPtr->mml = (frameDesc & 0x10) ? MINMATCH-1 : MINMATCH; if ((frameDesc & 0x20) != 0) return ERROR(frameParameter_unsupported); /* reserved 1 bit */ - fcsId = frameDesc >> 6; - switch(fcsId) + switch(frameDesc >> 6) /* fcsId */ { default: /* impossible */ case 0 : fparamsPtr->frameContentSize = 0; break; case 1 : fparamsPtr->frameContentSize = ip[5]; break; - case 2 : fparamsPtr->frameContentSize = MEM_readLE16(ip+5); break; + case 2 : fparamsPtr->frameContentSize = MEM_readLE16(ip+5)+256; break; case 3 : fparamsPtr->frameContentSize = MEM_readLE64(ip+5); break; } return 0; From 1c2c2bcaffb95a9516b907aec35c2ae7a8183b09 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 01:33:36 +0100 Subject: [PATCH 10/49] minor refactoring --- lib/zstd_compress.c | 9 +++++---- lib/zstd_decompress.c | 33 ++++++++++++++++----------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index b1b106b2b..6afcddeb8 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2205,19 +2205,20 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, /* Write Frame Header into ctx headerBuffer */ MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); { + BYTE* const op = (BYTE*)zc->headerBuffer; U32 const fcsSize[4] = { 0, 1, 2, 8 }; U32 const fcsId = (params.srcSize>0) + (params.srcSize>=256) + (params.srcSize>=65536+256); /* 0-3 */ BYTE fdescriptor = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); /* windowLog : 4 KB - 128 MB */ fdescriptor |= (BYTE)((params.searchLength==3)<<4); /* mml : 3-4 */ fdescriptor |= (BYTE)(fcsId << 6); - ((BYTE*)zc->headerBuffer)[4] = fdescriptor; + op[4] = fdescriptor; switch(fcsId) { default: /* impossible */ case 0 : break; - case 1 : ((BYTE*)zc->headerBuffer)[5] = (BYTE)(params.srcSize); break; - case 2 : MEM_writeLE16(((BYTE*)zc->headerBuffer)+5, (U16)(params.srcSize-256)); break; - case 3 : MEM_writeLE64(((BYTE*)zc->headerBuffer)+5, (U64)(params.srcSize)); break; + case 1 : op[5] = (BYTE)(params.srcSize); break; + case 2 : MEM_writeLE16(op+5, (U16)(params.srcSize-256)); break; + case 3 : MEM_writeLE64(op+5, (U64)(params.srcSize)); break; } zc->hbSize = ZSTD_frameHeaderSize_min + fcsSize[fcsId]; } diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 736e0a275..4007541c7 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -303,39 +303,38 @@ static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) /** ZSTD_getFrameParams() : * decode Frame Header, or provide expected `srcSize`. * @return : 0, `fparamsPtr` is correctly filled, -* >0, not enough srcSize, provide expected `srcSize`, +* >0, `srcSize` is too small, result is expected `srcSize`, * or an error code, which can be tested using ZSTD_isError() */ -size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize) +size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t const srcSize) { const BYTE* ip = (const BYTE*)src; - BYTE frameDesc; if (srcSize < ZSTD_frameHeaderSize_min) return ZSTD_frameHeaderSize_min; if (MEM_readLE32(src) != ZSTD_MAGICNUMBER) return ERROR(prefix_unknown); + /* ensure there is enough `srcSize` to fully read/decode frame header */ { size_t const fhsize = ZSTD_frameHeaderSize(src, srcSize); if (srcSize < fhsize) return fhsize; } memset(fparamsPtr, 0, sizeof(*fparamsPtr)); - frameDesc = ip[4]; - fparamsPtr->windowLog = (frameDesc & 0xF) + ZSTD_WINDOWLOG_ABSOLUTEMIN; - fparamsPtr->mml = (frameDesc & 0x10) ? MINMATCH-1 : MINMATCH; - if ((frameDesc & 0x20) != 0) return ERROR(frameParameter_unsupported); /* reserved 1 bit */ - switch(frameDesc >> 6) /* fcsId */ - { - default: /* impossible */ - case 0 : fparamsPtr->frameContentSize = 0; break; - case 1 : fparamsPtr->frameContentSize = ip[5]; break; - case 2 : fparamsPtr->frameContentSize = MEM_readLE16(ip+5)+256; break; - case 3 : fparamsPtr->frameContentSize = MEM_readLE64(ip+5); break; - } + { BYTE const frameDesc = ip[4]; + fparamsPtr->windowLog = (frameDesc & 0xF) + ZSTD_WINDOWLOG_ABSOLUTEMIN; + fparamsPtr->mml = (frameDesc & 0x10) ? MINMATCH-1 : MINMATCH; + if ((frameDesc & 0x20) != 0) return ERROR(frameParameter_unsupported); /* reserved 1 bit */ + switch(frameDesc >> 6) /* fcsId */ + { + default: /* impossible */ + case 0 : fparamsPtr->frameContentSize = 0; break; + case 1 : fparamsPtr->frameContentSize = ip[5]; break; + case 2 : fparamsPtr->frameContentSize = MEM_readLE16(ip+5)+256; break; + case 3 : fparamsPtr->frameContentSize = MEM_readLE64(ip+5); break; + } } return 0; } /** ZSTD_decodeFrameHeader() : -* decode Frame Header. -* srcSize must be the size provided by ZSTD_decodeFrameHeader_Part1(). +* `srcSize` must be the size provided by ZSTD_frameHeaderSize(). * @return : 0, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* zc, const void* src, size_t srcSize) { From 09b21ee2f67b4fd1dd2bfccb538d38f7811b8ad6 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 12:56:03 +0100 Subject: [PATCH 11/49] fix fileio bug with new zbuff simplified zbuff decoding --- lib/zbuff.c | 115 ++++++++++++++---------------------------- lib/zstd_decompress.c | 2 +- programs/fileio.c | 37 +++++++++----- 3 files changed, 62 insertions(+), 92 deletions(-) diff --git a/lib/zbuff.c b/lib/zbuff.c index 69341df8e..a08060cf4 100644 --- a/lib/zbuff.c +++ b/lib/zbuff.c @@ -40,7 +40,7 @@ ***************************************/ #include #include "error_private.h" -#include "zstd_static.h" +#include "zstd_internal.h" #include "zbuff_static.h" @@ -50,7 +50,7 @@ static size_t ZBUFF_blockHeaderSize = 3; static size_t ZBUFF_endFrameSize = 3; -/** ************************************************ +/*_************************************************** * Streaming compression * * A ZBUFF_CCtx object is required to track streaming operation. @@ -88,13 +88,13 @@ typedef enum { ZBUFFcs_init, ZBUFFcs_load, ZBUFFcs_flush } ZBUFF_cStage; /* *** Ressources *** */ struct ZBUFF_CCtx_s { ZSTD_CCtx* zc; - char* inBuff; + char* inBuff; size_t inBuffSize; size_t inToCompress; size_t inBuffPos; size_t inBuffTarget; size_t blockSize; - char* outBuff; + char* outBuff; size_t outBuffSize; size_t outBuffContentSize; size_t outBuffFlushedSize; @@ -123,8 +123,6 @@ size_t ZBUFF_freeCCtx(ZBUFF_CCtx* zbc) /* *** Initialization *** */ -#define MIN(a,b) ( ((a)<(b)) ? (a) : (b) ) -#define BLOCKSIZE (128 * 1024) /* a bit too "magic", should come from reference */ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, const void* dict, size_t dictSize, ZSTD_parameters params) { size_t neededInBuffSize; @@ -172,9 +170,9 @@ ZSTDLIB_API size_t ZBUFF_compressInitDictionary(ZBUFF_CCtx* zbc, const void* dic /* *** Compression *** */ -static size_t ZBUFF_limitCopy(void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static size_t ZBUFF_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - size_t length = MIN(maxDstSize, srcSize); + size_t length = MIN(dstCapacity, srcSize); memcpy(dst, src, length); return length; } @@ -322,12 +320,10 @@ size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr) * just follow indications from ZBUFF_decompressContinue() to minimize latency. It should always be <= 128 KB + 3 . * *******************************************************************************/ -typedef enum { ZBUFFds_init, ZBUFFds_readHeader, ZBUFFds_loadHeader, ZBUFFds_decodeHeader, +typedef enum { ZBUFFds_init, ZBUFFds_readHeader, ZBUFFds_read, ZBUFFds_load, ZBUFFds_flush } ZBUFF_dStage; /* *** Resource management *** */ - -#define ZSTD_frameHeaderSize_max 5 /* too magical, should come from reference */ struct ZBUFF_DCtx_s { ZSTD_DCtx* zc; ZSTD_frameParams fParams; @@ -338,9 +334,7 @@ struct ZBUFF_DCtx_s { size_t outBuffSize; size_t outStart; size_t outEnd; - size_t hPos; ZBUFF_dStage stage; - unsigned char headerBuffer[ZSTD_frameHeaderSize_max]; }; /* typedef'd to ZBUFF_DCtx within "zstd_buffered.h" */ @@ -370,7 +364,7 @@ size_t ZBUFF_freeDCtx(ZBUFF_DCtx* zbc) size_t ZBUFF_decompressInitDictionary(ZBUFF_DCtx* zbc, const void* dict, size_t dictSize) { zbc->stage = ZBUFFds_readHeader; - zbc->hPos = zbc->inPos = zbc->outStart = zbc->outEnd = 0; + zbc->inPos = zbc->outStart = zbc->outEnd = 0; return ZSTD_decompressBegin_usingDict(zbc->zc, dict, dictSize); } @@ -402,69 +396,36 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, case ZBUFFds_readHeader : /* read header from src */ - { - size_t headerSize = ZSTD_getFrameParams(&(zbc->fParams), src, *srcSizePtr); + { size_t const headerSize = ZSTD_getFrameParams(&(zbc->fParams), src, *srcSizePtr); if (ZSTD_isError(headerSize)) return headerSize; if (headerSize) { - /* not enough input to decode header : tell how many bytes would be necessary */ - memcpy(zbc->headerBuffer+zbc->hPos, src, *srcSizePtr); - zbc->hPos += *srcSizePtr; + /* not enough input to decode header : needs headerSize > *srcSizePtr */ *dstCapacityPtr = 0; - zbc->stage = ZBUFFds_loadHeader; - return headerSize - zbc->hPos; - } - zbc->stage = ZBUFFds_decodeHeader; - break; - } + *srcSizePtr = 0; + return headerSize; + } } - case ZBUFFds_loadHeader: - /* complete header from src */ + /* Frame header provides buffer sizes */ + { size_t const neededInSize = BLOCKSIZE; /* a block is never > BLOCKSIZE */ + if (zbc->inBuffSize < neededInSize) { + free(zbc->inBuff); + zbc->inBuffSize = neededInSize; + zbc->inBuff = (char*)malloc(neededInSize); + if (zbc->inBuff == NULL) return ERROR(memory_allocation); + } } { - size_t headerSize = ZBUFF_limitCopy( - zbc->headerBuffer + zbc->hPos, ZSTD_frameHeaderSize_max - zbc->hPos, - src, *srcSizePtr); - zbc->hPos += headerSize; - ip += headerSize; - headerSize = ZSTD_getFrameParams(&(zbc->fParams), zbc->headerBuffer, zbc->hPos); - if (ZSTD_isError(headerSize)) return headerSize; - if (headerSize) { - /* not enough input to decode header : tell how many bytes would be necessary */ - *dstCapacityPtr = 0; - return headerSize - zbc->hPos; - } - // zbc->stage = ZBUFFds_decodeHeader; break; /* useless : stage follows */ - } - - case ZBUFFds_decodeHeader: - /* apply header to create / resize buffers */ - { - size_t neededOutSize = (size_t)1 << zbc->fParams.windowLog; - size_t neededInSize = BLOCKSIZE; /* a block is never > BLOCKSIZE */ - if (zbc->inBuffSize < neededInSize) { - free(zbc->inBuff); - zbc->inBuffSize = neededInSize; - zbc->inBuff = (char*)malloc(neededInSize); - if (zbc->inBuff == NULL) return ERROR(memory_allocation); - } - if (zbc->outBuffSize < neededOutSize) { - free(zbc->outBuff); - zbc->outBuffSize = neededOutSize; - zbc->outBuff = (char*)malloc(neededOutSize); - if (zbc->outBuff == NULL) return ERROR(memory_allocation); - } } - if (zbc->hPos) { - /* some data already loaded into headerBuffer : transfer into inBuff */ - memcpy(zbc->inBuff, zbc->headerBuffer, zbc->hPos); - zbc->inPos = zbc->hPos; - zbc->hPos = 0; - zbc->stage = ZBUFFds_load; - break; - } - zbc->stage = ZBUFFds_read; + size_t const neededOutSize = (size_t)1 << zbc->fParams.windowLog; + if (zbc->outBuffSize < neededOutSize) { + free(zbc->outBuff); + zbc->outBuffSize = neededOutSize; + zbc->outBuff = (char*)malloc(neededOutSize); + if (zbc->outBuff == NULL) return ERROR(memory_allocation); + } } + zbc->stage = ZBUFFds_read; case ZBUFFds_read: { - size_t neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); + size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); if (neededInSize==0) { /* end of frame */ zbc->stage = ZBUFFds_init; notDone = 0; @@ -472,7 +433,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, } if ((size_t)(iend-ip) >= neededInSize) { /* directly decode from src */ - size_t decodedSize = ZSTD_decompressContinue(zbc->zc, + size_t const decodedSize = ZSTD_decompressContinue(zbc->zc, zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart, ip, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; @@ -488,8 +449,8 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, case ZBUFFds_load: { - size_t neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); - size_t toLoad = neededInSize - zbc->inPos; /* should always be <= remaining space within inBuff */ + size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zbc->zc); + size_t const toLoad = neededInSize - zbc->inPos; /* should always be <= remaining space within inBuff */ size_t loadedSize; if (toLoad > zbc->inBuffSize - zbc->inPos) return ERROR(corruption_detected); /* should never happen */ loadedSize = ZBUFF_limitCopy(zbc->inBuff + zbc->inPos, toLoad, ip, iend-ip); @@ -497,7 +458,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, zbc->inPos += loadedSize; if (loadedSize < toLoad) { notDone = 0; break; } /* not enough input, wait for more */ { - size_t decodedSize = ZSTD_decompressContinue(zbc->zc, + size_t const decodedSize = ZSTD_decompressContinue(zbc->zc, zbc->outBuff + zbc->outStart, zbc->outBuffSize - zbc->outStart, zbc->inBuff, neededInSize); if (ZSTD_isError(decodedSize)) return decodedSize; @@ -509,8 +470,8 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, } } case ZBUFFds_flush: { - size_t toFlushSize = zbc->outEnd - zbc->outStart; - size_t flushedSize = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize); + size_t const toFlushSize = zbc->outEnd - zbc->outStart; + size_t const flushedSize = ZBUFF_limitCopy(op, oend-op, zbc->outBuff + zbc->outStart, toFlushSize); op += flushedSize; zbc->outStart += flushedSize; if (flushedSize == toFlushSize) { @@ -526,12 +487,12 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, default: return ERROR(GENERIC); /* impossible */ } } + /* result */ *srcSizePtr = ip-istart; *dstCapacityPtr = op-ostart; - { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbc->zc); - if (nextSrcSizeHint > ZBUFF_blockHeaderSize) nextSrcSizeHint+= ZBUFF_blockHeaderSize; /* get next block header too */ + if (nextSrcSizeHint > ZBUFF_blockHeaderSize) nextSrcSizeHint+= ZBUFF_blockHeaderSize; /* get following block header too */ nextSrcSizeHint -= zbc->inPos; /* already loaded*/ return nextSrcSizeHint; } diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 4007541c7..685e6de44 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -305,7 +305,7 @@ static size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize) * @return : 0, `fparamsPtr` is correctly filled, * >0, `srcSize` is too small, result is expected `srcSize`, * or an error code, which can be tested using ZSTD_isError() */ -size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t const srcSize) +size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t srcSize) { const BYTE* ip = (const BYTE*)src; diff --git a/programs/fileio.c b/programs/fileio.c index c0ec891e3..907d990a1 100644 --- a/programs/fileio.c +++ b/programs/fileio.c @@ -64,7 +64,7 @@ #include /* stat64 */ #include "mem.h" #include "fileio.h" -#include "zstd_static.h" /* ZSTD_magicNumber */ +#include "zstd_static.h" /* ZSTD_magicNumber, ZSTD_frameHeaderSize_max */ #include "zbuff_static.h" #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) @@ -242,7 +242,7 @@ static FILE* FIO_openDstFile(const char* dstFileName) /*! FIO_loadFile() : -* creates a buffer, pointed by *bufferPtr, +* creates a buffer, pointed by `*bufferPtr`, * loads `filename` content into it, * up to MAX_DICT_SIZE bytes */ @@ -342,6 +342,7 @@ static int FIO_compressFilename_internal(cRess_t ress, /* init */ filesize = MAX(FIO_getFileSize(srcFileName),dictSize); params = ZSTD_getParams(cLevel, filesize); + params.srcSize = filesize; if (g_maxWLog) if (params.windowLog > g_maxWLog) params.windowLog = g_maxWLog; errorCode = ZBUFF_compressInit_advanced(ress.ctx, ress.dictBuffer, ress.dictBufferSize, params); if (ZBUFF_isError(errorCode)) EXM_THROW(21, "Error initializing compression : %s", ZBUFF_getErrorName(errorCode)); @@ -394,7 +395,7 @@ static int FIO_compressFilename_internal(cRess_t ress, /*! FIO_compressFilename_internal() : - * same as FIO_compressFilename_extRess(), with ress.desFile already opened + * same as FIO_compressFilename_extRess(), with ress.destFile already opened (typically stdout) * @return : 0 : compression completed correctly, * 1 : missing or pb opening srcFileName */ @@ -432,10 +433,7 @@ static int FIO_compressFilename_extRess(cRess_t ress, if (ress.dstFile==0) { fclose(ress.srcFile); return 1; } result = FIO_compressFilename_internal(ress, dstFileName, srcFileName, cLevel); - - if (result != 0) { - remove(dstFileName); - } + if (result!=0) remove(dstFileName); /* remove operation artefact */ fclose(ress.srcFile); /* no pb to expect : only reading */ if (fclose(ress.dstFile)) EXM_THROW(28, "Write error : cannot properly close %s", dstFileName); @@ -556,35 +554,46 @@ static void FIO_freeDResources(dRess_t ress) } +/** FIO_decompressFrame() : + @return : size of decoded frame +*/ unsigned long long FIO_decompressFrame(dRess_t ress, FILE* foutput, FILE* finput, size_t alreadyLoaded) { U64 frameSize = 0; - size_t readSize=alreadyLoaded; + size_t readSize; + + ZBUFF_decompressInitDictionary(ress.dctx, ress.dictBuffer, ress.dictBufferSize); + + /* Complete Header loading */ + { size_t const toLoad = ZSTD_frameHeaderSize_max - alreadyLoaded; /* assumption : alreadyLoaded <= ZSTD_frameHeaderSize_max */ + size_t const checkSize = fread(((char*)ress.srcBuffer) + alreadyLoaded, 1, toLoad, finput); + if (checkSize != toLoad) EXM_THROW(32, "Read error"); + } + readSize = ZSTD_frameHeaderSize_max; /* Main decompression Loop */ - ZBUFF_decompressInitDictionary(ress.dctx, ress.dictBuffer, ress.dictBufferSize); while (1) { /* Decode */ - size_t sizeCheck; size_t inSize=readSize, decodedSize=ress.dstBufferSize; size_t toRead = ZBUFF_decompressContinue(ress.dctx, ress.dstBuffer, &decodedSize, ress.srcBuffer, &inSize); if (ZBUFF_isError(toRead)) EXM_THROW(36, "Decoding error : %s", ZBUFF_getErrorName(toRead)); readSize -= inSize; /* Write block */ - sizeCheck = fwrite(ress.dstBuffer, 1, decodedSize, foutput); - if (sizeCheck != decodedSize) EXM_THROW(37, "Write error : unable to write data block to destination file"); + { size_t const sizeCheck = fwrite(ress.dstBuffer, 1, decodedSize, foutput); + if (sizeCheck != decodedSize) EXM_THROW(37, "Write error : unable to write data block into destination"); } frameSize += decodedSize; DISPLAYUPDATE(2, "\rDecoded : %u MB... ", (U32)(frameSize>>20) ); - if (toRead == 0) break; + if (toRead == 0) break; /* end of frame */ if (readSize) EXM_THROW(38, "Decoding error : should consume entire input"); /* Fill input buffer */ if (toRead > ress.srcBufferSize) EXM_THROW(34, "too large block"); readSize = fread(ress.srcBuffer, 1, toRead, finput); - if (readSize != toRead) EXM_THROW(35, "Read error"); + if (readSize != toRead) + EXM_THROW(35, "Read error"); } return frameSize; From 346bffbc681d9b2aab9b041c228a040f71796a35 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 15:24:52 +0100 Subject: [PATCH 12/49] Added frame content size test within fuzzer --- lib/zstd_decompress.c | 2 +- programs/fuzzer.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 685e6de44..6508dbcd4 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -1033,7 +1033,7 @@ size_t ZSTD_decompress(void* dst, size_t maxDstSize, const void* src, size_t src } -/* ****************************** +/*_****************************** * Streaming Decompression API ********************************/ size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) diff --git a/programs/fuzzer.c b/programs/fuzzer.c index 697695b38..55e0c7d70 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -513,8 +513,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit CHECK(ZSTD_isError(cSize), "ZSTD_compressCCtx failed"); /* compression failure test : too small dest buffer */ - if (cSize > 3) - { + if (cSize > 3) { const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */ const size_t tooSmallSize = cSize - missing; static const U32 endMark = 0x4DC2B1A9; @@ -526,6 +525,13 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); } + /* decompression header test */ + { ZSTD_frameParams dParams; + size_t const check = ZSTD_getFrameParams(&dParams, cBuffer, cSize); + CHECK(ZSTD_isError(check), "Frame Parameters extraction failed"); + CHECK(dParams.frameContentSize != sampleSize, "Frame content size incorrect"); + } + /* successfull decompression tests*/ dSupSize = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1; dSize = ZSTD_decompress(dstBuffer, sampleSize + dSupSize, cBuffer, cSize); From 6cb41356e8a93920909185e94872c69d17820c03 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 15:47:38 +0100 Subject: [PATCH 13/49] update doc / comments --- NEWS | 4 ++++ lib/zstd_static.h | 9 ++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index ccbf15eb5..f1d4ed214 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +v0.6.0 +Stronger high compression modes, thanks to Przemyslaw Skibinski +API : ZSTD_getFrameParams() provides size of decompressed content + v0.5.1 New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski Changed : Dictionary builder integrated into libzstd and zstd cli diff --git a/lib/zstd_static.h b/lib/zstd_static.h index f6eb8aa39..be67784ef 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -187,11 +187,14 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds A ZSTD_DCtx object can be re-used multiple times. First optional operation is to retrieve frame parameters, using ZSTD_getFrameParams(). - It requires to read the beginning of compressed frame. + It can provide the minimum size of buffer required to properly decompress data, + and optionally the final size of uncompressed content. + (Note : content size is an optional info that may not be present. 0 means : content size unknown) + It is done by reading a certain amount of the beginning of compressed frame. The amount of data to read is variable, from ZSTD_frameHeaderSize_min to ZSTD_frameHeaderSize_max. - If you don't provide enough length, function will return the minimum size it wants to produce a result. + If `srcSize` is too small for operation to succeed, function will return the minimum size it requires to produce a result. Result : 0 when successful, it means the ZSTD_frameParams structure has been filled. - >0 : means there is not enough data into src. Provides the expected size to successfully decode header. + >0 : means there is not enough data into `src`. Provides the expected size to successfully decode header. errorCode, which can be tested using ZSTD_isError() Start decompression, with ZSTD_decompressBegin() or ZSTD_decompressBegin_usingDict(). From 34b20ec2c6a8fe7a0bfbc162791ff841721144b8 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 20:47:23 +0100 Subject: [PATCH 14/49] fullbench can measure speed of zbuff --- NEWS | 1 + programs/Makefile | 4 +- programs/fullbench.c | 117 ++++++++++++++++++++++++++----------------- 3 files changed, 74 insertions(+), 48 deletions(-) diff --git a/NEWS b/NEWS index f1d4ed214..f78cd65fb 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ v0.6.0 Stronger high compression modes, thanks to Przemyslaw Skibinski API : ZSTD_getFrameParams() provides size of decompressed content +New : highest compression modes require `--ultra` command to fully unleash their capacity v0.5.1 New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski diff --git a/programs/Makefile b/programs/Makefile index 4a650c488..ca2ba99fc 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -112,11 +112,11 @@ zstd-frugal: $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c zstdcli.c fileio.c zstd-small: clean CFLAGS="-Os -s" $(MAKE) zstd-frugal -fullbench : $(ZSTD_FILES) \ +fullbench : $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c \ datagen.c fullbench.c $(CC) $(FLAGS) $^ -o $@$(EXT) -fullbench32: $(ZSTD_FILES) \ +fullbench32: $(ZSTD_FILES) $(ZSTDDIR)/zbuff.c \ datagen.c fullbench.c $(CC) -m32 $(FLAGS) $^ -o $@$(EXT) diff --git a/programs/fullbench.c b/programs/fullbench.c index 0eeb88e85..8d9e57d6c 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -1,6 +1,6 @@ /* fullbench.c - Detailed bench program for zstd - Copyright (C) Yann Collet 2014-2015 + Copyright (C) Yann Collet 2014-2016 GPL v2 License @@ -19,11 +19,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd - - ztsd public forum : https://groups.google.com/forum/#!forum/lz4c + - zstd homepage : http://www.zstd.net */ -/************************************** +/*_************************************ * Compiler Options **************************************/ /* Disable some Visual warning messages */ @@ -44,7 +43,7 @@ #endif -/************************************** +/*_************************************ * Includes **************************************/ #include /* malloc */ @@ -63,10 +62,11 @@ #include "mem.h" #include "zstd_static.h" #include "fse_static.h" +#include "zbuff.h" #include "datagen.h" -/************************************** +/*_************************************ * Compiler Options **************************************/ /* S_ISREG & gettimeofday() are not supported by MSVC */ @@ -75,7 +75,7 @@ #endif -/************************************** +/*_************************************ * Constants **************************************/ #define PROGRAM_DESCRIPTION "Zstandard speed analyzer" @@ -100,13 +100,13 @@ static const size_t sampleSize = 10000000; -/************************************** +/*_************************************ * Macros **************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) -/************************************** +/*_************************************ * Benchmark Parameters **************************************/ static int nbIterations = NBLOOPS; @@ -119,7 +119,7 @@ void BMK_SetNbIterations(int nbLoops) } -/********************************************************* +/*_******************************************************* * Private functions *********************************************************/ @@ -156,8 +156,7 @@ static int BMK_GetMilliStart(void) static int BMK_GetMilliSpan( int nTimeStart ) { int nSpan = BMK_GetMilliStart() - nTimeStart; - if ( nSpan < 0 ) - nSpan += 0x100000 * 1000; + if ( nSpan < 0 ) nSpan += 0x100000 * 1000; return nSpan; } @@ -165,16 +164,15 @@ static int BMK_GetMilliSpan( int nTimeStart ) static size_t BMK_findMaxMem(U64 requiredMem) { size_t step = 64 MB; - BYTE* testmem=NULL; + void* testmem = NULL; requiredMem = (((requiredMem >> 26) + 1) << 26); if (requiredMem > MAX_MEM) requiredMem = MAX_MEM; requiredMem += 2*step; - while (!testmem) - { + while (!testmem) { requiredMem -= step; - testmem = (BYTE*) malloc ((size_t)requiredMem); + testmem = malloc ((size_t)requiredMem); } free (testmem); @@ -197,12 +195,11 @@ static U64 BMK_GetFileSize(char* infilename) } -/********************************************************* +/*_******************************************************* * Benchmark wrappers *********************************************************/ typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; -typedef struct -{ +typedef struct { blockType_t blockType; U32 unusedBits; U32 origSize; @@ -211,9 +208,6 @@ typedef struct static size_t g_cSize = 0; static ZSTD_DCtx* g_dctxPtr = NULL; -extern size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr); -extern size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, const void* src, size_t srcSize); - size_t local_ZSTD_compress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) { (void)buff2; @@ -233,6 +227,8 @@ size_t local_ZSTD_decodeLiteralsBlock(void* dst, size_t dstSize, void* buff2, co return ZSTD_decodeLiteralsBlock((ZSTD_DCtx*)g_dctxPtr, buff2, g_cSize); } +extern size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr); +extern size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, const void* src, size_t srcSize); size_t local_ZSTD_decodeSeqHeaders(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) { U32 DTableML[FSE_DTABLE_SIZE_U32(10)], DTableLL[FSE_DTABLE_SIZE_U32(10)], DTableOffb[FSE_DTABLE_SIZE_U32(9)]; /* MLFSELog, LLFSELog and OffFSELog are not public values */ @@ -244,8 +240,34 @@ size_t local_ZSTD_decodeSeqHeaders(void* dst, size_t dstSize, void* buff2, const } +static ZBUFF_CCtx* g_zbcc = NULL; +size_t local_ZBUFF_compress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) +{ + size_t compressedSize; + size_t srcRead = srcSize, dstWritten = dstSize; + (void)buff2; + ZBUFF_compressInit(g_zbcc, 1); + ZBUFF_compressContinue(g_zbcc, dst, &dstWritten, src, &srcRead); + compressedSize = dstWritten; + dstWritten = dstSize-compressedSize; + ZBUFF_compressEnd(g_zbcc, ((char*)dst)+compressedSize, &dstWritten); + compressedSize += dstWritten; + return compressedSize; +} -/********************************************************* +static ZBUFF_DCtx* g_zbdc = NULL; +size_t local_ZBUFF_decompress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) +{ + size_t srcRead = g_cSize, dstWritten = dstSize; + (void)src; (void)srcSize; + ZBUFF_decompressInit(g_zbdc); + ZBUFF_decompressContinue(g_zbdc, dst, &dstWritten, buff2, &srcRead); + return dstWritten; +} + + + +/*_******************************************************* * Bench functions *********************************************************/ size_t benchMem(void* src, size_t srcSize, U32 benchNb) @@ -274,6 +296,12 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) case 32: benchFunction = local_ZSTD_decodeSeqHeaders; benchName = "ZSTD_decodeSeqHeaders"; break; + case 41: + benchFunction = local_ZBUFF_compress; benchName = "ZBUFF_compressContinue"; + break; + case 42: + benchFunction = local_ZBUFF_decompress; benchName = "ZBUFF_decompressContinue"; + break; default : return 0; } @@ -283,8 +311,7 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) dstBuff = (BYTE*)malloc(dstBuffSize); buff2 = (BYTE*)malloc(dstBuffSize); g_dctxPtr = ZSTD_createDCtx(); - if ((!dstBuff) || (!buff2)) - { + if ((!dstBuff) || (!buff2)) { DISPLAY("\nError: not enough memory!\n"); free(dstBuff); free(buff2); return 12; @@ -301,8 +328,7 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) blockProperties_t bp; g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); ZSTD_getcBlockSize(dstBuff+4, dstBuffSize, &bp); /* Get 1st block type */ - if (bp.blockType != bt_compressed) - { + if (bp.blockType != bt_compressed) { DISPLAY("ZSTD_decodeLiteralsBlock : impossible to test on this sample (not compressible)\n"); goto _cleanOut; } @@ -332,6 +358,13 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */ break; } + case 41 : + if (g_zbcc==NULL) g_zbcc=ZBUFF_createCCtx(); + break; + case 42 : + if (g_zbdc==NULL) g_zbdc=ZBUFF_createDCtx(); + g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1); + break; /* test functions */ /* by convention, test functions can be added > 100 */ @@ -352,8 +385,7 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) milliTime = BMK_GetMilliStart(); while(BMK_GetMilliStart() == milliTime); milliTime = BMK_GetMilliStart(); - while(BMK_GetMilliSpan(milliTime) < TIMELOOP) - { + while(BMK_GetMilliSpan(milliTime) < TIMELOOP) { errorCode = benchFunction(dstBuff, dstBuffSize, buff2, src, srcSize); if (ZSTD_isError(errorCode)) { DISPLAY("ERROR ! %s() => %s !! \n", benchName, ZSTD_getErrorName(errorCode)); exit(1); } nbRounds++; @@ -383,8 +415,7 @@ int benchSample(U32 benchNb) /* Allocation */ origBuff = (char*) malloc((size_t)benchedSize); - if(!origBuff) - { + if(!origBuff) { DISPLAY("\nError: not enough memory!\n"); return 12; } @@ -407,11 +438,9 @@ int benchSample(U32 benchNb) int benchFiles(char** fileNamesTable, int nbFiles, U32 benchNb) { - int fileIdx=0; - /* Loop for each file */ - while (fileIdx inFileSize) benchedSize = (size_t)inFileSize; - if (benchedSize < inFileSize) - { + if (benchedSize < inFileSize) { DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20)); } /* Alloc */ origBuff = (char*) malloc((size_t)benchedSize); - if(!origBuff) - { + if(!origBuff) { DISPLAY("\nError: not enough memory!\n"); fclose(inFile); return 12; @@ -451,8 +477,7 @@ int benchFiles(char** fileNamesTable, int nbFiles, U32 benchNb) readSize = fread(origBuff, 1, benchedSize, inFile); fclose(inFile); - if(readSize != benchedSize) - { + if(readSize != benchedSize) { DISPLAY("\nError: problem reading file '%s' !! \n", inFileName); free(origBuff); return 13; @@ -471,7 +496,7 @@ int benchFiles(char** fileNamesTable, int nbFiles, U32 benchNb) } -int usage(char* exename) +static int usage(char* exename) { DISPLAY( "Usage :\n"); DISPLAY( " %s [arg] file1 file2 ... fileX\n", exename); @@ -480,7 +505,7 @@ int usage(char* exename) return 0; } -int usage_advanced(void) +static int usage_advanced(void) { DISPLAY( "\nAdvanced options :\n"); DISPLAY( " -b# : test only function # \n"); @@ -489,7 +514,7 @@ int usage_advanced(void) return 0; } -int badusage(char* exename) +static int badusage(char* exename) { DISPLAY("Wrong parameters\n"); usage(exename); From cc5e8f222a3053cf8f7f746d884cbd539048bade Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 21:12:51 +0100 Subject: [PATCH 15/49] fixed fullbench visual project --- visual/2013/fullbench/fullbench.vcxproj | 3 +++ visual/2013/fullbench/fullbench.vcxproj.filters | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/visual/2013/fullbench/fullbench.vcxproj b/visual/2013/fullbench/fullbench.vcxproj index 3797960f4..afee2370c 100644 --- a/visual/2013/fullbench/fullbench.vcxproj +++ b/visual/2013/fullbench/fullbench.vcxproj @@ -161,6 +161,7 @@ + @@ -175,6 +176,8 @@ + + diff --git a/visual/2013/fullbench/fullbench.vcxproj.filters b/visual/2013/fullbench/fullbench.vcxproj.filters index 3a82000fb..1d5f9c59b 100644 --- a/visual/2013/fullbench/fullbench.vcxproj.filters +++ b/visual/2013/fullbench/fullbench.vcxproj.filters @@ -33,6 +33,9 @@ Fichiers sources + + Fichiers sources + @@ -68,5 +71,11 @@ Fichiers d%27en-tête + + Fichiers d%27en-tête + + + Fichiers d%27en-tête + \ No newline at end of file From f141eaa21179777ca0108690cd15138e346389c1 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 21:13:52 +0100 Subject: [PATCH 16/49] fullbench : ZSTD_decompress is now option 2 --- programs/fullbench.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/programs/fullbench.c b/programs/fullbench.c index 8d9e57d6c..fb9c7ed35 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -287,7 +287,7 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) case 1: benchFunction = local_ZSTD_compress; benchName = "ZSTD_compress"; break; - case 11: + case 2: benchFunction = local_ZSTD_decompress; benchName = "ZSTD_decompress"; break; case 31: @@ -320,7 +320,7 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) /* Preparation */ switch(benchNb) { - case 11: + case 2: g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1); break; case 31: /* ZSTD_decodeLiteralsBlock */ From 69afc716d3442c45a57ebf51e0e579dfffb30c51 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 15 Mar 2016 21:44:39 +0100 Subject: [PATCH 17/49] minor refactoring, from `char*` to `const char*` --- programs/fullbench.c | 70 ++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 45 deletions(-) diff --git a/programs/fullbench.c b/programs/fullbench.c index fb9c7ed35..125dc809a 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -180,7 +180,7 @@ static size_t BMK_findMaxMem(U64 requiredMem) } -static U64 BMK_GetFileSize(char* infilename) +static U64 BMK_GetFileSize(const char* infilename) { int r; #if defined(_MSC_VER) @@ -345,8 +345,7 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); /* it would be better to use direct block compression here */ ip += 5; /* Skip frame Header */ blockSize = ZSTD_getcBlockSize(ip, dstBuffSize, &bp); /* Get 1st block type */ - if (bp.blockType != bt_compressed) - { + if (bp.blockType != bt_compressed) { DISPLAY("ZSTD_decodeSeqHeaders : impossible to test on this sample (not compressible)\n"); goto _cleanOut; } @@ -374,8 +373,7 @@ size_t benchMem(void* src, size_t srcSize, U32 benchNb) { size_t i; for (i=0; i inFileSize) benchedSize = (size_t)inFileSize; - if (benchedSize < inFileSize) { + if (benchedSize < inFileSize) DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20)); - } /* Alloc */ - origBuff = (char*) malloc((size_t)benchedSize); - if(!origBuff) { - DISPLAY("\nError: not enough memory!\n"); - fclose(inFile); - return 12; - } + origBuff = malloc(benchedSize); + if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); fclose(inFile); return 12; } /* Fill input buffer */ DISPLAY("Loading %s... \r", inFileName); @@ -496,7 +480,7 @@ int benchFiles(char** fileNamesTable, int nbFiles, U32 benchNb) } -static int usage(char* exename) +static int usage(const char* exename) { DISPLAY( "Usage :\n"); DISPLAY( " %s [arg] file1 file2 ... fileX\n", exename); @@ -514,20 +498,20 @@ static int usage_advanced(void) return 0; } -static int badusage(char* exename) +static int badusage(const char* exename) { DISPLAY("Wrong parameters\n"); usage(exename); return 0; } -int main(int argc, char** argv) +int main(int argc, const char** argv) { int i, filenamesStart=0, result; - char* exename=argv[0]; - char* input_filename=0; + const char* exename=argv[0]; + const char* input_filename=0; U32 benchNb = 0, main_pause = 0; // Welcome message @@ -537,7 +521,7 @@ int main(int argc, char** argv) for(i=1; i= '0') && (argument[1]<= '9')) - { + while ((argument[1]>= '0') && (argument[1]<= '9')) { benchNb *= 10; benchNb += argument[1] - '0'; argument++; @@ -570,8 +553,7 @@ int main(int argc, char** argv) /* Modify Nb Iterations */ case 'i': - if ((argument[1] >='0') && (argument[1] <='9')) - { + if ((argument[1] >='0') && (argument[1] <='9')) { int iters = argument[1] - '0'; BMK_SetNbIterations(iters); argument++; @@ -580,10 +562,8 @@ int main(int argc, char** argv) /* Select specific algorithm to bench */ case 'P': - { - U32 proba32 = 0; - while ((argument[1]>= '0') && (argument[1]<= '9')) - { + { U32 proba32 = 0; + while ((argument[1]>= '0') && (argument[1]<= '9')) { proba32 *= 10; proba32 += argument[1] - '0'; argument++; From 569b81adb10b3122a977ec08676b3a5a8e336774 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 16 Mar 2016 15:26:51 +0100 Subject: [PATCH 18/49] changed `BLOCKSIZE` into `ZSTD_BLOCKSIZE_MAX` --- lib/zbuff.c | 59 ++++++++++++++++--------------- lib/zdict.c | 8 ++--- lib/zstd_compress.c | 6 ++-- lib/zstd_decompress.c | 18 +++++----- lib/zstd_internal.h | 7 ++-- lib/zstd_static.h | 31 ++++++++-------- programs/fullbench.c | 82 ++++++++++++++++++++----------------------- 7 files changed, 104 insertions(+), 107 deletions(-) diff --git a/lib/zbuff.c b/lib/zbuff.c index a08060cf4..386b47d5a 100644 --- a/lib/zbuff.c +++ b/lib/zbuff.c @@ -40,15 +40,16 @@ ***************************************/ #include #include "error_private.h" -#include "zstd_internal.h" +#include "zstd_internal.h" /* MIN, ZSTD_blockHeaderSize */ +#include "zstd_static.h" /* ZSTD_BLOCKSIZE_MAX */ #include "zbuff_static.h" /* ************************************* * Constants ***************************************/ -static size_t ZBUFF_blockHeaderSize = 3; -static size_t ZBUFF_endFrameSize = 3; +static size_t const ZBUFF_endFrameSize = ZSTD_BLOCKHEADERSIZE; + /*_************************************************** * Streaming compression @@ -59,28 +60,28 @@ static size_t ZBUFF_endFrameSize = 3; * ZBUFF_CCtx objects can be reused multiple times. * * Use ZBUFF_compressContinue() repetitively to consume your input. -* *srcSizePtr and *maxDstSizePtr can be any size. -* The function will report how many bytes were read or written by modifying *srcSizePtr and *maxDstSizePtr. +* *srcSizePtr and *dstCapacityPtr can be any size. +* The function will report how many bytes were read or written by modifying *srcSizePtr and *dstCapacityPtr. * Note that it may not consume the entire input, in which case it's up to the caller to call again the function with remaining input. -* The content of dst will be overwritten (up to *maxDstSizePtr) at each function call, so save its content if it matters or change dst . +* The content of dst will be overwritten (up to *dstCapacityPtr) at each function call, so save its content if it matters or change dst . * @return : a hint to preferred nb of bytes to use as input for next function call (it's only a hint, to improve latency) * or an error code, which can be tested using ZBUFF_isError(). * * ZBUFF_compressFlush() can be used to instruct ZBUFF to compress and output whatever remains within its buffer. -* Note that it will not output more than *maxDstSizePtr. +* Note that it will not output more than *dstCapacityPtr. * Therefore, some content might still be left into its internal buffer if dst buffer is too small. * @return : nb of bytes still present into internal buffer (0 if it's empty) * or an error code, which can be tested using ZBUFF_isError(). * * ZBUFF_compressEnd() instructs to finish a frame. * It will perform a flush and write frame epilogue. -* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *maxDstSizePtr is too small. +* Similar to ZBUFF_compressFlush(), it may not be able to output the entire internal buffer content if *dstCapacityPtr is too small. * @return : nb of bytes still present into internal buffer (0 if it's empty) * or an error code, which can be tested using ZBUFF_isError(). * * Hint : recommended buffer sizes (not compulsory) -* input : 128 KB block size is the internal unit, it improves latency to use this value. -* output : ZSTD_compressBound(128 KB) + 3 + 3 : ensures it's always possible to write/flush/end a full block at best speed. +* input : ZSTD_BLOCKSIZE_MAX (128 KB), internal unit size, it improves latency to use this value. +* output : ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize : ensures it's always possible to write/flush/end a full block at best speed. * **************************************************/ typedef enum { ZBUFFcs_init, ZBUFFcs_load, ZBUFFcs_flush } ZBUFF_cStage; @@ -137,7 +138,7 @@ size_t ZBUFF_compressInit_advanced(ZBUFF_CCtx* zbc, const void* dict, size_t dic zbc->inBuff = (char*)malloc(neededInBuffSize); if (zbc->inBuff == NULL) return ERROR(memory_allocation); } - zbc->blockSize = MIN(BLOCKSIZE, zbc->inBuffSize); + zbc->blockSize = MIN(ZSTD_BLOCKSIZE_MAX, zbc->inBuffSize); if (zbc->outBuffSize < ZSTD_compressBound(zbc->blockSize)+1) { zbc->outBuffSize = ZSTD_compressBound(zbc->blockSize)+1; free(zbc->outBuff); /* should not be necessary */ @@ -178,7 +179,7 @@ static size_t ZBUFF_limitCopy(void* dst, size_t dstCapacity, const void* src, si } static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, - void* dst, size_t* maxDstSizePtr, + void* dst, size_t* dstCapacityPtr, const void* src, size_t* srcSizePtr, int flush) /* aggregate : wait for full block before compressing */ { @@ -188,7 +189,7 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, const char* const iend = istart + *srcSizePtr; char* const ostart = (char*)dst; char* op = ostart; - char* const oend = ostart + *maxDstSizePtr; + char* const oend = ostart + *dstCapacityPtr; while (notDone) { switch(zbc->stage) @@ -248,7 +249,7 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, } *srcSizePtr = ip - istart; - *maxDstSizePtr = op - ostart; + *dstCapacityPtr = op - ostart; { size_t hintInSize = zbc->inBuffTarget - zbc->inBuffPos; if (hintInSize==0) hintInSize = zbc->blockSize; @@ -257,30 +258,30 @@ static size_t ZBUFF_compressContinue_generic(ZBUFF_CCtx* zbc, } size_t ZBUFF_compressContinue(ZBUFF_CCtx* zbc, - void* dst, size_t* maxDstSizePtr, + void* dst, size_t* dstCapacityPtr, const void* src, size_t* srcSizePtr) { - return ZBUFF_compressContinue_generic(zbc, dst, maxDstSizePtr, src, srcSizePtr, 0); + return ZBUFF_compressContinue_generic(zbc, dst, dstCapacityPtr, src, srcSizePtr, 0); } /* *** Finalize *** */ -size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr) +size_t ZBUFF_compressFlush(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) { size_t srcSize = 0; - ZBUFF_compressContinue_generic(zbc, dst, maxDstSizePtr, &srcSize, &srcSize, 1); /* use a valid src address instead of NULL, as some sanitizer don't like it */ + ZBUFF_compressContinue_generic(zbc, dst, dstCapacityPtr, &srcSize, &srcSize, 1); /* use a valid src address instead of NULL, as some sanitizer don't like it */ return zbc->outBuffContentSize - zbc->outBuffFlushedSize; } -size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr) +size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* dstCapacityPtr) { BYTE* const ostart = (BYTE*)dst; BYTE* op = ostart; - BYTE* const oend = ostart + *maxDstSizePtr; - size_t outSize = *maxDstSizePtr; + BYTE* const oend = ostart + *dstCapacityPtr; + size_t outSize = *dstCapacityPtr; size_t epilogueSize, remaining; ZBUFF_compressFlush(zbc, dst, &outSize); /* flush any remaining inBuff */ op += outSize; @@ -291,7 +292,7 @@ size_t ZBUFF_compressEnd(ZBUFF_CCtx* zbc, void* dst, size_t* maxDstSizePtr) remaining = ZBUFF_compressFlush(zbc, op, &outSize); /* attempt to flush epilogue into dst */ op += outSize; if (!remaining) zbc->stage = ZBUFFcs_init; /* close only if nothing left to flush */ - *maxDstSizePtr = op-ostart; /* tells how many bytes were written */ + *dstCapacityPtr = op-ostart; /* tells how many bytes were written */ return remaining; } @@ -406,7 +407,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, } } /* Frame header provides buffer sizes */ - { size_t const neededInSize = BLOCKSIZE; /* a block is never > BLOCKSIZE */ + { size_t const neededInSize = ZSTD_BLOCKSIZE_MAX; /* a block is never > ZSTD_BLOCKSIZE_MAX */ if (zbc->inBuffSize < neededInSize) { free(zbc->inBuff); zbc->inBuffSize = neededInSize; @@ -476,7 +477,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, zbc->outStart += flushedSize; if (flushedSize == toFlushSize) { zbc->stage = ZBUFFds_read; - if (zbc->outStart + BLOCKSIZE > zbc->outBuffSize) + if (zbc->outStart + ZSTD_BLOCKSIZE_MAX > zbc->outBuffSize) zbc->outStart = zbc->outEnd = 0; break; } @@ -492,7 +493,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, *dstCapacityPtr = op-ostart; { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zbc->zc); - if (nextSrcSizeHint > ZBUFF_blockHeaderSize) nextSrcSizeHint+= ZBUFF_blockHeaderSize; /* get following block header too */ + if (nextSrcSizeHint > ZSTD_blockHeaderSize) nextSrcSizeHint+= ZSTD_blockHeaderSize; /* get following block header too */ nextSrcSizeHint -= zbc->inPos; /* already loaded*/ return nextSrcSizeHint; } @@ -506,7 +507,7 @@ size_t ZBUFF_decompressContinue(ZBUFF_DCtx* zbc, unsigned ZBUFF_isError(size_t errorCode) { return ERR_isError(errorCode); } const char* ZBUFF_getErrorName(size_t errorCode) { return ERR_getErrorName(errorCode); } -size_t ZBUFF_recommendedCInSize(void) { return BLOCKSIZE; } -size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_compressBound(BLOCKSIZE) + ZBUFF_blockHeaderSize + ZBUFF_endFrameSize; } -size_t ZBUFF_recommendedDInSize(void) { return BLOCKSIZE + ZBUFF_blockHeaderSize /* block header size*/ ; } -size_t ZBUFF_recommendedDOutSize(void) { return BLOCKSIZE; } +size_t ZBUFF_recommendedCInSize(void) { return ZSTD_BLOCKSIZE_MAX; } +size_t ZBUFF_recommendedCOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + ZBUFF_endFrameSize; } +size_t ZBUFF_recommendedDInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize /* block header size*/ ; } +size_t ZBUFF_recommendedDOutSize(void) { return ZSTD_BLOCKSIZE_MAX; } diff --git a/lib/zdict.c b/lib/zdict.c index 2b3d3ae8a..a7c8090a8 100644 --- a/lib/zdict.c +++ b/lib/zdict.c @@ -587,7 +587,7 @@ typedef struct { ZSTD_CCtx* ref; ZSTD_CCtx* zc; - void* workPlace; /* must be BLOCKSIZE allocated */ + void* workPlace; /* must be ZSTD_BLOCKSIZE_MAX allocated */ } EStats_ress_t; @@ -599,9 +599,9 @@ static void ZDICT_countEStats(EStats_ress_t esr, const U32* u32Ptr; seqStore_t seqStore; - if (srcSize > BLOCKSIZE) srcSize = BLOCKSIZE; /* protection vs large samples */ + if (srcSize > ZSTD_BLOCKSIZE_MAX) srcSize = ZSTD_BLOCKSIZE_MAX; /* protection vs large samples */ ZSTD_copyCCtx(esr.zc, esr.ref); - ZSTD_compressBlock(esr.zc, esr.workPlace, BLOCKSIZE, src, srcSize); + ZSTD_compressBlock(esr.zc, esr.workPlace, ZSTD_BLOCKSIZE_MAX, src, srcSize); seqStore = ZSTD_copySeqStore(esr.zc); /* count stats */ @@ -654,7 +654,7 @@ static size_t ZDICT_analyzeEntropy(void* dstBuffer, size_t maxDstSize, for (u=0; u<=MaxLL; u++) litlengthCount[u]=1; esr.ref = ZSTD_createCCtx(); esr.zc = ZSTD_createCCtx(); - esr.workPlace = malloc(BLOCKSIZE); + esr.workPlace = malloc(ZSTD_BLOCKSIZE_MAX); if (!esr.ref || !esr.zc || !esr.workPlace) { eSize = ERROR(memory_allocation); DISPLAYLEVEL(1, "Not enough memory"); diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 6afcddeb8..980b5c770 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -169,7 +169,7 @@ void ZSTD_validateParams(ZSTD_parameters* params) size_t ZSTD_sizeofCCtx(ZSTD_parameters params) /* hidden interface, for paramagrill */ { /* copy / pasted from ZSTD_resetCCtx_advanced */ - const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog); + const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.windowLog); const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog; const U32 divider = (params.searchLength==3) ? 3 : 4; const size_t maxNbSeq = blockSize / divider; @@ -186,7 +186,7 @@ size_t ZSTD_sizeofCCtx(ZSTD_parameters params) /* hidden interface, for parama static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, ZSTD_parameters params) { /* note : params considered validated here */ - const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog); + const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.windowLog); const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog; const U32 divider = (params.searchLength==3) ? 3 : 4; const size_t maxNbSeq = blockSize / divider; @@ -2079,7 +2079,7 @@ size_t ZSTD_compressContinue (ZSTD_CCtx* zc, size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong); + if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); zc->params.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */ ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.searchLength); return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0); diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 6508dbcd4..2d89a2de8 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -143,7 +143,7 @@ struct ZSTD_DCtx_s const BYTE* litPtr; size_t litBufSize; size_t litSize; - BYTE litBuffer[BLOCKSIZE + WILDCOPY_OVERLENGTH]; + BYTE litBuffer[ZSTD_BLOCKSIZE_MAX + WILDCOPY_OVERLENGTH]; BYTE headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX]; }; /* typedef'd to ZSTD_DCtx within "zstd_static.h" */ @@ -181,7 +181,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx) void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) { memcpy(dstDCtx, srcDCtx, - sizeof(ZSTD_DCtx) - (BLOCKSIZE+WILDCOPY_OVERLENGTH + ZSTD_frameHeaderSize_max)); /* no need to copy workspace */ + sizeof(ZSTD_DCtx) - (ZSTD_BLOCKSIZE_MAX+WILDCOPY_OVERLENGTH + ZSTD_frameHeaderSize_max)); /* no need to copy workspace */ } @@ -411,7 +411,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litCSize = ((istart[2] & 3) << 16) + (istart[3] << 8) + istart[4]; break; } - if (litSize > BLOCKSIZE) return ERROR(corruption_detected); + if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected); if (HUF_isError(singleStream ? HUF_decompress1X2(dctx->litBuffer, litSize, istart+lhSize, litCSize) : @@ -419,7 +419,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, return ERROR(corruption_detected); dctx->litPtr = dctx->litBuffer; - dctx->litBufSize = BLOCKSIZE+8; + dctx->litBufSize = ZSTD_BLOCKSIZE_MAX+8; dctx->litSize = litSize; return litCSize + lhSize; } @@ -442,7 +442,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (HUF_isError(errorCode)) return ERROR(corruption_detected); dctx->litPtr = dctx->litBuffer; - dctx->litBufSize = BLOCKSIZE+WILDCOPY_OVERLENGTH; + dctx->litBufSize = ZSTD_BLOCKSIZE_MAX+WILDCOPY_OVERLENGTH; dctx->litSize = litSize; return litCSize + lhSize; } @@ -468,7 +468,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, if (litSize+lhSize > srcSize) return ERROR(corruption_detected); memcpy(dctx->litBuffer, istart+lhSize, litSize); dctx->litPtr = dctx->litBuffer; - dctx->litBufSize = BLOCKSIZE+8; + dctx->litBufSize = ZSTD_BLOCKSIZE_MAX+8; dctx->litSize = litSize; return lhSize+litSize; } @@ -495,10 +495,10 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, litSize = ((istart[0] & 15) << 16) + (istart[1] << 8) + istart[2]; break; } - if (litSize > BLOCKSIZE) return ERROR(corruption_detected); + if (litSize > ZSTD_BLOCKSIZE_MAX) return ERROR(corruption_detected); memset(dctx->litBuffer, istart[lhSize], litSize); dctx->litPtr = dctx->litBuffer; - dctx->litBufSize = BLOCKSIZE+WILDCOPY_OVERLENGTH; + dctx->litBufSize = ZSTD_BLOCKSIZE_MAX+WILDCOPY_OVERLENGTH; dctx->litSize = litSize; return lhSize+1; } @@ -892,7 +892,7 @@ static size_t ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx, const BYTE* ip = (const BYTE*)src; size_t litCSize; - if (srcSize >= BLOCKSIZE) return ERROR(srcSize_wrong); + if (srcSize >= ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong); ZSTD_LOG_BLOCK("%p: ZSTD_decompressBlock_internal searchLength=%d\n", dctx->base, dctx->params.searchLength); diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index d67505caa..642c3777c 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -27,7 +27,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd + - zstd homepage : https://www.zstd.net */ #ifndef ZSTD_CCOMMON_H_MODULE #define ZSTD_CCOMMON_H_MODULE @@ -71,9 +71,8 @@ #define MB *(1 <<20) #define GB *(1U<<30) -#define BLOCKSIZE (128 KB) /* define, for static allocation */ - -static const size_t ZSTD_blockHeaderSize = 3; +#define ZSTD_BLOCKHEADERSIZE 3 /* because C standard does not allow a static const value to be defined using another static const value .... :( */ +static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; #define BIT7 128 #define BIT6 64 diff --git a/lib/zstd_static.h b/lib/zstd_static.h index be67784ef..cb140a494 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -93,8 +93,8 @@ ZSTDLIB_API unsigned ZSTD_maxCLevel (void); /*! ZSTD_getParams() : * @return ZSTD_parameters structure for a selected compression level and srcSize. -* `srcSizeHint` value is optional, select 0 if not known */ -ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint); +* `srcSize` value is optional, select 0 if not known */ +ZSTDLIB_API ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSize); /*! ZSTD_validateParams() : * correct params value to remain within authorized range */ @@ -112,7 +112,7 @@ ZSTDLIB_API size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, * Same as ZSTD_compress_usingDict, but using a reference context `preparedCCtx`, where dictionary has been loaded. * It avoids reloading the dictionary each time. * `preparedCCtx` must have been properly initialized using ZSTD_compressBegin_usingDict() or ZSTD_compressBegin_advanced(). -* Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the compression operation */ +* Requires 2 contexts : 1 for reference (preparedCCtx) which will not be modified, and 1 to run the compression operation (cctx) */ ZSTDLIB_API size_t ZSTD_compress_usingPreparedCCtx( ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx, void* dst, size_t dstCapacity, @@ -124,19 +124,19 @@ ZSTDLIB_API size_t ZSTD_compress_usingPreparedCCtx( * Same as ZSTD_decompress_usingDict, but using a reference context `preparedDCtx`, where dictionary has been loaded. * It avoids reloading the dictionary each time. * `preparedDCtx` must have been properly initialized using ZSTD_decompressBegin_usingDict(). -* Requires 2 contexts : 1 for reference, which will not be modified, and 1 to run the decompression operation */ +* Requires 2 contexts : 1 for reference (preparedDCtx), which will not be modified, and 1 to run the decompression operation (dctx) */ ZSTDLIB_API size_t ZSTD_decompress_usingPreparedDCtx( - ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx, - void* dst, size_t dstCapacity, - const void* src, size_t srcSize); + ZSTD_DCtx* dctx, const ZSTD_DCtx* preparedDCtx, + void* dst, size_t dstCapacity, + const void* src, size_t srcSize); /* ************************************** * Streaming functions (direct mode) ****************************************/ ZSTDLIB_API size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel); -ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, int compressionLevel); -ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict,size_t dictSize, ZSTD_parameters params); +ZSTDLIB_API size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel); +ZSTDLIB_API size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, ZSTD_parameters params); ZSTDLIB_API size_t ZSTD_copyCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx); ZSTDLIB_API size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); @@ -187,11 +187,11 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds A ZSTD_DCtx object can be re-used multiple times. First optional operation is to retrieve frame parameters, using ZSTD_getFrameParams(). - It can provide the minimum size of buffer required to properly decompress data, + It can provide the minimum size of rolling buffer required to properly decompress data, and optionally the final size of uncompressed content. (Note : content size is an optional info that may not be present. 0 means : content size unknown) - It is done by reading a certain amount of the beginning of compressed frame. - The amount of data to read is variable, from ZSTD_frameHeaderSize_min to ZSTD_frameHeaderSize_max. + Frame parameters are extracted from the beginning of compressed frame. + The amount of data to read is variable, from ZSTD_frameHeaderSize_min to ZSTD_frameHeaderSize_max (so if `srcSize` >= ZSTD_frameHeaderSize_max, it will always work) If `srcSize` is too small for operation to succeed, function will return the minimum size it requires to produce a result. Result : 0 when successful, it means the ZSTD_frameParams structure has been filled. >0 : means there is not enough data into `src`. Provides the expected size to successfully decode header. @@ -206,7 +206,7 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds ZSTD_decompressContinue() needs previous data blocks during decompression, up to (1 << windowlog). They should preferably be located contiguously, prior to current block. Alternatively, a round buffer is also possible. - @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst'. + @result of ZSTD_decompressContinue() is the number of bytes regenerated within 'dst' (necessarily <= dstCapacity) It can be zero, which is not an error; it just means ZSTD_decompressContinue() has decoded some header. A frame is fully decoded when ZSTD_nextSrcSizeToDecompress() returns zero. @@ -218,10 +218,10 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds * Block functions ****************************************/ /*! Block functions produce and decode raw zstd blocks, without frame metadata. - User will have to take in charge required information to regenerate data, such as block sizes. + User will have to take in charge required information to regenerate data, such as compressed and content sizes. A few rules to respect : - - Uncompressed block size must be <= 128 KB + - Uncompressed block size must be <= ZSTD_BLOCKSIZE_MAX (128 KB) - Compressing or decompressing requires a context structure + Use ZSTD_createCCtx() and ZSTD_createDCtx() - It is necessary to init context before starting @@ -235,6 +235,7 @@ ZSTDLIB_API size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t ds + ZSTD_decompressBlock() doesn't accept uncompressed data as input !! */ +#define ZSTD_BLOCKSIZE_MAX (128 * 1024) /* define, for static allocation */ size_t ZSTD_compressBlock (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize); diff --git a/programs/fullbench.c b/programs/fullbench.c index 125dc809a..192761d85 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -97,7 +97,7 @@ #define DEFAULT_CHUNKSIZE (4<<20) #define COMPRESSIBILITY_DEFAULT 0.50 -static const size_t sampleSize = 10000000; +static const size_t g_sampleSize = 10000000; /*_************************************ @@ -256,7 +256,7 @@ size_t local_ZBUFF_compress(void* dst, size_t dstSize, void* buff2, const void* } static ZBUFF_DCtx* g_zbdc = NULL; -size_t local_ZBUFF_decompress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) +static size_t local_ZBUFF_decompress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) { size_t srcRead = g_cSize, dstWritten = dstSize; (void)src; (void)srcSize; @@ -270,7 +270,7 @@ size_t local_ZBUFF_decompress(void* dst, size_t dstSize, void* buff2, const void /*_******************************************************* * Bench functions *********************************************************/ -size_t benchMem(void* src, size_t srcSize, U32 benchNb) +static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) { BYTE* dstBuff; size_t dstBuffSize; @@ -405,9 +405,9 @@ _cleanOut: } -int benchSample(U32 benchNb) +static int benchSample(U32 benchNb) { - size_t const benchedSize = sampleSize; + size_t const benchedSize = g_sampleSize; const char* name = "Sample 10MiB"; /* Allocation */ @@ -430,16 +430,15 @@ int benchSample(U32 benchNb) } -int benchFiles(const char** fileNamesTable, int nbFiles, U32 benchNb) +static int benchFiles(const char** fileNamesTable, const int nbFiles, U32 benchNb) { /* Loop for each file */ - int fileIdx=0; - while (fileIdx inFileSize) benchedSize = (size_t)inFileSize; if (benchedSize < inFileSize) - DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20)); + DISPLAY("Not enough memory for '%s' full size; testing %u MB only...\n", inFileName, (U32)(benchedSize>>20)); /* Alloc */ origBuff = malloc(benchedSize); @@ -458,14 +457,14 @@ int benchFiles(const char** fileNamesTable, int nbFiles, U32 benchNb) /* Fill input buffer */ DISPLAY("Loading %s... \r", inFileName); - readSize = fread(origBuff, 1, benchedSize, inFile); - fclose(inFile); - - if(readSize != benchedSize) { - DISPLAY("\nError: problem reading file '%s' !! \n", inFileName); - free(origBuff); - return 13; - } + { + size_t readSize = fread(origBuff, 1, benchedSize, inFile); + fclose(inFile); + if (readSize != benchedSize) { + DISPLAY("\nError: problem reading file '%s' !! \n", inFileName); + free(origBuff); + return 13; + } } /* bench */ DISPLAY("\r%79s\r", ""); @@ -474,6 +473,8 @@ int benchFiles(const char** fileNamesTable, int nbFiles, U32 benchNb) benchMem(origBuff, benchedSize, benchNb); else for (benchNb=0; benchNb<100; benchNb++) benchMem(origBuff, benchedSize, benchNb); + + free(origBuff); } return 0; @@ -489,8 +490,9 @@ static int usage(const char* exename) return 0; } -static int usage_advanced(void) +static int usage_advanced(const char* exename) { + usage(exename); DISPLAY( "\nAdvanced options :\n"); DISPLAY( " -b# : test only function # \n"); DISPLAY( " -i# : iteration loops [1-9](default : %i)\n", NBLOOPS); @@ -502,41 +504,34 @@ static int badusage(const char* exename) { DISPLAY("Wrong parameters\n"); usage(exename); - return 0; + return 1; } int main(int argc, const char** argv) { - int i, - filenamesStart=0, - result; - const char* exename=argv[0]; - const char* input_filename=0; + int i, filenamesStart=0, result; + const char* exename = argv[0]; + const char* input_filename = NULL; U32 benchNb = 0, main_pause = 0; - // Welcome message DISPLAY(WELCOME_MESSAGE); + if (argc<1) return badusage(exename); - if (argc<1) { badusage(exename); return 1; } - - for(i=1; i= '0') && (argument[1]<= '9')) { @@ -573,7 +568,7 @@ int main(int argc, const char** argv) break; /* Unknown command */ - default : badusage(exename); return 1; + default : return badusage(exename); } } continue; @@ -583,9 +578,10 @@ int main(int argc, const char** argv) if (!input_filename) { input_filename=argument; filenamesStart=i; continue; } } - if (filenamesStart==0) + if (filenamesStart==0) /* no input file */ result = benchSample(benchNb); - else result = benchFiles(argv+filenamesStart, argc-filenamesStart, benchNb); + else + result = benchFiles(argv+filenamesStart, argc-filenamesStart, benchNb); if (main_pause) { int unused; printf("press enter...\n"); unused = getchar(); (void)unused; } From 31922d793132a10a2a067305789c5b7e7e680ef2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 16 Mar 2016 16:05:18 +0100 Subject: [PATCH 19/49] Added : ability to test direct-streaming functions `ZSTD_compressContinue()` and `ZSTD_decompressContinue()` --- programs/fullbench.c | 77 +++++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 18 deletions(-) diff --git a/programs/fullbench.c b/programs/fullbench.c index 192761d85..8b43d20e1 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -205,26 +205,25 @@ typedef struct { U32 origSize; } blockProperties_t; -static size_t g_cSize = 0; -static ZSTD_DCtx* g_dctxPtr = NULL; - size_t local_ZSTD_compress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) { (void)buff2; return ZSTD_compress(dst, dstSize, src, srcSize, 1); } +static size_t g_cSize = 0; size_t local_ZSTD_decompress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) { (void)src; (void)srcSize; return ZSTD_decompress(dst, dstSize, buff2, g_cSize); } +static ZSTD_DCtx* g_zdc = NULL; extern size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* ctx, const void* src, size_t srcSize); size_t local_ZSTD_decodeLiteralsBlock(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) { (void)src; (void)srcSize; (void)dst; (void)dstSize; - return ZSTD_decodeLiteralsBlock((ZSTD_DCtx*)g_dctxPtr, buff2, g_cSize); + return ZSTD_decodeLiteralsBlock((ZSTD_DCtx*)g_zdc, buff2, g_cSize); } extern size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr); @@ -241,30 +240,62 @@ size_t local_ZSTD_decodeSeqHeaders(void* dst, size_t dstSize, void* buff2, const static ZBUFF_CCtx* g_zbcc = NULL; -size_t local_ZBUFF_compress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) +size_t local_ZBUFF_compress(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize) { size_t compressedSize; - size_t srcRead = srcSize, dstWritten = dstSize; + size_t srcRead = srcSize, dstWritten = dstCapacity; (void)buff2; ZBUFF_compressInit(g_zbcc, 1); ZBUFF_compressContinue(g_zbcc, dst, &dstWritten, src, &srcRead); compressedSize = dstWritten; - dstWritten = dstSize-compressedSize; + dstWritten = dstCapacity-compressedSize; ZBUFF_compressEnd(g_zbcc, ((char*)dst)+compressedSize, &dstWritten); compressedSize += dstWritten; return compressedSize; } static ZBUFF_DCtx* g_zbdc = NULL; -static size_t local_ZBUFF_decompress(void* dst, size_t dstSize, void* buff2, const void* src, size_t srcSize) +static size_t local_ZBUFF_decompress(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize) { - size_t srcRead = g_cSize, dstWritten = dstSize; + size_t srcRead = g_cSize, dstWritten = dstCapacity; (void)src; (void)srcSize; ZBUFF_decompressInit(g_zbdc); ZBUFF_decompressContinue(g_zbdc, dst, &dstWritten, buff2, &srcRead); return dstWritten; } +static ZSTD_CCtx* g_zcc = NULL; +size_t local_ZSTD_compressContinue(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize) +{ + size_t compressedSize; + (void)buff2; + ZSTD_compressBegin(g_zcc, 1); + compressedSize = ZSTD_compressContinue(g_zcc, dst, dstCapacity, src, srcSize); + compressedSize += ZSTD_compressEnd(g_zcc, ((char*)dst)+compressedSize, dstCapacity-compressedSize); + return compressedSize; +} + +size_t local_ZSTD_decompressContinue(void* dst, size_t dstCapacity, void* buff2, const void* src, size_t srcSize) +{ + size_t regeneratedSize = 0; + const BYTE* ip = (const BYTE*)buff2; + const BYTE* const iend = ip + g_cSize; + BYTE* op = (BYTE*)dst; + size_t remainingCapacity = dstCapacity; + + (void)src; (void)srcSize; + ZSTD_decompressBegin(g_zdc); + while (ip < iend) { + size_t const iSize = ZSTD_nextSrcSizeToDecompress(g_zdc); + size_t const decodedSize = ZSTD_decompressContinue(g_zdc, op, remainingCapacity, ip, iSize); + ip += iSize; + regeneratedSize += decodedSize; + op += decodedSize; + remainingCapacity -= decodedSize; + } + + return regeneratedSize; +} /*_******************************************************* @@ -290,6 +321,12 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) case 2: benchFunction = local_ZSTD_decompress; benchName = "ZSTD_decompress"; break; + case 11: + benchFunction = local_ZSTD_compressContinue; benchName = "ZSTD_compressContinue"; + break; + case 12: + benchFunction = local_ZSTD_decompressContinue; benchName = "ZSTD_decompressContinue"; + break; case 31: benchFunction = local_ZSTD_decodeLiteralsBlock; benchName = "ZSTD_decodeLiteralsBlock"; break; @@ -310,7 +347,6 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) dstBuffSize = ZSTD_compressBound(srcSize); dstBuff = (BYTE*)malloc(dstBuffSize); buff2 = (BYTE*)malloc(dstBuffSize); - g_dctxPtr = ZSTD_createDCtx(); if ((!dstBuff) || (!buff2)) { DISPLAY("\nError: not enough memory!\n"); free(dstBuff); free(buff2); @@ -323,9 +359,15 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) case 2: g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1); break; + case 11 : + if (g_zcc==NULL) g_zcc = ZSTD_createCCtx(); + break; + case 12 : + if (g_zdc==NULL) g_zdc = ZSTD_createDCtx(); + g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1); + break; case 31: /* ZSTD_decodeLiteralsBlock */ - { - blockProperties_t bp; + { blockProperties_t bp; g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); ZSTD_getcBlockSize(dstBuff+4, dstBuffSize, &bp); /* Get 1st block type */ if (bp.blockType != bt_compressed) { @@ -337,8 +379,8 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) break; } case 32: /* ZSTD_decodeSeqHeaders */ - { - blockProperties_t bp; + if (g_zdc==NULL) g_zdc = ZSTD_createDCtx(); + { blockProperties_t bp; const BYTE* ip = dstBuff; const BYTE* iend; size_t blockSize; @@ -351,17 +393,17 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) } iend = ip + 3 + blockSize; /* End of first block */ ip += 3; /* skip block header */ - ip += ZSTD_decodeLiteralsBlock(g_dctxPtr, ip, iend-ip); /* skip literal segment */ + ip += ZSTD_decodeLiteralsBlock(g_zdc, ip, iend-ip); /* skip literal segment */ g_cSize = iend-ip; memcpy(buff2, ip, g_cSize); /* copy rest of block (it starts by SeqHeader) */ srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */ break; } case 41 : - if (g_zbcc==NULL) g_zbcc=ZBUFF_createCCtx(); + if (g_zbcc==NULL) g_zbcc = ZBUFF_createCCtx(); break; case 42 : - if (g_zbdc==NULL) g_zbdc=ZBUFF_createDCtx(); + if (g_zbdc==NULL) g_zbdc = ZBUFF_createDCtx(); g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1); break; @@ -400,7 +442,6 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) _cleanOut: free(dstBuff); free(buff2); - ZSTD_freeDCtx(g_dctxPtr); return 0; } From fbc40b82d754fe67815b7ed0379210f20383847f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Wed, 16 Mar 2016 16:53:47 +0100 Subject: [PATCH 20/49] Update NEWS on #147 by @chipturner --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index f78cd65fb..d4abd36f9 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ v0.6.0 Stronger high compression modes, thanks to Przemyslaw Skibinski API : ZSTD_getFrameParams() provides size of decompressed content New : highest compression modes require `--ultra` command to fully unleash their capacity +Fixed : zstd cli return error code > 0 and removes dst file artifact when decompression fails, thanks to Chip Turner v0.5.1 New : Optimal parsing => Very high compression modes, thanks to Przemyslaw Skibinski From b40287aaef3c13da55ae4f5b80e34fe59eb629d4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 17 Mar 2016 12:11:16 +0100 Subject: [PATCH 21/49] Improved decompression speed (by @inikep) --- lib/zstd_decompress.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 2d89a2de8..17ba5822e 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -654,16 +654,12 @@ typedef struct { static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) { - size_t litLength; - size_t prevOffset; - size_t offset; - size_t matchLength; const BYTE* dumps = seqState->dumps; const BYTE* const de = seqState->dumpsEnd; + size_t litLength, offset, matchLength; /* Literal length */ litLength = FSE_peakSymbol(&(seqState->stateLL)); - prevOffset = litLength ? seq->offset : seqState->prevOffset; if (litLength == MaxLL) { U32 add = *dumps++; if (add < 255) litLength += add; @@ -686,7 +682,7 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) if (offsetCode==0) nbBits = 0; /* cmove */ offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits); if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); - if (offsetCode==0) offset = prevOffset; /* repcode, cmove */ + if (offsetCode==0) offset = litLength ? seq->offset : seqState->prevOffset; if (offsetCode | !litLength) seqState->prevOffset = seq->offset; /* cmove */ FSE_decodeSymbol(&(seqState->stateOffb), &(seqState->DStream)); /* update */ } From 808fa8ead8f8c7470db5ae1d6df8f875eafb7c91 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 17 Mar 2016 12:56:46 +0100 Subject: [PATCH 22/49] minor refactoring --- lib/zstd_decompress.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 17ba5822e..d3d7f64ef 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -677,9 +677,8 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) 1 /*fake*/, 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, /*fake*/ 1, 1, 1, 1 }; - U32 offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ - U32 nbBits = offsetCode - 1; - if (offsetCode==0) nbBits = 0; /* cmove */ + const U32 offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ + const U32 nbBits = offsetCode ? offsetCode-1 : 0; offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits); if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); if (offsetCode==0) offset = litLength ? seq->offset : seqState->prevOffset; From 3fd164e656e22baebca4e2d90b05091100afe893 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 17 Mar 2016 12:56:46 +0100 Subject: [PATCH 23/49] minor refactoring --- lib/zstd_decompress.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 17ba5822e..da9665cd1 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -656,12 +656,12 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) { const BYTE* dumps = seqState->dumps; const BYTE* const de = seqState->dumpsEnd; - size_t litLength, offset, matchLength; + size_t litLength, offset; /* Literal length */ litLength = FSE_peakSymbol(&(seqState->stateLL)); if (litLength == MaxLL) { - U32 add = *dumps++; + const U32 add = *dumps++; if (add < 255) litLength += add; else { litLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no risk : dumps is always followed by seq tables > 1 byte */ @@ -677,9 +677,8 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) 1 /*fake*/, 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, /*fake*/ 1, 1, 1, 1 }; - U32 offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ - U32 nbBits = offsetCode - 1; - if (offsetCode==0) nbBits = 0; /* cmove */ + const U32 offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ + const U32 nbBits = offsetCode ? offsetCode-1 : 0; offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits); if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); if (offsetCode==0) offset = litLength ? seq->offset : seqState->prevOffset; @@ -692,23 +691,25 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); /* MatchLength */ - matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); - if (matchLength == MaxML) { - U32 add = *dumps++; - if (add < 255) matchLength += add; - else { - matchLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */ - if (matchLength&1) matchLength>>=1, dumps += 3; - else matchLength = (U16)(matchLength)>>1, dumps += 2; + { + size_t matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); + if (matchLength == MaxML) { + const U32 add = *dumps++; + if (add < 255) matchLength += add; + else { + matchLength = MEM_readLE32(dumps) & 0xFFFFFF; /* no pb : dumps is always followed by seq tables > 1 byte */ + if (matchLength&1) matchLength>>=1, dumps += 3; + else matchLength = (U16)(matchLength)>>1, dumps += 2; + } + if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ } - if (dumps >= de) dumps = de-1; /* late correction, to avoid read overflow (data is now corrupted anyway) */ + matchLength += mls; + seq->matchLength = matchLength; } - matchLength += mls; /* save result */ seq->litLength = litLength; seq->offset = offset; - seq->matchLength = matchLength; seqState->dumps = dumps; #if 0 /* debug */ From cdabd4a2a6004874007a06bed40c3d3cf22ca756 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 17 Mar 2016 16:18:36 +0100 Subject: [PATCH 24/49] switched fullbench time measurement to clock_t from --- programs/fullbench.c | 77 +++++++++++--------------------------------- 1 file changed, 18 insertions(+), 59 deletions(-) diff --git a/programs/fullbench.c b/programs/fullbench.c index 8b43d20e1..a5e9fadaa 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -51,13 +51,7 @@ #include /* stat64 */ #include /* stat64 */ #include /* strcmp */ - -/* Use ftime() if gettimeofday() is not available on your target */ -#if defined(BMK_LEGACY_TIMER) -# include /* timeb, ftime */ -#else -# include /* gettimeofday */ -#endif +#include /* clock_t, clock, CLOCKS_PER_SEC */ #include "mem.h" #include "zstd_static.h" @@ -90,7 +84,7 @@ #define MB *(1<<20) #define NBLOOPS 6 -#define TIMELOOP 2500 +#define TIMELOOP_S 2 #define KNUTH 2654435761U #define MAX_MEM (1984 MB) @@ -122,42 +116,10 @@ void BMK_SetNbIterations(int nbLoops) /*_******************************************************* * Private functions *********************************************************/ - -#if defined(BMK_LEGACY_TIMER) - -static int BMK_GetMilliStart(void) +static clock_t BMK_clockSpan( clock_t clockStart ) { - /* Based on Legacy ftime() - * Rolls over every ~ 12.1 days (0x100000/24/60/60) - * Use GetMilliSpan to correct for rollover */ - struct timeb tb; - int nCount; - ftime( &tb ); - nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000); - return nCount; -} - -#else - -static int BMK_GetMilliStart(void) -{ - /* Based on newer gettimeofday() - * Use GetMilliSpan to correct for rollover */ - struct timeval tv; - int nCount; - gettimeofday(&tv, NULL); - nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000); - return nCount; -} - -#endif - - -static int BMK_GetMilliSpan( int nTimeStart ) -{ - int nSpan = BMK_GetMilliStart() - nTimeStart; - if ( nSpan < 0 ) nSpan += 0x100000 * 1000; - return nSpan; + const clock_t clockEnd = clock(); + return clockEnd - clockStart; /* overflow possible */ } @@ -310,7 +272,6 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) const char* benchName; size_t (*benchFunction)(void* dst, size_t dstSize, void* verifBuff, const void* src, size_t srcSize); double bestTime = 100000000.; - size_t errorCode = 0; /* Selection */ switch(benchNb) @@ -416,28 +377,26 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) { size_t i; for (i=0; i %s !! \n", benchName, ZSTD_getErrorName(errorCode)); exit(1); } - nbRounds++; + clockStart = clock(); + while (clock() == clockStart); + clockStart = clock(); + for (nbRounds=0; BMK_clockSpan(clockStart) < timeLoop; nbRounds++) { + benchResult = benchFunction(dstBuff, dstBuffSize, buff2, src, srcSize); + if (ZSTD_isError(benchResult)) { DISPLAY("ERROR ! %s() => %s !! \n", benchName, ZSTD_getErrorName(benchResult)); exit(1); } } - milliTime = BMK_GetMilliSpan(milliTime); - - averageTime = (double)milliTime / nbRounds; + averageTime = (((double)BMK_clockSpan(clockStart)) / CLOCKS_PER_SEC) / nbRounds; if (averageTime < bestTime) bestTime = averageTime; - DISPLAY("%2i- %-30.30s : %7.1f MB/s (%9u)\r", loopNb, benchName, (double)srcSize / bestTime / 1000., (U32)errorCode); + DISPLAY("%2i- %-30.30s : %7.1f MB/s (%9u)\r", loopNb, benchName, (double)srcSize / (1 MB) / bestTime, (U32)benchResult); } - - DISPLAY("%2u- %-30.30s : %7.1f MB/s (%9u)\n", benchNb, benchName, (double)srcSize / bestTime / 1000., (U32)errorCode); + DISPLAY("%2u\n", benchNb); _cleanOut: free(dstBuff); From 512220a82fd0e230ce21f0383e3ed14d6ffc7022 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 17 Mar 2016 16:42:16 +0100 Subject: [PATCH 25/49] fullbench : restored -b31 (decodeLiterals) and -b32 (decodeSeqHeaders) --- programs/fullbench.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/programs/fullbench.c b/programs/fullbench.c index a5e9fadaa..b3edd5405 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -328,32 +328,42 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) g_cSize = ZSTD_compress(buff2, dstBuffSize, src, srcSize, 1); break; case 31: /* ZSTD_decodeLiteralsBlock */ + if (g_zdc==NULL) g_zdc = ZSTD_createDCtx(); { blockProperties_t bp; + ZSTD_frameParams zfp; + size_t frameHeaderSize, skippedSize; g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); - ZSTD_getcBlockSize(dstBuff+4, dstBuffSize, &bp); /* Get 1st block type */ + frameHeaderSize = ZSTD_getFrameParams(&zfp, dstBuff, ZSTD_frameHeaderSize_min); + if (frameHeaderSize==0) frameHeaderSize = ZSTD_frameHeaderSize_min; + ZSTD_getcBlockSize(dstBuff+frameHeaderSize, dstBuffSize, &bp); /* Get 1st block type */ if (bp.blockType != bt_compressed) { DISPLAY("ZSTD_decodeLiteralsBlock : impossible to test on this sample (not compressible)\n"); goto _cleanOut; } - memcpy(buff2, dstBuff+8, g_cSize-8); + skippedSize = frameHeaderSize + 3 /* ZSTD_blockHeaderSize */; + memcpy(buff2, dstBuff+skippedSize, g_cSize-skippedSize); srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */ break; } case 32: /* ZSTD_decodeSeqHeaders */ if (g_zdc==NULL) g_zdc = ZSTD_createDCtx(); { blockProperties_t bp; + ZSTD_frameParams zfp; const BYTE* ip = dstBuff; const BYTE* iend; - size_t blockSize; + size_t frameHeaderSize, cBlockSize; ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); /* it would be better to use direct block compression here */ - ip += 5; /* Skip frame Header */ - blockSize = ZSTD_getcBlockSize(ip, dstBuffSize, &bp); /* Get 1st block type */ + g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, 1); + frameHeaderSize = ZSTD_getFrameParams(&zfp, dstBuff, ZSTD_frameHeaderSize_min); + if (frameHeaderSize==0) frameHeaderSize = ZSTD_frameHeaderSize_min; + ip += frameHeaderSize; /* Skip frame Header */ + cBlockSize = ZSTD_getcBlockSize(ip, dstBuffSize, &bp); /* Get 1st block type */ if (bp.blockType != bt_compressed) { DISPLAY("ZSTD_decodeSeqHeaders : impossible to test on this sample (not compressible)\n"); goto _cleanOut; } - iend = ip + 3 + blockSize; /* End of first block */ - ip += 3; /* skip block header */ + iend = ip + 3 /* ZSTD_blockHeaderSize */ + cBlockSize; /* End of first block */ + ip += 3 /* ZSTD_blockHeaderSize */; /* skip block header */ ip += ZSTD_decodeLiteralsBlock(g_zdc, ip, iend-ip); /* skip literal segment */ g_cSize = iend-ip; memcpy(buff2, ip, g_cSize); /* copy rest of block (it starts by SeqHeader) */ From 699b14db1bf58d99a4fc4fd7d9e8044255fd6607 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Thu, 17 Mar 2016 19:37:33 +0100 Subject: [PATCH 26/49] bench : changed timer to clock_t, reduced timeloop to 1sec --- programs/bench.c | 117 ++++++++++++++----------------------------- programs/fullbench.c | 34 ++++++------- 2 files changed, 51 insertions(+), 100 deletions(-) diff --git a/programs/bench.c b/programs/bench.c index 82e28d405..e819cc242 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -40,11 +40,6 @@ # define _LARGEFILE64_SOURCE #endif -/* S_ISREG & gettimeofday() are not supported by MSVC */ -#if defined(_MSC_VER) || defined(_WIN32) -# define BMK_LEGACY_TIMER 1 -#endif - /* ************************************* * Includes @@ -54,13 +49,7 @@ #include /* fprintf, fopen, ftello64 */ #include /* stat64 */ #include /* stat64 */ - -/* Use ftime() if gettimeofday() is not available */ -#if defined(BMK_LEGACY_TIMER) -# include /* timeb, ftime */ -#else -# include /* gettimeofday */ -#endif +#include /* clock_t, clock, CLOCKS_PER_SEC */ /* sleep : posix - windows - others */ #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))) @@ -95,7 +84,7 @@ * Constants ***************************************/ #define NBLOOPS 3 -#define TIMELOOP_MS 2500 +#define TIMELOOP_S 1 #define ACTIVEPERIOD_S 70 #define COOLPERIOD_S 10 @@ -156,44 +145,11 @@ void BMK_SetBlockSize(size_t blockSize) /* ******************************************************** * Private functions **********************************************************/ - -#if defined(BMK_LEGACY_TIMER) - -static int BMK_GetMilliStart(void) +static clock_t BMK_clockSpan( clock_t clockStart ) { - /* Based on Legacy ftime() - * Rolls over every ~ 12.1 days (0x100000/24/60/60) - * Use GetMilliSpan to correct for rollover */ - struct timeb tb; - int nCount; - ftime( &tb ); - nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000); - return nCount; + return clock() - clockStart; /* works even if overflow, span limited to <= ~30mn */ } -#else - -static int BMK_GetMilliStart(void) -{ - /* Based on newer gettimeofday() - * Use GetMilliSpan to correct for rollover */ - struct timeval tv; - int nCount; - gettimeofday(&tv, NULL); - nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000); - return nCount; -} - -#endif - - -static int BMK_GetMilliSpan( int nTimeStart ) -{ - int nSpan = BMK_GetMilliStart() - nTimeStart; - if ( nSpan < 0 ) - nSpan += 0x100000 * 1000; - return nSpan; -} static U64 BMK_getFileSize(const char* infilename) { @@ -255,14 +211,14 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, /* Init blockTable data */ { - U32 fileNb; const char* srcPtr = (const char*)srcBuffer; char* cPtr = (char*)compressedBuffer; char* resPtr = (char*)resultBuffer; + U32 fileNb; for (fileNb=0; fileNb ACTIVEPERIOD_S*1000) { + if (BMK_clockSpan(coolTime) > ACTIVEPERIOD_S * CLOCKS_PER_SEC) { DISPLAY("\rcooling down ... \r"); BMK_sleep(COOLPERIOD_S); - coolTime = BMK_GetMilliStart(); + coolTime = clock(); } /* Compression */ DISPLAY("%2i-%-17.17s :%10u ->\r", loopNb, displayName, (U32)srcSize); - memset(compressedBuffer, 0xE5, maxCompressedSize); + memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */ nbLoops = 0; - milliTime = BMK_GetMilliStart(); - while (BMK_GetMilliStart() == milliTime); - milliTime = BMK_GetMilliStart(); - while (BMK_GetMilliSpan(milliTime) < TIMELOOP_MS) { + clockStart = clock(); + while (clock() == clockStart); + clockStart = clock(); + while (BMK_clockSpan(clockStart) < TIMELOOP_S * CLOCKS_PER_SEC) { ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, MAX(dictBufferSize, largestBlockSize))); for (blockNb=0; blockNb%10i (%5.3f),%6.1f MB/s\r", loopNb, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000.); + DISPLAY("%2i-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s\r", + loopNb, displayName, (U32)srcSize, (U32)cSize, ratio, + (double)srcSize / 1000000. / (fastestC / CLOCKS_PER_SEC) ); #if 1 /* Decompression */ memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ nbLoops = 0; - milliTime = BMK_GetMilliStart(); - while (BMK_GetMilliStart() == milliTime); - milliTime = BMK_GetMilliStart(); + clockStart = clock(); + while (clock() == clockStart); + clockStart = clock(); - for ( ; BMK_GetMilliSpan(milliTime) < TIMELOOP_MS; nbLoops++) { + for ( ; BMK_clockSpan(clockStart) < TIMELOOP_S * CLOCKS_PER_SEC; nbLoops++) { ZSTD_decompressBegin_usingDict(refDCtx, dictBuffer, dictBufferSize); for (blockNb=0; blockNb%10i (%5.3f),%6.1f MB/s ,%6.1f MB/s\r", loopNb, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000., (double)srcSize / fastestD / 1000.); + clockSpan = BMK_clockSpan(clockStart); + if ((double)clockSpan < fastestD*nbLoops) fastestD = (double)clockSpan / nbLoops; + DISPLAY("%2i-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s ,%6.1f MB/s\r", + loopNb, displayName, (U32)srcSize, (U32)cSize, ratio, + (double)srcSize / 1000000. / (fastestC / CLOCKS_PER_SEC), + (double)srcSize / 1000000. / (fastestD / CLOCKS_PER_SEC) ); /* CRC Checking */ _findError: @@ -385,10 +346,7 @@ _findError: #endif } - if (crcOrig == crcCheck) - DISPLAY("%2i-%-17.17s :%10i ->%10i (%5.3f),%6.1f MB/s ,%6.1f MB/s \n", cLevel, displayName, (int)srcSize, (int)cSize, ratio, (double)srcSize / fastestC / 1000., (double)srcSize / fastestD / 1000.); - else - DISPLAY("%2i-\n", cLevel); + DISPLAY("%2i-\n", cLevel); } /* clean up */ @@ -424,7 +382,7 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, const size_t* fileSizes, unsigned nbFiles, const void* dictBuffer, size_t dictBufferSize) { - if (cLevel < 0) { + if (cLevel < 0) { /* range mode : test all levels from 1 to l */ int l; for (l=1; l <= -cLevel; l++) { BMK_benchMem(srcBuffer, benchedSize, @@ -451,12 +409,11 @@ static U64 BMK_getTotalFileSize(const char** fileNamesTable, unsigned nbFiles) static void BMK_loadFiles(void* buffer, size_t bufferSize, size_t* fileSizes, - const char** fileNamesTable, unsigned nbFiles) + const char** fileNamesTable, unsigned const nbFiles) { - BYTE* buff = (BYTE*)buffer; size_t pos = 0; - unsigned n; + unsigned n; for (n=0; n bufferSize-pos) fileSize = bufferSize-pos; - readSize = fread(buff+pos, 1, (size_t)fileSize, f); + readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f); if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]); pos += readSize; fileSizes[n] = (size_t)fileSize; @@ -548,7 +505,7 @@ static void BMK_syntheticTest(int cLevel, double compressibility) int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, const char* dictFileName, int cLevel) { - double compressibility = (double)g_compressibilityDefault / 100; + double const compressibility = (double)g_compressibilityDefault / 100; if (nbFiles == 0) BMK_syntheticTest(cLevel, compressibility); diff --git a/programs/fullbench.c b/programs/fullbench.c index b3edd5405..b4afcf112 100644 --- a/programs/fullbench.c +++ b/programs/fullbench.c @@ -37,11 +37,6 @@ # define _LARGEFILE64_SOURCE #endif -/* S_ISREG & gettimeofday() are not supported by MSVC */ -#if defined(_MSC_VER) || defined(_WIN32) -# define BMK_LEGACY_TIMER 1 -#endif - /*_************************************ * Includes @@ -103,13 +98,13 @@ static const size_t g_sampleSize = 10000000; /*_************************************ * Benchmark Parameters **************************************/ -static int nbIterations = NBLOOPS; +static U32 g_nbIterations = NBLOOPS; static double g_compressibility = COMPRESSIBILITY_DEFAULT; -void BMK_SetNbIterations(int nbLoops) +static void BMK_SetNbIterations(U32 nbLoops) { - nbIterations = nbLoops; - DISPLAY("- %i iterations -\n", nbIterations); + g_nbIterations = nbLoops; + DISPLAY("- %i iterations -\n", g_nbIterations); } @@ -118,27 +113,26 @@ void BMK_SetNbIterations(int nbLoops) *********************************************************/ static clock_t BMK_clockSpan( clock_t clockStart ) { - const clock_t clockEnd = clock(); - return clockEnd - clockStart; /* overflow possible */ + return clock() - clockStart; /* works even if overflow, span limited to <= ~30mn */ } static size_t BMK_findMaxMem(U64 requiredMem) { - size_t step = 64 MB; + const size_t step = 64 MB; void* testmem = NULL; requiredMem = (((requiredMem >> 26) + 1) << 26); if (requiredMem > MAX_MEM) requiredMem = MAX_MEM; - requiredMem += 2*step; - while (!testmem) { - requiredMem -= step; + requiredMem += step; + do { testmem = malloc ((size_t)requiredMem); - } + requiredMem -= step; + } while (!testmem); free (testmem); - return (size_t) (requiredMem - step); + return (size_t) requiredMem; } @@ -268,7 +262,6 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) BYTE* dstBuff; size_t dstBuffSize; BYTE* buff2; - int loopNb; const char* benchName; size_t (*benchFunction)(void* dst, size_t dstSize, void* verifBuff, const void* src, size_t srcSize); double bestTime = 100000000.; @@ -386,7 +379,8 @@ static size_t benchMem(const void* src, size_t srcSize, U32 benchNb) { size_t i; for (i=0; i Date: Thu, 17 Mar 2016 19:51:02 +0100 Subject: [PATCH 27/49] bench.c : implemented single pass mode `-i0` --- programs/bench.c | 17 +++++++++-------- programs/bench.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/programs/bench.c b/programs/bench.c index e819cc242..d1341fe1c 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -126,13 +126,13 @@ static U32 g_displayLevel = 2; /* 0 : no display; 1: errors; 2 : + result /* ************************************* * Benchmark Parameters ***************************************/ -static int nbIterations = NBLOOPS; +static U32 g_nbIterations = NBLOOPS; static size_t g_blockSize = 0; -void BMK_SetNbIterations(int nbLoops) +void BMK_SetNbIterations(unsigned nbLoops) { - nbIterations = nbLoops; - DISPLAY("- %i iterations -\n", nbIterations); + g_nbIterations = nbLoops; + DISPLAY("- %i iterations -\n", g_nbIterations); } void BMK_SetBlockSize(size_t blockSize) @@ -238,7 +238,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, /* Bench */ { - int loopNb; + U32 loopNb; size_t cSize = 0; double fastestC = 100000000., fastestD = 100000000.; double ratio = 0.; @@ -246,10 +246,11 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, clock_t coolTime = clock(); DISPLAY("\r%79s\r", ""); - for (loopNb = 1; loopNb <= nbIterations; loopNb++) { + for (loopNb = 1; loopNb <= (g_nbIterations + !g_nbIterations); loopNb++) { int nbLoops; U32 blockNb; clock_t clockStart, clockSpan; + clock_t const clockLoop = g_nbIterations ? TIMELOOP_S * CLOCKS_PER_SEC : 10; /* overheat protection */ if (BMK_clockSpan(coolTime) > ACTIVEPERIOD_S * CLOCKS_PER_SEC) { @@ -266,7 +267,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, clockStart = clock(); while (clock() == clockStart); clockStart = clock(); - while (BMK_clockSpan(clockStart) < TIMELOOP_S * CLOCKS_PER_SEC) { + while (BMK_clockSpan(clockStart) < clockLoop) { ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, MAX(dictBufferSize, largestBlockSize))); for (blockNb=0; blockNb Date: Fri, 18 Mar 2016 12:37:45 +0100 Subject: [PATCH 28/49] minor code refactoring --- lib/zstd_compress.c | 138 +++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 73 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 980b5c770..ebe4cdc92 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -445,7 +445,7 @@ size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, siz static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize) { BYTE* const ostart = (BYTE* const)dst; - const U32 flSize = 1 + (srcSize>31) + (srcSize>4095); + U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall); @@ -473,7 +473,7 @@ static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) { BYTE* const ostart = (BYTE* const)dst; - U32 flSize = 1 + (srcSize>31) + (srcSize>4095); + U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */ @@ -486,7 +486,7 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, cons ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8)); ostart[1] = (BYTE)srcSize; break; - default: /*note : should not be necessary : flSize is necessary within {1,2,3} */ + default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */ case 3: /* 2 - 2 - 20 */ ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16)); ostart[1] = (BYTE)(srcSize>>8); @@ -505,57 +505,57 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - const size_t minGain = ZSTD_minGain(srcSize); + size_t const minGain = ZSTD_minGain(srcSize); + size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); BYTE* const ostart = (BYTE*)dst; - const size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); U32 singleStream = srcSize < 256; U32 hType = IS_HUF; - size_t clitSize; + size_t cLitSize; if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ if (zc->flagStaticTables && (lhSize==3)) { hType = IS_PCH; singleStream = 1; - clitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable); + cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable); } else { - clitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12) + cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12) : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12); } - if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); - if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); + if ((cLitSize==0) || (cLitSize >= srcSize - minGain)) + return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + if (cLitSize==1) + return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); /* Build header */ switch(lhSize) { case 3: /* 2 - 2 - 10 - 10 */ ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6)); - ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8)); - ostart[2] = (BYTE)(clitSize); + ostart[1] = (BYTE)((srcSize<<2) + (cLitSize>>8)); + ostart[2] = (BYTE)(cLitSize); break; case 4: /* 2 - 2 - 14 - 14 */ ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6)); ostart[1] = (BYTE)(srcSize>> 2); - ostart[2] = (BYTE)((srcSize<<6) + (clitSize>>8)); - ostart[3] = (BYTE)(clitSize); + ostart[2] = (BYTE)((srcSize<<6) + (cLitSize>>8)); + ostart[3] = (BYTE)(cLitSize); break; - default: /* should not be necessary, lhSize is {3,4,5} */ + default: /* should not be necessary, lhSize is only {3,4,5} */ case 5: /* 2 - 2 - 18 - 18 */ ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6)); ostart[1] = (BYTE)(srcSize>>6); - ostart[2] = (BYTE)((srcSize<<2) + (clitSize>>16)); - ostart[3] = (BYTE)(clitSize>>8); - ostart[4] = (BYTE)(clitSize); + ostart[2] = (BYTE)((srcSize<<2) + (cLitSize>>16)); + ostart[3] = (BYTE)(cLitSize>>8); + ostart[4] = (BYTE)(cLitSize); break; } - return lhSize+clitSize; + return lhSize+cLitSize; } -#define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */ - size_t ZSTD_compressSequences(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, size_t srcSize) @@ -563,36 +563,30 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, const seqStore_t* seqStorePtr = &(zc->seqStore); U32 count[MaxSeq+1]; S16 norm[MaxSeq+1]; - size_t mostFrequent; - U32 max; FSE_CTable* CTable_LitLength = zc->litlengthCTable; FSE_CTable* CTable_OffsetBits = zc->offcodeCTable; FSE_CTable* CTable_MatchLength = zc->matchlengthCTable; U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ - const BYTE* const op_lit_start = seqStorePtr->litStart; const BYTE* const llTable = seqStorePtr->litLengthStart; const BYTE* const llPtr = seqStorePtr->litLength; const BYTE* const mlTable = seqStorePtr->matchLengthStart; const U32* const offsetTable = seqStorePtr->offsetStart; BYTE* const offCodeTable = seqStorePtr->offCodeStart; BYTE* const ostart = (BYTE*)dst; - BYTE* op = ostart; BYTE* const oend = ostart + dstCapacity; - const size_t nbSeq = llPtr - llTable; - const size_t minGain = ZSTD_minGain(srcSize); - const size_t maxCSize = srcSize - minGain; + BYTE* op = ostart; + size_t const nbSeq = llPtr - llTable; BYTE* seqHead; /* Compress literals */ +# define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */ { - size_t cSize; - size_t litSize = seqStorePtr->lit - op_lit_start; - const size_t minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY; - - if (litSize <= minLitSize) - cSize = ZSTD_noCompressLiterals(op, dstCapacity, op_lit_start, litSize); - else - cSize = ZSTD_compressLiterals(zc, op, dstCapacity, op_lit_start, litSize); + const BYTE* const literals = seqStorePtr->litStart; + size_t const litSize = seqStorePtr->lit - literals; + size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY; + size_t const cSize = (litSize <= minLitSize) ? + ZSTD_noCompressLiterals(op, dstCapacity, literals, litSize) : + ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize); if (ZSTD_isError(cSize)) return cSize; op += cSize; } @@ -609,7 +603,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, return ERROR(dstSize_tooSmall); seqHead = op; { - size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart; + size_t const dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart; if (dumpsLength < 512) { op[0] = (BYTE)(dumpsLength >> 8); op[1] = (BYTE)(dumpsLength); @@ -629,8 +623,8 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, #define MAX_SEQ_FOR_STATIC_FSE 1000 /* CTable for Literal Lengths */ - max = MaxLL; - mostFrequent = FSE_countFast(count, &max, llTable, nbSeq); + { U32 max = MaxLL; + size_t const mostFrequent = FSE_countFast(count, &max, llTable, nbSeq); if ((mostFrequent == nbSeq) && (nbSeq > 2)) { *op++ = llTable[0]; FSE_buildCTable_rle(CTable_LitLength, (BYTE)max); @@ -643,7 +637,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, } else { size_t NCountSize; size_t nbSeq_1 = nbSeq; - U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max); + const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max); if (count[llTable[nbSeq-1]]>1) { count[llTable[nbSeq-1]]--; nbSeq_1--; } FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ @@ -651,17 +645,13 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, op += NCountSize; FSE_buildCTable(CTable_LitLength, norm, max, tableLog); LLtype = FSE_ENCODING_DYNAMIC; - } + }} - /* CTable for Offset codes */ - { /* create Offset codes */ - size_t i; for (i=0; i 2)) { *op++ = offCodeTable[0]; FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max); @@ -674,7 +664,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, } else { size_t NCountSize; size_t nbSeq_1 = nbSeq; - U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max); + const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max); if (count[offCodeTable[nbSeq-1]]>1) { count[offCodeTable[nbSeq-1]]--; nbSeq_1--; } FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max); NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ @@ -682,11 +672,11 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, op += NCountSize; FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog); Offtype = FSE_ENCODING_DYNAMIC; - } + }} /* CTable for MatchLengths */ - max = MaxML; - mostFrequent = FSE_countFast(count, &max, mlTable, nbSeq); + { U32 max = MaxML; + size_t const mostFrequent = FSE_countFast(count, &max, mlTable, nbSeq); if ((mostFrequent == nbSeq) && (nbSeq > 2)) { *op++ = *mlTable; FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max); @@ -698,29 +688,27 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, MLtype = FSE_ENCODING_RAW; } else { size_t NCountSize; - U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max); + const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max); FSE_normalizeCount(norm, tableLog, count, nbSeq, max); NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */ if (FSE_isError(NCountSize)) return ERROR(GENERIC); op += NCountSize; FSE_buildCTable(CTable_MatchLength, norm, max, tableLog); MLtype = FSE_ENCODING_DYNAMIC; - } + }} seqHead[0] += (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); zc->flagStaticTables = 0; /* Encoding Sequences */ { - size_t streamSize, errorCode; BIT_CStream_t blockStream; - FSE_CState_t stateMatchLength; - FSE_CState_t stateOffsetBits; - FSE_CState_t stateLitLength; - int i; + FSE_CState_t stateMatchLength; + FSE_CState_t stateOffsetBits; + FSE_CState_t stateLitLength; - errorCode = BIT_initCStream(&blockStream, op, oend-op); - if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); /* not enough space remaining */ + { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op); + if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */ /* first symbols */ FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlTable[nbSeq-1]); @@ -729,12 +717,12 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, BIT_addBits(&blockStream, offsetTable[nbSeq-1], offCodeTable[nbSeq-1] ? (offCodeTable[nbSeq-1]-1) : 0); BIT_flushBits(&blockStream); - for (i=(int)nbSeq-2; i>=0; i--) { - BYTE mlCode = mlTable[i]; - U32 offset = offsetTable[i]; - BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/ - U32 nbBits = (offCode-1) + (!offCode); - BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/ + { int i; for (i=(int)nbSeq-2; i>=0; i--) { + const BYTE mlCode = mlTable[i]; + const U32 offset = offsetTable[i]; + const BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/ + const U32 nbBits = (offCode-1) + (!offCode); + const BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/ FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 17 */ /* 17 */ if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ FSE_encodeSymbol(&blockStream, &stateLitLength, litLength); /* 17 */ /* 27 */ @@ -742,20 +730,24 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */ BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 62 */ /* 24 bits max in 32-bits mode */ BIT_flushBits(&blockStream); /* 7 */ /* 7 */ - } + }} FSE_flushCState(&blockStream, &stateMatchLength); FSE_flushCState(&blockStream, &stateOffsetBits); FSE_flushCState(&blockStream, &stateLitLength); - streamSize = BIT_closeCStream(&blockStream); + { size_t const streamSize = BIT_closeCStream(&blockStream); if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */ - op += streamSize; + op += streamSize; } } /* check compressibility */ _check_compressibility: - if ((size_t)(op-ostart) >= maxCSize) return 0; + { + size_t const minGain = ZSTD_minGain(srcSize); + size_t const maxCSize = srcSize - minGain; + if ((size_t)(op-ostart) >= maxCSize) return 0; + } return op - ostart; } From a8e54654bcf9607243996e7d5792ef8496080c7c Mon Sep 17 00:00:00 2001 From: Christophe Chevalier Date: Fri, 18 Mar 2016 14:20:33 +0100 Subject: [PATCH 29/49] Made all vs2013 vcxproj build to the same folders - Add OutDir = $(SolutionDir)bin\$(Platform)\$(Configuration)\ to all projects --- visual/2013/fullbench/fullbench.vcxproj | 1 + visual/2013/fuzzer/fuzzer.vcxproj | 1 + visual/2013/zstd/zstd.vcxproj | 3 +-- visual/2013/zstdlib/zstdlib.vcxproj | 7 +------ 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/visual/2013/fullbench/fullbench.vcxproj b/visual/2013/fullbench/fullbench.vcxproj index afee2370c..8252d03d0 100644 --- a/visual/2013/fullbench/fullbench.vcxproj +++ b/visual/2013/fullbench/fullbench.vcxproj @@ -22,6 +22,7 @@ {61ABD629-1CC8-4FD7-9281-6B8DBB9D3DF8} Win32Proj fullbench + $(SolutionDir)bin\$(Platform)\$(Configuration)\ diff --git a/visual/2013/fuzzer/fuzzer.vcxproj b/visual/2013/fuzzer/fuzzer.vcxproj index 0844efe74..49738e0ca 100644 --- a/visual/2013/fuzzer/fuzzer.vcxproj +++ b/visual/2013/fuzzer/fuzzer.vcxproj @@ -22,6 +22,7 @@ {6FD4352B-346C-4703-96EA-D4A8B9A6976E} Win32Proj fuzzer + $(SolutionDir)bin\$(Platform)\$(Configuration)\ diff --git a/visual/2013/zstd/zstd.vcxproj b/visual/2013/zstd/zstd.vcxproj index 99d308b9f..6d8b2b6cb 100644 --- a/visual/2013/zstd/zstd.vcxproj +++ b/visual/2013/zstd/zstd.vcxproj @@ -69,6 +69,7 @@ {4E52A41A-F33B-4C7A-8C36-A1A6B4F4277C} Win32Proj zstd + $(SolutionDir)bin\$(Platform)\$(Configuration)\ @@ -127,13 +128,11 @@ false $(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); false - $(SolutionDir)$(Configuration)\ false $(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); false - $(SolutionDir)$(Configuration)\ diff --git a/visual/2013/zstdlib/zstdlib.vcxproj b/visual/2013/zstdlib/zstdlib.vcxproj index b13bc98ff..e44699d4a 100644 --- a/visual/2013/zstdlib/zstdlib.vcxproj +++ b/visual/2013/zstdlib/zstdlib.vcxproj @@ -24,8 +24,6 @@ - - @@ -48,6 +46,7 @@ {8BFD8150-94D5-4BF9-8A50-7BD9929A0850} Win32Proj zstdlib + $(SolutionDir)bin\$(Platform)\$(Configuration)\ @@ -96,7 +95,6 @@ true zstdlib_x86 $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ $(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); true @@ -104,14 +102,12 @@ true zstdlib_x64 $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ $(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); true false zstdlib_x86 - $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ $(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); false @@ -119,7 +115,6 @@ false zstdlib_x64 - $(SolutionDir)$(Platform)\$(Configuration)\ $(Platform)\$(Configuration)\ $(SolutionDir)..\..\programs\legacy;$(SolutionDir)..\..\lib\legacy;$(SolutionDir)..\..\lib;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath); false From 39c596ca5803bc9407f7686d634db53853593efb Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 18 Mar 2016 21:40:56 +0100 Subject: [PATCH 30/49] minor simplifications --- lib/zstd_decompress.c | 62 +++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index da9665cd1..7a38bf9ba 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -516,7 +516,6 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen const BYTE* ip = istart; const BYTE* const iend = istart + srcSize; U32 LLtype, Offtype, MLtype; - U32 LLlog, Offlog, MLlog; size_t dumpsLength; /* check */ @@ -553,82 +552,75 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen /* check */ if (ip > iend-3) return ERROR(srcSize_wrong); /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */ - /* sequences */ + /* Build DTables */ { S16 norm[MaxML+1]; /* assumption : MaxML >= MaxLL >= MaxOff */ - size_t headerSize; - /* Build DTables */ switch(LLtype) { - U32 max; case FSE_ENCODING_RLE : - LLlog = 0; FSE_buildDTable_rle(DTableLL, *ip++); break; case FSE_ENCODING_RAW : - LLlog = LLbits; FSE_buildDTable_raw(DTableLL, LLbits); break; case FSE_ENCODING_STATIC: break; - case FSE_ENCODING_DYNAMIC : default : /* impossible */ - max = MaxLL; - headerSize = FSE_readNCount(norm, &max, &LLlog, ip, iend-ip); - if (FSE_isError(headerSize)) return ERROR(GENERIC); - if (LLlog > LLFSELog) return ERROR(corruption_detected); - ip += headerSize; - FSE_buildDTable(DTableLL, norm, max, LLlog); + case FSE_ENCODING_DYNAMIC : + { U32 LLlog, max = MaxLL; + size_t const headerSize = FSE_readNCount(norm, &max, &LLlog, ip, iend-ip); + if (FSE_isError(headerSize)) return ERROR(GENERIC); + if (LLlog > LLFSELog) return ERROR(corruption_detected); + ip += headerSize; + FSE_buildDTable(DTableLL, norm, max, LLlog); + } } switch(Offtype) { - U32 max; case FSE_ENCODING_RLE : - Offlog = 0; if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ FSE_buildDTable_rle(DTableOffb, *ip++ & MaxOff); /* if *ip > MaxOff, data is corrupted */ break; case FSE_ENCODING_RAW : - Offlog = Offbits; FSE_buildDTable_raw(DTableOffb, Offbits); break; case FSE_ENCODING_STATIC: break; - case FSE_ENCODING_DYNAMIC : default : /* impossible */ - max = MaxOff; - headerSize = FSE_readNCount(norm, &max, &Offlog, ip, iend-ip); - if (FSE_isError(headerSize)) return ERROR(GENERIC); - if (Offlog > OffFSELog) return ERROR(corruption_detected); - ip += headerSize; - FSE_buildDTable(DTableOffb, norm, max, Offlog); + case FSE_ENCODING_DYNAMIC : + { + U32 Offlog, max = MaxOff; + size_t const headerSize = FSE_readNCount(norm, &max, &Offlog, ip, iend-ip); + if (FSE_isError(headerSize)) return ERROR(GENERIC); + if (Offlog > OffFSELog) return ERROR(corruption_detected); + ip += headerSize; + FSE_buildDTable(DTableOffb, norm, max, Offlog); + } } switch(MLtype) { - U32 max; case FSE_ENCODING_RLE : - MLlog = 0; if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ FSE_buildDTable_rle(DTableML, *ip++); break; case FSE_ENCODING_RAW : - MLlog = MLbits; FSE_buildDTable_raw(DTableML, MLbits); break; case FSE_ENCODING_STATIC: break; - case FSE_ENCODING_DYNAMIC : default : /* impossible */ - max = MaxML; - headerSize = FSE_readNCount(norm, &max, &MLlog, ip, iend-ip); - if (FSE_isError(headerSize)) return ERROR(GENERIC); - if (MLlog > MLFSELog) return ERROR(corruption_detected); - ip += headerSize; - FSE_buildDTable(DTableML, norm, max, MLlog); - } } + case FSE_ENCODING_DYNAMIC : + { U32 MLlog, max = MaxML; + size_t const headerSize = FSE_readNCount(norm, &max, &MLlog, ip, iend-ip); + if (FSE_isError(headerSize)) return ERROR(GENERIC); + if (MLlog > MLFSELog) return ERROR(corruption_detected); + ip += headerSize; + FSE_buildDTable(DTableML, norm, max, MLlog); + } + } } /* Build DTables */ return ip-istart; } From 4db09efde416632cb6b18025e9c976db7ba70f97 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 18 Mar 2016 22:23:49 +0100 Subject: [PATCH 31/49] simplifications --- lib/zstd_decompress.c | 141 ++++++++++++++++++------------------------ lib/zstd_internal.h | 6 +- 2 files changed, 62 insertions(+), 85 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 7a38bf9ba..d8d7837a5 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -508,6 +508,39 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, } +/*! ZSTD_buildSeqTable() : + @return : nb bytes read from src, + or an error code if it fails, testable with ZSTD_isError() +*/ +static size_t ZSTD_buildSeqTable(FSE_DTable* DTable, U32 type, U32 rawBits, U32 maxLog, + const void* src, size_t srcSize) +{ + switch(type) + { + case FSE_ENCODING_RLE : + if (!srcSize) return ERROR(srcSize_wrong); + FSE_buildDTable_rle(DTable, *(const BYTE*)src); + return 1; + case FSE_ENCODING_RAW : + FSE_buildDTable_raw(DTable, rawBits); + return 0; + case FSE_ENCODING_STATIC: + return 0; + default : /* impossible */ + case FSE_ENCODING_DYNAMIC : + { U32 tableLog, max = (1< maxLog) return ERROR(corruption_detected); + FSE_buildDTable(DTable, norm, max, tableLog); + return headerSize; + } } +} + + + + size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLengthPtr, FSE_DTable* DTableLL, FSE_DTable* DTableML, FSE_DTable* DTableOffb, const void* src, size_t srcSize) @@ -516,11 +549,9 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen const BYTE* ip = istart; const BYTE* const iend = istart + srcSize; U32 LLtype, Offtype, MLtype; - size_t dumpsLength; /* check */ - if (srcSize < MIN_SEQUENCES_SIZE) - return ERROR(srcSize_wrong); + if (srcSize < MIN_SEQUENCES_SIZE) return ERROR(srcSize_wrong); /* SeqHead */ *nbSeq = *ip++; @@ -536,91 +567,37 @@ size_t ZSTD_decodeSeqHeaders(int* nbSeq, const BYTE** dumpsPtr, size_t* dumpsLen LLtype = *ip >> 6; Offtype = (*ip >> 4) & 3; MLtype = (*ip >> 2) & 3; - if (*ip & 2) { - dumpsLength = ip[2]; - dumpsLength += ip[1] << 8; - ip += 3; - } else { - dumpsLength = ip[1]; - dumpsLength += (ip[0] & 1) << 8; - ip += 2; + { size_t dumpsLength; + if (*ip & 2) { + dumpsLength = ip[2]; + dumpsLength += ip[1] << 8; + ip += 3; + } else { + dumpsLength = ip[1]; + dumpsLength += (ip[0] & 1) << 8; + ip += 2; + } + *dumpsPtr = ip; + ip += dumpsLength; + *dumpsLengthPtr = dumpsLength; } - *dumpsPtr = ip; - ip += dumpsLength; - *dumpsLengthPtr = dumpsLength; /* check */ if (ip > iend-3) return ERROR(srcSize_wrong); /* min : all 3 are "raw", hence no header, but at least xxLog bits per type */ /* Build DTables */ - { - S16 norm[MaxML+1]; /* assumption : MaxML >= MaxLL >= MaxOff */ - - switch(LLtype) - { - case FSE_ENCODING_RLE : - FSE_buildDTable_rle(DTableLL, *ip++); - break; - case FSE_ENCODING_RAW : - FSE_buildDTable_raw(DTableLL, LLbits); - break; - case FSE_ENCODING_STATIC: - break; - default : /* impossible */ - case FSE_ENCODING_DYNAMIC : - { U32 LLlog, max = MaxLL; - size_t const headerSize = FSE_readNCount(norm, &max, &LLlog, ip, iend-ip); - if (FSE_isError(headerSize)) return ERROR(GENERIC); - if (LLlog > LLFSELog) return ERROR(corruption_detected); - ip += headerSize; - FSE_buildDTable(DTableLL, norm, max, LLlog); - } - } - - switch(Offtype) - { - case FSE_ENCODING_RLE : - if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ - FSE_buildDTable_rle(DTableOffb, *ip++ & MaxOff); /* if *ip > MaxOff, data is corrupted */ - break; - case FSE_ENCODING_RAW : - FSE_buildDTable_raw(DTableOffb, Offbits); - break; - case FSE_ENCODING_STATIC: - break; - default : /* impossible */ - case FSE_ENCODING_DYNAMIC : - { - U32 Offlog, max = MaxOff; - size_t const headerSize = FSE_readNCount(norm, &max, &Offlog, ip, iend-ip); - if (FSE_isError(headerSize)) return ERROR(GENERIC); - if (Offlog > OffFSELog) return ERROR(corruption_detected); - ip += headerSize; - FSE_buildDTable(DTableOffb, norm, max, Offlog); - } - } - - switch(MLtype) - { - case FSE_ENCODING_RLE : - if (ip > iend-2) return ERROR(srcSize_wrong); /* min : "raw", hence no header, but at least xxLog bits */ - FSE_buildDTable_rle(DTableML, *ip++); - break; - case FSE_ENCODING_RAW : - FSE_buildDTable_raw(DTableML, MLbits); - break; - case FSE_ENCODING_STATIC: - break; - default : /* impossible */ - case FSE_ENCODING_DYNAMIC : - { U32 MLlog, max = MaxML; - size_t const headerSize = FSE_readNCount(norm, &max, &MLlog, ip, iend-ip); - if (FSE_isError(headerSize)) return ERROR(GENERIC); - if (MLlog > MLFSELog) return ERROR(corruption_detected); - ip += headerSize; - FSE_buildDTable(DTableML, norm, max, MLlog); - } - } } /* Build DTables */ + { size_t const bhSize = ZSTD_buildSeqTable(DTableLL, LLtype, LLbits, LLFSELog, ip, iend-ip); + if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); + ip += bhSize; + } + { size_t const bhSize = ZSTD_buildSeqTable(DTableOffb, Offtype, Offbits, OffFSELog, ip, iend-ip); + if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); + ip += bhSize; + } + { size_t const bhSize = ZSTD_buildSeqTable(DTableML, MLtype, MLbits, MLFSELog, ip, iend-ip); + if (ZSTD_isError(bhSize)) return ERROR(corruption_detected); + ip += bhSize; + } return ip-istart; } diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index 642c3777c..c5cc64cd5 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -90,6 +90,8 @@ static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; #define REPCODE_STARTVALUE 1 #define ZSTD_WINDOWLOG_ABSOLUTEMIN 12 +#define LONGNBSEQ 0x7F00 + #define Litbits 8 #define MLbits 7 #define LLbits 6 @@ -101,9 +103,7 @@ static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; #define MLFSELog 10 #define LLFSELog 10 #define OffFSELog 9 -#define MaxSeq MAX(MaxLL, MaxML) - -#define LONGNBSEQ 0x7F00 +#define MaxSeq MAX(MaxLL, MaxML) /* Assumption : MaxOff < MaxLL,MaxML */ #define FSE_ENCODING_RAW 0 #define FSE_ENCODING_RLE 1 From f3120413cce912886d808726b481a06462e6a8db Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 11:40:19 +0100 Subject: [PATCH 32/49] Fixed : decoder error on erroneous data --- programs/fuzzer.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/programs/fuzzer.c b/programs/fuzzer.c index 55e0c7d70..72d71ea98 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -596,18 +596,16 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit } /* decompress noisy source */ - { - U32 noiseSrc = FUZ_rand(&lseed) % 5; - const U32 endMark = 0xA9B1C3D6; - U32 endCheck; + { U32 const noiseSrc = FUZ_rand(&lseed) % 5; + U32 const endMark = 0xA9B1C3D6; srcBuffer = cNoiseBuffer[noiseSrc]; memcpy(dstBuffer+sampleSize, &endMark, 4); errorCode = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize); /* result *may* be an unlikely success, but even then, it must strictly respect dest buffer boundaries */ CHECK((!ZSTD_isError(errorCode)) && (errorCode>sampleSize), "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)errorCode, (U32)sampleSize); - memcpy(&endCheck, dstBuffer+sampleSize, 4); - CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow"); + { U32 endCheck; memcpy(&endCheck, dstBuffer+sampleSize, 4); + CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow"); } } } From d1d210f3fb3675e0f6b79545f3fef309b02339dc Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 12:12:07 +0100 Subject: [PATCH 33/49] minor code refactor --- lib/bitstream.h | 57 +++++++------- lib/fse.c | 2 +- lib/zstd_decompress.c | 24 +++--- programs/.gitignore | 2 + programs/fuzzer.c | 178 ++++++++++++++++-------------------------- 5 files changed, 109 insertions(+), 154 deletions(-) diff --git a/lib/bitstream.h b/lib/bitstream.h index 006a927f0..44c0241fa 100644 --- a/lib/bitstream.h +++ b/lib/bitstream.h @@ -56,10 +56,9 @@ extern "C" { /*-****************************************** * bitStream encoding API (write forward) ********************************************/ -/*! -* bitStream can mix input from multiple sources. -* A critical property of these streams is that they encode and decode in **reverse** direction. -* So the first bit sequence you add will be the last to be read, like a LIFO stack. +/* bitStream can mix input from multiple sources. +* A critical property of these streams is that they encode and decode in **reverse** direction. +* So the first bit sequence you add will be the last to be read, like a LIFO stack. */ typedef struct { @@ -75,10 +74,9 @@ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC); MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); -/*! -* Start by initCStream, providing the size of buffer to write into. +/*Start by initCStream, providing the size of buffer to write into. * bitStream will never write outside of this buffer. -* @dstCapacity must be >= sizeof(size_t), otherwise @return will be an error code. +* `dstCapacity` must be >= sizeof(size_t), otherwise @return will be an error code. * * bits are first added to a local register. * Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems. @@ -90,7 +88,7 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); * * Last operation is to close the bitStream. * The function returns the final size of CStream in bytes. -* If data couldn't fit into @dstBuffer, it will return a 0 ( == not storable) +* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable) */ @@ -117,8 +115,7 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); -/*! -* Start by invoking BIT_initDStream(). +/*Start by invoking BIT_initDStream(). * A chunk of the bitStream is then stored into a local register. * Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). * You can then retrieve bitFields stored into the local register, **in reverse order**. @@ -190,7 +187,7 @@ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits) bitC->bitPos += nbBits; } -/*! BIT_addBitsFast +/*! BIT_addBitsFast() : * works only if `value` is _clean_, meaning all high bits above nbBits are 0 */ MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { @@ -198,7 +195,7 @@ MEM_STATIC void BIT_addBitsFast(BIT_CStream_t* bitC, size_t value, unsigned nbBi bitC->bitPos += nbBits; } -/*! BIT_flushBitsFast +/*! BIT_flushBitsFast() : * unsafe version; does not check buffer overflow */ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) { @@ -219,8 +216,8 @@ MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */ } -/*! BIT_closeCStream - * @result : size of CStream, in bytes, or 0 if it cannot fit into dstBuffer */ +/*! BIT_closeCStream() : + * @return : size of CStream, in bytes, or 0 if it cannot fit into dstBuffer */ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) { char* endPtr; @@ -241,12 +238,12 @@ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) /*-******************************************************** * bitStream decoding **********************************************************/ -/*!BIT_initDStream +/*!BIT_initDStream() : * Initialize a BIT_DStream_t. -* @bitD : a pointer to an already allocated BIT_DStream_t structure -* @srcBuffer must point at the beginning of a bitStream -* @srcSize must be the exact size of the bitStream -* @result : size of stream (== srcSize) or an errorCode if a problem is detected +* `bitD` : a pointer to an already allocated BIT_DStream_t structure. +* `srcBuffer` must point at the beginning of a bitStream. +* `srcSize` must be the exact size of the bitStream. +* @return : size of stream (== srcSize) or an errorCode if a problem is detected */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) { @@ -284,24 +281,24 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si return srcSize; } -/*!BIT_lookBits - * Provides next n bits from local register - * local register is not modified (bits are still present for next read/look) - * On 32-bits, maxNbBits==25 - * On 64-bits, maxNbBits==57 +/*!BIT_lookBits() : + * Provides next n bits from local register. + * local register is not modified (bits are still present for next read/look). + * On 32-bits, maxNbBits==24. + * On 64-bits, maxNbBits==56. * @return : value extracted */ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) { - const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; + U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask); } -/*! BIT_lookBitsFast : +/*! BIT_lookBitsFast*() : * unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) { - const U32 bitMask = sizeof(bitD->bitContainer)*8 - 1; + U32 const bitMask = sizeof(bitD->bitContainer)*8 - 1; return (bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> (((bitMask+1)-nbBits) & bitMask); } @@ -310,7 +307,7 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) bitD->bitsConsumed += nbBits; } -/*!BIT_readBits +/*!BIT_readBits() : * Read next n bits from local register. * pay attention to not read more than nbBits contained into local register. * @return : extracted value. @@ -322,7 +319,7 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) return value; } -/*!BIT_readBitsFast : +/*!BIT_readBitsFast() : * unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { @@ -360,7 +357,7 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) } } -/*! BIT_endOfDStream +/*! BIT_endOfDStream() : * @return Tells if DStream has reached its exact end */ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) diff --git a/lib/fse.c b/lib/fse.c index a445f3285..291e64192 100644 --- a/lib/fse.c +++ b/lib/fse.c @@ -466,7 +466,7 @@ size_t FSE_readNCount (short* normalizedCounter, unsigned* maxSVPtr, unsigned* t bitStream >>= 2; } { - const short max = (short)((2*threshold-1)-remaining); + short const max = (short)((2*threshold-1)-remaining); short count; if ((bitStream & (threshold-1)) < (U32)max) { diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index d8d7837a5..5cf9c17c3 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -515,11 +515,12 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, static size_t ZSTD_buildSeqTable(FSE_DTable* DTable, U32 type, U32 rawBits, U32 maxLog, const void* src, size_t srcSize) { + U32 max = (1< max, data is corrupted */ return 1; case FSE_ENCODING_RAW : FSE_buildDTable_raw(DTable, rawBits); @@ -528,7 +529,7 @@ static size_t ZSTD_buildSeqTable(FSE_DTable* DTable, U32 type, U32 rawBits, U32 return 0; default : /* impossible */ case FSE_ENCODING_DYNAMIC : - { U32 tableLog, max = (1<stateOffb)); /* <= maxOff, by table construction */ - const U32 nbBits = offsetCode ? offsetCode-1 : 0; + { static const U32 offsetPrefix[MaxOff+1] = { + 1 /*fake*/, 1, 2, 4, 8, 0x10, 0x20, 0x40, + 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, + 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, + 0x800000, 0x1000000, 0x2000000, 0x4000000, /*fake*/ 1, 1, 1, 1 }; + U32 const offsetCode = FSE_peakSymbol(&(seqState->stateOffb)); /* <= maxOff, by table construction */ + U32 const nbBits = offsetCode ? offsetCode-1 : 0; offset = offsetPrefix[offsetCode] + BIT_readBits(&(seqState->DStream), nbBits); if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); if (offsetCode==0) offset = litLength ? seq->offset : seqState->prevOffset; @@ -727,8 +726,7 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, return sequenceLength; } /* span extDict & currentPrefixSegment */ - { - size_t length1 = dictEnd - match; + { size_t const length1 = dictEnd - match; memmove(oLitEnd, match, length1); op = oLitEnd + length1; sequence.matchLength -= length1; diff --git a/programs/.gitignore b/programs/.gitignore index 525037b94..a1d72aad1 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -5,6 +5,8 @@ fullbench fullbench32 fuzzer fuzzer32 +zbufftest +zbufftest32 datagen paramgrill diff --git a/programs/fuzzer.c b/programs/fuzzer.c index 72d71ea98..8bd2a1866 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -153,8 +153,7 @@ static int basicUnitTests(U32 seed, double compressibility) CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH); compressedBuffer = malloc(ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH)); decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH); - if (!CNBuffer || !compressedBuffer || !decodedBuffer) - { + if (!CNBuffer || !compressedBuffer || !decodedBuffer) { DISPLAY("Not enough memory, aborting\n"); testResult = 1; goto _end; @@ -174,11 +173,9 @@ static int basicUnitTests(U32 seed, double compressibility) if (result != COMPRESSIBLE_NOISE_LENGTH) goto _output_error; DISPLAYLEVEL(4, "OK \n"); - { - size_t i; + { size_t i; DISPLAYLEVEL(4, "test%3i : check decompressed result : ", testNb++); - for (i=0; i>= 3; - if (buffNb & 7) - { + if (buffNb & 7) { const U32 tnb[2] = { 1, 3 }; buffNb = tnb[buffNb >> 3]; - } - else - { + } else { const U32 tnb[2] = { 0, 4 }; buffNb = tnb[buffNb >> 3]; } @@ -506,7 +492,6 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit crcOrig = XXH64(sampleBuffer, sampleSize, 0); /* compression test */ - //cLevelMod = MAX(1, 38 - (int)(MAX(9, sampleSizeLog) * 2)); /* high levels only for small samples, for manageable speed */ cLevelMod = MIN( ZSTD_maxCLevel(), (U32)MAX(1, 55 - 3*(int)sampleSizeLog) ); /* high levels only for small samples, for manageable speed */ cLevel = (FUZ_rand(&lseed) % cLevelMod) +1; cSize = ZSTD_compressCCtx(ctx, cBuffer, cBufferSize, sampleBuffer, sampleSize, cLevel); @@ -517,12 +502,11 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */ const size_t tooSmallSize = cSize - missing; static const U32 endMark = 0x4DC2B1A9; - U32 endCheck; memcpy(dstBuffer+tooSmallSize, &endMark, 4); errorCode = ZSTD_compressCCtx(ctx, dstBuffer, tooSmallSize, sampleBuffer, sampleSize, cLevel); CHECK(!ZSTD_isError(errorCode), "ZSTD_compressCCtx should have failed ! (buffer too small : %u < %u)", (U32)tooSmallSize, (U32)cSize); - memcpy(&endCheck, dstBuffer+tooSmallSize, 4); - CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); + { U32 endCheck; memcpy(&endCheck, dstBuffer+tooSmallSize, 4); + CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); } } /* decompression header test */ @@ -542,8 +526,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit free(sampleBuffer); /* no longer useful after this point */ /* truncated src decompression test */ - { - const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */ + { const size_t missing = (FUZ_rand(&lseed) % (cSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */ const size_t tooSmallSize = cSize - missing; void* cBufferTooSmall = malloc(tooSmallSize); /* valgrind will catch overflows */ CHECK(cBufferTooSmall == NULL, "not enough memory !"); @@ -554,8 +537,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit } /* too small dst decompression test */ - if (sampleSize > 3) - { + if (sampleSize > 3) { const size_t missing = (FUZ_rand(&lseed) % (sampleSize-2)) + 1; /* no problem, as cSize > 4 (frameHeaderSizer) */ const size_t tooSmallSize = sampleSize - missing; static const BYTE token = 0xA9; @@ -566,39 +548,32 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit } /* noisy src decompression test */ - if (cSize > 6) - { - const U32 maxNbBits = FUZ_highbit32((U32)(cSize-4)); - size_t pos = 4; /* preserve magic number (too easy to detect) */ - U32 nbBits = FUZ_rand(&lseed) % maxNbBits; - size_t mask = (1<0) nbBits--; - mask = (1< cSize ) noiseLength = cSize-pos; - noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength); - memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength); - pos += noiseLength; - - /* keep some original src */ - nbBits = FUZ_rand(&lseed) % maxNbBits; - mask = (1< 6) { + /* insert noise into src */ + { U32 const maxNbBits = FUZ_highbit32((U32)(cSize-4)); + size_t pos = 4; /* preserve magic number (too easy to detect) */ + for (;;) { + /* keep some original src */ + { U32 const nbBits = FUZ_rand(&lseed) % maxNbBits; + size_t const mask = (1<0) nbBits--; + mask = (1< cSize ) noiseLength = cSize-pos; + noiseStart = FUZ_rand(&lseed) % (srcBufferSize - noiseLength); + memcpy(cBuffer + pos, srcBuffer + noiseStart, noiseLength); + pos += noiseLength; + } } } /* decompress noisy source */ - { U32 const noiseSrc = FUZ_rand(&lseed) % 5; - U32 const endMark = 0xA9B1C3D6; - srcBuffer = cNoiseBuffer[noiseSrc]; + { U32 const endMark = 0xA9B1C3D6; memcpy(dstBuffer+sampleSize, &endMark, 4); errorCode = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize); /* result *may* be an unlikely success, but even then, it must strictly respect dest buffer boundaries */ @@ -606,8 +581,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)errorCode, (U32)sampleSize); { U32 endCheck; memcpy(&endCheck, dstBuffer+sampleSize, 4); CHECK(endMark!=endCheck, "ZSTD_decompress on noisy src : dst buffer overflow"); } - } - } + } } /* noisy src decompression test */ /* Streaming compression of scattered segments test */ XXH64_reset(xxh64, 0); @@ -629,8 +603,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit errorCode = ZSTD_copyCCtx(ctx, refCtx); CHECK (ZSTD_isError(errorCode), "ZSTD_copyCCtx error : %s", ZSTD_getErrorName(errorCode)); totalTestSize = 0; cSize = 0; - for (n=0; n='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { nbTests *= 10; nbTests += *argument - '0'; argument++; @@ -777,8 +742,7 @@ int main(int argc, char** argv) case 'T': argument++; nbTests=0; g_testTime=0; - while ((*argument>='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { g_testTime *= 10; g_testTime += *argument - '0'; argument++; @@ -792,8 +756,7 @@ int main(int argc, char** argv) argument++; seed=0; seedset=1; - while ((*argument>='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { seed *= 10; seed += *argument - '0'; argument++; @@ -803,8 +766,7 @@ int main(int argc, char** argv) case 't': argument++; testNb=0; - while ((*argument>='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { testNb *= 10; testNb += *argument - '0'; argument++; @@ -814,8 +776,7 @@ int main(int argc, char** argv) case 'P': /* compressibility % */ argument++; proba=0; - while ((*argument>='0') && (*argument<='9')) - { + while ((*argument>='0') && (*argument<='9')) { proba *= 10; proba += *argument - '0'; argument++; @@ -826,10 +787,7 @@ int main(int argc, char** argv) default: return FUZ_usage(programName); - } - } - } - } + } } } } /* for (argNb=1; argNb Date: Sat, 19 Mar 2016 12:47:52 +0100 Subject: [PATCH 34/49] minor refactoring --- programs/fuzzer.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/programs/fuzzer.c b/programs/fuzzer.c index 8bd2a1866..a7aa728dd 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -445,13 +445,12 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit srcBuffer = cNoiseBuffer[2]; /* catch up testNb */ - for (testNb=1; testNb < startTest; testNb++) - FUZ_rand(&coreSeed); + for (testNb=1; testNb < startTest; testNb++) FUZ_rand(&coreSeed); - /* test loop */ + /* main test loop */ for ( ; (testNb <= nbTests) || (FUZ_GetMilliSpan(startTime) < g_testTime); testNb++ ) { size_t sampleSize, sampleStart, maxTestSize, totalTestSize; - size_t cSize, dSize, dSupSize, errorCode, totalCSize, totalGenSize; + size_t cSize, dSize, errorCode, totalCSize, totalGenSize; U32 sampleSizeLog, buffNb, cLevelMod, nbChunks, n; XXH64_CREATESTATE_STATIC(xxh64); U64 crcOrig, crcDest; @@ -460,9 +459,8 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit const BYTE* dict; size_t dictSize; - /* init */ - if (nbTests >= testNb) - { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); } + /* notification */ + if (nbTests >= testNb) { DISPLAYUPDATE(2, "\r%6u/%6u ", testNb, nbTests); } else { DISPLAYUPDATE(2, "\r%6u ", testNb); } FUZ_rand(&coreSeed); @@ -477,8 +475,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit } else { const U32 tnb[2] = { 0, 4 }; buffNb = tnb[buffNb >> 3]; - } - } + } } srcBuffer = cNoiseBuffer[buffNb]; sampleSizeLog = FUZ_rand(&lseed) % maxSampleLog; sampleSize = (size_t)1 << sampleSizeLog; @@ -509,19 +506,20 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit CHECK(endCheck != endMark, "ZSTD_compressCCtx : dst buffer overflow"); } } - /* decompression header test */ + /* frame header decompression test */ { ZSTD_frameParams dParams; size_t const check = ZSTD_getFrameParams(&dParams, cBuffer, cSize); CHECK(ZSTD_isError(check), "Frame Parameters extraction failed"); CHECK(dParams.frameContentSize != sampleSize, "Frame content size incorrect"); } - /* 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) (srcSize : %u ; cSize : %u)", ZSTD_getErrorName(dSize), (U32)sampleSize, (U32)cSize); - crcDest = XXH64(dstBuffer, sampleSize, 0); - CHECK(crcOrig != crcDest, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize); + /* successful decompression test */ + { size_t margin = (FUZ_rand(&lseed) & 1) ? 0 : (FUZ_rand(&lseed) & 31) + 1; + dSize = ZSTD_decompress(dstBuffer, sampleSize + margin, cBuffer, cSize); + 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, "decompression result corrupted (pos %u / %u)", (U32)findDiff(sampleBuffer, dstBuffer, sampleSize), (U32)sampleSize); + } free(sampleBuffer); /* no longer useful after this point */ @@ -576,7 +574,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit { U32 const endMark = 0xA9B1C3D6; memcpy(dstBuffer+sampleSize, &endMark, 4); errorCode = ZSTD_decompress(dstBuffer, sampleSize, cBuffer, cSize); - /* result *may* be an unlikely success, but even then, it must strictly respect dest buffer boundaries */ + /* result *may* be an unlikely success, but even then, it must strictly respect dst buffer boundaries */ CHECK((!ZSTD_isError(errorCode)) && (errorCode>sampleSize), "ZSTD_decompress on noisy src : result is too large : %u > %u (dst buffer)", (U32)errorCode, (U32)sampleSize); { U32 endCheck; memcpy(&endCheck, dstBuffer+sampleSize, 4); From 0d9ce04cd5769247572b64e15f454c0c16b8dfe2 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 13:21:08 +0100 Subject: [PATCH 35/49] minor refactoring --- programs/fuzzer.c | 112 +++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 61 deletions(-) diff --git a/programs/fuzzer.c b/programs/fuzzer.c index a7aa728dd..d53586c17 100644 --- a/programs/fuzzer.c +++ b/programs/fuzzer.c @@ -1,6 +1,6 @@ /* Fuzzer test tool for zstd - Copyright (C) Yann Collet 2014-2105 + Copyright (C) Yann Collet 2014-2016 GPL v2 License @@ -19,11 +19,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - - ZSTD source repository : https://github.com/Cyan4973/zstd - - ZSTD public forum : https://groups.google.com/forum/#!forum/lz4c + - ZSTD homepage : http://www.zstd.net */ -/************************************** +/*-************************************ * Compiler specific **************************************/ #ifdef _MSC_VER /* Visual Studio */ @@ -32,14 +31,8 @@ # pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */ #endif -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */ -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */ -#endif - -/************************************** +/*-************************************ * Includes **************************************/ #include /* free */ @@ -52,8 +45,8 @@ #include "mem.h" -/************************************** - Constants +/*-************************************ +* Constants **************************************/ #ifndef ZSTD_VERSION # define ZSTD_VERSION "" @@ -63,15 +56,12 @@ #define MB *(1U<<20) #define GB *(1U<<30) +static const size_t COMPRESSIBLE_NOISE_LENGTH = 10 MB; /* capital, used to be a macro */ +static const U32 FUZ_compressibility_default = 50; static const U32 nbTestsDefault = 30000; -#define COMPRESSIBLE_NOISE_LENGTH (10 MB) -#define FUZ_COMPRESSIBILITY_DEFAULT 50 -static const U32 prime1 = 2654435761U; -static const U32 prime2 = 2246822519U; - -/************************************** +/*-************************************ * Display Macros **************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) @@ -85,10 +75,8 @@ static U32 g_displayLevel = 2; static const U32 g_refreshRate = 150; static U32 g_displayTime = 0; -static U32 g_testTime = 0; - -/********************************************************* +/*-******************************************************* * Fuzzer functions *********************************************************/ #define MIN(a,b) ((a)<(b)?(a):(b)) @@ -117,6 +105,8 @@ static U32 FUZ_GetMilliSpan(U32 nTimeStart) # define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r))) unsigned int FUZ_rand(unsigned int* src) { + static const U32 prime1 = 2654435761U; + static const U32 prime2 = 2246822519U; U32 rand32 = *src; rand32 *= prime1; rand32 += prime2; @@ -130,8 +120,7 @@ static unsigned FUZ_highbit32(U32 v32) { unsigned nbBits = 0; if (v32==0) return 0; - while (v32) - { + while (v32) { v32 >>= 1; nbBits ++; } @@ -161,13 +150,13 @@ static int basicUnitTests(U32 seed, double compressibility) RDG_genBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, 0., randState); /* Basic tests */ - DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); + DISPLAYLEVEL(4, "test%3i : compress %u bytes : ", testNb++, (U32)COMPRESSIBLE_NOISE_LENGTH); result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(COMPRESSIBLE_NOISE_LENGTH), CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1); if (ZSTD_isError(result)) goto _output_error; cSize = result; DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/COMPRESSIBLE_NOISE_LENGTH*100); - DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, COMPRESSIBLE_NOISE_LENGTH); + DISPLAYLEVEL(4, "test%3i : decompress %u bytes : ", testNb++, (U32)COMPRESSIBLE_NOISE_LENGTH); result = ZSTD_decompress(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, compressedBuffer, cSize); if (ZSTD_isError(result)) goto _output_error; if (result != COMPRESSIBLE_NOISE_LENGTH) goto _output_error; @@ -342,35 +331,36 @@ static int basicUnitTests(U32 seed, double compressibility) #define NB3BYTESSEQLOG 9 #define NB3BYTESSEQ (1 << NB3BYTESSEQLOG) #define NB3BYTESSEQMASK (NB3BYTESSEQ-1) + /* creates a buffer full of 3-bytes sequences */ { BYTE _3BytesSeqs[NB3BYTESSEQ][3]; - U32 r = 1; + U32 rSeed = 1; + /* create batch of 3-bytes sequences */ { int i; for (i=0; i < NB3BYTESSEQ; i++) { - _3BytesSeqs[i][0] = (BYTE)(FUZ_rand(&r) & 255); - _3BytesSeqs[i][1] = (BYTE)(FUZ_rand(&r) & 255); - _3BytesSeqs[i][2] = (BYTE)(FUZ_rand(&r) & 255); + _3BytesSeqs[i][0] = (BYTE)(FUZ_rand(&rSeed) & 255); + _3BytesSeqs[i][1] = (BYTE)(FUZ_rand(&rSeed) & 255); + _3BytesSeqs[i][2] = (BYTE)(FUZ_rand(&rSeed) & 255); }} - { int i; for (i=0; i < _3BYTESTESTLENGTH; ) { - U32 id = FUZ_rand(&r) & NB3BYTESSEQMASK; + /* randomly fills CNBuffer with prepared 3-bytes sequences */ + { int i; for (i=0; i < _3BYTESTESTLENGTH; ) { /* note : CNBuffer size > _3BYTESTESTLENGTH+3 */ + U32 id = FUZ_rand(&rSeed) & NB3BYTESSEQMASK; ((BYTE*)CNBuffer)[i+0] = _3BytesSeqs[id][0]; ((BYTE*)CNBuffer)[i+1] = _3BytesSeqs[id][1]; ((BYTE*)CNBuffer)[i+2] = _3BytesSeqs[id][2]; i += 3; - }} + } }} + DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++); + result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH), CNBuffer, _3BYTESTESTLENGTH, 19); + if (ZSTD_isError(result)) goto _output_error; + cSize = result; + DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100); - DISPLAYLEVEL(4, "test%3i : compress lots 3-bytes sequences : ", testNb++); - result = ZSTD_compress(compressedBuffer, ZSTD_compressBound(_3BYTESTESTLENGTH), CNBuffer, _3BYTESTESTLENGTH, 19); - if (ZSTD_isError(result)) goto _output_error; - cSize = result; - DISPLAYLEVEL(4, "OK (%u bytes : %.2f%%)\n", (U32)cSize, (double)cSize/_3BYTESTESTLENGTH*100); - - DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++); - result = ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize); - if (ZSTD_isError(result)) goto _output_error; - if (result != _3BYTESTESTLENGTH) goto _output_error; - DISPLAYLEVEL(4, "OK \n"); - } + DISPLAYLEVEL(4, "test%3i : decompress lots 3-bytes sequence : ", testNb++); + result = ZSTD_decompress(decodedBuffer, _3BYTESTESTLENGTH, compressedBuffer, cSize); + if (ZSTD_isError(result)) goto _output_error; + if (result != _3BYTESTESTLENGTH) goto _output_error; + DISPLAYLEVEL(4, "OK \n"); _end: free(CNBuffer); @@ -396,13 +386,13 @@ static size_t findDiff(const void* buf1, const void* buf2, size_t max) return i; } -# define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \ - DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; } +#define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \ + DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; } static const U32 maxSrcLog = 23; static const U32 maxSampleLog = 22; -int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibility) +int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, U32 maxDuration, double compressibility) { BYTE* cNoiseBuffer[5]; BYTE* srcBuffer; @@ -448,7 +438,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit for (testNb=1; testNb < startTest; testNb++) FUZ_rand(&coreSeed); /* main test loop */ - for ( ; (testNb <= nbTests) || (FUZ_GetMilliSpan(startTime) < g_testTime); testNb++ ) { + for ( ; (testNb <= nbTests) || (FUZ_GetMilliSpan(startTime) < maxDuration); testNb++ ) { size_t sampleSize, sampleStart, maxTestSize, totalTestSize; size_t cSize, dSize, errorCode, totalCSize, totalGenSize; U32 sampleSizeLog, buffNb, cLevelMod, nbChunks, n; @@ -464,7 +454,7 @@ int fuzzerTests(U32 seed, U32 nbTests, unsigned startTest, double compressibilit else { DISPLAYUPDATE(2, "\r%6u ", testNb); } FUZ_rand(&coreSeed); - lseed = coreSeed ^ prime1; + { U32 const prime1 = 2654435761U; lseed = coreSeed ^ prime1; } buffNb = FUZ_rand(&lseed) & 127; if (buffNb & 7) buffNb=2; else { @@ -680,7 +670,7 @@ int FUZ_usage(const char* programName) DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault); DISPLAY( " -s# : Select seed (default:prompt user)\n"); DISPLAY( " -t# : Select starting test number (default:0)\n"); - DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT); + DISPLAY( " -P# : Select compressibility in %% (default:%u%%)\n", FUZ_compressibility_default); DISPLAY( " -v : verbose\n"); DISPLAY( " -p : pause at the end\n"); DISPLAY( " -h : display help and exit\n"); @@ -695,9 +685,10 @@ int main(int argc, const char** argv) int argNb; int nbTests = nbTestsDefault; int testNb = 0; - int proba = FUZ_COMPRESSIBILITY_DEFAULT; + U32 proba = FUZ_compressibility_default; int result=0; U32 mainPause = 0; + U32 maxDuration = 0; const char* programName; /* Check command line */ @@ -728,7 +719,7 @@ int main(int argc, const char** argv) break; case 'i': - argument++; g_testTime=0; + argument++; maxDuration=0; nbTests=0; while ((*argument>='0') && (*argument<='9')) { nbTests *= 10; @@ -739,15 +730,15 @@ int main(int argc, const char** argv) case 'T': argument++; - nbTests=0; g_testTime=0; + nbTests=0; maxDuration=0; while ((*argument>='0') && (*argument<='9')) { - g_testTime *= 10; - g_testTime += *argument - '0'; + maxDuration *= 10; + maxDuration += *argument - '0'; argument++; } - if (*argument=='m') g_testTime *=60, argument++; + if (*argument=='m') maxDuration *=60, argument++; if (*argument=='n') argument++; - g_testTime *= 1000; + maxDuration *= 1000; break; case 's': @@ -779,7 +770,6 @@ int main(int argc, const char** argv) proba += *argument - '0'; argument++; } - if (proba<0) proba=0; if (proba>100) proba=100; break; @@ -792,12 +782,12 @@ int main(int argc, const char** argv) if (!seedset) seed = FUZ_GetMilliStart() % 10000; DISPLAY("Seed = %u\n", seed); - if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) DISPLAY("Compressibility : %i%%\n", proba); + if (proba!=FUZ_compressibility_default) DISPLAY("Compressibility : %u%%\n", proba); if (testNb==0) result = basicUnitTests(0, ((double)proba) / 100); /* constant seed for predictability */ if (!result) - result = fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100); + result = fuzzerTests(seed, nbTests, testNb, maxDuration, ((double)proba) / 100); if (mainPause) { int unused; DISPLAY("Press Enter \n"); From 01e5b951996411f5280e48c0703debeea9d47382 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 14:14:31 +0100 Subject: [PATCH 36/49] code refactor --- lib/bitstream.h | 119 +++++++++++++++++++++++------------------- lib/zstd_decompress.c | 93 ++++++++++++++------------------- 2 files changed, 104 insertions(+), 108 deletions(-) diff --git a/lib/bitstream.h b/lib/bitstream.h index 44c0241fa..e12379306 100644 --- a/lib/bitstream.h +++ b/lib/bitstream.h @@ -41,7 +41,7 @@ extern "C" { /* -* This API consists of small unitary functions, which highly benefit from being inlined. +* This API consists of small unitary functions, which must be inlined for best performance. * Since link-time-optimization is not available for all compilers, * these functions are defined into a .h to be included. */ @@ -74,21 +74,21 @@ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC); MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC); -/*Start by initCStream, providing the size of buffer to write into. -* bitStream will never write outside of this buffer. -* `dstCapacity` must be >= sizeof(size_t), otherwise @return will be an error code. +/* Start with initCStream, providing the size of buffer to write into. +* bitStream will never write outside of this buffer. +* `dstCapacity` must be >= sizeof(size_t), otherwise @return will be an error code. * -* bits are first added to a local register. -* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems. -* Writing data into memory is an explicit operation, performed by the flushBits function. -* Hence keep track how many bits are potentially stored into local register to avoid register overflow. -* After a flushBits, a maximum of 7 bits might still be stored into local register. +* bits are first added to a local register. +* Local register is size_t, hence 64-bits on 64-bits systems, or 32-bits on 32-bits systems. +* Writing data into memory is an explicit operation, performed by the flushBits function. +* Hence keep track how many bits are potentially stored into local register to avoid register overflow. +* After a flushBits, a maximum of 7 bits might still be stored into local register. * -* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers. +* Avoid storing elements of more than 24 bits if you want compatibility with 32-bits bitstream readers. * -* Last operation is to close the bitStream. -* The function returns the final size of CStream in bytes. -* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable) +* Last operation is to close the bitStream. +* The function returns the final size of CStream in bytes. +* If data couldn't fit into `dstBuffer`, it will return a 0 ( == not storable) */ @@ -115,14 +115,14 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD); MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* bitD); -/*Start by invoking BIT_initDStream(). -* A chunk of the bitStream is then stored into a local register. -* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). -* You can then retrieve bitFields stored into the local register, **in reverse order**. -* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. -* A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished. -* Otherwise, it can be less than that, so proceed accordingly. -* Checking if DStream has reached its end can be performed with BIT_endOfDStream() +/* Start by invoking BIT_initDStream(). +* A chunk of the bitStream is then stored into a local register. +* Local register size is 64-bits on 64-bits systems, 32-bits on 32-bits systems (size_t). +* You can then retrieve bitFields stored into the local register, **in reverse order**. +* Local register is explicitly reloaded from memory by the BIT_reloadDStream() method. +* A reload guarantee a minimum of ((8*sizeof(size_t))-7) bits when its result is BIT_DStream_unfinished. +* Otherwise, it can be less than that, so proceed accordingly. +* Checking if DStream has reached its end can be performed with BIT_endOfDStream() */ @@ -169,17 +169,24 @@ MEM_STATIC unsigned BIT_highbit32 (register U32 val) /*-************************************************************** * bitStream encoding ****************************************************************/ -MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* startPtr, size_t maxSize) +/*! BIT_initCStream() : + * `dstCapacity` must be > sizeof(void*) + * @return : 0 if success, + otherwise an error code (can be tested using ERR_isError() ) */ +MEM_STATIC size_t BIT_initCStream(BIT_CStream_t* bitC, void* startPtr, size_t dstCapacity) { bitC->bitContainer = 0; bitC->bitPos = 0; bitC->startPtr = (char*)startPtr; bitC->ptr = bitC->startPtr; - bitC->endPtr = bitC->startPtr + maxSize - sizeof(bitC->ptr); - if (maxSize < sizeof(bitC->ptr)) return ERROR(dstSize_tooSmall); + bitC->endPtr = bitC->startPtr + dstCapacity - sizeof(bitC->ptr); + if (dstCapacity <= sizeof(bitC->ptr)) return ERROR(dstSize_tooSmall); return 0; } +/*! BIT_addBits() : + can add up to 26 bits into `bitC`. + Does not check for register overflow ! */ MEM_STATIC void BIT_addBits(BIT_CStream_t* bitC, size_t value, unsigned nbBits) { static const unsigned mask[] = { 0, 1, 3, 7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF }; /* up to 26 bits */ @@ -206,6 +213,9 @@ MEM_STATIC void BIT_flushBitsFast(BIT_CStream_t* bitC) bitC->bitContainer >>= nbBytes*8; /* if bitPos >= sizeof(bitContainer)*8 --> undefined behavior */ } +/*! BIT_flushBits() : + * safe version; check for buffer overflow, and prevents it. + * note : does not signal buffer overflow. This will be revealed later on using BIT_closeCStream() */ MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) { size_t nbBytes = bitC->bitPos >> 3; @@ -217,33 +227,28 @@ MEM_STATIC void BIT_flushBits(BIT_CStream_t* bitC) } /*! BIT_closeCStream() : - * @return : size of CStream, in bytes, or 0 if it cannot fit into dstBuffer */ + * @return : size of CStream, in bytes, + or 0 if it could not fit into dstBuffer */ MEM_STATIC size_t BIT_closeCStream(BIT_CStream_t* bitC) { - char* endPtr; - BIT_addBitsFast(bitC, 1, 1); /* endMark */ BIT_flushBits(bitC); - if (bitC->ptr >= bitC->endPtr) /* too close to buffer's end */ - return 0; /* not storable */ + if (bitC->ptr >= bitC->endPtr) return 0; /* doesn't fit within authorized budget : cancel */ - endPtr = bitC->ptr; - endPtr += bitC->bitPos > 0; /* remaining bits (incomplete byte) */ - - return (endPtr - bitC->startPtr); + return (bitC->ptr - bitC->startPtr) + (bitC->bitPos > 0); } /*-******************************************************** * bitStream decoding **********************************************************/ -/*!BIT_initDStream() : -* Initialize a BIT_DStream_t. -* `bitD` : a pointer to an already allocated BIT_DStream_t structure. -* `srcBuffer` must point at the beginning of a bitStream. -* `srcSize` must be the exact size of the bitStream. -* @return : size of stream (== srcSize) or an errorCode if a problem is detected +/*! BIT_initDStream() : +* Initialize a BIT_DStream_t. +* `bitD` : a pointer to an already allocated BIT_DStream_t structure. +* `srcBuffer` must point at the beginning of a bitStream. +* `srcSize` must be the exact size of the bitStream, in bytes. +* @return : size of stream (== srcSize) or an errorCode if a problem is detected */ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, size_t srcSize) { @@ -281,12 +286,12 @@ MEM_STATIC size_t BIT_initDStream(BIT_DStream_t* bitD, const void* srcBuffer, si return srcSize; } -/*!BIT_lookBits() : - * Provides next n bits from local register. - * local register is not modified (bits are still present for next read/look). - * On 32-bits, maxNbBits==24. - * On 64-bits, maxNbBits==56. - * @return : value extracted +/*! BIT_lookBits() : + * Provides next n bits from local register. + * local register is not modified (bits are still present for next read/look). + * On 32-bits, maxNbBits==24. + * On 64-bits, maxNbBits==56. + * @return : value extracted */ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) { @@ -294,7 +299,7 @@ MEM_STATIC size_t BIT_lookBits(BIT_DStream_t* bitD, U32 nbBits) return ((bitD->bitContainer << (bitD->bitsConsumed & bitMask)) >> 1) >> ((bitMask-nbBits) & bitMask); } -/*! BIT_lookBitsFast*() : +/*! BIT_lookBitsFast() : * unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_lookBitsFast(BIT_DStream_t* bitD, U32 nbBits) { @@ -307,10 +312,10 @@ MEM_STATIC void BIT_skipBits(BIT_DStream_t* bitD, U32 nbBits) bitD->bitsConsumed += nbBits; } -/*!BIT_readBits() : - * Read next n bits from local register. - * pay attention to not read more than nbBits contained into local register. - * @return : extracted value. +/*! BIT_readBits() : + * Read next n bits from local register. + * pay attention to not read more than nbBits contained into local register. + * @return : extracted value. */ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) { @@ -319,8 +324,8 @@ MEM_STATIC size_t BIT_readBits(BIT_DStream_t* bitD, U32 nbBits) return value; } -/*!BIT_readBitsFast() : -* unsafe version; only works only if nbBits >= 1 */ +/*! BIT_readBitsFast() : +* unsafe version; only works only if nbBits >= 1 */ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) { size_t value = BIT_lookBitsFast(bitD, nbBits); @@ -328,6 +333,11 @@ MEM_STATIC size_t BIT_readBitsFast(BIT_DStream_t* bitD, U32 nbBits) return value; } +/*! BIT_reloadDStream() : +* Refill `BIT_DStream_t` from src buffer previously defined (see BIT_initDStream() ). +* This function is safe, it guarantees it will not read beyond src buffer. +* @return : status of `BIT_DStream_t` internal register. + if status == unfinished, internal register is filled with >= (sizeof(size_t)*8 - 7) bits */ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) { if (bitD->bitsConsumed > (sizeof(bitD->bitContainer)*8)) /* should never happen */ @@ -343,8 +353,7 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) if (bitD->bitsConsumed < sizeof(bitD->bitContainer)*8) return BIT_DStream_endOfBuffer; return BIT_DStream_completed; } - { - U32 nbBytes = bitD->bitsConsumed >> 3; + { U32 nbBytes = bitD->bitsConsumed >> 3; BIT_DStream_status result = BIT_DStream_unfinished; if (bitD->ptr - nbBytes < bitD->start) { nbBytes = (U32)(bitD->ptr - bitD->start); /* ptr > start */ @@ -358,7 +367,7 @@ MEM_STATIC BIT_DStream_status BIT_reloadDStream(BIT_DStream_t* bitD) } /*! BIT_endOfDStream() : -* @return Tells if DStream has reached its exact end +* @return Tells if DStream has exactly reached its end (all bits consumed). */ MEM_STATIC unsigned BIT_endOfDStream(const BIT_DStream_t* DStream) { diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 5cf9c17c3..35404417e 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -26,7 +26,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - zstd source repository : https://github.com/Cyan4973/zstd + - zstd homepage : http://www.zstd.net */ /* *************************************************************** @@ -84,16 +84,6 @@ #endif -/*-************************************* -* Local types -***************************************/ -typedef struct -{ - blockType_t blockType; - U32 origSize; -} blockProperties_t; - - /*_******************************************************* * Memory operations **********************************************************/ @@ -335,7 +325,7 @@ size_t ZSTD_getFrameParams(ZSTD_frameParams* fparamsPtr, const void* src, size_t /** ZSTD_decodeFrameHeader() : * `srcSize` must be the size provided by ZSTD_frameHeaderSize(). -* @return : 0, or an error code, which can be tested using ZSTD_isError() */ +* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* zc, const void* src, size_t srcSize) { size_t result = ZSTD_getFrameParams(&(zc->fParams), src, srcSize); @@ -344,19 +334,23 @@ static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* zc, const void* src, size_t srcS } +typedef struct +{ + blockType_t blockType; + U32 origSize; +} blockProperties_t; + +/*! ZSTD_getcBlockSize() : +* Provides the size of compressed block from block header `src` */ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { const BYTE* const in = (const BYTE* const)src; - BYTE headerFlags; - U32 cSize; + size_t cSize; - if (srcSize < 3) - return ERROR(srcSize_wrong); + if (srcSize < ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); - headerFlags = *in; + bpPtr->blockType = (blockType_t)((*in) >> 6); cSize = in[2] + (in[1]<<8) + ((in[0] & 7)<<16); - - bpPtr->blockType = (blockType_t)(headerFlags >> 6); bpPtr->origSize = (bpPtr->blockType == bt_rle) ? cSize : 0; if (bpPtr->blockType == bt_end) return 0; @@ -365,9 +359,9 @@ size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bp } -static size_t ZSTD_copyRawBlock(void* dst, size_t maxDstSize, const void* src, size_t srcSize) +static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - if (srcSize > maxDstSize) return ERROR(dstSize_tooSmall); + if (srcSize > dstCapacity) return ERROR(dstSize_tooSmall); memcpy(dst, src, srcSize); return srcSize; } @@ -619,7 +613,6 @@ typedef struct { } seqState_t; - static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) { const BYTE* dumps = seqState->dumps; @@ -659,8 +652,7 @@ static void ZSTD_decodeSequence(seq_t* seq, seqState_t* seqState, const U32 mls) if (MEM_32bits()) BIT_reloadDStream(&(seqState->DStream)); /* MatchLength */ - { - size_t matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); + { size_t matchLength = FSE_decodeSymbol(&(seqState->stateML), &(seqState->DStream)); if (matchLength == MaxML) { const U32 add = *dumps++; if (add < 255) matchLength += add; @@ -755,8 +747,7 @@ FORCE_INLINE size_t ZSTD_execSequence(BYTE* op, match += oend_8 - op; op = oend_8; } - while (op < oMatchEnd) - *op++ = *match++; + while (op < oMatchEnd) *op++ = *match++; } else { ZSTD_wildcopy(op, match, sequence.matchLength-8); /* works even if matchLength < 8 */ } @@ -826,8 +817,7 @@ static size_t ZSTD_decompressSequences( } /* last literal segment */ - { - size_t lastLLSize = litEnd - litPtr; + { size_t const lastLLSize = litEnd - litPtr; if (litPtr > litEnd) return ERROR(corruption_detected); /* too many literals already used */ if (op+lastLLSize > oend) return ERROR(dstSize_tooSmall); memcpy(op, litPtr, lastLLSize); @@ -882,39 +872,36 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, /*! ZSTD_decompress_continueDCtx() : * `dctx` must have been properly initialized */ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize) { const BYTE* ip = (const BYTE*)src; const BYTE* iend = ip + srcSize; BYTE* const ostart = (BYTE* const)dst; BYTE* op = ostart; - BYTE* const oend = ostart + maxDstSize; + BYTE* const oend = ostart + dstCapacity; size_t remainingSize = srcSize; blockProperties_t blockProperties; - /* Frame Header */ - { - size_t frameHeaderSize, errorCode; - if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); + /* check */ + if (srcSize < ZSTD_frameHeaderSize_min+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT==1) - { - const U32 magicNumber = MEM_readLE32(src); - if (ZSTD_isLegacy(magicNumber)) - return ZSTD_decompressLegacy(dst, maxDstSize, src, srcSize, magicNumber); - } + { const U32 magicNumber = MEM_readLE32(src); + if (ZSTD_isLegacy(magicNumber)) + return ZSTD_decompressLegacy(dst, dstCapacity, src, srcSize, magicNumber); + } #endif - frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min); + + /* Frame Header */ + { size_t const frameHeaderSize = ZSTD_frameHeaderSize(src, ZSTD_frameHeaderSize_min); if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize; if (srcSize < frameHeaderSize+ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); - errorCode = ZSTD_decodeFrameHeader(dctx, src, frameHeaderSize); - if (ZSTD_isError(errorCode)) return errorCode; + if (ZSTD_decodeFrameHeader(dctx, src, frameHeaderSize)) return ERROR(corruption_detected); ip += frameHeaderSize; remainingSize -= frameHeaderSize; } /* Loop on each block */ - while (1) - { + while (1) { size_t decodedSize=0; size_t cBlockSize = ZSTD_getcBlockSize(ip, iend-ip, &blockProperties); if (ZSTD_isError(cBlockSize)) return cBlockSize; @@ -954,45 +941,45 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx, size_t ZSTD_decompress_usingPreparedDCtx(ZSTD_DCtx* dctx, const ZSTD_DCtx* refDCtx, - void* dst, size_t maxDstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize) { ZSTD_copyDCtx(dctx, refDCtx); ZSTD_checkContinuity(dctx, dst); - return ZSTD_decompressFrame(dctx, dst, maxDstSize, src, srcSize); + return ZSTD_decompressFrame(dctx, dst, dstCapacity, src, srcSize); } size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx, - void* dst, size_t maxDstSize, + void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize) { ZSTD_decompressBegin_usingDict(dctx, dict, dictSize); ZSTD_LOG_BLOCK("%p: ZSTD_decompressBegin_usingDict searchLength=%d\n", dctx->base, dctx->params.searchLength); ZSTD_checkContinuity(dctx, dst); - return ZSTD_decompressFrame(dctx, dst, maxDstSize, src, srcSize); + return ZSTD_decompressFrame(dctx, dst, dstCapacity, src, srcSize); } -size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize) +size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - return ZSTD_decompress_usingDict(dctx, dst, maxDstSize, src, srcSize, NULL, 0); + return ZSTD_decompress_usingDict(dctx, dst, dstCapacity, src, srcSize, NULL, 0); } -size_t ZSTD_decompress(void* dst, size_t maxDstSize, const void* src, size_t srcSize) +size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize) { #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE==1) size_t regenSize; ZSTD_DCtx* dctx = ZSTD_createDCtx(); if (dctx==NULL) return ERROR(memory_allocation); - regenSize = ZSTD_decompressDCtx(dctx, dst, maxDstSize, src, srcSize); + regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize); ZSTD_freeDCtx(dctx); return regenSize; #else ZSTD_DCtx dctx; - return ZSTD_decompressDCtx(&dctx, dst, maxDstSize, src, srcSize); + return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize); #endif } From 90a03a95a1a20ce8b8cf4c5036a6869678ff0515 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 14:47:31 +0100 Subject: [PATCH 37/49] minor performance fix (decompression) --- lib/zstd_decompress.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 35404417e..6b9b12972 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -506,7 +506,7 @@ size_t ZSTD_decodeLiteralsBlock(ZSTD_DCtx* dctx, @return : nb bytes read from src, or an error code if it fails, testable with ZSTD_isError() */ -static size_t ZSTD_buildSeqTable(FSE_DTable* DTable, U32 type, U32 rawBits, U32 maxLog, +FORCE_INLINE size_t ZSTD_buildSeqTable(FSE_DTable* DTable, U32 type, U32 rawBits, U32 maxLog, const void* src, size_t srcSize) { U32 max = (1< maxLog) return ERROR(corruption_detected); FSE_buildDTable(DTable, norm, max, tableLog); return headerSize; From 37f3d1b2ab8266a90a046e86ff7575176e5259ba Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 15:11:42 +0100 Subject: [PATCH 38/49] minor refactor --- lib/zstd_compress.c | 12 ++++-------- lib/zstd_decompress.c | 3 --- lib/zstd_internal.h | 33 ++++++++++++++++----------------- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index ebe4cdc92..e7c249bfe 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -948,7 +948,6 @@ static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls) /*-************************************* * Fast Scan ***************************************/ -#define FILLHASHSTEP 3 static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) { U32* const hashTable = zc->hashTable; @@ -956,10 +955,11 @@ static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls) const BYTE* const base = zc->base; const BYTE* ip = base + zc->nextToUpdate; const BYTE* const iend = ((const BYTE*)end) - 8; + const size_t fastHashFillStep = 3; while(ip <= iend) { hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base); - ip += FILLHASHSTEP; + ip += fastHashFillStep; } } @@ -980,10 +980,8 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, const BYTE* const lowest = base + lowIndex; const BYTE* const iend = istart + srcSize; const BYTE* const ilimit = iend - 8; - size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE; - /* init */ ZSTD_resetSeqStore(seqStorePtr); if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE; @@ -2196,9 +2194,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, /* Write Frame Header into ctx headerBuffer */ MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); - { - BYTE* const op = (BYTE*)zc->headerBuffer; - U32 const fcsSize[4] = { 0, 1, 2, 8 }; + { BYTE* const op = (BYTE*)zc->headerBuffer; U32 const fcsId = (params.srcSize>0) + (params.srcSize>=256) + (params.srcSize>=65536+256); /* 0-3 */ BYTE fdescriptor = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); /* windowLog : 4 KB - 128 MB */ fdescriptor |= (BYTE)((params.searchLength==3)<<4); /* mml : 3-4 */ @@ -2212,7 +2208,7 @@ size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc, case 2 : MEM_writeLE16(op+5, (U16)(params.srcSize-256)); break; case 3 : MEM_writeLE64(op+5, (U64)(params.srcSize)); break; } - zc->hbSize = ZSTD_frameHeaderSize_min + fcsSize[fcsId]; + zc->hbSize = ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId]; } zc->stage = 0; diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 6b9b12972..ecc4329bd 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -75,7 +75,6 @@ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ # pragma warning(disable : 4324) /* disable: C4324: padded structure */ #else -# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # ifdef __GNUC__ # define FORCE_INLINE static inline __attribute__((always_inline)) # else @@ -276,8 +275,6 @@ void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx) TO DO */ -static const size_t ZSTD_fcs_fieldSize[4] = { 0, 1, 2, 8 }; - /** ZSTD_frameHeaderSize() : * srcSize must be >= ZSTD_frameHeaderSize_min. * @return : size of the Frame Header */ diff --git a/lib/zstd_internal.h b/lib/zstd_internal.h index c5cc64cd5..ba350c4f6 100644 --- a/lib/zstd_internal.h +++ b/lib/zstd_internal.h @@ -71,9 +71,6 @@ #define MB *(1 <<20) #define GB *(1U<<30) -#define ZSTD_BLOCKHEADERSIZE 3 /* because C standard does not allow a static const value to be defined using another static const value .... :( */ -static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; - #define BIT7 128 #define BIT6 64 #define BIT5 32 @@ -81,16 +78,28 @@ static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; #define BIT1 2 #define BIT0 1 +#define ZSTD_WINDOWLOG_ABSOLUTEMIN 12 +static const size_t ZSTD_fcs_fieldSize[4] = { 0, 1, 2, 8 }; + +#define ZSTD_BLOCKHEADERSIZE 3 /* because C standard does not allow a static const value to be defined using another static const value .... :( */ +static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; +typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; + +#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ +#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ + +#define HufLog 12 + #define IS_HUF 0 #define IS_PCH 1 #define IS_RAW 2 #define IS_RLE 3 +#define LONGNBSEQ 0x7F00 + #define MINMATCH 4 #define REPCODE_STARTVALUE 1 -#define ZSTD_WINDOWLOG_ABSOLUTEMIN 12 - -#define LONGNBSEQ 0x7F00 +#define HASHLOG3 17 #define Litbits 8 #define MLbits 7 @@ -110,26 +119,16 @@ static const size_t ZSTD_blockHeaderSize = ZSTD_BLOCKHEADERSIZE; #define FSE_ENCODING_STATIC 2 #define FSE_ENCODING_DYNAMIC 3 -#define HufLog 12 -#define HASHLOG3 17 - -#define MIN_SEQUENCES_SIZE 1 /* nbSeq==0 */ -#define MIN_CBLOCK_SIZE (1 /*litCSize*/ + 1 /* RLE or RAW */ + MIN_SEQUENCES_SIZE /* nbSeq==0 */) /* for a non-null block */ - -#define WILDCOPY_OVERLENGTH 8 - -typedef enum { bt_compressed, bt_raw, bt_rle, bt_end } blockType_t; - /*-******************************************* * Shared functions to include for inlining *********************************************/ static void ZSTD_copy8(void* dst, const void* src) { memcpy(dst, src, 8); } - #define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; } /*! ZSTD_wildcopy() : * custom version of memcpy(), can copy up to 7 bytes too many (8 bytes if length==0) */ +#define WILDCOPY_OVERLENGTH 8 MEM_STATIC void ZSTD_wildcopy(void* dst, const void* src, size_t length) { const BYTE* ip = (const BYTE*)src; From bb604486f1e60beb21e73110d27802b16b31bc59 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 15:18:42 +0100 Subject: [PATCH 39/49] fixed clang warning --- lib/zstd_compress.c | 2 +- lib/zstd_decompress.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index e7c249bfe..7b2cc1437 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -62,7 +62,7 @@ /*-************************************* * Constants ***************************************/ -static const U32 g_searchStrength = 8; +static const U32 g_searchStrength = 8; /* control skip over incompressible data */ /*-************************************* diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index ecc4329bd..887348294 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -342,7 +342,7 @@ typedef struct size_t ZSTD_getcBlockSize(const void* src, size_t srcSize, blockProperties_t* bpPtr) { const BYTE* const in = (const BYTE* const)src; - size_t cSize; + U32 cSize; if (srcSize < ZSTD_blockHeaderSize) return ERROR(srcSize_wrong); From e74215e3c73283e09c2f12dd8845f80882add813 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 16:09:09 +0100 Subject: [PATCH 40/49] performance fix for small files --- lib/zstd_compress.c | 59 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 7b2cc1437..bdf5569e4 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -143,17 +143,15 @@ static unsigned ZSTD_highbit(U32 val); optimize for `srcSize` if srcSize > 0 */ void ZSTD_validateParams(ZSTD_parameters* params) { - const U32 btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt); - const U32 searchLengthMax = (params->strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1; - const U32 searchLengthMin = (params->strategy == ZSTD_btopt) ? ZSTD_SEARCHLENGTH_MIN : ZSTD_SEARCHLENGTH_MIN+1; - /* validate params */ if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */ CLAMP(params->windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); CLAMP(params->contentLog, ZSTD_CONTENTLOG_MIN, ZSTD_CONTENTLOG_MAX); CLAMP(params->hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); CLAMP(params->searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); - CLAMP(params->searchLength, searchLengthMin, searchLengthMax); + { U32 const searchLengthMin = (params->strategy == ZSTD_btopt) ? ZSTD_SEARCHLENGTH_MIN : ZSTD_SEARCHLENGTH_MIN+1; + U32 const searchLengthMax = (params->strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1; + CLAMP(params->searchLength, searchLengthMin, searchLengthMax); } CLAMP(params->targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); if ((U32)params->strategy>(U32)ZSTD_btopt) params->strategy = ZSTD_btopt; @@ -163,23 +161,18 @@ void ZSTD_validateParams(ZSTD_parameters* params) if (params->windowLog > srcLog) params->windowLog = srcLog; } if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ - if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_CONTENTLOG_MAX */ + { U32 const btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt); + if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; } /* <= ZSTD_CONTENTLOG_MAX */ } size_t ZSTD_sizeofCCtx(ZSTD_parameters params) /* hidden interface, for paramagrill */ -{ /* copy / pasted from ZSTD_resetCCtx_advanced */ - const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.windowLog); - const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog; - const U32 divider = (params.searchLength==3) ? 3 : 4; - const size_t maxNbSeq = blockSize / divider; - const size_t tokenSpace = blockSize + 8*maxNbSeq; - const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog) + (1 << HASHLOG3)) * sizeof(U32); - const size_t optSpace = ((1<workSpaceSize; + ZSTD_freeCCtx(zc); + return size; } } @@ -187,24 +180,29 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, ZSTD_parameters params) { /* note : params considered validated here */ const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.windowLog); - const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog; const U32 divider = (params.searchLength==3) ? 3 : 4; const size_t maxNbSeq = blockSize / divider; const size_t tokenSpace = blockSize + 8*maxNbSeq; - const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog) + (1 << HASHLOG3)) * sizeof(U32); - const size_t optSpace = ((1<workSpaceSize < neededSpace) { - free(zc->workSpace); - zc->workSpace = malloc(neededSpace); - if (zc->workSpace == NULL) return ERROR(memory_allocation); - zc->workSpaceSize = neededSpace; + /* Check if workSpace is large enough, alloc a new one if needed */ + { size_t const optSpace = ((1<workSpaceSize < neededSpace) { + free(zc->workSpace); + zc->workSpace = malloc(neededSpace); + if (zc->workSpace == NULL) return ERROR(memory_allocation); + zc->workSpaceSize = neededSpace; + } } + memset(zc->workSpace, 0, tableSpace ); /* reset only tables */ zc->hashTable3 = (U32*)(zc->workSpace); - zc->hashTable = zc->hashTable3 + ((size_t)1 << HASHLOG3); + zc->hashTable = zc->hashTable3 + h3Size; zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog); zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog); zc->hufTable = (HUF_CElt*)zc->seqStore.buffer; @@ -251,7 +249,8 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) { const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog; - const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog) + (1 << HASHLOG3)) * sizeof(U32); + const size_t h3Size = (srcCCtx->params.searchLength == 3) ? (1 << HASHLOG3) : 0; + const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog) + h3Size) * sizeof(U32); if (srcCCtx->stage!=0) return ERROR(stage_wrong); From c6eea2b2f2ed0a9c8a47fd57aab3873f3024ff20 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 17:18:00 +0100 Subject: [PATCH 41/49] Improved speed for small files --- lib/zstd_compress.c | 51 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index bdf5569e4..87e54fa59 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -157,12 +157,14 @@ void ZSTD_validateParams(ZSTD_parameters* params) /* correct params, to use less memory */ if ((params->srcSize > 0) && (params->srcSize < (1<srcSize)-1) + 1; + U32 const srcLog = ZSTD_highbit((U32)(params->srcSize)-1) + 1; if (params->windowLog > srcLog) params->windowLog = srcLog; } - if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ + if (params->hashLog > params->windowLog) params->hashLog = params->windowLog; { U32 const btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt); if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; } /* <= ZSTD_CONTENTLOG_MAX */ + + if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ } @@ -170,9 +172,9 @@ size_t ZSTD_sizeofCCtx(ZSTD_parameters params) /* hidden interface, for parama { ZSTD_CCtx* zc = ZSTD_createCCtx(); ZSTD_compressBegin_advanced(zc, NULL, 0, params); - { size_t size = sizeof(*zc) + zc->workSpaceSize; - ZSTD_freeCCtx(zc); - return size; } + { size_t const size = sizeof(*zc) + zc->workSpaceSize; + ZSTD_freeCCtx(zc); + return size; } } @@ -183,9 +185,10 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, const U32 divider = (params.searchLength==3) ? 3 : 4; const size_t maxNbSeq = blockSize / divider; const size_t tokenSpace = blockSize + 8*maxNbSeq; - const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog; + const size_t contentSize = (params.strategy == ZSTD_fast) ? 0 : (1 << params.contentLog); + const size_t hSize = 1 << params.hashLog; const size_t h3Size = (params.searchLength==3) ? (1 << HASHLOG3) : 0; - const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog) + h3Size) * sizeof(U32); + const size_t tableSpace = (contentSize + hSize + h3Size) * sizeof(U32); /* Check if workSpace is large enough, alloc a new one if needed */ { size_t const optSpace = ((1<workSpace = malloc(neededSpace); if (zc->workSpace == NULL) return ERROR(memory_allocation); zc->workSpaceSize = neededSpace; - } - } + } } memset(zc->workSpace, 0, tableSpace ); /* reset only tables */ zc->hashTable3 = (U32*)(zc->workSpace); zc->hashTable = zc->hashTable3 + h3Size; - zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog); - zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog); + zc->contentTable = zc->hashTable + hSize; + zc->seqStore.buffer = zc->contentTable + contentSize; zc->hufTable = (HUF_CElt*)zc->seqStore.buffer; zc->flagStaticTables = 0; zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256; @@ -248,30 +250,31 @@ static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, * @return : 0, or an error code */ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) { - const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog; - const size_t h3Size = (srcCCtx->params.searchLength == 3) ? (1 << HASHLOG3) : 0; - const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog) + h3Size) * sizeof(U32); - if (srcCCtx->stage!=0) return ERROR(stage_wrong); ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params); /* copy tables */ - memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace); + { const size_t contentSize = (srcCCtx->params.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.contentLog); + const size_t hSize = 1 << srcCCtx->params.hashLog; + const size_t h3Size = (srcCCtx->params.searchLength == 3) ? (1 << HASHLOG3) : 0; + const size_t tableSpace = (contentSize + hSize + h3Size) * sizeof(U32); + memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace); + } /* copy frame header */ dstCCtx->hbSize = srcCCtx->hbSize; memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize); /* copy dictionary pointers */ - dstCCtx->nextToUpdate= srcCCtx->nextToUpdate; - dstCCtx->nextToUpdate3 = srcCCtx->nextToUpdate3; - dstCCtx->nextSrc = srcCCtx->nextSrc; - dstCCtx->base = srcCCtx->base; - dstCCtx->dictBase = srcCCtx->dictBase; - dstCCtx->dictLimit = srcCCtx->dictLimit; - dstCCtx->lowLimit = srcCCtx->lowLimit; - dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd; + dstCCtx->nextToUpdate = srcCCtx->nextToUpdate; + dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3; + dstCCtx->nextSrc = srcCCtx->nextSrc; + dstCCtx->base = srcCCtx->base; + dstCCtx->dictBase = srcCCtx->dictBase; + dstCCtx->dictLimit = srcCCtx->dictLimit; + dstCCtx->lowLimit = srcCCtx->lowLimit; + dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd; /* copy entropy tables */ dstCCtx->flagStaticTables = srcCCtx->flagStaticTables; From 70e45771791b4f6363dcc934725a5ad6722ba9fd Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sat, 19 Mar 2016 18:08:32 +0100 Subject: [PATCH 42/49] minor code refactoring --- lib/zstd_compress.c | 142 ++++++++++++++++++++------------------------ programs/bench.c | 2 +- 2 files changed, 66 insertions(+), 78 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 87e54fa59..c075d50ea 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -155,7 +155,7 @@ void ZSTD_validateParams(ZSTD_parameters* params) CLAMP(params->targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); if ((U32)params->strategy>(U32)ZSTD_btopt) params->strategy = ZSTD_btopt; - /* correct params, to use less memory */ + /* resize params, to use less memory when necessary */ if ((params->srcSize > 0) && (params->srcSize < (1<srcSize)-1) + 1; if (params->windowLog > srcLog) params->windowLog = srcLog; @@ -703,8 +703,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, zc->flagStaticTables = 0; /* Encoding Sequences */ - { - BIT_CStream_t blockStream; + { BIT_CStream_t blockStream; FSE_CState_t stateMatchLength; FSE_CState_t stateOffsetBits; FSE_CState_t stateLitLength; @@ -739,14 +738,13 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, FSE_flushCState(&blockStream, &stateLitLength); { size_t const streamSize = BIT_closeCStream(&blockStream); - if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */ - op += streamSize; } + if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */ + op += streamSize; } } /* check compressibility */ _check_compressibility: - { - size_t const minGain = ZSTD_minGain(srcSize); + { size_t const minGain = ZSTD_minGain(srcSize); size_t const maxCSize = srcSize - minGain; if ((size_t)(op-ostart) >= maxCSize) return 0; } @@ -1028,8 +1026,8 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, while ( (ip <= ilimit) && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) { /* store sequence */ - size_t rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); - size_t tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */ + size_t const rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend); + { size_t const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */ hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base); ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode); ip += rlCode+MINMATCH; @@ -1037,8 +1035,8 @@ void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc, continue; /* faster when present ... (?) */ } } } - { /* Last Literals */ - size_t lastLLSize = iend - anchor; + /* Last Literals */ + { size_t const lastLLSize = iend - anchor; memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -1156,8 +1154,7 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, } } } /* Last Literals */ - { - size_t lastLLSize = iend - anchor; + { size_t const lastLLSize = iend - anchor; memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -1600,10 +1597,9 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, if (depth==0) goto _storeSequence; } - { - /* first search (depth 0) */ - size_t offsetFound = 99999999; - size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); + /* first search (depth 0) */ + { size_t offsetFound = 99999999; + size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); if (ml2 > matchLength) matchLength = ml2, start = ip, offset=offsetFound; } @@ -1618,17 +1614,16 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, while (ip= MINMATCH) && (gain2 > gain1)) matchLength = mlRep, 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) + 4); + { size_t offset2=99999999; + size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); + int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4); if ((ml2 >= MINMATCH) && (gain2 > gain1)) { matchLength = ml2, offset = offset2, start = ip; continue; /* search a better one */ @@ -1638,17 +1633,16 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, if ((depth==2) && (ip= 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); + { size_t offset2=99999999; + size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); + int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7); if ((ml2 >= MINMATCH) && (gain2 > gain1)) { matchLength = ml2, offset = offset2, start = ip; continue; @@ -1665,8 +1659,7 @@ void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx, /* store sequence */ _storeSequence: - { - size_t litLength = start - anchor; + { size_t const litLength = start - anchor; ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } @@ -1686,8 +1679,7 @@ _storeSequence: } } /* Last Literals */ - { - size_t lastLLSize = iend - anchor; + { size_t const lastLLSize = iend - anchor; memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } @@ -1771,10 +1763,9 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, if (depth==0) goto _storeSequence; } } - { - /* first search (depth 0) */ - size_t offsetFound = 99999999; - size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); + /* first search (depth 0) */ + { size_t offsetFound = 99999999; + size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls); if (ml2 > matchLength) matchLength = ml2, start = ip, offset=offsetFound; } @@ -1798,19 +1789,18 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, if (MEM_read32(ip) == MEM_read32(repMatch)) { /* repcode detected */ const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend; - size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; - int gain2 = (int)(repLength * 3); - int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1); + size_t const repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH; + int const gain2 = (int)(repLength * 3); + int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1); if ((repLength >= MINMATCH) && (gain2 > gain1)) matchLength = repLength, offset = 0, start = ip; } } /* search match, depth 1 */ - { - 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) + 4); + { size_t offset2=99999999; + size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); + int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4); if ((ml2 >= MINMATCH) && (gain2 > gain1)) { matchLength = ml2, offset = offset2, start = ip; continue; /* search a better one */ @@ -1837,11 +1827,10 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, } } /* search match, depth 2 */ - { - 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); + { size_t offset2=99999999; + size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls); + int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */ + int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7); if ((ml2 >= MINMATCH) && (gain2 > gain1)) { matchLength = ml2, offset = offset2, start = ip; continue; @@ -1964,8 +1953,9 @@ static size_t ZSTD_compress_generic (ZSTD_CCtx* zc, if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ if (remaining < blockSize) blockSize = remaining; - if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */ - U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist; + if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { + /* enforce maxDist */ + U32 const newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist; if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit; if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit; } @@ -2020,7 +2010,7 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, /* Check if blocks follow each other */ if (src != zc->nextSrc) { /* not contiguous */ - size_t delta = zc->nextSrc - ip; + size_t const delta = zc->nextSrc - ip; zc->lowLimit = zc->dictLimit; zc->dictLimit = (U32)(zc->nextSrc - zc->base); zc->dictBase = zc->base; @@ -2031,10 +2021,10 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, /* preemptive overflow correction */ if (zc->lowLimit > (1<<30)) { - U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_btopt); - U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1; - U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */ - U32 correction = zc->lowLimit - newLowLimit; + U32 const btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_btopt); + U32 const contentMask = (1 << (zc->params.contentLog - btplus)) - 1; + U32 const newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */ + U32 const correction = zc->lowLimit - newLowLimit; ZSTD_reduceIndex(zc, correction); zc->base += correction; zc->dictBase += correction; @@ -2051,10 +2041,9 @@ static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc, } zc->nextSrc = ip + srcSize; - { - size_t cSize; - if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize); - else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize); + { size_t const cSize = frame ? + ZSTD_compress_generic (zc, dst, dstSize, src, srcSize) : + ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize); if (ZSTD_isError(cSize)) return cSize; return cSize + hbSize; } @@ -2138,7 +2127,7 @@ static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t short litlengthNCount[MaxLL+1]; unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog; - const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize); + size_t const hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize); if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted); zc->flagStaticTables = 1; dict = (const char*)dict + hufHeaderSize; @@ -2241,7 +2230,7 @@ size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t dstCapacity) BYTE* op = (BYTE*)dst; size_t hbSize = 0; - /* empty frame */ + /* special case : empty frame : header still within internal buffer */ if (zc->stage==0) { hbSize = zc->hbSize; if (dstCapacity <= hbSize) return ERROR(dstSize_tooSmall); @@ -2265,16 +2254,15 @@ size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* prepare void* dst, size_t dstCapacity, const void* src, size_t srcSize) { - size_t outSize; - size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx); - if (ZSTD_isError(errorCode)) return errorCode; - errorCode = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize); - if (ZSTD_isError(errorCode)) return errorCode; - outSize = errorCode; - errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, dstCapacity-outSize); - if (ZSTD_isError(errorCode)) return errorCode; - outSize += errorCode; - return outSize; + { size_t const errorCode = ZSTD_copyCCtx(cctx, preparedCCtx); + if (ZSTD_isError(errorCode)) return errorCode; + } + { size_t const cSize = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize); + if (ZSTD_isError(cSize)) return cSize; + { size_t const endSize = ZSTD_compressEnd(cctx, (char*)dst+cSize, dstCapacity-cSize); + if (ZSTD_isError(endSize)) return endSize; + return cSize + endSize; + } } } diff --git a/programs/bench.c b/programs/bench.c index d1341fe1c..40be13f55 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -347,7 +347,7 @@ _findError: #endif } - DISPLAY("%2i-\n", cLevel); + DISPLAY("%2i#\n", cLevel); } /* clean up */ From a5c2c08c68a232d951fbd720880a1409370c1030 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 20 Mar 2016 01:09:18 +0100 Subject: [PATCH 43/49] code refactoring --- lib/zstd_compress.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index c075d50ea..7147a329c 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -501,7 +501,7 @@ static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, cons } -size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } +static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, void* dst, size_t dstCapacity, @@ -514,8 +514,14 @@ static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, U32 hType = IS_HUF; size_t cLitSize; - if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ + /* small ? don't even attempt compression (speed opt) */ +# define LITERAL_NOENTROPY 63 + { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY; + if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); + } + + if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ if (zc->flagStaticTables && (lhSize==3)) { hType = IS_PCH; singleStream = 1; @@ -581,14 +587,9 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, BYTE* seqHead; /* Compress literals */ -# define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */ - { - const BYTE* const literals = seqStorePtr->litStart; + { const BYTE* const literals = seqStorePtr->litStart; size_t const litSize = seqStorePtr->lit - literals; - size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY; - size_t const cSize = (litSize <= minLitSize) ? - ZSTD_noCompressLiterals(op, dstCapacity, literals, litSize) : - ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize); + size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize); if (ZSTD_isError(cSize)) return cSize; op += cSize; } @@ -604,8 +605,7 @@ size_t ZSTD_compressSequences(ZSTD_CCtx* zc, if ((oend-op) < 3 /* dumps */ + 1 /*seqHead*/) return ERROR(dstSize_tooSmall); seqHead = op; - { - size_t const dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart; + { size_t const dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart; if (dumpsLength < 512) { op[0] = (BYTE)(dumpsLength >> 8); op[1] = (BYTE)(dumpsLength); From 516ba880223d756b9d16ded3e12b3989b20ecd0e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 20 Mar 2016 05:40:39 +0100 Subject: [PATCH 44/49] updated huff0 --- lib/huff0.c | 231 ++++++++++++++++++++------------------------- lib/huff0.h | 22 ++--- lib/huff0_static.h | 4 +- 3 files changed, 114 insertions(+), 143 deletions(-) diff --git a/lib/huff0.c b/lib/huff0.c index 7afb13377..505adceca 100644 --- a/lib/huff0.c +++ b/lib/huff0.c @@ -1,6 +1,6 @@ /* ****************************************************************** Huff0 : Huffman coder, part of New Generation Entropy library - Copyright (C) 2013-2015, Yann Collet. + Copyright (C) 2013-2016, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -103,8 +103,7 @@ typedef struct nodeElt_s { } nodeElt; /*! HUF_writeCTable() : - @dst : destination buffer - @CTable : huffman tree to save, using huff0 representation + `CTable` : huffman tree to save, using huff0 representation. @return : size of saved CTable */ size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, U32 maxSymbolValue, U32 huffLog) @@ -181,66 +180,58 @@ size_t HUF_readCTable (HUF_CElt* CTable, U32 maxSymbolValue, const void* src, si BYTE huffWeight[HUF_MAX_SYMBOL_VALUE + 1]; U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1]; /* large enough for values from 0 to 16 */ U32 tableLog = 0; - size_t iSize; + size_t readSize; U32 nbSymbols = 0; - U32 n; - U32 nextRankStart; //memset(huffWeight, 0, sizeof(huffWeight)); /* is not necessary, even though some analyzer complain ... */ /* get symbol weights */ - iSize = HUF_readStats(huffWeight, HUF_MAX_SYMBOL_VALUE+1, rankVal, &nbSymbols, &tableLog, src, srcSize); - if (HUF_isError(iSize)) return iSize; + readSize = HUF_readStats(huffWeight, HUF_MAX_SYMBOL_VALUE+1, rankVal, &nbSymbols, &tableLog, src, srcSize); + if (HUF_isError(readSize)) return readSize; /* check result */ if (tableLog > HUF_MAX_TABLELOG) return ERROR(tableLog_tooLarge); if (nbSymbols > maxSymbolValue+1) return ERROR(maxSymbolValue_tooSmall); /* Prepare base value per rank */ - nextRankStart = 0; - for (n=1; n<=tableLog; n++) { - U32 current = nextRankStart; - nextRankStart += (rankVal[n] << (n-1)); - rankVal[n] = current; - } + { U32 n, nextRankStart = 0; + for (n=1; n<=tableLog; n++) { + U32 current = nextRankStart; + nextRankStart += (rankVal[n] << (n-1)); + rankVal[n] = current; + } } /* fill nbBits */ - for (n=0; n0; n--) { + { U32 n; for (n=0; n0; n--) { valPerRank[n] = min; /* get starting value within each rank */ min += nbPerRank[n]; min >>= 1; } } - for (n=0; n<=maxSymbolValue; n++) - CTable[n].val = valPerRank[CTable[n].nbBits]++; /* assign value within rank, symbol order */ + /* assign value within rank, symbol order */ + { U32 n; for (n=0; n<=maxSymbolValue; n++) CTable[n].val = valPerRank[CTable[n].nbBits]++; } } - return iSize; + return readSize; } static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) { - int totalCost = 0; const U32 largestBits = huffNode[lastNonNull].nbBits; - - /* early exit : all is fine */ - if (largestBits <= maxNbBits) return largestBits; + if (largestBits <= maxNbBits) return largestBits; /* early exit : no elt > maxNbBits */ /* there are several too large elements (at least >= 2) */ - { + { int totalCost = 0; const U32 baseCost = 1 << (largestBits - maxNbBits); U32 n = lastNonNull; @@ -248,26 +239,25 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) totalCost += baseCost - (1 << (largestBits - huffNode[n].nbBits)); huffNode[n].nbBits = (BYTE)maxNbBits; n --; - } /* n stops at huffNode[n].nbBits <= maxNbBits */ - while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using (maxNbBits-1) */ + } /* n stops at huffNode[n].nbBits <= maxNbBits */ + while (huffNode[n].nbBits == maxNbBits) n--; /* n end at index of smallest symbol using < maxNbBits */ /* renorm totalCost */ totalCost >>= (largestBits - maxNbBits); /* note : totalCost is necessarily a multiple of baseCost */ /* repay normalized cost */ - { - const U32 noSymbol = 0xF0F0F0F0; + { U32 const noSymbol = 0xF0F0F0F0; U32 rankLast[HUF_MAX_TABLELOG+1]; - U32 currentNbBits = maxNbBits; int pos; /* Get pos of last (smallest) symbol per rank */ memset(rankLast, 0xF0, sizeof(rankLast)); - for (pos=n ; pos >= 0; pos--) { - if (huffNode[pos].nbBits >= currentNbBits) continue; - currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ - rankLast[maxNbBits-currentNbBits] = pos; - } + { U32 currentNbBits = maxNbBits; + for (pos=n ; pos >= 0; pos--) { + if (huffNode[pos].nbBits >= currentNbBits) continue; + currentNbBits = huffNode[pos].nbBits; /* < maxNbBits */ + rankLast[maxNbBits-currentNbBits] = pos; + } } while (totalCost > 0) { U32 nBitsToDecrease = BIT_highbit32(totalCost) + 1; @@ -276,9 +266,8 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) U32 lowPos = rankLast[nBitsToDecrease-1]; if (highPos == noSymbol) continue; if (lowPos == noSymbol) break; - { - U32 highTotal = huffNode[highPos].count; - U32 lowTotal = 2 * huffNode[lowPos].count; + { U32 const highTotal = huffNode[highPos].count; + U32 const lowTotal = 2 * huffNode[lowPos].count; if (highTotal <= lowTotal) break; } } /* only triggered when no more rank 1 symbol left => find closest one (note : there is necessarily at least one !) */ @@ -294,7 +283,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) rankLast[nBitsToDecrease]--; if (huffNode[rankLast[nBitsToDecrease]].nbBits != maxNbBits-nBitsToDecrease) rankLast[nBitsToDecrease] = noSymbol; /* this rank is now empty */ - } } + } } /* while (totalCost > 0) */ while (totalCost < 0) { /* Sometimes, cost correction overshoot */ if (rankLast[1] == noSymbol) { /* special case : no rank 1 symbol (using maxNbBits-1); let's create one from largest rank 0 (using maxNbBits) */ @@ -307,7 +296,7 @@ static U32 HUF_setMaxHeight(nodeElt* huffNode, U32 lastNonNull, U32 maxNbBits) huffNode[ rankLast[1] + 1 ].nbBits--; rankLast[1]++; totalCost ++; - } } } + } } } /* there are several too large elements (at least >= 2) */ return maxNbBits; } @@ -331,8 +320,8 @@ static void HUF_sort(nodeElt* huffNode, const U32* count, U32 maxSymbolValue) for (n=30; n>0; n--) rank[n-1].base += rank[n].base; for (n=0; n<32; n++) rank[n].current = rank[n].base; for (n=0; n<=maxSymbolValue; n++) { - U32 c = count[n]; - U32 r = BIT_highbit32(c+1) + 1; + U32 const c = count[n]; + U32 const r = BIT_highbit32(c+1) + 1; U32 pos = rank[r].current++; while ((pos > rank[r].base) && (c > huffNode[pos-1].count)) huffNode[pos]=huffNode[pos-1], pos--; huffNode[pos].count = c; @@ -389,21 +378,18 @@ size_t HUF_buildCTable (HUF_CElt* tree, const U32* count, U32 maxSymbolValue, U3 maxNbBits = HUF_setMaxHeight(huffNode, nonNullRank, maxNbBits); /* fill result into tree (val, nbBits) */ - { - U16 nbPerRank[HUF_MAX_TABLELOG+1] = {0}; + { U16 nbPerRank[HUF_MAX_TABLELOG+1] = {0}; U16 valPerRank[HUF_MAX_TABLELOG+1] = {0}; if (maxNbBits > HUF_MAX_TABLELOG) return ERROR(GENERIC); /* check fit into table */ for (n=0; n<=nonNullRank; n++) nbPerRank[huffNode[n].nbBits]++; - { - /* determine stating value per rank */ - U16 min = 0; + /* determine stating value per rank */ + { U16 min = 0; for (n=maxNbBits; n>0; n--) { valPerRank[n] = min; /* get starting value within each rank */ min += nbPerRank[n]; min >>= 1; - } - } + } } for (n=0; n<=maxSymbolValue; n++) tree[huffNode[n].byte].nbBits = huffNode[n].nbBits; /* push nbBits per symbol, symbol order */ for (n=0; n<=maxSymbolValue; n++) @@ -432,17 +418,16 @@ size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, si { const BYTE* ip = (const BYTE*) src; BYTE* const ostart = (BYTE*)dst; - BYTE* op = ostart; BYTE* const oend = ostart + dstSize; + BYTE* op = ostart; size_t n; const unsigned fast = (dstSize >= HUF_BLOCKBOUND(srcSize)); - size_t errorCode; BIT_CStream_t bitC; /* init */ if (dstSize < 8) return 0; /* not enough space to compress */ - errorCode = BIT_initCStream(&bitC, op, oend-op); - if (HUF_isError(errorCode)) return 0; + { size_t const errorCode = BIT_initCStream(&bitC, op, oend-op); + if (HUF_isError(errorCode)) return 0; } n = srcSize & ~3; /* join to mod 4 */ switch (srcSize & 3) @@ -475,12 +460,12 @@ size_t HUF_compress1X_usingCTable(void* dst, size_t dstSize, const void* src, si size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable) { size_t segmentSize = (srcSize+3)/4; /* first 3 segments */ - size_t errorCode; const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; BYTE* const ostart = (BYTE*) dst; - BYTE* op = ostart; BYTE* const oend = ostart + dstSize; + BYTE* op = ostart; + size_t errorCode; if (dstSize < 6 + 1 + 1 + 1 + 8) return 0; /* minimum space to compress successfully */ if (srcSize < 12) return 0; /* no saving possible : too small input */ @@ -523,8 +508,8 @@ static size_t HUF_compress_internal ( unsigned singleStream) { BYTE* const ostart = (BYTE*)dst; - BYTE* op = ostart; BYTE* const oend = ostart + dstSize; + BYTE* op = ostart; U32 count[HUF_MAX_SYMBOL_VALUE+1]; HUF_CElt CTable[HUF_MAX_SYMBOL_VALUE+1]; @@ -573,8 +558,8 @@ static size_t HUF_compress_internal ( size_t HUF_compress1X (void* dst, size_t dstSize, - const void* src, size_t srcSize, - unsigned maxSymbolValue, unsigned huffLog) + const void* src, size_t srcSize, + unsigned maxSymbolValue, unsigned huffLog) { return HUF_compress_internal(dst, dstSize, src, srcSize, maxSymbolValue, huffLog, 1); } @@ -602,9 +587,9 @@ typedef struct { U16 sequence; BYTE nbBits; BYTE length; } HUF_DEltX4; /* doubl typedef struct { BYTE symbol; BYTE weight; } sortedSymbol_t; -/*! HUF_readStats - Read compact Huffman tree, saved by HUF_writeCTable - @huffWeight : destination buffer +/*! HUF_readStats() : + Read compact Huffman tree, saved by HUF_writeCTable(). + `huffWeight` is destination buffer. @return : size read from `src` */ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, @@ -616,13 +601,12 @@ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, const BYTE* ip = (const BYTE*) src; size_t iSize = ip[0]; size_t oSize; - U32 n; //memset(huffWeight, 0, hwSize); /* is not necessary, even though some analyzer complain ... */ if (iSize >= 128) { /* special header */ if (iSize >= (242)) { /* RLE */ - static int l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 }; + static U32 l[14] = { 1, 2, 3, 4, 7, 8, 15, 16, 31, 32, 63, 64, 127, 128 }; oSize = l[iSize-242]; memset(huffWeight, 1, hwSize); iSize = 0; @@ -633,10 +617,11 @@ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, if (iSize+1 > srcSize) return ERROR(srcSize_wrong); if (oSize >= hwSize) return ERROR(corruption_detected); ip += 1; - for (n=0; n> 4; - huffWeight[n+1] = ip[n/2] & 15; - } } } + { U32 n; + for (n=0; n> 4; + huffWeight[n+1] = ip[n/2] & 15; + } } } } else { /* header compressed with FSE (normal case) */ if (iSize+1 > srcSize) return ERROR(srcSize_wrong); oSize = FSE_decompress(huffWeight, hwSize-1, ip+1, iSize); /* max (hwSize-1) values decoded, as last one is implied */ @@ -646,20 +631,20 @@ static size_t HUF_readStats(BYTE* huffWeight, size_t hwSize, U32* rankStats, /* collect weight stats */ memset(rankStats, 0, (HUF_ABSOLUTEMAX_TABLELOG + 1) * sizeof(U32)); weightTotal = 0; - for (n=0; n= HUF_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); rankStats[huffWeight[n]]++; weightTotal += (1 << huffWeight[n]) >> 1; - } + }} /* get last non-null symbol weight (implied, total must be 2^n) */ tableLog = BIT_highbit32(weightTotal) + 1; if (tableLog > HUF_ABSOLUTEMAX_TABLELOG) return ERROR(corruption_detected); - { /* determine last weight */ - U32 total = 1 << tableLog; - U32 rest = total - weightTotal; - U32 verif = 1 << BIT_highbit32(rest); - U32 lastWeight = BIT_highbit32(rest) + 1; + /* determine last weight */ + { U32 const total = 1 << tableLog; + U32 const rest = total - weightTotal; + U32 const verif = 1 << BIT_highbit32(rest); + U32 const lastWeight = BIT_highbit32(rest) + 1; if (verif != rest) return ERROR(corruption_detected); /* last value must be a clean power of 2 */ huffWeight[oSize] = (BYTE)lastWeight; rankStats[lastWeight]++; @@ -724,12 +709,13 @@ size_t HUF_readDTableX2 (U16* DTable, const void* src, size_t srcSize) return iSize; } + static BYTE HUF_decodeSymbolX2(BIT_DStream_t* Dstream, const HUF_DEltX2* dt, const U32 dtLog) { - const size_t val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ - const BYTE c = dt[val].byte; - BIT_skipBits(Dstream, dt[val].nbBits); - return c; + const size_t val = BIT_lookBitsFast(Dstream, dtLog); /* note : dtLog >= 1 */ + const BYTE c = dt[val].byte; + BIT_skipBits(Dstream, dt[val].nbBits); + return c; } #define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \ @@ -773,13 +759,13 @@ size_t HUF_decompress1X2_usingDTable( { BYTE* op = (BYTE*)dst; BYTE* const oend = op + dstSize; - size_t errorCode; const U32 dtLog = DTable[0]; const void* dtPtr = DTable; const HUF_DEltX2* const dt = ((const HUF_DEltX2*)dtPtr)+1; BIT_DStream_t bitD; - errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize); - if (HUF_isError(errorCode)) return errorCode; + + { size_t const errorCode = BIT_initDStream(&bitD, cSrc, cSrcSize); + if (HUF_isError(errorCode)) return errorCode; } HUF_decodeStreamX2(op, &bitD, oend, dt, dtLog); @@ -793,9 +779,8 @@ size_t HUF_decompress1X2 (void* dst, size_t dstSize, const void* cSrc, size_t cS { HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_MAX_TABLELOG); const BYTE* ip = (const BYTE*) cSrc; - size_t errorCode; - errorCode = HUF_readDTableX2 (DTable, cSrc, cSrcSize); + size_t const errorCode = HUF_readDTableX2 (DTable, cSrc, cSrcSize); if (HUF_isError(errorCode)) return errorCode; if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); ip += errorCode; @@ -812,8 +797,8 @@ size_t HUF_decompress4X2_usingDTable( { /* Check */ if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - { - const BYTE* const istart = (const BYTE*) cSrc; + + { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; BYTE* const oend = ostart + dstSize; const void* const dtPtr = DTable; @@ -903,9 +888,8 @@ size_t HUF_decompress4X2 (void* dst, size_t dstSize, const void* cSrc, size_t cS { HUF_CREATE_STATIC_DTABLEX2(DTable, HUF_MAX_TABLELOG); const BYTE* ip = (const BYTE*) cSrc; - size_t errorCode; - errorCode = HUF_readDTableX2 (DTable, cSrc, cSrcSize); + size_t const errorCode = HUF_readDTableX2 (DTable, cSrc, cSrcSize); if (HUF_isError(errorCode)) return errorCode; if (errorCode >= cSrcSize) return ERROR(srcSize_wrong); ip += errorCode; @@ -926,7 +910,6 @@ static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 co { HUF_DEltX4 DElt; U32 rankVal[HUF_ABSOLUTEMAX_TABLELOG + 1]; - U32 s; /* get pre-calculated rankVal */ memcpy(rankVal, rankValOrigin, sizeof(rankVal)); @@ -942,7 +925,7 @@ static void HUF_fillDTableX4Level2(HUF_DEltX4* DTable, U32 sizeLog, const U32 co } /* fill DTable */ - for (s=0; s= 1 */ rankVal[weight] += length; - } + }} } typedef U32 rankVal_t[HUF_ABSOLUTEMAX_TABLELOG][HUF_ABSOLUTEMAX_TABLELOG + 1]; @@ -992,16 +975,14 @@ static void HUF_fillDTableX4(HUF_DEltX4* DTable, const U32 targetLog, sortedList+sortedRank, sortedListSize-sortedRank, nbBitsBaseline, symbol); } else { - U32 i; - const U32 end = start + length; HUF_DEltX4 DElt; - MEM_writeLE16(&(DElt.sequence), symbol); - DElt.nbBits = (BYTE)(nbBits); - DElt.length = 1; - for (i = start; i < end; i++) - DTable[i] = DElt; - } + DElt.nbBits = (BYTE)(nbBits); + DElt.length = 1; + { U32 u; + const U32 end = start + length; + for (u = start; u < end; u++) DTable[u] = DElt; + } } rankVal[weight] += length; } } @@ -1034,8 +1015,7 @@ size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize) for (maxW = tableLog; rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ /* Get start index of each weight */ - { - U32 w, nextRankStart = 0; + { U32 w, nextRankStart = 0; for (w=1; w<=maxW; w++) { U32 current = nextRankStart; nextRankStart += rankStats[w]; @@ -1046,8 +1026,7 @@ size_t HUF_readDTableX4 (U32* DTable, const void* src, size_t srcSize) } /* sort symbols by weight */ - { - U32 s; + { U32 s; for (s=0; s= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; @@ -1194,8 +1171,7 @@ size_t HUF_decompress4X4_usingDTable( { if (cSrcSize < 10) return ERROR(corruption_detected); /* strict minimum : jump table + 1 byte per stream */ - { - const BYTE* const istart = (const BYTE*) cSrc; + { const BYTE* const istart = (const BYTE*) cSrc; BYTE* const ostart = (BYTE*) dst; BYTE* const oend = ostart + dstSize; const void* const dtPtr = DTable; @@ -1385,8 +1361,7 @@ size_t HUF_readDTableX6 (U32* DTable, const void* src, size_t srcSize) for (maxW = tableLog; maxW && rankStats[maxW]==0; maxW--) {} /* necessarily finds a solution before 0 */ /* Get start index of each weight */ - { - U32 w, nextRankStart = 0; + { U32 w, nextRankStart = 0; for (w=1; w<=maxW; w++) { U32 current = nextRankStart; nextRankStart += rankStats[w]; @@ -1397,8 +1372,7 @@ size_t HUF_readDTableX6 (U32* DTable, const void* src, size_t srcSize) } /* sort symbols by weight */ - { - U32 s; + { U32 s; for (s=0; s= cSrcSize) return ERROR(srcSize_wrong); ip += hSize; diff --git a/lib/huff0.h b/lib/huff0.h index fe28d7bea..9d6e11f76 100644 --- a/lib/huff0.h +++ b/lib/huff0.h @@ -48,24 +48,24 @@ extern "C" { /* **************************************** * Huff0 simple functions ******************************************/ -size_t HUF_compress(void* dst, size_t maxDstSize, +size_t HUF_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize); size_t HUF_decompress(void* dst, size_t dstSize, const void* cSrc, size_t cSrcSize); -/*! -HUF_compress(): +/* +HUF_compress() : Compress content of buffer 'src', of size 'srcSize', into destination buffer 'dst'. - 'dst' buffer must be already allocated. Compression runs faster if maxDstSize >= HUF_compressBound(srcSize). + 'dst' buffer must be already allocated. Compression runs faster if dstCapacity >= HUF_compressBound(srcSize). Note : srcSize must be <= 128 KB - @return : size of compressed data (<= maxDstSize) + @return : size of compressed data (<= dstCapacity) Special values : if return == 0, srcData is not compressible => Nothing is stored within dst !!! - if return == 1, srcData is a single repeated byte symbol (RLE compression) + if return == 1, srcData is a single repeated byte symbol (RLE compression). if HUF_isError(return), compression failed (more details using HUF_getErrorName()) -HUF_decompress(): +HUF_decompress() : Decompress Huff0 data from buffer 'cSrc', of size 'cSrcSize', into already allocated destination buffer 'dst', of size 'dstSize'. - @dstSize : must be the **exact** size of original (uncompressed) data. + `dstSize` : must be the **exact** size of original (uncompressed) data. Note : in contrast with FSE, HUF_decompress can regenerate RLE (cSrcSize==1) and uncompressed (cSrcSize==dstSize) data, because it knows size to regenerate. @@ -77,11 +77,11 @@ HUF_decompress(): /* **************************************** * Tool functions ******************************************/ -size_t HUF_compressBound(size_t size); /* maximum compressed size */ +size_t HUF_compressBound(size_t size); /**< maximum compressed size */ /* Error Management */ -unsigned HUF_isError(size_t code); /* tells if a return value is an error code */ -const char* HUF_getErrorName(size_t code); /* provides error code string (useful for debugging) */ +unsigned HUF_isError(size_t code); /**< tells if a return value is an error code */ +const char* HUF_getErrorName(size_t code); /**< provides error code string (useful for debugging) */ /* **************************************** diff --git a/lib/huff0_static.h b/lib/huff0_static.h index 84033964a..32d66d352 100644 --- a/lib/huff0_static.h +++ b/lib/huff0_static.h @@ -85,7 +85,7 @@ HUF_compress() does the following: 1. count symbol occurrence from source[] into table count[] using FSE_count() 2. build Huffman table from count using HUF_buildCTable() 3. save Huffman table to memory buffer using HUF_writeCTable() -4. encode the data stream using HUF_compress_usingCTable() +4. encode the data stream using HUF_compress4X_usingCTable() The following API allows targeting specific sub-functions for advanced tasks. For example, it's possible to compress several blocks using the same 'CTable', @@ -95,7 +95,7 @@ or to save and regenerate 'CTable' using external methods. typedef struct HUF_CElt_s HUF_CElt; /* incomplete type */ size_t HUF_buildCTable (HUF_CElt* CTable, const unsigned* count, unsigned maxSymbolValue, unsigned maxNbBits); size_t HUF_writeCTable (void* dst, size_t maxDstSize, const HUF_CElt* CTable, unsigned maxSymbolValue, unsigned huffLog); -size_t HUF_compress4X_into4Segments(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); +size_t HUF_compress4X_usingCTable(void* dst, size_t dstSize, const void* src, size_t srcSize, const HUF_CElt* CTable); /*! From de406eebcd2330ada599d3c8d6e3192fff1abe0f Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 20 Mar 2016 15:46:10 +0100 Subject: [PATCH 45/49] minor code refactor --- lib/error_private.h | 12 +++---- lib/error_public.h | 5 ++- lib/zstd_compress.c | 8 ++--- lib/zstd_static.h | 5 ++- programs/bench.c | 77 +++++++++++++++++++++------------------------ 5 files changed, 49 insertions(+), 58 deletions(-) diff --git a/lib/error_private.h b/lib/error_private.h index c0c3f4900..ff0b829fc 100644 --- a/lib/error_private.h +++ b/lib/error_private.h @@ -28,7 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - Source repository : https://github.com/Cyan4973/zstd + - Homepage : http://www.zstd.net ****************************************************************** */ /* Note : this module is expected to remain private, do not expose it */ @@ -62,7 +62,7 @@ extern "C" { /*-**************************************** -* Customization +* Customization (error_public.h) ******************************************/ typedef ZSTD_ErrorCode ERR_enum; #define PREFIX(name) ZSTD_error_##name @@ -74,7 +74,7 @@ typedef ZSTD_ErrorCode ERR_enum; #ifdef ERROR # undef ERROR /* reported already defined on VS 2015 (Rich Geldreich) */ #endif -#define ERROR(name) (size_t)-PREFIX(name) +#define ERROR(name) ((size_t)-PREFIX(name)) ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); } @@ -101,12 +101,12 @@ ERR_STATIC const char* ERR_getErrorName(size_t code) case PREFIX(dstSize_tooSmall): return "Destination buffer is too small"; case PREFIX(srcSize_wrong): return "Src size incorrect"; case PREFIX(corruption_detected): return "Corrupted block detected"; - case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory"; - case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max possible Symbol Value : too large"; + case PREFIX(tableLog_tooLarge): return "tableLog requires too much memory : unsupported"; + case PREFIX(maxSymbolValue_tooLarge): return "Unsupported max Symbol Value : too large"; case PREFIX(maxSymbolValue_tooSmall): return "Specified maxSymbolValue is too small"; case PREFIX(dictionary_corrupted): return "Dictionary is corrupted"; case PREFIX(maxCode): - default: return notErrorCode; /* should be impossible, due to ERR_getError() */ + default: return notErrorCode; /* impossible, due to ERR_getError() */ } } diff --git a/lib/error_public.h b/lib/error_public.h index 655e28e0c..073b8c6a9 100644 --- a/lib/error_public.h +++ b/lib/error_public.h @@ -28,7 +28,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - - Source repository : https://github.com/Cyan4973/zstd + - Homepage : http://www.zstd.net ****************************************************************** */ #ifndef ERROR_PUBLIC_H_MODULE #define ERROR_PUBLIC_H_MODULE @@ -60,8 +60,7 @@ typedef enum { ZSTD_error_maxCode } ZSTD_ErrorCode; -/* note : functions provide error codes in reverse negative order, - so compare with (size_t)(0-enum) */ +/* note : compare with size_t function results using ZSTD_getError() */ #if defined (__cplusplus) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 7147a329c..689d48feb 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -2431,18 +2431,18 @@ static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = { /*! ZSTD_getParams() : * @return ZSTD_parameters structure for a selected compression level and srcSize. -* `srcSizeHint` value is optional, select 0 if not known */ -ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint) +* `srcSize` value is optional, select 0 if not known */ +ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSize) { ZSTD_parameters result; - int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ + int tableID = ((srcSize-1) <= 256 KB) + ((srcSize-1) <= 128 KB) + ((srcSize-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ if (compressionLevel<=0) compressionLevel = 1; if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; #if ZSTD_OPT_DEBUG >= 1 tableID=0; #endif result = ZSTD_defaultParameters[tableID][compressionLevel]; - result.srcSize = srcSizeHint; + result.srcSize = srcSize; return result; } diff --git a/lib/zstd_static.h b/lib/zstd_static.h index cb140a494..4ae771fde 100644 --- a/lib/zstd_static.h +++ b/lib/zstd_static.h @@ -73,8 +73,7 @@ extern "C" { /* from faster to stronger */ typedef enum { ZSTD_fast, ZSTD_greedy, ZSTD_lazy, ZSTD_lazy2, ZSTD_btlazy2, ZSTD_btopt } ZSTD_strategy; -typedef struct -{ +typedef struct { U64 srcSize; /* optional : tells how much bytes are present in the frame. Use 0 if not known. */ U32 windowLog; /* largest match distance : larger == more compression, more memory needed during decompression */ U32 contentLog; /* full search segment : larger == more compression, slower, more memory (useless for fast) */ @@ -245,7 +244,7 @@ size_t ZSTD_decompressBlock(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, cons ***************************************/ #include "error_public.h" /*! ZSTD_getErrorCode() : - convert a `size_t` function result into a `ZSTD_error_code` enum type, + convert a `size_t` function result into a `ZSTD_ErrorCode` enum type, which can be used to compare directly with enum list published into "error_public.h" */ ZSTD_ErrorCode ZSTD_getError(size_t code); diff --git a/programs/bench.c b/programs/bench.c index 40be13f55..c74c03df2 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -190,7 +190,6 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, { const size_t blockSize = (g_blockSize ? g_blockSize : srcSize) + (!srcSize); /* avoid div by 0 */ const U32 maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles; - size_t largestBlockSize = 0; blockParam_t* const blockTable = (blockParam_t*) malloc(maxNbBlocks * sizeof(blockParam_t)); const size_t maxCompressedSize = ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); /* add some room for safety */ void* const compressedBuffer = malloc(maxCompressedSize); @@ -199,28 +198,27 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, ZSTD_CCtx* ctx = ZSTD_createCCtx(); ZSTD_DCtx* refDCtx = ZSTD_createDCtx(); ZSTD_DCtx* dctx = ZSTD_createDCtx(); - U64 crcOrig = XXH64(srcBuffer, srcSize, 0); - U32 nbBlocks = 0; + U64 const crcOrig = XXH64(srcBuffer, srcSize, 0); + U32 nbBlocks; + + /* checks */ + if (!compressedBuffer || !resultBuffer || !blockTable || !refCtx || !ctx || !refDCtx || !dctx) + EXM_THROW(31, "not enough memory"); /* init */ if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* can only display 17 characters */ - /* Memory allocation & restrictions */ - if (!compressedBuffer || !resultBuffer || !blockTable || !refCtx || !ctx || !refDCtx || !dctx) - EXM_THROW(31, "not enough memory"); - /* Init blockTable data */ - { - const char* srcPtr = (const char*)srcBuffer; + { const char* srcPtr = (const char*)srcBuffer; char* cPtr = (char*)compressedBuffer; char* resPtr = (char*)resultBuffer; U32 fileNb; - for (fileNb=0; fileNb largestBlockSize) largestBlockSize = thisBlockSize; } } } /* warmimg up memory */ RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1); /* Bench */ - { - U32 loopNb; - size_t cSize = 0; + { size_t cSize = 0; double fastestC = 100000000., fastestD = 100000000.; double ratio = 0.; U64 crcCheck = 0; clock_t coolTime = clock(); + U32 testNb; DISPLAY("\r%79s\r", ""); - for (loopNb = 1; loopNb <= (g_nbIterations + !g_nbIterations); loopNb++) { + for (testNb = 1; testNb <= (g_nbIterations + !g_nbIterations); testNb++) { int nbLoops; - U32 blockNb; clock_t clockStart, clockSpan; clock_t const clockLoop = g_nbIterations ? TIMELOOP_S * CLOCKS_PER_SEC : 10; @@ -260,45 +255,43 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, } /* Compression */ - DISPLAY("%2i-%-17.17s :%10u ->\r", loopNb, displayName, (U32)srcSize); + DISPLAY("%2i-%-17.17s :%10u ->\r", testNb, displayName, (U32)srcSize); memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */ - nbLoops = 0; clockStart = clock(); while (clock() == clockStart); clockStart = clock(); - while (BMK_clockSpan(clockStart) < clockLoop) { - ZSTD_compressBegin_advanced(refCtx, dictBuffer, dictBufferSize, ZSTD_getParams(cLevel, MAX(dictBufferSize, largestBlockSize))); + + for (nbLoops = 0 ; BMK_clockSpan(clockStart) < clockLoop ; nbLoops++) { + U32 blockNb; + ZSTD_compressBegin_usingDict(refCtx, dictBuffer, dictBufferSize, cLevel); for (blockNb=0; blockNb%10u (%5.3f),%6.1f MB/s\r", - loopNb, displayName, (U32)srcSize, (U32)cSize, ratio, + testNb, displayName, (U32)srcSize, (U32)cSize, ratio, (double)srcSize / 1000000. / (fastestC / CLOCKS_PER_SEC) ); #if 1 /* Decompression */ memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */ - nbLoops = 0; clockStart = clock(); while (clock() == clockStart); clockStart = clock(); - for ( ; BMK_clockSpan(clockStart) < clockLoop; nbLoops++) { + for (nbLoops = 0 ; BMK_clockSpan(clockStart) < clockLoop ; nbLoops++) { + U32 blockNb; ZSTD_decompressBegin_usingDict(refDCtx, dictBuffer, dictBufferSize); for (blockNb=0; blockNb%10u (%5.3f),%6.1f MB/s ,%6.1f MB/s\r", - loopNb, displayName, (U32)srcSize, (U32)cSize, ratio, + testNb, displayName, (U32)srcSize, (U32)cSize, ratio, (double)srcSize / 1000000. / (fastestC / CLOCKS_PER_SEC), (double)srcSize / 1000000. / (fastestD / CLOCKS_PER_SEC) ); @@ -343,12 +336,11 @@ _findError: printf("no difference detected\n"); } } break; - } + } /* if (crcOrig!=crcCheck) */ #endif - } - + } /* for (testNb = 1; testNb <= (g_nbIterations + !g_nbIterations); testNb++) */ DISPLAY("%2i#\n", cLevel); - } + } /* Bench */ /* clean up */ free(compressedBuffer); @@ -363,19 +355,20 @@ _findError: static size_t BMK_findMaxMem(U64 requiredMem) { - size_t step = 64 MB; + size_t const step = 64 MB; BYTE* testmem = NULL; requiredMem = (((requiredMem >> 26) + 1) << 26); - requiredMem += 2 * step; + requiredMem += step; if (requiredMem > maxMemory) requiredMem = maxMemory; - while (!testmem) { - requiredMem -= step; + do { testmem = (BYTE*)malloc((size_t)requiredMem); - } + requiredMem -= step; + } while (!testmem); + free(testmem); - return (size_t)(requiredMem - step); + return (size_t)(requiredMem); } static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, From 524473804667495da0263108644bc2c60feb9e3b Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 20 Mar 2016 16:00:00 +0100 Subject: [PATCH 46/49] minor code refactoring --- lib/zstd_compress.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index 689d48feb..a699f3e43 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -1105,7 +1105,7 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, U32 offset; hashTable[h] = current; /* update hash table */ - if ( ((repIndex <= dictLimit-4) || (repIndex >= dictLimit)) + if ( ((repIndex >= dictLimit) || (repIndex <= dictLimit-4)) && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) { const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend; mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr); @@ -1113,10 +1113,11 @@ static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx, offset = 0; } else { if ( (matchIndex < lowLimit) || - (MEM_read32(match) != MEM_read32(ip)) ) - { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; } - { - const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend; + (MEM_read32(match) != MEM_read32(ip)) ) { + ip += ((ip-anchor) >> g_searchStrength) + 1; + continue; + } + { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend; const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr; mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr); while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */ @@ -1373,7 +1374,7 @@ static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* con idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0); } -/** Tree updater, providing best match */ +/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */ static size_t ZSTD_BtFindBestMatch ( ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iLimit, @@ -1462,7 +1463,7 @@ U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls) U32 idx = zc->nextToUpdate; while(idx < target) { - size_t h = ZSTD_hashPtr(base+idx, hashLog, mls); + size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls); NEXT_IN_CHAIN(idx, chainMask) = hashTable[h]; hashTable[h] = idx; idx++; @@ -1499,9 +1500,8 @@ size_t ZSTD_HcFindBestMatch_generic ( /* HC4 match finder */ matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls); - while ((matchIndex>lowLimit) && (nbAttempts)) { + for ( ; (matchIndex>lowLimit) && (nbAttempts) ; nbAttempts--) { size_t currentMl=0; - nbAttempts--; if ((!extDict) || matchIndex >= dictLimit) { match = base + matchIndex; if (match[ml] == ip[ml]) /* potentially better */ @@ -1849,8 +1849,7 @@ void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx, /* store sequence */ _storeSequence: - { - size_t litLength = start - anchor; + { size_t const litLength = start - anchor; ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH); anchor = ip = start + matchLength; } @@ -1875,8 +1874,7 @@ _storeSequence: } } /* Last Literals */ - { - size_t lastLLSize = iend - anchor; + { size_t const lastLLSize = iend - anchor; memcpy(seqStorePtr->lit, anchor, lastLLSize); seqStorePtr->lit += lastLLSize; } From ecabfe3777a08e007ed6c5cb660f6174dc75c783 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Sun, 20 Mar 2016 16:20:06 +0100 Subject: [PATCH 47/49] Improved index overflow protection --- lib/zstd_compress.c | 33 +++++++++++++++++++++------------ programs/playTests.sh | 2 +- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/zstd_compress.c b/lib/zstd_compress.c index a699f3e43..cfb2519ad 100644 --- a/lib/zstd_compress.c +++ b/lib/zstd_compress.c @@ -289,22 +289,31 @@ size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx) } -/*! ZSTD_reduceIndex() : -* rescale indexes to avoid future overflow (indexes are U32) */ -static void ZSTD_reduceIndex (ZSTD_CCtx* zc, - const U32 reducerValue) +/*! ZSTD_reduceTable() : +* rescale indexes from a table (indexes are U32) */ +static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue) { - const U32 contentLog = (zc->params.strategy == ZSTD_fast) ? 1 : zc->params.contentLog; - const U32 tableSpaceU32 = (1 << contentLog) + (1 << zc->params.hashLog); - U32* table32 = zc->hashTable; - U32 index; - - for (index=0 ; index < tableSpaceU32 ; index++) { - if (table32[index] < reducerValue) table32[index] = 0; - else table32[index] -= reducerValue; + U32 u; + for (u=0 ; u < size ; u++) { + if (table[u] < reducerValue) table[u] = 0; + else table[u] -= reducerValue; } } +/*! ZSTD_reduceIndex() : +* rescale all indexes to avoid future overflow (indexes are U32) */ +static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) +{ + { const U32 hSize = 1 << zc->params.hashLog; + ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); } + + { const U32 contentSize = (zc->params.strategy == ZSTD_fast) ? 0 : (1 << zc->params.contentLog); + ZSTD_reduceTable(zc->contentTable, contentSize, reducerValue); } + + { const U32 h3Size = (zc->params.searchLength == 3) ? (1 << HASHLOG3) : 0; + ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); } +} + /*-******************************************************* * Block entropic compression diff --git a/programs/playTests.sh b/programs/playTests.sh index 891ab9d4e..444d91ebe 100755 --- a/programs/playTests.sh +++ b/programs/playTests.sh @@ -143,7 +143,7 @@ roundTripTest -g50000000 -P94 18 roundTripTest -g50000000 -P94 19 roundTripTest -g99000000 -P99 20 -roundTripTest -g6000000000 -P99 q +roundTripTest -g6000000000 -P99 1 rm tmp* From e91477c1716987479e10201c5f50d0f2f31fa1d4 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Mon, 21 Mar 2016 14:22:38 +0100 Subject: [PATCH 48/49] minor variable isolation --- lib/zstd_decompress.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/zstd_decompress.c b/lib/zstd_decompress.c index 887348294..c90b88552 100644 --- a/lib/zstd_decompress.c +++ b/lib/zstd_decompress.c @@ -762,7 +762,7 @@ static size_t ZSTD_decompressSequences( BYTE* const ostart = (BYTE* const)dst; BYTE* op = ostart; BYTE* const oend = ostart + maxDstSize; - size_t errorCode, dumpsLength; + size_t dumpsLength; const BYTE* litPtr = dctx->litPtr; const BYTE* const litLimit_8 = litPtr + dctx->litBufSize - 8; const BYTE* const litEnd = litPtr + dctx->litSize; @@ -777,11 +777,12 @@ static size_t ZSTD_decompressSequences( const U32 mls = dctx->fParams.mml; /* Build Decoding Tables */ - errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, + { size_t const errorCode = ZSTD_decodeSeqHeaders(&nbSeq, &dumps, &dumpsLength, DTableLL, DTableML, DTableOffb, ip, seqSize); - if (ZSTD_isError(errorCode)) return errorCode; - ip += errorCode; + if (ZSTD_isError(errorCode)) return errorCode; + ip += errorCode; + } /* Regen sequences */ if (nbSeq) { @@ -793,8 +794,8 @@ static size_t ZSTD_decompressSequences( seqState.dumps = dumps; seqState.dumpsEnd = dumps + dumpsLength; seqState.prevOffset = REPCODE_STARTVALUE; - errorCode = BIT_initDStream(&(seqState.DStream), ip, iend-ip); - if (ERR_isError(errorCode)) return ERROR(corruption_detected); + { size_t const errorCode = BIT_initDStream(&(seqState.DStream), ip, iend-ip); + if (ERR_isError(errorCode)) return ERROR(corruption_detected); } FSE_initDState(&(seqState.stateLL), &(seqState.DStream), DTableLL); FSE_initDState(&(seqState.stateOffb), &(seqState.DStream), DTableOffb); FSE_initDState(&(seqState.stateML), &(seqState.DStream), DTableML); @@ -804,8 +805,7 @@ static size_t ZSTD_decompressSequences( nbSeq--; ZSTD_decodeSequence(&sequence, &seqState, mls); oneSeqSize = ZSTD_execSequence(op, oend, sequence, &litPtr, litLimit_8, base, vBase, dictEnd); - if (ZSTD_isError(oneSeqSize)) - return oneSeqSize; + if (ZSTD_isError(oneSeqSize)) return oneSeqSize; op += oneSeqSize; } From 5a854af006bf2ab28133c4cf3ec3d30c53feb73a Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Tue, 22 Mar 2016 00:22:50 +0100 Subject: [PATCH 49/49] Fixed #153, reported by @thatsafunnyname --- programs/Makefile | 22 +++++++++++----------- programs/zstdcli.c | 30 +++++++++++++++--------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/programs/Makefile b/programs/Makefile index ca2ba99fc..6aca9768e 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -215,19 +215,19 @@ test-zbuff: zbufftest test-zbuff32: zbufftest32 ./zbufftest32 $(ZBUFFTEST) +valgrindTest: VALGRIND = valgrind --leak-check=full --error-exitcode=1 valgrindTest: zstd datagen fuzzer fullbench zbufftest @echo "\n ---- valgrind tests : memory analyzer ----" - valgrind --leak-check=yes --error-exitcode=1 ./datagen -g50M > $(VOID) - ./datagen -g16KB > tmp - valgrind --leak-check=yes --error-exitcode=1 ./zstd -vf tmp -o $(VOID) - ./datagen -g2930KB > tmp - valgrind --leak-check=yes --error-exitcode=1 ./zstd -5 -vf tmp -o tmp2 - valgrind --leak-check=yes --error-exitcode=1 ./zstd -vdf tmp2 -o $(VOID) - ./datagen -g64MB > tmp - valgrind --leak-check=yes --error-exitcode=1 ./zstd -vf tmp -o $(VOID) + $(VALGRIND) ./datagen -g50M > $(VOID) + $(VALGRIND) ./zstd ; if [ $$? -eq 0 ] ; then echo "zstd without argument should have failed"; false; fi + ./datagen -g80 | $(VALGRIND) ./zstd - -c > $(VOID) + ./datagen -g16KB | $(VALGRIND) ./zstd -vf - -o $(VOID) + ./datagen -g2930KB | $(VALGRIND) ./zstd -5 -vf - -o tmp + $(VALGRIND) ./zstd -vdf tmp -o $(VOID) + ./datagen -g64MB | $(VALGRIND) ./zstd -vf - -o $(VOID) @rm tmp - valgrind --leak-check=yes --error-exitcode=1 ./fuzzer -T1mn -t1 - valgrind --leak-check=yes --error-exitcode=1 ./fullbench -i1 - valgrind --leak-check=yes --error-exitcode=1 ./zbufftest -T1mn + $(VALGRIND) ./fuzzer -T1mn -t1 + $(VALGRIND) ./fullbench -i1 + $(VALGRIND) ./zbufftest -T1mn endif diff --git a/programs/zstdcli.c b/programs/zstdcli.c index adfaa793d..86d6bff78 100644 --- a/programs/zstdcli.c +++ b/programs/zstdcli.c @@ -167,6 +167,8 @@ static void waitEnter(void) } +#define CLEAN_RETURN(i) { operationResult = (i); goto _end; } + int main(int argCount, const char** argv) { int i, @@ -211,8 +213,8 @@ int main(int argCount, const char** argv) /* long commands (--long-word) */ if (!strcmp(argument, "--decompress")) { decode=1; continue; } if (!strcmp(argument, "--force")) { FIO_overwriteMode(); continue; } - if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; } - if (!strcmp(argument, "--help")) { displayOut=stdout; return usage_advanced(programName); } + if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); } + if (!strcmp(argument, "--help")) { displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); } if (!strcmp(argument, "--verbose")) { displayLevel=4; continue; } if (!strcmp(argument, "--quiet")) { displayLevel--; continue; } if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; displayLevel=1; continue; } @@ -244,16 +246,16 @@ int main(int argCount, const char** argv) } dictCLevel = cLevel; if (dictCLevel > ZSTD_maxCLevel()) - return badusage(programName); + CLEAN_RETURN(badusage(programName)); continue; } switch(argument[0]) { /* Display help */ - case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); return 0; /* Version Only */ + case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); /* Version Only */ case 'H': - case 'h': displayOut=stdout; return usage_advanced(programName); + case 'h': displayOut=stdout; CLEAN_RETURN(usage_advanced(programName)); /* Decoding */ case 'd': decode=1; argument++; break; @@ -288,8 +290,7 @@ int main(int argCount, const char** argv) /* Modify Nb Iterations (benchmark only) */ case 'i': - { - int iters= 0; + { U32 iters= 0; argument++; while ((*argument >='0') && (*argument <='9')) iters *= 10, iters += *argument++ - '0'; @@ -299,8 +300,7 @@ int main(int argCount, const char** argv) /* cut input into blocks (benchmark only) */ case 'B': - { - size_t bSize = 0; + { size_t bSize = 0; argument++; while ((*argument >='0') && (*argument <='9')) bSize *= 10, bSize += *argument++ - '0'; @@ -329,11 +329,11 @@ int main(int argCount, const char** argv) case 'p': main_pause=1; argument++; break; /* unknown command */ - default : return badusage(programName); + default : CLEAN_RETURN(badusage(programName)); } } continue; - } + } /* if (argument[0]=='-') */ if (nextEntryIsDictionary) { nextEntryIsDictionary = 0; @@ -389,17 +389,17 @@ int main(int argCount, const char** argv) if(!filenameIdx) filenameIdx=1, filenameTable[0]=stdinmark, outFileName=stdoutmark; /* Check if input/output defined as console; trigger an error in this case */ - if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) return badusage(programName); - if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) return badusage(programName); + if (!strcmp(filenameTable[0], stdinmark) && IS_CONSOLE(stdin) ) CLEAN_RETURN(badusage(programName)); + if (outFileName && !strcmp(outFileName, stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) CLEAN_RETURN(badusage(programName)); /* user-selected output filename, only possible with a single file */ if (outFileName && strcmp(outFileName,stdoutmark) && strcmp(outFileName,nulmark) && (filenameIdx>1)) { DISPLAY("Too many files (%u) on the command line. \n", filenameIdx); - return filenameIdx; + CLEAN_RETURN(filenameIdx); } /* No warning message in pipe mode (stdin + stdout) or multiple mode */ - if (!strcmp(filenameTable[0], stdinmark) && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1; + if (!strcmp(filenameTable[0], stdinmark) && outFileName && !strcmp(outFileName,stdoutmark) && (displayLevel==2)) displayLevel=1; if ((filenameIdx>1) && (displayLevel==2)) displayLevel=1; /* IO Stream/File */