xref: /freebsd/sys/contrib/zstd/programs/benchzstd.c (revision a0483764f3d68669e9b7db074bcbd45b050166bb)
1*a0483764SConrad Meyer /*
2*a0483764SConrad Meyer  * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3*a0483764SConrad Meyer  * All rights reserved.
4*a0483764SConrad Meyer  *
5*a0483764SConrad Meyer  * This source code is licensed under both the BSD-style license (found in the
6*a0483764SConrad Meyer  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*a0483764SConrad Meyer  * in the COPYING file in the root directory of this source tree).
8*a0483764SConrad Meyer  * You may select, at your option, one of the above-listed licenses.
9*a0483764SConrad Meyer  */
10*a0483764SConrad Meyer 
11*a0483764SConrad Meyer 
12*a0483764SConrad Meyer /* **************************************
13*a0483764SConrad Meyer *  Tuning parameters
14*a0483764SConrad Meyer ****************************************/
15*a0483764SConrad Meyer #ifndef BMK_TIMETEST_DEFAULT_S   /* default minimum time per test */
16*a0483764SConrad Meyer #define BMK_TIMETEST_DEFAULT_S 3
17*a0483764SConrad Meyer #endif
18*a0483764SConrad Meyer 
19*a0483764SConrad Meyer 
20*a0483764SConrad Meyer /* *************************************
21*a0483764SConrad Meyer *  Includes
22*a0483764SConrad Meyer ***************************************/
23*a0483764SConrad Meyer #include "platform.h"    /* Large Files support */
24*a0483764SConrad Meyer #include "util.h"        /* UTIL_getFileSize, UTIL_sleep */
25*a0483764SConrad Meyer #include <stdlib.h>      /* malloc, free */
26*a0483764SConrad Meyer #include <string.h>      /* memset, strerror */
27*a0483764SConrad Meyer #include <stdio.h>       /* fprintf, fopen */
28*a0483764SConrad Meyer #include <errno.h>
29*a0483764SConrad Meyer #include <assert.h>      /* assert */
30*a0483764SConrad Meyer 
31*a0483764SConrad Meyer #include "benchfn.h"
32*a0483764SConrad Meyer #include "mem.h"
33*a0483764SConrad Meyer #define ZSTD_STATIC_LINKING_ONLY
34*a0483764SConrad Meyer #include "zstd.h"
35*a0483764SConrad Meyer #include "datagen.h"     /* RDG_genBuffer */
36*a0483764SConrad Meyer #include "xxhash.h"
37*a0483764SConrad Meyer #include "benchzstd.h"
38*a0483764SConrad Meyer #include "zstd_errors.h"
39*a0483764SConrad Meyer 
40*a0483764SConrad Meyer 
41*a0483764SConrad Meyer /* *************************************
42*a0483764SConrad Meyer *  Constants
43*a0483764SConrad Meyer ***************************************/
44*a0483764SConrad Meyer #ifndef ZSTD_GIT_COMMIT
45*a0483764SConrad Meyer #  define ZSTD_GIT_COMMIT_STRING ""
46*a0483764SConrad Meyer #else
47*a0483764SConrad Meyer #  define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
48*a0483764SConrad Meyer #endif
49*a0483764SConrad Meyer 
50*a0483764SConrad Meyer #define TIMELOOP_MICROSEC     (1*1000000ULL) /* 1 second */
51*a0483764SConrad Meyer #define TIMELOOP_NANOSEC      (1*1000000000ULL) /* 1 second */
52*a0483764SConrad Meyer #define ACTIVEPERIOD_MICROSEC (70*TIMELOOP_MICROSEC) /* 70 seconds */
53*a0483764SConrad Meyer #define COOLPERIOD_SEC        10
54*a0483764SConrad Meyer 
55*a0483764SConrad Meyer #define KB *(1 <<10)
56*a0483764SConrad Meyer #define MB *(1 <<20)
57*a0483764SConrad Meyer #define GB *(1U<<30)
58*a0483764SConrad Meyer 
59*a0483764SConrad Meyer #define BMK_RUNTEST_DEFAULT_MS 1000
60*a0483764SConrad Meyer 
61*a0483764SConrad Meyer static const size_t maxMemory = (sizeof(size_t)==4)  ?
62*a0483764SConrad Meyer                     /* 32-bit */ (2 GB - 64 MB) :
63*a0483764SConrad Meyer                     /* 64-bit */ (size_t)(1ULL << ((sizeof(size_t)*8)-31));
64*a0483764SConrad Meyer 
65*a0483764SConrad Meyer 
66*a0483764SConrad Meyer /* *************************************
67*a0483764SConrad Meyer *  console display
68*a0483764SConrad Meyer ***************************************/
69*a0483764SConrad Meyer #define DISPLAY(...)         fprintf(stderr, __VA_ARGS__)
70*a0483764SConrad Meyer #define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
71*a0483764SConrad Meyer /* 0 : no display;   1: errors;   2 : + result + interaction + warnings;   3 : + progression;   4 : + information */
72*a0483764SConrad Meyer 
73*a0483764SConrad Meyer static const U64 g_refreshRate = SEC_TO_MICRO / 6;
74*a0483764SConrad Meyer static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
75*a0483764SConrad Meyer 
76*a0483764SConrad Meyer #define DISPLAYUPDATE(l, ...) { if (displayLevel>=l) { \
77*a0483764SConrad Meyer             if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (displayLevel>=4)) \
78*a0483764SConrad Meyer             { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
79*a0483764SConrad Meyer             if (displayLevel>=4) fflush(stderr); } } }
80*a0483764SConrad Meyer 
81*a0483764SConrad Meyer 
82*a0483764SConrad Meyer /* *************************************
83*a0483764SConrad Meyer *  Exceptions
84*a0483764SConrad Meyer ***************************************/
85*a0483764SConrad Meyer #ifndef DEBUG
86*a0483764SConrad Meyer #  define DEBUG 0
87*a0483764SConrad Meyer #endif
88*a0483764SConrad Meyer #define DEBUGOUTPUT(...) { if (DEBUG) DISPLAY(__VA_ARGS__); }
89*a0483764SConrad Meyer 
90*a0483764SConrad Meyer #define EXM_THROW_INT(errorNum, ...)  {               \
91*a0483764SConrad Meyer     DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__);    \
92*a0483764SConrad Meyer     DISPLAYLEVEL(1, "Error %i : ", errorNum);         \
93*a0483764SConrad Meyer     DISPLAYLEVEL(1, __VA_ARGS__);                     \
94*a0483764SConrad Meyer     DISPLAYLEVEL(1, " \n");                           \
95*a0483764SConrad Meyer     return errorNum;                                  \
96*a0483764SConrad Meyer }
97*a0483764SConrad Meyer 
98*a0483764SConrad Meyer #define CHECK_Z(zf) {              \
99*a0483764SConrad Meyer     size_t const zerr = zf;        \
100*a0483764SConrad Meyer     if (ZSTD_isError(zerr)) {      \
101*a0483764SConrad Meyer         DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__);  \
102*a0483764SConrad Meyer         DISPLAY("Error : ");       \
103*a0483764SConrad Meyer         DISPLAY("%s failed : %s",  \
104*a0483764SConrad Meyer                 #zf, ZSTD_getErrorName(zerr));   \
105*a0483764SConrad Meyer         DISPLAY(" \n");            \
106*a0483764SConrad Meyer         exit(1);                   \
107*a0483764SConrad Meyer     }                              \
108*a0483764SConrad Meyer }
109*a0483764SConrad Meyer 
110*a0483764SConrad Meyer #define RETURN_ERROR(errorNum, retType, ...)  {       \
111*a0483764SConrad Meyer     retType r;                                        \
112*a0483764SConrad Meyer     memset(&r, 0, sizeof(retType));                   \
113*a0483764SConrad Meyer     DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__);    \
114*a0483764SConrad Meyer     DISPLAYLEVEL(1, "Error %i : ", errorNum);         \
115*a0483764SConrad Meyer     DISPLAYLEVEL(1, __VA_ARGS__);                     \
116*a0483764SConrad Meyer     DISPLAYLEVEL(1, " \n");                           \
117*a0483764SConrad Meyer     r.tag = errorNum;                                 \
118*a0483764SConrad Meyer     return r;                                         \
119*a0483764SConrad Meyer }
120*a0483764SConrad Meyer 
121*a0483764SConrad Meyer 
122*a0483764SConrad Meyer /* *************************************
123*a0483764SConrad Meyer *  Benchmark Parameters
124*a0483764SConrad Meyer ***************************************/
125*a0483764SConrad Meyer 
126*a0483764SConrad Meyer BMK_advancedParams_t BMK_initAdvancedParams(void) {
127*a0483764SConrad Meyer     BMK_advancedParams_t const res = {
128*a0483764SConrad Meyer         BMK_both, /* mode */
129*a0483764SConrad Meyer         BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
130*a0483764SConrad Meyer         0, /* blockSize */
131*a0483764SConrad Meyer         0, /* nbWorkers */
132*a0483764SConrad Meyer         0, /* realTime */
133*a0483764SConrad Meyer         0, /* additionalParam */
134*a0483764SConrad Meyer         0, /* ldmFlag */
135*a0483764SConrad Meyer         0, /* ldmMinMatch */
136*a0483764SConrad Meyer         0, /* ldmHashLog */
137*a0483764SConrad Meyer         0, /* ldmBuckSizeLog */
138*a0483764SConrad Meyer         0  /* ldmHashRateLog */
139*a0483764SConrad Meyer     };
140*a0483764SConrad Meyer     return res;
141*a0483764SConrad Meyer }
142*a0483764SConrad Meyer 
143*a0483764SConrad Meyer 
144*a0483764SConrad Meyer /* ********************************************************
145*a0483764SConrad Meyer *  Bench functions
146*a0483764SConrad Meyer **********************************************************/
147*a0483764SConrad Meyer typedef struct {
148*a0483764SConrad Meyer     const void* srcPtr;
149*a0483764SConrad Meyer     size_t srcSize;
150*a0483764SConrad Meyer     void*  cPtr;
151*a0483764SConrad Meyer     size_t cRoom;
152*a0483764SConrad Meyer     size_t cSize;
153*a0483764SConrad Meyer     void*  resPtr;
154*a0483764SConrad Meyer     size_t resSize;
155*a0483764SConrad Meyer } blockParam_t;
156*a0483764SConrad Meyer 
157*a0483764SConrad Meyer #undef MIN
158*a0483764SConrad Meyer #undef MAX
159*a0483764SConrad Meyer #define MIN(a,b)    ((a) < (b) ? (a) : (b))
160*a0483764SConrad Meyer #define MAX(a,b)    ((a) > (b) ? (a) : (b))
161*a0483764SConrad Meyer 
162*a0483764SConrad Meyer static void BMK_initCCtx(ZSTD_CCtx* ctx,
163*a0483764SConrad Meyer     const void* dictBuffer, size_t dictBufferSize, int cLevel,
164*a0483764SConrad Meyer     const ZSTD_compressionParameters* comprParams, const BMK_advancedParams_t* adv) {
165*a0483764SConrad Meyer     ZSTD_CCtx_reset(ctx, ZSTD_reset_session_and_parameters);
166*a0483764SConrad Meyer     if (adv->nbWorkers==1) {
167*a0483764SConrad Meyer         CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, 0));
168*a0483764SConrad Meyer     } else {
169*a0483764SConrad Meyer         CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, adv->nbWorkers));
170*a0483764SConrad Meyer     }
171*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, cLevel));
172*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_enableLongDistanceMatching, adv->ldmFlag));
173*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmMinMatch, adv->ldmMinMatch));
174*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashLog, adv->ldmHashLog));
175*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmBucketSizeLog, adv->ldmBucketSizeLog));
176*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog));
177*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_windowLog, comprParams->windowLog));
178*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_hashLog, comprParams->hashLog));
179*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_chainLog, comprParams->chainLog));
180*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_searchLog, comprParams->searchLog));
181*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_minMatch, comprParams->minMatch));
182*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_targetLength, comprParams->targetLength));
183*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_strategy, comprParams->strategy));
184*a0483764SConrad Meyer     CHECK_Z(ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize));
185*a0483764SConrad Meyer }
186*a0483764SConrad Meyer 
187*a0483764SConrad Meyer static void BMK_initDCtx(ZSTD_DCtx* dctx,
188*a0483764SConrad Meyer     const void* dictBuffer, size_t dictBufferSize) {
189*a0483764SConrad Meyer     CHECK_Z(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
190*a0483764SConrad Meyer     CHECK_Z(ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize));
191*a0483764SConrad Meyer }
192*a0483764SConrad Meyer 
193*a0483764SConrad Meyer 
194*a0483764SConrad Meyer typedef struct {
195*a0483764SConrad Meyer     ZSTD_CCtx* cctx;
196*a0483764SConrad Meyer     const void* dictBuffer;
197*a0483764SConrad Meyer     size_t dictBufferSize;
198*a0483764SConrad Meyer     int cLevel;
199*a0483764SConrad Meyer     const ZSTD_compressionParameters* comprParams;
200*a0483764SConrad Meyer     const BMK_advancedParams_t* adv;
201*a0483764SConrad Meyer } BMK_initCCtxArgs;
202*a0483764SConrad Meyer 
203*a0483764SConrad Meyer static size_t local_initCCtx(void* payload) {
204*a0483764SConrad Meyer     BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)payload;
205*a0483764SConrad Meyer     BMK_initCCtx(ag->cctx, ag->dictBuffer, ag->dictBufferSize, ag->cLevel, ag->comprParams, ag->adv);
206*a0483764SConrad Meyer     return 0;
207*a0483764SConrad Meyer }
208*a0483764SConrad Meyer 
209*a0483764SConrad Meyer typedef struct {
210*a0483764SConrad Meyer     ZSTD_DCtx* dctx;
211*a0483764SConrad Meyer     const void* dictBuffer;
212*a0483764SConrad Meyer     size_t dictBufferSize;
213*a0483764SConrad Meyer } BMK_initDCtxArgs;
214*a0483764SConrad Meyer 
215*a0483764SConrad Meyer static size_t local_initDCtx(void* payload) {
216*a0483764SConrad Meyer     BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload;
217*a0483764SConrad Meyer     BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize);
218*a0483764SConrad Meyer     return 0;
219*a0483764SConrad Meyer }
220*a0483764SConrad Meyer 
221*a0483764SConrad Meyer 
222*a0483764SConrad Meyer /* `addArgs` is the context */
223*a0483764SConrad Meyer static size_t local_defaultCompress(
224*a0483764SConrad Meyer                     const void* srcBuffer, size_t srcSize,
225*a0483764SConrad Meyer                     void* dstBuffer, size_t dstSize,
226*a0483764SConrad Meyer                     void* addArgs)
227*a0483764SConrad Meyer {
228*a0483764SConrad Meyer     ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
229*a0483764SConrad Meyer     return ZSTD_compress2(cctx, dstBuffer, dstSize, srcBuffer, srcSize);
230*a0483764SConrad Meyer }
231*a0483764SConrad Meyer 
232*a0483764SConrad Meyer /* `addArgs` is the context */
233*a0483764SConrad Meyer static size_t local_defaultDecompress(
234*a0483764SConrad Meyer                     const void* srcBuffer, size_t srcSize,
235*a0483764SConrad Meyer                     void* dstBuffer, size_t dstCapacity,
236*a0483764SConrad Meyer                     void* addArgs)
237*a0483764SConrad Meyer {
238*a0483764SConrad Meyer     size_t moreToFlush = 1;
239*a0483764SConrad Meyer     ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs;
240*a0483764SConrad Meyer     ZSTD_inBuffer in;
241*a0483764SConrad Meyer     ZSTD_outBuffer out;
242*a0483764SConrad Meyer     in.src = srcBuffer; in.size = srcSize; in.pos = 0;
243*a0483764SConrad Meyer     out.dst = dstBuffer; out.size = dstCapacity; out.pos = 0;
244*a0483764SConrad Meyer     while (moreToFlush) {
245*a0483764SConrad Meyer         if(out.pos == out.size) {
246*a0483764SConrad Meyer             return (size_t)-ZSTD_error_dstSize_tooSmall;
247*a0483764SConrad Meyer         }
248*a0483764SConrad Meyer         moreToFlush = ZSTD_decompressStream(dctx, &out, &in);
249*a0483764SConrad Meyer         if (ZSTD_isError(moreToFlush)) {
250*a0483764SConrad Meyer             return moreToFlush;
251*a0483764SConrad Meyer         }
252*a0483764SConrad Meyer     }
253*a0483764SConrad Meyer     return out.pos;
254*a0483764SConrad Meyer 
255*a0483764SConrad Meyer }
256*a0483764SConrad Meyer 
257*a0483764SConrad Meyer 
258*a0483764SConrad Meyer /* ================================================================= */
259*a0483764SConrad Meyer /*      Benchmark Zstandard, mem-to-mem scenarios                    */
260*a0483764SConrad Meyer /* ================================================================= */
261*a0483764SConrad Meyer 
262*a0483764SConrad Meyer int BMK_isSuccessful_benchOutcome(BMK_benchOutcome_t outcome)
263*a0483764SConrad Meyer {
264*a0483764SConrad Meyer     return outcome.tag == 0;
265*a0483764SConrad Meyer }
266*a0483764SConrad Meyer 
267*a0483764SConrad Meyer BMK_benchResult_t BMK_extract_benchResult(BMK_benchOutcome_t outcome)
268*a0483764SConrad Meyer {
269*a0483764SConrad Meyer     assert(outcome.tag == 0);
270*a0483764SConrad Meyer     return outcome.internal_never_use_directly;
271*a0483764SConrad Meyer }
272*a0483764SConrad Meyer 
273*a0483764SConrad Meyer static BMK_benchOutcome_t BMK_benchOutcome_error(void)
274*a0483764SConrad Meyer {
275*a0483764SConrad Meyer     BMK_benchOutcome_t b;
276*a0483764SConrad Meyer     memset(&b, 0, sizeof(b));
277*a0483764SConrad Meyer     b.tag = 1;
278*a0483764SConrad Meyer     return b;
279*a0483764SConrad Meyer }
280*a0483764SConrad Meyer 
281*a0483764SConrad Meyer static BMK_benchOutcome_t BMK_benchOutcome_setValidResult(BMK_benchResult_t result)
282*a0483764SConrad Meyer {
283*a0483764SConrad Meyer     BMK_benchOutcome_t b;
284*a0483764SConrad Meyer     b.tag = 0;
285*a0483764SConrad Meyer     b.internal_never_use_directly = result;
286*a0483764SConrad Meyer     return b;
287*a0483764SConrad Meyer }
288*a0483764SConrad Meyer 
289*a0483764SConrad Meyer 
290*a0483764SConrad Meyer /* benchMem with no allocation */
291*a0483764SConrad Meyer static BMK_benchOutcome_t
292*a0483764SConrad Meyer BMK_benchMemAdvancedNoAlloc(
293*a0483764SConrad Meyer                     const void** srcPtrs, size_t* srcSizes,
294*a0483764SConrad Meyer                     void** cPtrs, size_t* cCapacities, size_t* cSizes,
295*a0483764SConrad Meyer                     void** resPtrs, size_t* resSizes,
296*a0483764SConrad Meyer                     void** resultBufferPtr, void* compressedBuffer,
297*a0483764SConrad Meyer                     size_t maxCompressedSize,
298*a0483764SConrad Meyer                     BMK_timedFnState_t* timeStateCompress,
299*a0483764SConrad Meyer                     BMK_timedFnState_t* timeStateDecompress,
300*a0483764SConrad Meyer 
301*a0483764SConrad Meyer                     const void* srcBuffer, size_t srcSize,
302*a0483764SConrad Meyer                     const size_t* fileSizes, unsigned nbFiles,
303*a0483764SConrad Meyer                     const int cLevel,
304*a0483764SConrad Meyer                     const ZSTD_compressionParameters* comprParams,
305*a0483764SConrad Meyer                     const void* dictBuffer, size_t dictBufferSize,
306*a0483764SConrad Meyer                     ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
307*a0483764SConrad Meyer                     int displayLevel, const char* displayName,
308*a0483764SConrad Meyer                     const BMK_advancedParams_t* adv)
309*a0483764SConrad Meyer {
310*a0483764SConrad Meyer     size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize);  /* avoid div by 0 */
311*a0483764SConrad Meyer     BMK_benchResult_t benchResult;
312*a0483764SConrad Meyer     size_t const loadedCompressedSize = srcSize;
313*a0483764SConrad Meyer     size_t cSize = 0;
314*a0483764SConrad Meyer     double ratio = 0.;
315*a0483764SConrad Meyer     U32 nbBlocks;
316*a0483764SConrad Meyer 
317*a0483764SConrad Meyer     assert(cctx != NULL); assert(dctx != NULL);
318*a0483764SConrad Meyer 
319*a0483764SConrad Meyer     /* init */
320*a0483764SConrad Meyer     memset(&benchResult, 0, sizeof(benchResult));
321*a0483764SConrad Meyer     if (strlen(displayName)>17) displayName += strlen(displayName) - 17;   /* display last 17 characters */
322*a0483764SConrad Meyer     if (adv->mode == BMK_decodeOnly) {  /* benchmark only decompression : source must be already compressed */
323*a0483764SConrad Meyer         const char* srcPtr = (const char*)srcBuffer;
324*a0483764SConrad Meyer         U64 totalDSize64 = 0;
325*a0483764SConrad Meyer         U32 fileNb;
326*a0483764SConrad Meyer         for (fileNb=0; fileNb<nbFiles; fileNb++) {
327*a0483764SConrad Meyer             U64 const fSize64 = ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
328*a0483764SConrad Meyer             if (fSize64==0) RETURN_ERROR(32, BMK_benchOutcome_t, "Impossible to determine original size ");
329*a0483764SConrad Meyer             totalDSize64 += fSize64;
330*a0483764SConrad Meyer             srcPtr += fileSizes[fileNb];
331*a0483764SConrad Meyer         }
332*a0483764SConrad Meyer         {   size_t const decodedSize = (size_t)totalDSize64;
333*a0483764SConrad Meyer             assert((U64)decodedSize == totalDSize64);   /* check overflow */
334*a0483764SConrad Meyer             free(*resultBufferPtr);
335*a0483764SConrad Meyer             *resultBufferPtr = malloc(decodedSize);
336*a0483764SConrad Meyer             if (!(*resultBufferPtr)) {
337*a0483764SConrad Meyer                 RETURN_ERROR(33, BMK_benchOutcome_t, "not enough memory");
338*a0483764SConrad Meyer             }
339*a0483764SConrad Meyer             if (totalDSize64 > decodedSize) {  /* size_t overflow */
340*a0483764SConrad Meyer                 free(*resultBufferPtr);
341*a0483764SConrad Meyer                 RETURN_ERROR(32, BMK_benchOutcome_t, "original size is too large");
342*a0483764SConrad Meyer             }
343*a0483764SConrad Meyer             cSize = srcSize;
344*a0483764SConrad Meyer             srcSize = decodedSize;
345*a0483764SConrad Meyer             ratio = (double)srcSize / (double)cSize;
346*a0483764SConrad Meyer         }
347*a0483764SConrad Meyer     }
348*a0483764SConrad Meyer 
349*a0483764SConrad Meyer     /* Init data blocks  */
350*a0483764SConrad Meyer     {   const char* srcPtr = (const char*)srcBuffer;
351*a0483764SConrad Meyer         char* cPtr = (char*)compressedBuffer;
352*a0483764SConrad Meyer         char* resPtr = (char*)(*resultBufferPtr);
353*a0483764SConrad Meyer         U32 fileNb;
354*a0483764SConrad Meyer         for (nbBlocks=0, fileNb=0; fileNb<nbFiles; fileNb++) {
355*a0483764SConrad Meyer             size_t remaining = fileSizes[fileNb];
356*a0483764SConrad Meyer             U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly) ? 1 : (U32)((remaining + (blockSize-1)) / blockSize);
357*a0483764SConrad Meyer             U32 const blockEnd = nbBlocks + nbBlocksforThisFile;
358*a0483764SConrad Meyer             for ( ; nbBlocks<blockEnd; nbBlocks++) {
359*a0483764SConrad Meyer                 size_t const thisBlockSize = MIN(remaining, blockSize);
360*a0483764SConrad Meyer                 srcPtrs[nbBlocks] = srcPtr;
361*a0483764SConrad Meyer                 srcSizes[nbBlocks] = thisBlockSize;
362*a0483764SConrad Meyer                 cPtrs[nbBlocks] = cPtr;
363*a0483764SConrad Meyer                 cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly) ? thisBlockSize : ZSTD_compressBound(thisBlockSize);
364*a0483764SConrad Meyer                 resPtrs[nbBlocks] = resPtr;
365*a0483764SConrad Meyer                 resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly) ? (size_t) ZSTD_findDecompressedSize(srcPtr, thisBlockSize) : thisBlockSize;
366*a0483764SConrad Meyer                 srcPtr += thisBlockSize;
367*a0483764SConrad Meyer                 cPtr += cCapacities[nbBlocks];
368*a0483764SConrad Meyer                 resPtr += thisBlockSize;
369*a0483764SConrad Meyer                 remaining -= thisBlockSize;
370*a0483764SConrad Meyer                 if (adv->mode == BMK_decodeOnly) {
371*a0483764SConrad Meyer                     assert(nbBlocks==0);
372*a0483764SConrad Meyer                     cSizes[nbBlocks] = thisBlockSize;
373*a0483764SConrad Meyer                     benchResult.cSize = thisBlockSize;
374*a0483764SConrad Meyer                 }
375*a0483764SConrad Meyer             }
376*a0483764SConrad Meyer         }
377*a0483764SConrad Meyer     }
378*a0483764SConrad Meyer 
379*a0483764SConrad Meyer     /* warmimg up `compressedBuffer` */
380*a0483764SConrad Meyer     if (adv->mode == BMK_decodeOnly) {
381*a0483764SConrad Meyer         memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
382*a0483764SConrad Meyer     } else {
383*a0483764SConrad Meyer         RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
384*a0483764SConrad Meyer     }
385*a0483764SConrad Meyer 
386*a0483764SConrad Meyer     /* Bench */
387*a0483764SConrad Meyer     {   U64 const crcOrig = (adv->mode == BMK_decodeOnly) ? 0 : XXH64(srcBuffer, srcSize, 0);
388*a0483764SConrad Meyer #       define NB_MARKS 4
389*a0483764SConrad Meyer         const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
390*a0483764SConrad Meyer         U32 markNb = 0;
391*a0483764SConrad Meyer         int compressionCompleted = (adv->mode == BMK_decodeOnly);
392*a0483764SConrad Meyer         int decompressionCompleted = (adv->mode == BMK_compressOnly);
393*a0483764SConrad Meyer         BMK_benchParams_t cbp, dbp;
394*a0483764SConrad Meyer         BMK_initCCtxArgs cctxprep;
395*a0483764SConrad Meyer         BMK_initDCtxArgs dctxprep;
396*a0483764SConrad Meyer 
397*a0483764SConrad Meyer         cbp.benchFn = local_defaultCompress;
398*a0483764SConrad Meyer         cbp.benchPayload = cctx;
399*a0483764SConrad Meyer         cbp.initFn = local_initCCtx;
400*a0483764SConrad Meyer         cbp.initPayload = &cctxprep;
401*a0483764SConrad Meyer         cbp.errorFn = ZSTD_isError;
402*a0483764SConrad Meyer         cbp.blockCount = nbBlocks;
403*a0483764SConrad Meyer         cbp.srcBuffers = srcPtrs;
404*a0483764SConrad Meyer         cbp.srcSizes = srcSizes;
405*a0483764SConrad Meyer         cbp.dstBuffers = cPtrs;
406*a0483764SConrad Meyer         cbp.dstCapacities = cCapacities;
407*a0483764SConrad Meyer         cbp.blockResults = cSizes;
408*a0483764SConrad Meyer 
409*a0483764SConrad Meyer         cctxprep.cctx = cctx;
410*a0483764SConrad Meyer         cctxprep.dictBuffer = dictBuffer;
411*a0483764SConrad Meyer         cctxprep.dictBufferSize = dictBufferSize;
412*a0483764SConrad Meyer         cctxprep.cLevel = cLevel;
413*a0483764SConrad Meyer         cctxprep.comprParams = comprParams;
414*a0483764SConrad Meyer         cctxprep.adv = adv;
415*a0483764SConrad Meyer 
416*a0483764SConrad Meyer         dbp.benchFn = local_defaultDecompress;
417*a0483764SConrad Meyer         dbp.benchPayload = dctx;
418*a0483764SConrad Meyer         dbp.initFn = local_initDCtx;
419*a0483764SConrad Meyer         dbp.initPayload = &dctxprep;
420*a0483764SConrad Meyer         dbp.errorFn = ZSTD_isError;
421*a0483764SConrad Meyer         dbp.blockCount = nbBlocks;
422*a0483764SConrad Meyer         dbp.srcBuffers = (const void* const *) cPtrs;
423*a0483764SConrad Meyer         dbp.srcSizes = cSizes;
424*a0483764SConrad Meyer         dbp.dstBuffers = resPtrs;
425*a0483764SConrad Meyer         dbp.dstCapacities = resSizes;
426*a0483764SConrad Meyer         dbp.blockResults = NULL;
427*a0483764SConrad Meyer 
428*a0483764SConrad Meyer         dctxprep.dctx = dctx;
429*a0483764SConrad Meyer         dctxprep.dictBuffer = dictBuffer;
430*a0483764SConrad Meyer         dctxprep.dictBufferSize = dictBufferSize;
431*a0483764SConrad Meyer 
432*a0483764SConrad Meyer         DISPLAYLEVEL(2, "\r%70s\r", "");   /* blank line */
433*a0483764SConrad Meyer         DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->\r", marks[markNb], displayName, (unsigned)srcSize);
434*a0483764SConrad Meyer 
435*a0483764SConrad Meyer         while (!(compressionCompleted && decompressionCompleted)) {
436*a0483764SConrad Meyer             if (!compressionCompleted) {
437*a0483764SConrad Meyer                 BMK_runOutcome_t const cOutcome = BMK_benchTimedFn( timeStateCompress, cbp);
438*a0483764SConrad Meyer 
439*a0483764SConrad Meyer                 if (!BMK_isSuccessful_runOutcome(cOutcome)) {
440*a0483764SConrad Meyer                     return BMK_benchOutcome_error();
441*a0483764SConrad Meyer                 }
442*a0483764SConrad Meyer 
443*a0483764SConrad Meyer                 {   BMK_runTime_t const cResult = BMK_extract_runTime(cOutcome);
444*a0483764SConrad Meyer                     cSize = cResult.sumOfReturn;
445*a0483764SConrad Meyer                     ratio = (double)srcSize / cSize;
446*a0483764SConrad Meyer                     {   BMK_benchResult_t newResult;
447*a0483764SConrad Meyer                         newResult.cSpeed = ((U64)srcSize * TIMELOOP_NANOSEC / cResult.nanoSecPerRun);
448*a0483764SConrad Meyer                         benchResult.cSize = cSize;
449*a0483764SConrad Meyer                         if (newResult.cSpeed > benchResult.cSpeed)
450*a0483764SConrad Meyer                             benchResult.cSpeed = newResult.cSpeed;
451*a0483764SConrad Meyer                 }   }
452*a0483764SConrad Meyer 
453*a0483764SConrad Meyer                 {   int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
454*a0483764SConrad Meyer                     DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
455*a0483764SConrad Meyer                             marks[markNb], displayName,
456*a0483764SConrad Meyer                             (unsigned)srcSize, (unsigned)cSize,
457*a0483764SConrad Meyer                             ratioAccuracy, ratio,
458*a0483764SConrad Meyer                             benchResult.cSpeed < (10 MB) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT);
459*a0483764SConrad Meyer                 }
460*a0483764SConrad Meyer                 compressionCompleted = BMK_isCompleted_TimedFn(timeStateCompress);
461*a0483764SConrad Meyer             }
462*a0483764SConrad Meyer 
463*a0483764SConrad Meyer             if(!decompressionCompleted) {
464*a0483764SConrad Meyer                 BMK_runOutcome_t const dOutcome = BMK_benchTimedFn(timeStateDecompress, dbp);
465*a0483764SConrad Meyer 
466*a0483764SConrad Meyer                 if(!BMK_isSuccessful_runOutcome(dOutcome)) {
467*a0483764SConrad Meyer                     return BMK_benchOutcome_error();
468*a0483764SConrad Meyer                 }
469*a0483764SConrad Meyer 
470*a0483764SConrad Meyer                 {   BMK_runTime_t const dResult = BMK_extract_runTime(dOutcome);
471*a0483764SConrad Meyer                     U64 const newDSpeed = (srcSize * TIMELOOP_NANOSEC / dResult.nanoSecPerRun);
472*a0483764SConrad Meyer                     if (newDSpeed > benchResult.dSpeed)
473*a0483764SConrad Meyer                         benchResult.dSpeed = newDSpeed;
474*a0483764SConrad Meyer                 }
475*a0483764SConrad Meyer 
476*a0483764SConrad Meyer                 {   int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
477*a0483764SConrad Meyer                     DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
478*a0483764SConrad Meyer                             marks[markNb], displayName,
479*a0483764SConrad Meyer                             (unsigned)srcSize, (unsigned)benchResult.cSize,
480*a0483764SConrad Meyer                             ratioAccuracy, ratio,
481*a0483764SConrad Meyer                             benchResult.cSpeed < (10 MB) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT,
482*a0483764SConrad Meyer                             (double)benchResult.dSpeed / MB_UNIT);
483*a0483764SConrad Meyer                 }
484*a0483764SConrad Meyer                 decompressionCompleted = BMK_isCompleted_TimedFn(timeStateDecompress);
485*a0483764SConrad Meyer             }
486*a0483764SConrad Meyer             markNb = (markNb+1) % NB_MARKS;
487*a0483764SConrad Meyer         }   /* while (!(compressionCompleted && decompressionCompleted)) */
488*a0483764SConrad Meyer 
489*a0483764SConrad Meyer         /* CRC Checking */
490*a0483764SConrad Meyer         {   const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
491*a0483764SConrad Meyer             U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
492*a0483764SConrad Meyer             if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) {
493*a0483764SConrad Meyer                 size_t u;
494*a0483764SConrad Meyer                 DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x   \n",
495*a0483764SConrad Meyer                         displayName, (unsigned)crcOrig, (unsigned)crcCheck);
496*a0483764SConrad Meyer                 for (u=0; u<srcSize; u++) {
497*a0483764SConrad Meyer                     if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) {
498*a0483764SConrad Meyer                         unsigned segNb, bNb, pos;
499*a0483764SConrad Meyer                         size_t bacc = 0;
500*a0483764SConrad Meyer                         DISPLAY("Decoding error at pos %u ", (unsigned)u);
501*a0483764SConrad Meyer                         for (segNb = 0; segNb < nbBlocks; segNb++) {
502*a0483764SConrad Meyer                             if (bacc + srcSizes[segNb] > u) break;
503*a0483764SConrad Meyer                             bacc += srcSizes[segNb];
504*a0483764SConrad Meyer                         }
505*a0483764SConrad Meyer                         pos = (U32)(u - bacc);
506*a0483764SConrad Meyer                         bNb = pos / (128 KB);
507*a0483764SConrad Meyer                         DISPLAY("(sample %u, block %u, pos %u) \n", segNb, bNb, pos);
508*a0483764SConrad Meyer                         if (u>5) {
509*a0483764SConrad Meyer                             int n;
510*a0483764SConrad Meyer                             DISPLAY("origin: ");
511*a0483764SConrad Meyer                             for (n=-5; n<0; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
512*a0483764SConrad Meyer                             DISPLAY(" :%02X:  ", ((const BYTE*)srcBuffer)[u]);
513*a0483764SConrad Meyer                             for (n=1; n<3; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
514*a0483764SConrad Meyer                             DISPLAY(" \n");
515*a0483764SConrad Meyer                             DISPLAY("decode: ");
516*a0483764SConrad Meyer                             for (n=-5; n<0; n++) DISPLAY("%02X ", resultBuffer[u+n]);
517*a0483764SConrad Meyer                             DISPLAY(" :%02X:  ", resultBuffer[u]);
518*a0483764SConrad Meyer                             for (n=1; n<3; n++) DISPLAY("%02X ", resultBuffer[u+n]);
519*a0483764SConrad Meyer                             DISPLAY(" \n");
520*a0483764SConrad Meyer                         }
521*a0483764SConrad Meyer                         break;
522*a0483764SConrad Meyer                     }
523*a0483764SConrad Meyer                     if (u==srcSize-1) {  /* should never happen */
524*a0483764SConrad Meyer                         DISPLAY("no difference detected\n");
525*a0483764SConrad Meyer                     }
526*a0483764SConrad Meyer                 }
527*a0483764SConrad Meyer             }
528*a0483764SConrad Meyer         }   /* CRC Checking */
529*a0483764SConrad Meyer 
530*a0483764SConrad Meyer         if (displayLevel == 1) {   /* hidden display mode -q, used by python speed benchmark */
531*a0483764SConrad Meyer             double const cSpeed = (double)benchResult.cSpeed / MB_UNIT;
532*a0483764SConrad Meyer             double const dSpeed = (double)benchResult.dSpeed / MB_UNIT;
533*a0483764SConrad Meyer             if (adv->additionalParam) {
534*a0483764SConrad Meyer                 DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s  %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, adv->additionalParam);
535*a0483764SConrad Meyer             } else {
536*a0483764SConrad Meyer                 DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s  %s\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName);
537*a0483764SConrad Meyer             }
538*a0483764SConrad Meyer         }
539*a0483764SConrad Meyer 
540*a0483764SConrad Meyer         DISPLAYLEVEL(2, "%2i#\n", cLevel);
541*a0483764SConrad Meyer     }   /* Bench */
542*a0483764SConrad Meyer 
543*a0483764SConrad Meyer     benchResult.cMem = (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
544*a0483764SConrad Meyer     return BMK_benchOutcome_setValidResult(benchResult);
545*a0483764SConrad Meyer }
546*a0483764SConrad Meyer 
547*a0483764SConrad Meyer BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
548*a0483764SConrad Meyer                         void* dstBuffer, size_t dstCapacity,
549*a0483764SConrad Meyer                         const size_t* fileSizes, unsigned nbFiles,
550*a0483764SConrad Meyer                         int cLevel, const ZSTD_compressionParameters* comprParams,
551*a0483764SConrad Meyer                         const void* dictBuffer, size_t dictBufferSize,
552*a0483764SConrad Meyer                         int displayLevel, const char* displayName, const BMK_advancedParams_t* adv)
553*a0483764SConrad Meyer 
554*a0483764SConrad Meyer {
555*a0483764SConrad Meyer     int const dstParamsError = !dstBuffer ^ !dstCapacity;  /* must be both NULL or none */
556*a0483764SConrad Meyer 
557*a0483764SConrad Meyer     size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ;
558*a0483764SConrad Meyer     U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles;
559*a0483764SConrad Meyer 
560*a0483764SConrad Meyer     /* these are the blockTable parameters, just split up */
561*a0483764SConrad Meyer     const void ** const srcPtrs = (const void**)malloc(maxNbBlocks * sizeof(void*));
562*a0483764SConrad Meyer     size_t* const srcSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
563*a0483764SConrad Meyer 
564*a0483764SConrad Meyer 
565*a0483764SConrad Meyer     void ** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
566*a0483764SConrad Meyer     size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
567*a0483764SConrad Meyer     size_t* const cCapacities = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
568*a0483764SConrad Meyer 
569*a0483764SConrad Meyer     void ** const resPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
570*a0483764SConrad Meyer     size_t* const resSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
571*a0483764SConrad Meyer 
572*a0483764SConrad Meyer     BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
573*a0483764SConrad Meyer     BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
574*a0483764SConrad Meyer 
575*a0483764SConrad Meyer     ZSTD_CCtx* const cctx = ZSTD_createCCtx();
576*a0483764SConrad Meyer     ZSTD_DCtx* const dctx = ZSTD_createDCtx();
577*a0483764SConrad Meyer 
578*a0483764SConrad Meyer     const size_t maxCompressedSize = dstCapacity ? dstCapacity : ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024);
579*a0483764SConrad Meyer 
580*a0483764SConrad Meyer     void* const internalDstBuffer = dstBuffer ? NULL : malloc(maxCompressedSize);
581*a0483764SConrad Meyer     void* const compressedBuffer = dstBuffer ? dstBuffer : internalDstBuffer;
582*a0483764SConrad Meyer 
583*a0483764SConrad Meyer     BMK_benchOutcome_t outcome = BMK_benchOutcome_error();  /* error by default */
584*a0483764SConrad Meyer 
585*a0483764SConrad Meyer     void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
586*a0483764SConrad Meyer 
587*a0483764SConrad Meyer     int allocationincomplete = !srcPtrs || !srcSizes || !cPtrs ||
588*a0483764SConrad Meyer         !cSizes || !cCapacities || !resPtrs || !resSizes ||
589*a0483764SConrad Meyer         !timeStateCompress || !timeStateDecompress ||
590*a0483764SConrad Meyer         !cctx || !dctx ||
591*a0483764SConrad Meyer         !compressedBuffer || !resultBuffer;
592*a0483764SConrad Meyer 
593*a0483764SConrad Meyer 
594*a0483764SConrad Meyer     if (!allocationincomplete && !dstParamsError) {
595*a0483764SConrad Meyer         outcome = BMK_benchMemAdvancedNoAlloc(srcPtrs, srcSizes,
596*a0483764SConrad Meyer                                             cPtrs, cCapacities, cSizes,
597*a0483764SConrad Meyer                                             resPtrs, resSizes,
598*a0483764SConrad Meyer                                             &resultBuffer,
599*a0483764SConrad Meyer                                             compressedBuffer, maxCompressedSize,
600*a0483764SConrad Meyer                                             timeStateCompress, timeStateDecompress,
601*a0483764SConrad Meyer                                             srcBuffer, srcSize,
602*a0483764SConrad Meyer                                             fileSizes, nbFiles,
603*a0483764SConrad Meyer                                             cLevel, comprParams,
604*a0483764SConrad Meyer                                             dictBuffer, dictBufferSize,
605*a0483764SConrad Meyer                                             cctx, dctx,
606*a0483764SConrad Meyer                                             displayLevel, displayName, adv);
607*a0483764SConrad Meyer     }
608*a0483764SConrad Meyer 
609*a0483764SConrad Meyer     /* clean up */
610*a0483764SConrad Meyer     BMK_freeTimedFnState(timeStateCompress);
611*a0483764SConrad Meyer     BMK_freeTimedFnState(timeStateDecompress);
612*a0483764SConrad Meyer 
613*a0483764SConrad Meyer     ZSTD_freeCCtx(cctx);
614*a0483764SConrad Meyer     ZSTD_freeDCtx(dctx);
615*a0483764SConrad Meyer 
616*a0483764SConrad Meyer     free(internalDstBuffer);
617*a0483764SConrad Meyer     free(resultBuffer);
618*a0483764SConrad Meyer 
619*a0483764SConrad Meyer     free((void*)srcPtrs);
620*a0483764SConrad Meyer     free(srcSizes);
621*a0483764SConrad Meyer     free(cPtrs);
622*a0483764SConrad Meyer     free(cSizes);
623*a0483764SConrad Meyer     free(cCapacities);
624*a0483764SConrad Meyer     free(resPtrs);
625*a0483764SConrad Meyer     free(resSizes);
626*a0483764SConrad Meyer 
627*a0483764SConrad Meyer     if(allocationincomplete) {
628*a0483764SConrad Meyer         RETURN_ERROR(31, BMK_benchOutcome_t, "allocation error : not enough memory");
629*a0483764SConrad Meyer     }
630*a0483764SConrad Meyer 
631*a0483764SConrad Meyer     if(dstParamsError) {
632*a0483764SConrad Meyer         RETURN_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
633*a0483764SConrad Meyer     }
634*a0483764SConrad Meyer     return outcome;
635*a0483764SConrad Meyer }
636*a0483764SConrad Meyer 
637*a0483764SConrad Meyer BMK_benchOutcome_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
638*a0483764SConrad Meyer                         const size_t* fileSizes, unsigned nbFiles,
639*a0483764SConrad Meyer                         int cLevel, const ZSTD_compressionParameters* comprParams,
640*a0483764SConrad Meyer                         const void* dictBuffer, size_t dictBufferSize,
641*a0483764SConrad Meyer                         int displayLevel, const char* displayName) {
642*a0483764SConrad Meyer 
643*a0483764SConrad Meyer     BMK_advancedParams_t const adv = BMK_initAdvancedParams();
644*a0483764SConrad Meyer     return BMK_benchMemAdvanced(srcBuffer, srcSize,
645*a0483764SConrad Meyer                                 NULL, 0,
646*a0483764SConrad Meyer                                 fileSizes, nbFiles,
647*a0483764SConrad Meyer                                 cLevel, comprParams,
648*a0483764SConrad Meyer                                 dictBuffer, dictBufferSize,
649*a0483764SConrad Meyer                                 displayLevel, displayName, &adv);
650*a0483764SConrad Meyer }
651*a0483764SConrad Meyer 
652*a0483764SConrad Meyer static BMK_benchOutcome_t BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
653*a0483764SConrad Meyer                             const size_t* fileSizes, unsigned nbFiles,
654*a0483764SConrad Meyer                             int cLevel, const ZSTD_compressionParameters* comprParams,
655*a0483764SConrad Meyer                             const void* dictBuffer, size_t dictBufferSize,
656*a0483764SConrad Meyer                             int displayLevel, const char* displayName,
657*a0483764SConrad Meyer                             BMK_advancedParams_t const * const adv)
658*a0483764SConrad Meyer {
659*a0483764SConrad Meyer     const char* pch = strrchr(displayName, '\\'); /* Windows */
660*a0483764SConrad Meyer     if (!pch) pch = strrchr(displayName, '/');    /* Linux */
661*a0483764SConrad Meyer     if (pch) displayName = pch+1;
662*a0483764SConrad Meyer 
663*a0483764SConrad Meyer     if (adv->realTime) {
664*a0483764SConrad Meyer         DISPLAYLEVEL(2, "Note : switching to real-time priority \n");
665*a0483764SConrad Meyer         SET_REALTIME_PRIORITY;
666*a0483764SConrad Meyer     }
667*a0483764SConrad Meyer 
668*a0483764SConrad Meyer     if (displayLevel == 1 && !adv->additionalParam)   /* --quiet mode */
669*a0483764SConrad Meyer         DISPLAY("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",
670*a0483764SConrad Meyer                 ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING,
671*a0483764SConrad Meyer                 (unsigned)benchedSize, adv->nbSeconds, (unsigned)(adv->blockSize>>10));
672*a0483764SConrad Meyer 
673*a0483764SConrad Meyer     return BMK_benchMemAdvanced(srcBuffer, benchedSize,
674*a0483764SConrad Meyer                                 NULL, 0,
675*a0483764SConrad Meyer                                 fileSizes, nbFiles,
676*a0483764SConrad Meyer                                 cLevel, comprParams,
677*a0483764SConrad Meyer                                 dictBuffer, dictBufferSize,
678*a0483764SConrad Meyer                                 displayLevel, displayName, adv);
679*a0483764SConrad Meyer }
680*a0483764SConrad Meyer 
681*a0483764SConrad Meyer BMK_benchOutcome_t BMK_syntheticTest(int cLevel, double compressibility,
682*a0483764SConrad Meyer                           const ZSTD_compressionParameters* compressionParams,
683*a0483764SConrad Meyer                           int displayLevel, const BMK_advancedParams_t* adv)
684*a0483764SConrad Meyer {
685*a0483764SConrad Meyer     char name[20] = {0};
686*a0483764SConrad Meyer     size_t const benchedSize = 10000000;
687*a0483764SConrad Meyer     void* srcBuffer;
688*a0483764SConrad Meyer     BMK_benchOutcome_t res;
689*a0483764SConrad Meyer 
690*a0483764SConrad Meyer     if (cLevel > ZSTD_maxCLevel()) {
691*a0483764SConrad Meyer         RETURN_ERROR(15, BMK_benchOutcome_t, "Invalid Compression Level");
692*a0483764SConrad Meyer     }
693*a0483764SConrad Meyer 
694*a0483764SConrad Meyer     /* Memory allocation */
695*a0483764SConrad Meyer     srcBuffer = malloc(benchedSize);
696*a0483764SConrad Meyer     if (!srcBuffer) RETURN_ERROR(21, BMK_benchOutcome_t, "not enough memory");
697*a0483764SConrad Meyer 
698*a0483764SConrad Meyer     /* Fill input buffer */
699*a0483764SConrad Meyer     RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
700*a0483764SConrad Meyer 
701*a0483764SConrad Meyer     /* Bench */
702*a0483764SConrad Meyer     snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));
703*a0483764SConrad Meyer     res = BMK_benchCLevel(srcBuffer, benchedSize,
704*a0483764SConrad Meyer                     &benchedSize /* ? */, 1 /* ? */,
705*a0483764SConrad Meyer                     cLevel, compressionParams,
706*a0483764SConrad Meyer                     NULL, 0,  /* dictionary */
707*a0483764SConrad Meyer                     displayLevel, name, adv);
708*a0483764SConrad Meyer 
709*a0483764SConrad Meyer     /* clean up */
710*a0483764SConrad Meyer     free(srcBuffer);
711*a0483764SConrad Meyer 
712*a0483764SConrad Meyer     return res;
713*a0483764SConrad Meyer }
714*a0483764SConrad Meyer 
715*a0483764SConrad Meyer 
716*a0483764SConrad Meyer 
717*a0483764SConrad Meyer static size_t BMK_findMaxMem(U64 requiredMem)
718*a0483764SConrad Meyer {
719*a0483764SConrad Meyer     size_t const step = 64 MB;
720*a0483764SConrad Meyer     BYTE* testmem = NULL;
721*a0483764SConrad Meyer 
722*a0483764SConrad Meyer     requiredMem = (((requiredMem >> 26) + 1) << 26);
723*a0483764SConrad Meyer     requiredMem += step;
724*a0483764SConrad Meyer     if (requiredMem > maxMemory) requiredMem = maxMemory;
725*a0483764SConrad Meyer 
726*a0483764SConrad Meyer     do {
727*a0483764SConrad Meyer         testmem = (BYTE*)malloc((size_t)requiredMem);
728*a0483764SConrad Meyer         requiredMem -= step;
729*a0483764SConrad Meyer     } while (!testmem && requiredMem > 0);
730*a0483764SConrad Meyer 
731*a0483764SConrad Meyer     free(testmem);
732*a0483764SConrad Meyer     return (size_t)(requiredMem);
733*a0483764SConrad Meyer }
734*a0483764SConrad Meyer 
735*a0483764SConrad Meyer /*! BMK_loadFiles() :
736*a0483764SConrad Meyer  *  Loads `buffer` with content of files listed within `fileNamesTable`.
737*a0483764SConrad Meyer  *  At most, fills `buffer` entirely. */
738*a0483764SConrad Meyer static int BMK_loadFiles(void* buffer, size_t bufferSize,
739*a0483764SConrad Meyer                          size_t* fileSizes,
740*a0483764SConrad Meyer                          const char* const * fileNamesTable, unsigned nbFiles,
741*a0483764SConrad Meyer                          int displayLevel)
742*a0483764SConrad Meyer {
743*a0483764SConrad Meyer     size_t pos = 0, totalSize = 0;
744*a0483764SConrad Meyer     unsigned n;
745*a0483764SConrad Meyer     for (n=0; n<nbFiles; n++) {
746*a0483764SConrad Meyer         FILE* f;
747*a0483764SConrad Meyer         U64 fileSize = UTIL_getFileSize(fileNamesTable[n]);
748*a0483764SConrad Meyer         if (UTIL_isDirectory(fileNamesTable[n])) {
749*a0483764SConrad Meyer             DISPLAYLEVEL(2, "Ignoring %s directory...       \n", fileNamesTable[n]);
750*a0483764SConrad Meyer             fileSizes[n] = 0;
751*a0483764SConrad Meyer             continue;
752*a0483764SConrad Meyer         }
753*a0483764SConrad Meyer         if (fileSize == UTIL_FILESIZE_UNKNOWN) {
754*a0483764SConrad Meyer             DISPLAYLEVEL(2, "Cannot evaluate size of %s, ignoring ... \n", fileNamesTable[n]);
755*a0483764SConrad Meyer             fileSizes[n] = 0;
756*a0483764SConrad Meyer             continue;
757*a0483764SConrad Meyer         }
758*a0483764SConrad Meyer         f = fopen(fileNamesTable[n], "rb");
759*a0483764SConrad Meyer         if (f==NULL) EXM_THROW_INT(10, "impossible to open file %s", fileNamesTable[n]);
760*a0483764SConrad Meyer         DISPLAYUPDATE(2, "Loading %s...       \r", fileNamesTable[n]);
761*a0483764SConrad Meyer         if (fileSize > bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n;   /* buffer too small - stop after this file */
762*a0483764SConrad Meyer         {   size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f);
763*a0483764SConrad Meyer             if (readSize != (size_t)fileSize) EXM_THROW_INT(11, "could not read %s", fileNamesTable[n]);
764*a0483764SConrad Meyer             pos += readSize;
765*a0483764SConrad Meyer         }
766*a0483764SConrad Meyer         fileSizes[n] = (size_t)fileSize;
767*a0483764SConrad Meyer         totalSize += (size_t)fileSize;
768*a0483764SConrad Meyer         fclose(f);
769*a0483764SConrad Meyer     }
770*a0483764SConrad Meyer 
771*a0483764SConrad Meyer     if (totalSize == 0) EXM_THROW_INT(12, "no data to bench");
772*a0483764SConrad Meyer     return 0;
773*a0483764SConrad Meyer }
774*a0483764SConrad Meyer 
775*a0483764SConrad Meyer BMK_benchOutcome_t BMK_benchFilesAdvanced(
776*a0483764SConrad Meyer                         const char* const * fileNamesTable, unsigned nbFiles,
777*a0483764SConrad Meyer                         const char* dictFileName, int cLevel,
778*a0483764SConrad Meyer                         const ZSTD_compressionParameters* compressionParams,
779*a0483764SConrad Meyer                         int displayLevel, const BMK_advancedParams_t* adv)
780*a0483764SConrad Meyer {
781*a0483764SConrad Meyer     void* srcBuffer = NULL;
782*a0483764SConrad Meyer     size_t benchedSize;
783*a0483764SConrad Meyer     void* dictBuffer = NULL;
784*a0483764SConrad Meyer     size_t dictBufferSize = 0;
785*a0483764SConrad Meyer     size_t* fileSizes = NULL;
786*a0483764SConrad Meyer     BMK_benchOutcome_t res;
787*a0483764SConrad Meyer     U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
788*a0483764SConrad Meyer 
789*a0483764SConrad Meyer     if (!nbFiles) {
790*a0483764SConrad Meyer         RETURN_ERROR(14, BMK_benchOutcome_t, "No Files to Benchmark");
791*a0483764SConrad Meyer     }
792*a0483764SConrad Meyer 
793*a0483764SConrad Meyer     if (cLevel > ZSTD_maxCLevel()) {
794*a0483764SConrad Meyer         RETURN_ERROR(15, BMK_benchOutcome_t, "Invalid Compression Level");
795*a0483764SConrad Meyer     }
796*a0483764SConrad Meyer 
797*a0483764SConrad Meyer     fileSizes = (size_t*)calloc(nbFiles, sizeof(size_t));
798*a0483764SConrad Meyer     if (!fileSizes) RETURN_ERROR(12, BMK_benchOutcome_t, "not enough memory for fileSizes");
799*a0483764SConrad Meyer 
800*a0483764SConrad Meyer     /* Load dictionary */
801*a0483764SConrad Meyer     if (dictFileName != NULL) {
802*a0483764SConrad Meyer         U64 const dictFileSize = UTIL_getFileSize(dictFileName);
803*a0483764SConrad Meyer         if (dictFileSize == UTIL_FILESIZE_UNKNOWN) {
804*a0483764SConrad Meyer             DISPLAYLEVEL(1, "error loading %s : %s \n", dictFileName, strerror(errno));
805*a0483764SConrad Meyer             free(fileSizes);
806*a0483764SConrad Meyer             RETURN_ERROR(9, BMK_benchOutcome_t, "benchmark aborted");
807*a0483764SConrad Meyer         }
808*a0483764SConrad Meyer         if (dictFileSize > 64 MB) {
809*a0483764SConrad Meyer             free(fileSizes);
810*a0483764SConrad Meyer             RETURN_ERROR(10, BMK_benchOutcome_t, "dictionary file %s too large", dictFileName);
811*a0483764SConrad Meyer         }
812*a0483764SConrad Meyer         dictBufferSize = (size_t)dictFileSize;
813*a0483764SConrad Meyer         dictBuffer = malloc(dictBufferSize);
814*a0483764SConrad Meyer         if (dictBuffer==NULL) {
815*a0483764SConrad Meyer             free(fileSizes);
816*a0483764SConrad Meyer             RETURN_ERROR(11, BMK_benchOutcome_t, "not enough memory for dictionary (%u bytes)",
817*a0483764SConrad Meyer                             (unsigned)dictBufferSize);
818*a0483764SConrad Meyer         }
819*a0483764SConrad Meyer 
820*a0483764SConrad Meyer         {   int const errorCode = BMK_loadFiles(dictBuffer, dictBufferSize,
821*a0483764SConrad Meyer                                                 fileSizes, &dictFileName /*?*/,
822*a0483764SConrad Meyer                                                 1 /*?*/, displayLevel);
823*a0483764SConrad Meyer             if (errorCode) {
824*a0483764SConrad Meyer                 res = BMK_benchOutcome_error();
825*a0483764SConrad Meyer                 goto _cleanUp;
826*a0483764SConrad Meyer         }   }
827*a0483764SConrad Meyer     }
828*a0483764SConrad Meyer 
829*a0483764SConrad Meyer     /* Memory allocation & restrictions */
830*a0483764SConrad Meyer     benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3;
831*a0483764SConrad Meyer     if ((U64)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad;
832*a0483764SConrad Meyer     if (benchedSize < totalSizeToLoad)
833*a0483764SConrad Meyer         DISPLAY("Not enough memory; testing %u MB only...\n", (unsigned)(benchedSize >> 20));
834*a0483764SConrad Meyer 
835*a0483764SConrad Meyer     srcBuffer = benchedSize ? malloc(benchedSize) : NULL;
836*a0483764SConrad Meyer     if (!srcBuffer) {
837*a0483764SConrad Meyer         free(dictBuffer);
838*a0483764SConrad Meyer         free(fileSizes);
839*a0483764SConrad Meyer         RETURN_ERROR(12, BMK_benchOutcome_t, "not enough memory");
840*a0483764SConrad Meyer     }
841*a0483764SConrad Meyer 
842*a0483764SConrad Meyer     /* Load input buffer */
843*a0483764SConrad Meyer     {   int const errorCode = BMK_loadFiles(srcBuffer, benchedSize,
844*a0483764SConrad Meyer                                         fileSizes, fileNamesTable, nbFiles,
845*a0483764SConrad Meyer                                         displayLevel);
846*a0483764SConrad Meyer         if (errorCode) {
847*a0483764SConrad Meyer             res = BMK_benchOutcome_error();
848*a0483764SConrad Meyer             goto _cleanUp;
849*a0483764SConrad Meyer     }   }
850*a0483764SConrad Meyer 
851*a0483764SConrad Meyer     /* Bench */
852*a0483764SConrad Meyer     {   char mfName[20] = {0};
853*a0483764SConrad Meyer         snprintf (mfName, sizeof(mfName), " %u files", nbFiles);
854*a0483764SConrad Meyer         {   const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
855*a0483764SConrad Meyer             res = BMK_benchCLevel(srcBuffer, benchedSize,
856*a0483764SConrad Meyer                                 fileSizes, nbFiles,
857*a0483764SConrad Meyer                                 cLevel, compressionParams,
858*a0483764SConrad Meyer                                 dictBuffer, dictBufferSize,
859*a0483764SConrad Meyer                                 displayLevel, displayName,
860*a0483764SConrad Meyer                                 adv);
861*a0483764SConrad Meyer     }   }
862*a0483764SConrad Meyer 
863*a0483764SConrad Meyer _cleanUp:
864*a0483764SConrad Meyer     free(srcBuffer);
865*a0483764SConrad Meyer     free(dictBuffer);
866*a0483764SConrad Meyer     free(fileSizes);
867*a0483764SConrad Meyer     return res;
868*a0483764SConrad Meyer }
869*a0483764SConrad Meyer 
870*a0483764SConrad Meyer 
871*a0483764SConrad Meyer BMK_benchOutcome_t BMK_benchFiles(
872*a0483764SConrad Meyer                     const char* const * fileNamesTable, unsigned nbFiles,
873*a0483764SConrad Meyer                     const char* dictFileName,
874*a0483764SConrad Meyer                     int cLevel, const ZSTD_compressionParameters* compressionParams,
875*a0483764SConrad Meyer                     int displayLevel)
876*a0483764SConrad Meyer {
877*a0483764SConrad Meyer     BMK_advancedParams_t const adv = BMK_initAdvancedParams();
878*a0483764SConrad Meyer     return BMK_benchFilesAdvanced(fileNamesTable, nbFiles, dictFileName, cLevel, compressionParams, displayLevel, &adv);
879*a0483764SConrad Meyer }
880