Path: blob/main/sys/contrib/zstd/zlibWrapper/examples/zwrapbench.c
48375 views
/*1* Copyright (c) 2016-present, Przemyslaw Skibinski, Yann Collet, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under both the BSD-style license (found in the5* LICENSE file in the root directory of this source tree) and the GPLv2 (found6* in the COPYING file in the root directory of this source tree).7*/8910/* *************************************11* Includes12***************************************/13#include "util.h" /* Compiler options, UTIL_GetFileSize, UTIL_sleep */14#include <stdlib.h> /* malloc, free */15#include <string.h> /* memset */16#include <stdio.h> /* fprintf, fopen, ftello64 */17#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */18#include <ctype.h> /* toupper */19#include <errno.h> /* errno */2021#include "timefn.h" /* UTIL_time_t, UTIL_getTime, UTIL_clockSpanMicro, UTIL_waitForNextTick */22#include "mem.h"23#define ZSTD_STATIC_LINKING_ONLY24#include "zstd.h"25#include "datagen.h" /* RDG_genBuffer */26#include "xxhash.h"2728#include "zstd_zlibwrapper.h"29303132/*-************************************33* Tuning parameters34**************************************/35#ifndef ZSTDCLI_CLEVEL_DEFAULT36# define ZSTDCLI_CLEVEL_DEFAULT 337#endif383940/*-************************************41* Constants42**************************************/43#define COMPRESSOR_NAME "Zstandard wrapper for zlib command line interface"44#ifndef ZSTD_VERSION45# define ZSTD_VERSION "v" ZSTD_VERSION_STRING46#endif47#define AUTHOR "Yann Collet"48#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s ***\n", COMPRESSOR_NAME, (int)(sizeof(size_t)*8), ZSTD_VERSION, AUTHOR4950#ifndef ZSTD_GIT_COMMIT51# define ZSTD_GIT_COMMIT_STRING ""52#else53# define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)54#endif5556#define NBLOOPS 357#define TIMELOOP_MICROSEC 1*1000000ULL /* 1 second */58#define ACTIVEPERIOD_MICROSEC 70*1000000ULL /* 70 seconds */59#define COOLPERIOD_SEC 106061#define KB *(1 <<10)62#define MB *(1 <<20)63#define GB *(1U<<30)6465static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t)(1ULL << ((sizeof(size_t)*8)-31));6667static U32 g_compressibilityDefault = 50;686970/* *************************************71* console display72***************************************/73#define DEFAULT_DISPLAY_LEVEL 274#define DISPLAY(...) fprintf(displayOut, __VA_ARGS__)75#define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); }76static unsigned g_displayLevel = DEFAULT_DISPLAY_LEVEL; /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */77static FILE* displayOut;7879#define DISPLAYUPDATE(l, ...) if (g_displayLevel>=l) { \80if ((clock() - g_time > refreshRate) || (g_displayLevel>=4)) \81{ g_time = clock(); DISPLAY(__VA_ARGS__); \82if (g_displayLevel>=4) fflush(displayOut); } }83static const clock_t refreshRate = CLOCKS_PER_SEC * 15 / 100;84static clock_t g_time = 0;858687/* *************************************88* Exceptions89***************************************/90#ifndef DEBUG91# define DEBUG 092#endif93#define DEBUGOUTPUT(...) { if (DEBUG) DISPLAY(__VA_ARGS__); }94#define EXM_THROW(error, ...) \95{ \96DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \97DISPLAYLEVEL(1, "Error %i : ", error); \98DISPLAYLEVEL(1, __VA_ARGS__); \99DISPLAYLEVEL(1, "\n"); \100exit(error); \101}102103104/* *************************************105* Benchmark Parameters106***************************************/107static unsigned g_nbIterations = NBLOOPS;108static size_t g_blockSize = 0;109int g_additionalParam = 0;110111void BMK_setNotificationLevel(unsigned level) { g_displayLevel=level; }112113void BMK_setAdditionalParam(int additionalParam) { g_additionalParam=additionalParam; }114115void BMK_SetNbIterations(unsigned nbLoops)116{117g_nbIterations = nbLoops;118DISPLAYLEVEL(3, "- test >= %u seconds per compression / decompression -\n", g_nbIterations);119}120121void BMK_SetBlockSize(size_t blockSize)122{123g_blockSize = blockSize;124DISPLAYLEVEL(2, "using blocks of size %u KB \n", (unsigned)(blockSize>>10));125}126127128/* ********************************************************129* Bench functions130**********************************************************/131#undef MIN132#undef MAX133#define MIN(a,b) ((a)<(b) ? (a) : (b))134#define MAX(a,b) ((a)>(b) ? (a) : (b))135136typedef struct137{138z_const char* srcPtr;139size_t srcSize;140char* cPtr;141size_t cRoom;142size_t cSize;143char* resPtr;144size_t resSize;145} blockParam_t;146147typedef enum { BMK_ZSTD, BMK_ZSTD_STREAM, BMK_ZLIB, BMK_ZWRAP_ZLIB, BMK_ZWRAP_ZSTD, BMK_ZLIB_REUSE, BMK_ZWRAP_ZLIB_REUSE, BMK_ZWRAP_ZSTD_REUSE } BMK_compressor;148149150static int BMK_benchMem(z_const void* srcBuffer, size_t srcSize,151const char* displayName, int cLevel,152const size_t* fileSizes, U32 nbFiles,153const void* dictBuffer, size_t dictBufferSize, BMK_compressor compressor)154{155size_t const blockSize = (g_blockSize>=32 ? g_blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ;156size_t const avgSize = MIN(g_blockSize, (srcSize / nbFiles));157U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles;158blockParam_t* const blockTable = (blockParam_t*) malloc(maxNbBlocks * sizeof(blockParam_t));159size_t const maxCompressedSize = ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024); /* add some room for safety */160void* const compressedBuffer = malloc(maxCompressedSize);161void* const resultBuffer = malloc(srcSize);162ZSTD_CCtx* const ctx = ZSTD_createCCtx();163ZSTD_DCtx* const dctx = ZSTD_createDCtx();164U32 nbBlocks;165166/* checks */167if (!compressedBuffer || !resultBuffer || !blockTable || !ctx || !dctx)168EXM_THROW(31, "allocation error : not enough memory");169170/* init */171if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* can only display 17 characters */172173/* Init blockTable data */174{ z_const char* srcPtr = (z_const char*)srcBuffer;175char* cPtr = (char*)compressedBuffer;176char* resPtr = (char*)resultBuffer;177U32 fileNb;178for (nbBlocks=0, fileNb=0; fileNb<nbFiles; fileNb++) {179size_t remaining = fileSizes[fileNb];180U32 const nbBlocksforThisFile = (U32)((remaining + (blockSize-1)) / blockSize);181U32 const blockEnd = nbBlocks + nbBlocksforThisFile;182for ( ; nbBlocks<blockEnd; nbBlocks++) {183size_t const thisBlockSize = MIN(remaining, blockSize);184blockTable[nbBlocks].srcPtr = srcPtr;185blockTable[nbBlocks].cPtr = cPtr;186blockTable[nbBlocks].resPtr = resPtr;187blockTable[nbBlocks].srcSize = thisBlockSize;188blockTable[nbBlocks].cRoom = ZSTD_compressBound(thisBlockSize);189srcPtr += thisBlockSize;190cPtr += blockTable[nbBlocks].cRoom;191resPtr += thisBlockSize;192remaining -= thisBlockSize;193} } }194195/* warming up memory */196RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);197198/* Bench */199{ U64 fastestC = (U64)(-1LL), fastestD = (U64)(-1LL);200U64 const crcOrig = XXH64(srcBuffer, srcSize, 0);201UTIL_time_t coolTime;202U64 const maxTime = (g_nbIterations * TIMELOOP_MICROSEC) + 100;203U64 totalCTime=0, totalDTime=0;204U32 cCompleted=0, dCompleted=0;205# define NB_MARKS 4206const char* const marks[NB_MARKS] = { " |", " /", " =", "\\" };207U32 markNb = 0;208size_t cSize = 0;209double ratio = 0.;210211coolTime = UTIL_getTime();212DISPLAYLEVEL(2, "\r%79s\r", "");213while (!cCompleted | !dCompleted) {214UTIL_time_t clockStart;215U64 clockLoop = g_nbIterations ? TIMELOOP_MICROSEC : 1;216217/* overheat protection */218if (UTIL_clockSpanMicro(coolTime) > ACTIVEPERIOD_MICROSEC) {219DISPLAYLEVEL(2, "\rcooling down ... \r");220UTIL_sleep(COOLPERIOD_SEC);221coolTime = UTIL_getTime();222}223224/* Compression */225DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->\r", marks[markNb], displayName, (unsigned)srcSize);226if (!cCompleted) memset(compressedBuffer, 0xE5, maxCompressedSize); /* warm up and erase result buffer */227228UTIL_sleepMilli(1); /* give processor time to other processes */229UTIL_waitForNextTick();230clockStart = UTIL_getTime();231232if (!cCompleted) { /* still some time to do compression tests */233U32 nbLoops = 0;234if (compressor == BMK_ZSTD) {235ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize);236ZSTD_customMem const cmem = { NULL, NULL, NULL };237ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dictBuffer, dictBufferSize, ZSTD_dlm_byRef, ZSTD_dct_auto, zparams.cParams, cmem);238if (cdict==NULL) EXM_THROW(1, "ZSTD_createCDict_advanced() allocation failure");239240do {241U32 blockNb;242size_t rSize;243for (blockNb=0; blockNb<nbBlocks; blockNb++) {244if (dictBufferSize) {245rSize = ZSTD_compress_usingCDict(ctx,246blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,247blockTable[blockNb].srcPtr,blockTable[blockNb].srcSize,248cdict);249} else {250rSize = ZSTD_compressCCtx (ctx,251blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,252blockTable[blockNb].srcPtr,blockTable[blockNb].srcSize, cLevel);253}254if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_compress_usingCDict() failed : %s", ZSTD_getErrorName(rSize));255blockTable[blockNb].cSize = rSize;256}257nbLoops++;258} while (UTIL_clockSpanMicro(clockStart) < clockLoop);259ZSTD_freeCDict(cdict);260} else if (compressor == BMK_ZSTD_STREAM) {261ZSTD_parameters const zparams = ZSTD_getParams(cLevel, avgSize, dictBufferSize);262ZSTD_inBuffer inBuffer;263ZSTD_outBuffer outBuffer;264ZSTD_CStream* zbc = ZSTD_createCStream();265size_t rSize;266ZSTD_CCtx_params* cctxParams = ZSTD_createCCtxParams();267268if (!cctxParams) EXM_THROW(1, "ZSTD_createCCtxParams() allocation failure");269if (zbc == NULL) EXM_THROW(1, "ZSTD_createCStream() allocation failure");270271{ int initErr = 0;272initErr |= ZSTD_isError(ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only));273initErr |= ZSTD_isError(ZSTD_CCtxParams_init_advanced(cctxParams, zparams));274initErr |= ZSTD_isError(ZSTD_CCtx_setParametersUsingCCtxParams(zbc, cctxParams));275initErr |= ZSTD_isError(ZSTD_CCtx_setPledgedSrcSize(zbc, avgSize));276initErr |= ZSTD_isError(ZSTD_CCtx_loadDictionary(zbc, dictBuffer, dictBufferSize));277278ZSTD_freeCCtxParams(cctxParams);279if (initErr) EXM_THROW(1, "CCtx init failed!");280}281282do {283U32 blockNb;284for (blockNb=0; blockNb<nbBlocks; blockNb++) {285rSize = ZSTD_CCtx_reset(zbc, ZSTD_reset_session_only);286if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_CCtx_reset() failed : %s", ZSTD_getErrorName(rSize));287rSize = ZSTD_CCtx_setPledgedSrcSize(zbc, blockTable[blockNb].srcSize);288if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_CCtx_setPledgedSrcSize() failed : %s", ZSTD_getErrorName(rSize));289inBuffer.src = blockTable[blockNb].srcPtr;290inBuffer.size = blockTable[blockNb].srcSize;291inBuffer.pos = 0;292outBuffer.dst = blockTable[blockNb].cPtr;293outBuffer.size = blockTable[blockNb].cRoom;294outBuffer.pos = 0;295rSize = ZSTD_compressStream(zbc, &outBuffer, &inBuffer);296if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_compressStream() failed : %s", ZSTD_getErrorName(rSize));297rSize = ZSTD_endStream(zbc, &outBuffer);298if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_endStream() failed : %s", ZSTD_getErrorName(rSize));299blockTable[blockNb].cSize = outBuffer.pos;300}301nbLoops++;302} while (UTIL_clockSpanMicro(clockStart) < clockLoop);303ZSTD_freeCStream(zbc);304} else if (compressor == BMK_ZWRAP_ZLIB_REUSE || compressor == BMK_ZWRAP_ZSTD_REUSE || compressor == BMK_ZLIB_REUSE) {305z_stream def;306int ret;307int useSetDict = (dictBuffer != NULL);308if (compressor == BMK_ZLIB_REUSE || compressor == BMK_ZWRAP_ZLIB_REUSE) ZWRAP_useZSTDcompression(0);309else ZWRAP_useZSTDcompression(1);310def.zalloc = Z_NULL;311def.zfree = Z_NULL;312def.opaque = Z_NULL;313ret = deflateInit(&def, cLevel);314if (ret != Z_OK) EXM_THROW(1, "deflateInit failure");315/* if (ZWRAP_isUsingZSTDcompression()) {316ret = ZWRAP_setPledgedSrcSize(&def, avgSize);317if (ret != Z_OK) EXM_THROW(1, "ZWRAP_setPledgedSrcSize failure");318} */319do {320U32 blockNb;321for (blockNb=0; blockNb<nbBlocks; blockNb++) {322if (ZWRAP_isUsingZSTDcompression())323ret = ZWRAP_deflateReset_keepDict(&def); /* reuse dictionary to make compression faster */324else325ret = deflateReset(&def);326if (ret != Z_OK) EXM_THROW(1, "deflateReset failure");327if (useSetDict) {328ret = deflateSetDictionary(&def, (const z_Bytef*)dictBuffer, dictBufferSize);329if (ret != Z_OK) EXM_THROW(1, "deflateSetDictionary failure");330if (ZWRAP_isUsingZSTDcompression()) useSetDict = 0; /* zstd doesn't require deflateSetDictionary after ZWRAP_deflateReset_keepDict */331}332def.next_in = (z_const z_Bytef*) blockTable[blockNb].srcPtr;333def.avail_in = (uInt)blockTable[blockNb].srcSize;334def.total_in = 0;335def.next_out = (z_Bytef*) blockTable[blockNb].cPtr;336def.avail_out = (uInt)blockTable[blockNb].cRoom;337def.total_out = 0;338ret = deflate(&def, Z_FINISH);339if (ret != Z_STREAM_END) EXM_THROW(1, "deflate failure ret=%d srcSize=%d" , ret, (int)blockTable[blockNb].srcSize);340blockTable[blockNb].cSize = def.total_out;341}342nbLoops++;343} while (UTIL_clockSpanMicro(clockStart) < clockLoop);344ret = deflateEnd(&def);345if (ret != Z_OK) EXM_THROW(1, "deflateEnd failure");346} else {347z_stream def;348if (compressor == BMK_ZLIB || compressor == BMK_ZWRAP_ZLIB) ZWRAP_useZSTDcompression(0);349else ZWRAP_useZSTDcompression(1);350do {351U32 blockNb;352for (blockNb=0; blockNb<nbBlocks; blockNb++) {353int ret;354def.zalloc = Z_NULL;355def.zfree = Z_NULL;356def.opaque = Z_NULL;357ret = deflateInit(&def, cLevel);358if (ret != Z_OK) EXM_THROW(1, "deflateInit failure");359if (dictBuffer) {360ret = deflateSetDictionary(&def, (const z_Bytef*)dictBuffer, dictBufferSize);361if (ret != Z_OK) EXM_THROW(1, "deflateSetDictionary failure");362}363def.next_in = (z_const z_Bytef*) blockTable[blockNb].srcPtr;364def.avail_in = (uInt)blockTable[blockNb].srcSize;365def.total_in = 0;366def.next_out = (z_Bytef*) blockTable[blockNb].cPtr;367def.avail_out = (uInt)blockTable[blockNb].cRoom;368def.total_out = 0;369ret = deflate(&def, Z_FINISH);370if (ret != Z_STREAM_END) EXM_THROW(1, "deflate failure");371ret = deflateEnd(&def);372if (ret != Z_OK) EXM_THROW(1, "deflateEnd failure");373blockTable[blockNb].cSize = def.total_out;374}375nbLoops++;376} while (UTIL_clockSpanMicro(clockStart) < clockLoop);377}378{ U64 const clockSpan = UTIL_clockSpanMicro(clockStart);379if (clockSpan < fastestC*nbLoops) fastestC = clockSpan / nbLoops;380totalCTime += clockSpan;381cCompleted = totalCTime>maxTime;382} }383384cSize = 0;385{ U32 blockNb; for (blockNb=0; blockNb<nbBlocks; blockNb++) cSize += blockTable[blockNb].cSize; }386ratio = (double)srcSize / (double)cSize;387markNb = (markNb+1) % NB_MARKS;388DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s\r",389marks[markNb], displayName, (unsigned)srcSize, (unsigned)cSize, ratio,390(double)srcSize / fastestC );391392(void)fastestD; (void)crcOrig; /* unused when decompression disabled */393#if 1394/* Decompression */395if (!dCompleted) memset(resultBuffer, 0xD6, srcSize); /* warm result buffer */396397UTIL_sleepMilli(1); /* give processor time to other processes */398UTIL_waitForNextTick();399clockStart = UTIL_getTime();400401if (!dCompleted) {402U32 nbLoops = 0;403if (compressor == BMK_ZSTD) {404ZSTD_DDict* ddict = ZSTD_createDDict(dictBuffer, dictBufferSize);405if (!ddict) EXM_THROW(2, "ZSTD_createDDict() allocation failure");406do {407unsigned blockNb;408for (blockNb=0; blockNb<nbBlocks; blockNb++) {409size_t const regenSize = ZSTD_decompress_usingDDict(dctx,410blockTable[blockNb].resPtr, blockTable[blockNb].srcSize,411blockTable[blockNb].cPtr, blockTable[blockNb].cSize,412ddict);413if (ZSTD_isError(regenSize)) {414DISPLAY("ZSTD_decompress_usingDDict() failed on block %u : %s \n",415blockNb, ZSTD_getErrorName(regenSize));416clockLoop = 0; /* force immediate test end */417break;418}419blockTable[blockNb].resSize = regenSize;420}421nbLoops++;422} while (UTIL_clockSpanMicro(clockStart) < clockLoop);423ZSTD_freeDDict(ddict);424} else if (compressor == BMK_ZSTD_STREAM) {425ZSTD_inBuffer inBuffer;426ZSTD_outBuffer outBuffer;427ZSTD_DStream* zbd = ZSTD_createDStream();428size_t rSize;429if (zbd == NULL) EXM_THROW(1, "ZSTD_createDStream() allocation failure");430rSize = ZSTD_initDStream_usingDict(zbd, dictBuffer, dictBufferSize);431if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_initDStream() failed : %s", ZSTD_getErrorName(rSize));432do {433U32 blockNb;434for (blockNb=0; blockNb<nbBlocks; blockNb++) {435rSize = ZSTD_DCtx_reset(zbd, ZSTD_reset_session_only);436if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_DCtx_reset() failed : %s", ZSTD_getErrorName(rSize));437inBuffer.src = blockTable[blockNb].cPtr;438inBuffer.size = blockTable[blockNb].cSize;439inBuffer.pos = 0;440outBuffer.dst = blockTable[blockNb].resPtr;441outBuffer.size = blockTable[blockNb].srcSize;442outBuffer.pos = 0;443rSize = ZSTD_decompressStream(zbd, &outBuffer, &inBuffer);444if (ZSTD_isError(rSize)) EXM_THROW(1, "ZSTD_decompressStream() failed : %s", ZSTD_getErrorName(rSize));445blockTable[blockNb].resSize = outBuffer.pos;446}447nbLoops++;448} while (UTIL_clockSpanMicro(clockStart) < clockLoop);449ZSTD_freeDStream(zbd);450} else if (compressor == BMK_ZWRAP_ZLIB_REUSE || compressor == BMK_ZWRAP_ZSTD_REUSE || compressor == BMK_ZLIB_REUSE) {451z_stream inf;452int ret;453if (compressor == BMK_ZLIB_REUSE) ZWRAP_setDecompressionType(ZWRAP_FORCE_ZLIB);454else ZWRAP_setDecompressionType(ZWRAP_AUTO);455inf.zalloc = Z_NULL;456inf.zfree = Z_NULL;457inf.opaque = Z_NULL;458ret = inflateInit(&inf);459if (ret != Z_OK) EXM_THROW(1, "inflateInit failure");460do {461U32 blockNb;462for (blockNb=0; blockNb<nbBlocks; blockNb++) {463if (ZWRAP_isUsingZSTDdecompression(&inf))464ret = ZWRAP_inflateReset_keepDict(&inf); /* reuse dictionary to make decompression faster; inflate will return Z_NEED_DICT only for the first time */465else466ret = inflateReset(&inf);467if (ret != Z_OK) EXM_THROW(1, "inflateReset failure");468inf.next_in = (z_const z_Bytef*) blockTable[blockNb].cPtr;469inf.avail_in = (uInt)blockTable[blockNb].cSize;470inf.total_in = 0;471inf.next_out = (z_Bytef*) blockTable[blockNb].resPtr;472inf.avail_out = (uInt)blockTable[blockNb].srcSize;473inf.total_out = 0;474ret = inflate(&inf, Z_FINISH);475if (ret == Z_NEED_DICT) {476ret = inflateSetDictionary(&inf, (const z_Bytef*)dictBuffer, dictBufferSize);477if (ret != Z_OK) EXM_THROW(1, "inflateSetDictionary failure");478ret = inflate(&inf, Z_FINISH);479}480if (ret != Z_STREAM_END) EXM_THROW(1, "inflate failure");481blockTable[blockNb].resSize = inf.total_out;482}483nbLoops++;484} while (UTIL_clockSpanMicro(clockStart) < clockLoop);485ret = inflateEnd(&inf);486if (ret != Z_OK) EXM_THROW(1, "inflateEnd failure");487} else {488z_stream inf;489if (compressor == BMK_ZLIB) ZWRAP_setDecompressionType(ZWRAP_FORCE_ZLIB);490else ZWRAP_setDecompressionType(ZWRAP_AUTO);491do {492U32 blockNb;493for (blockNb=0; blockNb<nbBlocks; blockNb++) {494int ret;495inf.zalloc = Z_NULL;496inf.zfree = Z_NULL;497inf.opaque = Z_NULL;498ret = inflateInit(&inf);499if (ret != Z_OK) EXM_THROW(1, "inflateInit failure");500inf.next_in = (z_const z_Bytef*) blockTable[blockNb].cPtr;501inf.avail_in = (uInt)blockTable[blockNb].cSize;502inf.total_in = 0;503inf.next_out = (z_Bytef*) blockTable[blockNb].resPtr;504inf.avail_out = (uInt)blockTable[blockNb].srcSize;505inf.total_out = 0;506ret = inflate(&inf, Z_FINISH);507if (ret == Z_NEED_DICT) {508ret = inflateSetDictionary(&inf, (const z_Bytef*) dictBuffer, dictBufferSize);509if (ret != Z_OK) EXM_THROW(1, "inflateSetDictionary failure");510ret = inflate(&inf, Z_FINISH);511}512if (ret != Z_STREAM_END) EXM_THROW(1, "inflate failure");513ret = inflateEnd(&inf);514if (ret != Z_OK) EXM_THROW(1, "inflateEnd failure");515blockTable[blockNb].resSize = inf.total_out;516}517nbLoops++;518} while (UTIL_clockSpanMicro(clockStart) < clockLoop);519}520{ U64 const clockSpan = UTIL_clockSpanMicro(clockStart);521if (clockSpan < fastestD*nbLoops) fastestD = clockSpan / nbLoops;522totalDTime += clockSpan;523dCompleted = totalDTime>maxTime;524} }525526markNb = (markNb+1) % NB_MARKS;527DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.3f),%6.1f MB/s ,%6.1f MB/s\r",528marks[markNb], displayName, (unsigned)srcSize, (unsigned)cSize, ratio,529(double)srcSize / fastestC,530(double)srcSize / fastestD );531532/* CRC Checking */533{ U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);534if (crcOrig!=crcCheck) {535size_t u;536DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n", displayName, (unsigned)crcOrig, (unsigned)crcCheck);537for (u=0; u<srcSize; u++) {538if (((const BYTE*)srcBuffer)[u] != ((const BYTE*)resultBuffer)[u]) {539unsigned segNb, bNb, pos;540size_t bacc = 0;541DISPLAY("Decoding error at pos %u ", (unsigned)u);542for (segNb = 0; segNb < nbBlocks; segNb++) {543if (bacc + blockTable[segNb].srcSize > u) break;544bacc += blockTable[segNb].srcSize;545}546pos = (U32)(u - bacc);547bNb = pos / (128 KB);548DISPLAY("(block %u, sub %u, pos %u) \n", segNb, bNb, pos);549break;550}551if (u==srcSize-1) { /* should never happen */552DISPLAY("no difference detected\n");553} }554break;555} } /* CRC Checking */556#endif557} /* for (testNb = 1; testNb <= (g_nbIterations + !g_nbIterations); testNb++) */558559if (g_displayLevel == 1) {560double cSpeed = (double)srcSize / fastestC;561double dSpeed = (double)srcSize / fastestD;562if (g_additionalParam)563DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, g_additionalParam);564else565DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName);566}567DISPLAYLEVEL(2, "%2i#\n", cLevel);568} /* Bench */569570/* clean up */571free(blockTable);572free(compressedBuffer);573free(resultBuffer);574ZSTD_freeCCtx(ctx);575ZSTD_freeDCtx(dctx);576return 0;577}578579580static size_t BMK_findMaxMem(U64 requiredMem)581{582size_t const step = 64 MB;583BYTE* testmem = NULL;584585requiredMem = (((requiredMem >> 26) + 1) << 26);586requiredMem += step;587if (requiredMem > maxMemory) requiredMem = maxMemory;588589do {590testmem = (BYTE*)malloc((size_t)requiredMem);591requiredMem -= step;592} while (!testmem && requiredMem); /* do not allocate zero bytes */593594free(testmem);595return (size_t)(requiredMem+1); /* avoid zero */596}597598static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize,599const char* displayName, int cLevel, int cLevelLast,600const size_t* fileSizes, unsigned nbFiles,601const void* dictBuffer, size_t dictBufferSize)602{603int l;604605const char* pch = strrchr(displayName, '\\'); /* Windows */606if (!pch) pch = strrchr(displayName, '/'); /* Linux */607if (pch) displayName = pch+1;608609SET_REALTIME_PRIORITY;610611if (g_displayLevel == 1 && !g_additionalParam)612DISPLAY("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",613ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING,614(unsigned)benchedSize, g_nbIterations, (unsigned)(g_blockSize>>10));615616if (cLevelLast < cLevel) cLevelLast = cLevel;617618DISPLAY("benchmarking zstd %s (using ZSTD_CStream)\n", ZSTD_VERSION_STRING);619for (l=cLevel; l <= cLevelLast; l++) {620BMK_benchMem(srcBuffer, benchedSize,621displayName, l,622fileSizes, nbFiles,623dictBuffer, dictBufferSize, BMK_ZSTD_STREAM);624}625626DISPLAY("benchmarking zstd %s (using ZSTD_CCtx)\n", ZSTD_VERSION_STRING);627for (l=cLevel; l <= cLevelLast; l++) {628BMK_benchMem(srcBuffer, benchedSize,629displayName, l,630fileSizes, nbFiles,631dictBuffer, dictBufferSize, BMK_ZSTD);632}633634DISPLAY("benchmarking zstd %s (using zlibWrapper)\n", ZSTD_VERSION_STRING);635for (l=cLevel; l <= cLevelLast; l++) {636BMK_benchMem(srcBuffer, benchedSize,637displayName, l,638fileSizes, nbFiles,639dictBuffer, dictBufferSize, BMK_ZWRAP_ZSTD_REUSE);640}641642DISPLAY("benchmarking zstd %s (zlibWrapper not reusing a context)\n", ZSTD_VERSION_STRING);643for (l=cLevel; l <= cLevelLast; l++) {644BMK_benchMem(srcBuffer, benchedSize,645displayName, l,646fileSizes, nbFiles,647dictBuffer, dictBufferSize, BMK_ZWRAP_ZSTD);648}649650651if (cLevelLast > Z_BEST_COMPRESSION) cLevelLast = Z_BEST_COMPRESSION;652653DISPLAY("\n");654DISPLAY("benchmarking zlib %s\n", ZLIB_VERSION);655for (l=cLevel; l <= cLevelLast; l++) {656BMK_benchMem(srcBuffer, benchedSize,657displayName, l,658fileSizes, nbFiles,659dictBuffer, dictBufferSize, BMK_ZLIB_REUSE);660}661662DISPLAY("benchmarking zlib %s (zlib not reusing a context)\n", ZLIB_VERSION);663for (l=cLevel; l <= cLevelLast; l++) {664BMK_benchMem(srcBuffer, benchedSize,665displayName, l,666fileSizes, nbFiles,667dictBuffer, dictBufferSize, BMK_ZLIB);668}669670DISPLAY("benchmarking zlib %s (using zlibWrapper)\n", ZLIB_VERSION);671for (l=cLevel; l <= cLevelLast; l++) {672BMK_benchMem(srcBuffer, benchedSize,673displayName, l,674fileSizes, nbFiles,675dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB_REUSE);676}677678DISPLAY("benchmarking zlib %s (zlibWrapper not reusing a context)\n", ZLIB_VERSION);679for (l=cLevel; l <= cLevelLast; l++) {680BMK_benchMem(srcBuffer, benchedSize,681displayName, l,682fileSizes, nbFiles,683dictBuffer, dictBufferSize, BMK_ZWRAP_ZLIB);684}685}686687688/*! BMK_loadFiles() :689Loads `buffer` with content of files listed within `fileNamesTable`.690At most, fills `buffer` entirely */691static void BMK_loadFiles(void* buffer, size_t bufferSize,692size_t* fileSizes,693const char** fileNamesTable, unsigned nbFiles)694{695size_t pos = 0, totalSize = 0;696unsigned n;697for (n=0; n<nbFiles; n++) {698FILE* f;699U64 fileSize = UTIL_getFileSize(fileNamesTable[n]);700if (UTIL_isDirectory(fileNamesTable[n])) {701DISPLAYLEVEL(2, "Ignoring %s directory... \n", fileNamesTable[n]);702fileSizes[n] = 0;703continue;704}705if (fileSize == UTIL_FILESIZE_UNKNOWN) {706DISPLAYLEVEL(2, "Cannot determine size of %s ... \n", fileNamesTable[n]);707fileSizes[n] = 0;708continue;709}710f = fopen(fileNamesTable[n], "rb");711if (f==NULL) EXM_THROW(10, "impossible to open file %s", fileNamesTable[n]);712DISPLAYUPDATE(2, "Loading %s... \r", fileNamesTable[n]);713if (fileSize > bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n; /* buffer too small - stop after this file */714{ size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f);715if (readSize != (size_t)fileSize) EXM_THROW(11, "could not read %s", fileNamesTable[n]);716pos += readSize; }717fileSizes[n] = (size_t)fileSize;718totalSize += (size_t)fileSize;719fclose(f);720}721722if (totalSize == 0) EXM_THROW(12, "no data to bench");723}724725static void BMK_benchFileTable(const char** fileNamesTable, unsigned nbFiles,726const char* dictFileName, int cLevel, int cLevelLast)727{728void* srcBuffer;729size_t benchedSize;730void* dictBuffer = NULL;731size_t dictBufferSize = 0;732size_t* fileSizes = (size_t*)malloc(nbFiles * sizeof(size_t));733U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);734char mfName[20] = {0};735736if (!fileSizes) EXM_THROW(12, "not enough memory for fileSizes");737738/* Load dictionary */739if (dictFileName != NULL) {740U64 const dictFileSize = UTIL_getFileSize(dictFileName);741if (dictFileSize > 64 MB)742EXM_THROW(10, "dictionary file %s too large", dictFileName);743dictBufferSize = (size_t)dictFileSize;744dictBuffer = malloc(dictBufferSize);745if (dictBuffer==NULL)746EXM_THROW(11, "not enough memory for dictionary (%u bytes)", (unsigned)dictBufferSize);747BMK_loadFiles(dictBuffer, dictBufferSize, fileSizes, &dictFileName, 1);748}749750/* Memory allocation & restrictions */751benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3;752if ((U64)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad;753if (benchedSize < totalSizeToLoad)754DISPLAY("Not enough memory; testing %u MB only...\n", (unsigned)(benchedSize >> 20));755srcBuffer = malloc(benchedSize + !benchedSize);756if (!srcBuffer) EXM_THROW(12, "not enough memory");757758/* Load input buffer */759BMK_loadFiles(srcBuffer, benchedSize, fileSizes, fileNamesTable, nbFiles);760761/* Bench */762snprintf (mfName, sizeof(mfName), " %u files", nbFiles);763{ const char* displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];764BMK_benchCLevel(srcBuffer, benchedSize,765displayName, cLevel, cLevelLast,766fileSizes, nbFiles,767dictBuffer, dictBufferSize);768}769770/* clean up */771free(srcBuffer);772free(dictBuffer);773free(fileSizes);774}775776777static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility)778{779char name[20] = {0};780size_t benchedSize = 10000000;781void* const srcBuffer = malloc(benchedSize);782783/* Memory allocation */784if (!srcBuffer) EXM_THROW(21, "not enough memory");785786/* Fill input buffer */787RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);788789/* Bench */790snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));791BMK_benchCLevel(srcBuffer, benchedSize, name, cLevel, cLevelLast, &benchedSize, 1, NULL, 0);792793/* clean up */794free(srcBuffer);795}796797798int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles,799const char* dictFileName, int cLevel, int cLevelLast)800{801double const compressibility = (double)g_compressibilityDefault / 100;802803if (nbFiles == 0)804BMK_syntheticTest(cLevel, cLevelLast, compressibility);805else806BMK_benchFileTable(fileNamesTable, nbFiles, dictFileName, cLevel, cLevelLast);807return 0;808}809810811812813/*-************************************814* Command Line815**************************************/816static int usage(const char* programName)817{818DISPLAY(WELCOME_MESSAGE);819DISPLAY( "Usage :\n");820DISPLAY( " %s [args] [FILE(s)] [-o file]\n", programName);821DISPLAY( "\n");822DISPLAY( "FILE : a filename\n");823DISPLAY( " with no FILE, or when FILE is - , read standard input\n");824DISPLAY( "Arguments :\n");825DISPLAY( " -D file: use `file` as Dictionary \n");826DISPLAY( " -h/-H : display help/long help and exit\n");827DISPLAY( " -V : display Version number and exit\n");828DISPLAY( " -v : verbose mode; specify multiple times to increase log level (default:%d)\n", DEFAULT_DISPLAY_LEVEL);829DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n");830#ifdef UTIL_HAS_CREATEFILELIST831DISPLAY( " -r : operate recursively on directories\n");832#endif833DISPLAY( "\n");834DISPLAY( "Benchmark arguments :\n");835DISPLAY( " -b# : benchmark file(s), using # compression level (default : %d) \n", ZSTDCLI_CLEVEL_DEFAULT);836DISPLAY( " -e# : test all compression levels from -bX to # (default: %d)\n", ZSTDCLI_CLEVEL_DEFAULT);837DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s)\n");838DISPLAY( " -B# : cut file into independent blocks of size # (default: no block)\n");839return 0;840}841842static int badusage(const char* programName)843{844DISPLAYLEVEL(1, "Incorrect parameters\n");845if (g_displayLevel >= 1) usage(programName);846return 1;847}848849static void waitEnter(void)850{851int unused;852DISPLAY("Press enter to continue...\n");853unused = getchar();854(void)unused;855}856857/*! readU32FromChar() :858@return : unsigned integer value reach from input in `char` format859Will also modify `*stringPtr`, advancing it to position where it stopped reading.860Note : this function can overflow if digit string > MAX_UINT */861static unsigned readU32FromChar(const char** stringPtr)862{863unsigned result = 0;864while ((**stringPtr >='0') && (**stringPtr <='9'))865result *= 10, result += (unsigned)(**stringPtr - '0'), (*stringPtr)++ ;866return result;867}868869870#define CLEAN_RETURN(i) { operationResult = (i); goto _end; }871872int main(int argCount, char** argv)873{874int argNb,875main_pause=0,876nextEntryIsDictionary=0,877operationResult=0,878nextArgumentIsFile=0;879int cLevel = ZSTDCLI_CLEVEL_DEFAULT;880int cLevelLast = 1;881unsigned recursive = 0;882FileNamesTable* filenames = UTIL_allocateFileNamesTable((size_t)argCount);883const char* programName = argv[0];884const char* dictFileName = NULL;885char* dynNameSpace = NULL;886887/* init */888if (filenames==NULL) { DISPLAY("zstd: %s \n", strerror(errno)); exit(1); }889displayOut = stderr;890891/* Pick out program name from path. Don't rely on stdlib because of conflicting behavior */892{ size_t pos;893for (pos = strlen(programName); pos > 0; pos--) { if (programName[pos] == '/') { pos++; break; } }894programName += pos;895}896897/* command switches */898for(argNb=1; argNb<argCount; argNb++) {899const char* argument = argv[argNb];900if(!argument) continue; /* Protection if argument empty */901902if (nextArgumentIsFile==0) {903904/* long commands (--long-word) */905if (!strcmp(argument, "--")) { nextArgumentIsFile=1; continue; }906if (!strcmp(argument, "--version")) { displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); }907if (!strcmp(argument, "--help")) { displayOut=stdout; CLEAN_RETURN(usage(programName)); }908if (!strcmp(argument, "--verbose")) { g_displayLevel++; continue; }909if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; }910911/* Decode commands (note : aggregated commands are allowed) */912if (argument[0]=='-') {913argument++;914915while (argument[0]!=0) {916switch(argument[0])917{918/* Display help */919case 'V': displayOut=stdout; DISPLAY(WELCOME_MESSAGE); CLEAN_RETURN(0); /* Version Only */920case 'H':921case 'h': displayOut=stdout; CLEAN_RETURN(usage(programName));922923/* Use file content as dictionary */924case 'D': nextEntryIsDictionary = 1; argument++; break;925926/* Verbose mode */927case 'v': g_displayLevel++; argument++; break;928929/* Quiet mode */930case 'q': g_displayLevel--; argument++; break;931932#ifdef UTIL_HAS_CREATEFILELIST933/* recursive */934case 'r': recursive=1; argument++; break;935#endif936937/* Benchmark */938case 'b':939/* first compression Level */940argument++;941cLevel = (int)readU32FromChar(&argument);942break;943944/* range bench (benchmark only) */945case 'e':946/* last compression Level */947argument++;948cLevelLast = (int)readU32FromChar(&argument);949break;950951/* Modify Nb Iterations (benchmark only) */952case 'i':953argument++;954{ U32 const iters = readU32FromChar(&argument);955BMK_setNotificationLevel(g_displayLevel);956BMK_SetNbIterations(iters);957}958break;959960/* cut input into blocks (benchmark only) */961case 'B':962argument++;963{ size_t bSize = readU32FromChar(&argument);964if (toupper(*argument)=='K') bSize<<=10, argument++; /* allows using KB notation */965if (toupper(*argument)=='M') bSize<<=20, argument++;966if (toupper(*argument)=='B') argument++;967BMK_setNotificationLevel(g_displayLevel);968BMK_SetBlockSize(bSize);969}970break;971972/* Pause at the end (-p) or set an additional param (-p#) (hidden option) */973case 'p': argument++;974if ((*argument>='0') && (*argument<='9')) {975BMK_setAdditionalParam((int)readU32FromChar(&argument));976} else977main_pause=1;978break;979/* unknown command */980default : CLEAN_RETURN(badusage(programName));981}982}983continue;984} /* if (argument[0]=='-') */985986} /* if (nextArgumentIsAFile==0) */987988if (nextEntryIsDictionary) {989nextEntryIsDictionary = 0;990dictFileName = argument;991continue;992}993994/* add filename to list */995UTIL_refFilename(filenames, argument);996}997998/* Welcome message (if verbose) */999DISPLAYLEVEL(3, WELCOME_MESSAGE);10001001#ifdef UTIL_HAS_CREATEFILELIST1002if (recursive) {1003UTIL_expandFNT(&filenames, 1);1004}1005#endif10061007BMK_setNotificationLevel(g_displayLevel);1008BMK_benchFiles(filenames->fileNames, (unsigned)filenames->tableSize, dictFileName, cLevel, cLevelLast);10091010_end:1011if (main_pause) waitEnter();1012free(dynNameSpace);1013UTIL_freeFileNamesTable(filenames);1014return operationResult;1015}101610171018