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