xref: /netbsd-src/external/bsd/zstd/dist/programs/benchzstd.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
1*3117ece4Schristos /*
2*3117ece4Schristos  * Copyright (c) Meta Platforms, Inc. and affiliates.
3*3117ece4Schristos  * All rights reserved.
4*3117ece4Schristos  *
5*3117ece4Schristos  * This source code is licensed under both the BSD-style license (found in the
6*3117ece4Schristos  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*3117ece4Schristos  * in the COPYING file in the root directory of this source tree).
8*3117ece4Schristos  * You may select, at your option, one of the above-listed licenses.
9*3117ece4Schristos  */
10*3117ece4Schristos 
11*3117ece4Schristos /* **************************************
12*3117ece4Schristos  *  Tuning parameters
13*3117ece4Schristos  ****************************************/
14*3117ece4Schristos #ifndef BMK_TIMETEST_DEFAULT_S /* default minimum time per test */
15*3117ece4Schristos #    define BMK_TIMETEST_DEFAULT_S 3
16*3117ece4Schristos #endif
17*3117ece4Schristos 
18*3117ece4Schristos /* *************************************
19*3117ece4Schristos  *  Includes
20*3117ece4Schristos  ***************************************/
21*3117ece4Schristos /* this must be included first */
22*3117ece4Schristos #include "platform.h" /* Large Files support, compiler specifics */
23*3117ece4Schristos 
24*3117ece4Schristos /* then following system includes */
25*3117ece4Schristos #include <assert.h> /* assert */
26*3117ece4Schristos #include <errno.h>
27*3117ece4Schristos #include <stdio.h>    /* fprintf, fopen */
28*3117ece4Schristos #include <stdlib.h>   /* malloc, free */
29*3117ece4Schristos #include <string.h>   /* memset, strerror */
30*3117ece4Schristos #include "util.h"     /* UTIL_getFileSize, UTIL_sleep */
31*3117ece4Schristos #include "../lib/common/mem.h"
32*3117ece4Schristos #include "benchfn.h"
33*3117ece4Schristos #include "timefn.h" /* UTIL_time_t */
34*3117ece4Schristos #ifndef ZSTD_STATIC_LINKING_ONLY
35*3117ece4Schristos #    define ZSTD_STATIC_LINKING_ONLY
36*3117ece4Schristos #endif
37*3117ece4Schristos #include "../lib/zstd.h"
38*3117ece4Schristos #include "datagen.h" /* RDG_genBuffer */
39*3117ece4Schristos #include "lorem.h"   /* LOREM_genBuffer */
40*3117ece4Schristos #ifndef XXH_INLINE_ALL
41*3117ece4Schristos #    define XXH_INLINE_ALL
42*3117ece4Schristos #endif
43*3117ece4Schristos #include "../lib/common/xxhash.h"
44*3117ece4Schristos #include "../lib/zstd_errors.h"
45*3117ece4Schristos #include "benchzstd.h"
46*3117ece4Schristos 
47*3117ece4Schristos /* *************************************
48*3117ece4Schristos  *  Constants
49*3117ece4Schristos  ***************************************/
50*3117ece4Schristos #ifndef ZSTD_GIT_COMMIT
51*3117ece4Schristos #    define ZSTD_GIT_COMMIT_STRING ""
52*3117ece4Schristos #else
53*3117ece4Schristos #    define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
54*3117ece4Schristos #endif
55*3117ece4Schristos 
56*3117ece4Schristos #define TIMELOOP_MICROSEC (1 * 1000000ULL)             /* 1 second */
57*3117ece4Schristos #define TIMELOOP_NANOSEC (1 * 1000000000ULL)           /* 1 second */
58*3117ece4Schristos #define ACTIVEPERIOD_MICROSEC (70 * TIMELOOP_MICROSEC) /* 70 seconds */
59*3117ece4Schristos #define COOLPERIOD_SEC 10
60*3117ece4Schristos 
61*3117ece4Schristos #define KB *(1 << 10)
62*3117ece4Schristos #define MB *(1 << 20)
63*3117ece4Schristos #define GB *(1U << 30)
64*3117ece4Schristos 
65*3117ece4Schristos #define BMK_RUNTEST_DEFAULT_MS 1000
66*3117ece4Schristos 
67*3117ece4Schristos static const size_t maxMemory = (sizeof(size_t) == 4)
68*3117ece4Schristos         ?
69*3117ece4Schristos         /* 32-bit */ (2 GB - 64 MB)
70*3117ece4Schristos         :
71*3117ece4Schristos         /* 64-bit */ (size_t)(1ULL << ((sizeof(size_t) * 8) - 31));
72*3117ece4Schristos 
73*3117ece4Schristos /* *************************************
74*3117ece4Schristos  *  console display
75*3117ece4Schristos  ***************************************/
76*3117ece4Schristos #define DISPLAY(...)                  \
77*3117ece4Schristos     {                                 \
78*3117ece4Schristos         fprintf(stderr, __VA_ARGS__); \
79*3117ece4Schristos         fflush(NULL);                 \
80*3117ece4Schristos     }
81*3117ece4Schristos #define DISPLAYLEVEL(l, ...)  \
82*3117ece4Schristos     if (displayLevel >= l) {  \
83*3117ece4Schristos         DISPLAY(__VA_ARGS__); \
84*3117ece4Schristos     }
85*3117ece4Schristos /* 0 : no display;   1: errors;   2 : + result + interaction + warnings;   3 : +
86*3117ece4Schristos  * progression;   4 : + information */
87*3117ece4Schristos #define OUTPUT(...)                   \
88*3117ece4Schristos     {                                 \
89*3117ece4Schristos         fprintf(stdout, __VA_ARGS__); \
90*3117ece4Schristos         fflush(NULL);                 \
91*3117ece4Schristos     }
92*3117ece4Schristos #define OUTPUTLEVEL(l, ...)  \
93*3117ece4Schristos     if (displayLevel >= l) { \
94*3117ece4Schristos         OUTPUT(__VA_ARGS__); \
95*3117ece4Schristos     }
96*3117ece4Schristos 
97*3117ece4Schristos /* *************************************
98*3117ece4Schristos  *  Exceptions
99*3117ece4Schristos  ***************************************/
100*3117ece4Schristos #ifndef DEBUG
101*3117ece4Schristos #    define DEBUG 0
102*3117ece4Schristos #endif
103*3117ece4Schristos #define DEBUGOUTPUT(...)          \
104*3117ece4Schristos     {                             \
105*3117ece4Schristos         if (DEBUG)                \
106*3117ece4Schristos             DISPLAY(__VA_ARGS__); \
107*3117ece4Schristos     }
108*3117ece4Schristos 
109*3117ece4Schristos #define RETURN_ERROR_INT(errorNum, ...)                \
110*3117ece4Schristos     {                                                  \
111*3117ece4Schristos         DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
112*3117ece4Schristos         DISPLAYLEVEL(1, "Error %i : ", errorNum);      \
113*3117ece4Schristos         DISPLAYLEVEL(1, __VA_ARGS__);                  \
114*3117ece4Schristos         DISPLAYLEVEL(1, " \n");                        \
115*3117ece4Schristos         return errorNum;                               \
116*3117ece4Schristos     }
117*3117ece4Schristos 
118*3117ece4Schristos #define CHECK_Z(zf)                                                  \
119*3117ece4Schristos     {                                                                \
120*3117ece4Schristos         size_t const zerr = zf;                                      \
121*3117ece4Schristos         if (ZSTD_isError(zerr)) {                                    \
122*3117ece4Schristos             DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__);           \
123*3117ece4Schristos             DISPLAY("Error : ");                                     \
124*3117ece4Schristos             DISPLAY("%s failed : %s", #zf, ZSTD_getErrorName(zerr)); \
125*3117ece4Schristos             DISPLAY(" \n");                                          \
126*3117ece4Schristos             exit(1);                                                 \
127*3117ece4Schristos         }                                                            \
128*3117ece4Schristos     }
129*3117ece4Schristos 
130*3117ece4Schristos #define RETURN_ERROR(errorNum, retType, ...)           \
131*3117ece4Schristos     {                                                  \
132*3117ece4Schristos         retType r;                                     \
133*3117ece4Schristos         memset(&r, 0, sizeof(retType));                \
134*3117ece4Schristos         DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
135*3117ece4Schristos         DISPLAYLEVEL(1, "Error %i : ", errorNum);      \
136*3117ece4Schristos         DISPLAYLEVEL(1, __VA_ARGS__);                  \
137*3117ece4Schristos         DISPLAYLEVEL(1, " \n");                        \
138*3117ece4Schristos         r.tag = errorNum;                              \
139*3117ece4Schristos         return r;                                      \
140*3117ece4Schristos     }
141*3117ece4Schristos 
142*3117ece4Schristos /* replacement for snprintf(), which is not supported by C89
143*3117ece4Schristos  * sprintf() would be the supported one, but it's labelled unsafe,
144*3117ece4Schristos  * so some modern static analyzer will flag it as such, making it unusable.
145*3117ece4Schristos  * formatString_u() replaces snprintf() for the specific case where there are only %u arguments */
146*3117ece4Schristos static int formatString_u(char* buffer, size_t buffer_size, const char* formatString, unsigned int value)
147*3117ece4Schristos {
148*3117ece4Schristos     size_t written = 0;
149*3117ece4Schristos     int i;
150*3117ece4Schristos     assert(value <= 100);
151*3117ece4Schristos 
152*3117ece4Schristos     for (i = 0; formatString[i] != '\0' && written < buffer_size - 1; ++i) {
153*3117ece4Schristos         if (formatString[i] != '%') {
154*3117ece4Schristos             buffer[written++] = formatString[i];
155*3117ece4Schristos             continue;
156*3117ece4Schristos         }
157*3117ece4Schristos 
158*3117ece4Schristos         if (formatString[++i] == 'u') {
159*3117ece4Schristos             /* Handle single digit */
160*3117ece4Schristos             if (value < 10) {
161*3117ece4Schristos                 buffer[written++] = '0' + (char)value;
162*3117ece4Schristos             } else if (value < 100) {
163*3117ece4Schristos                 /* Handle two digits */
164*3117ece4Schristos                 if (written >= buffer_size - 2) {
165*3117ece4Schristos                     return -1; /* buffer overflow */
166*3117ece4Schristos                 }
167*3117ece4Schristos                 buffer[written++] = '0' + (char)(value / 10);
168*3117ece4Schristos                 buffer[written++] = '0' + (char)(value % 10);
169*3117ece4Schristos             } else { /* 100 */
170*3117ece4Schristos                 if (written >= buffer_size - 3) {
171*3117ece4Schristos                     return -1; /* buffer overflow */
172*3117ece4Schristos                 }
173*3117ece4Schristos                 buffer[written++] = '1';
174*3117ece4Schristos                 buffer[written++] = '0';
175*3117ece4Schristos                 buffer[written++] = '0';
176*3117ece4Schristos             }
177*3117ece4Schristos         } else if (formatString[i] == '%') { /* Check for escaped percent sign */
178*3117ece4Schristos             buffer[written++] = '%';
179*3117ece4Schristos         } else {
180*3117ece4Schristos             return -1; /* unsupported format */
181*3117ece4Schristos         }
182*3117ece4Schristos     }
183*3117ece4Schristos 
184*3117ece4Schristos     if (written < buffer_size) {
185*3117ece4Schristos         buffer[written] = '\0';
186*3117ece4Schristos     } else {
187*3117ece4Schristos         buffer[0] = '\0'; /* Handle truncation */
188*3117ece4Schristos     }
189*3117ece4Schristos 
190*3117ece4Schristos     return (int)written;
191*3117ece4Schristos }
192*3117ece4Schristos 
193*3117ece4Schristos /* *************************************
194*3117ece4Schristos  *  Benchmark Parameters
195*3117ece4Schristos  ***************************************/
196*3117ece4Schristos 
197*3117ece4Schristos BMK_advancedParams_t BMK_initAdvancedParams(void)
198*3117ece4Schristos {
199*3117ece4Schristos     BMK_advancedParams_t const res = {
200*3117ece4Schristos         BMK_both,               /* mode */
201*3117ece4Schristos         BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
202*3117ece4Schristos         0,                      /* blockSize */
203*3117ece4Schristos         0,               /* targetCBlockSize */
204*3117ece4Schristos         0,                      /* nbWorkers */
205*3117ece4Schristos         0,                      /* realTime */
206*3117ece4Schristos         0,                      /* additionalParam */
207*3117ece4Schristos         0,                      /* ldmFlag */
208*3117ece4Schristos         0,                      /* ldmMinMatch */
209*3117ece4Schristos         0,                      /* ldmHashLog */
210*3117ece4Schristos         0,                      /* ldmBuckSizeLog */
211*3117ece4Schristos         0,                      /* ldmHashRateLog */
212*3117ece4Schristos         ZSTD_ps_auto,           /* literalCompressionMode */
213*3117ece4Schristos         0                       /* useRowMatchFinder */
214*3117ece4Schristos     };
215*3117ece4Schristos     return res;
216*3117ece4Schristos }
217*3117ece4Schristos 
218*3117ece4Schristos /* ********************************************************
219*3117ece4Schristos  *  Bench functions
220*3117ece4Schristos  **********************************************************/
221*3117ece4Schristos typedef struct {
222*3117ece4Schristos     const void* srcPtr;
223*3117ece4Schristos     size_t srcSize;
224*3117ece4Schristos     void* cPtr;
225*3117ece4Schristos     size_t cRoom;
226*3117ece4Schristos     size_t cSize;
227*3117ece4Schristos     void* resPtr;
228*3117ece4Schristos     size_t resSize;
229*3117ece4Schristos } blockParam_t;
230*3117ece4Schristos 
231*3117ece4Schristos #undef MIN
232*3117ece4Schristos #undef MAX
233*3117ece4Schristos #define MIN(a, b) ((a) < (b) ? (a) : (b))
234*3117ece4Schristos #define MAX(a, b) ((a) > (b) ? (a) : (b))
235*3117ece4Schristos 
236*3117ece4Schristos static void BMK_initCCtx(
237*3117ece4Schristos         ZSTD_CCtx* ctx,
238*3117ece4Schristos         const void* dictBuffer,
239*3117ece4Schristos         size_t dictBufferSize,
240*3117ece4Schristos         int cLevel,
241*3117ece4Schristos         const ZSTD_compressionParameters* comprParams,
242*3117ece4Schristos         const BMK_advancedParams_t* adv)
243*3117ece4Schristos {
244*3117ece4Schristos     ZSTD_CCtx_reset(ctx, ZSTD_reset_session_and_parameters);
245*3117ece4Schristos     if (adv->nbWorkers == 1) {
246*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, 0));
247*3117ece4Schristos     } else {
248*3117ece4Schristos         CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, adv->nbWorkers));
249*3117ece4Schristos     }
250*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, cLevel));
251*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
252*3117ece4Schristos             ctx, ZSTD_c_useRowMatchFinder, adv->useRowMatchFinder));
253*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
254*3117ece4Schristos             ctx, ZSTD_c_enableLongDistanceMatching, adv->ldmFlag));
255*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmMinMatch, adv->ldmMinMatch));
256*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashLog, adv->ldmHashLog));
257*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
258*3117ece4Schristos             ctx, ZSTD_c_ldmBucketSizeLog, adv->ldmBucketSizeLog));
259*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
260*3117ece4Schristos             ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog));
261*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
262*3117ece4Schristos             ctx, ZSTD_c_windowLog, (int)comprParams->windowLog));
263*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
264*3117ece4Schristos             ctx, ZSTD_c_hashLog, (int)comprParams->hashLog));
265*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
266*3117ece4Schristos             ctx, ZSTD_c_chainLog, (int)comprParams->chainLog));
267*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
268*3117ece4Schristos             ctx, ZSTD_c_searchLog, (int)comprParams->searchLog));
269*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
270*3117ece4Schristos             ctx, ZSTD_c_minMatch, (int)comprParams->minMatch));
271*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
272*3117ece4Schristos             ctx, ZSTD_c_targetLength, (int)comprParams->targetLength));
273*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
274*3117ece4Schristos             ctx,
275*3117ece4Schristos             ZSTD_c_literalCompressionMode,
276*3117ece4Schristos             (int)adv->literalCompressionMode));
277*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
278*3117ece4Schristos             ctx, ZSTD_c_strategy, (int)comprParams->strategy));
279*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_setParameter(
280*3117ece4Schristos             ctx, ZSTD_c_targetCBlockSize, (int)adv->targetCBlockSize));
281*3117ece4Schristos     CHECK_Z(ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize));
282*3117ece4Schristos }
283*3117ece4Schristos 
284*3117ece4Schristos static void
285*3117ece4Schristos BMK_initDCtx(ZSTD_DCtx* dctx, const void* dictBuffer, size_t dictBufferSize)
286*3117ece4Schristos {
287*3117ece4Schristos     CHECK_Z(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
288*3117ece4Schristos     CHECK_Z(ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize));
289*3117ece4Schristos }
290*3117ece4Schristos 
291*3117ece4Schristos typedef struct {
292*3117ece4Schristos     ZSTD_CCtx* cctx;
293*3117ece4Schristos     const void* dictBuffer;
294*3117ece4Schristos     size_t dictBufferSize;
295*3117ece4Schristos     int cLevel;
296*3117ece4Schristos     const ZSTD_compressionParameters* comprParams;
297*3117ece4Schristos     const BMK_advancedParams_t* adv;
298*3117ece4Schristos } BMK_initCCtxArgs;
299*3117ece4Schristos 
300*3117ece4Schristos static size_t local_initCCtx(void* payload)
301*3117ece4Schristos {
302*3117ece4Schristos     BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)payload;
303*3117ece4Schristos     BMK_initCCtx(
304*3117ece4Schristos             ag->cctx,
305*3117ece4Schristos             ag->dictBuffer,
306*3117ece4Schristos             ag->dictBufferSize,
307*3117ece4Schristos             ag->cLevel,
308*3117ece4Schristos             ag->comprParams,
309*3117ece4Schristos             ag->adv);
310*3117ece4Schristos     return 0;
311*3117ece4Schristos }
312*3117ece4Schristos 
313*3117ece4Schristos typedef struct {
314*3117ece4Schristos     ZSTD_DCtx* dctx;
315*3117ece4Schristos     const void* dictBuffer;
316*3117ece4Schristos     size_t dictBufferSize;
317*3117ece4Schristos } BMK_initDCtxArgs;
318*3117ece4Schristos 
319*3117ece4Schristos static size_t local_initDCtx(void* payload)
320*3117ece4Schristos {
321*3117ece4Schristos     BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload;
322*3117ece4Schristos     BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize);
323*3117ece4Schristos     return 0;
324*3117ece4Schristos }
325*3117ece4Schristos 
326*3117ece4Schristos /* `addArgs` is the context */
327*3117ece4Schristos static size_t local_defaultCompress(
328*3117ece4Schristos         const void* srcBuffer,
329*3117ece4Schristos         size_t srcSize,
330*3117ece4Schristos         void* dstBuffer,
331*3117ece4Schristos         size_t dstSize,
332*3117ece4Schristos         void* addArgs)
333*3117ece4Schristos {
334*3117ece4Schristos     ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
335*3117ece4Schristos     return ZSTD_compress2(cctx, dstBuffer, dstSize, srcBuffer, srcSize);
336*3117ece4Schristos }
337*3117ece4Schristos 
338*3117ece4Schristos /* `addArgs` is the context */
339*3117ece4Schristos static size_t local_defaultDecompress(
340*3117ece4Schristos         const void* srcBuffer,
341*3117ece4Schristos         size_t srcSize,
342*3117ece4Schristos         void* dstBuffer,
343*3117ece4Schristos         size_t dstCapacity,
344*3117ece4Schristos         void* addArgs)
345*3117ece4Schristos {
346*3117ece4Schristos     size_t moreToFlush    = 1;
347*3117ece4Schristos     ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs;
348*3117ece4Schristos     ZSTD_inBuffer in;
349*3117ece4Schristos     ZSTD_outBuffer out;
350*3117ece4Schristos     in.src   = srcBuffer;
351*3117ece4Schristos     in.size  = srcSize;
352*3117ece4Schristos     in.pos   = 0;
353*3117ece4Schristos     out.dst  = dstBuffer;
354*3117ece4Schristos     out.size = dstCapacity;
355*3117ece4Schristos     out.pos  = 0;
356*3117ece4Schristos     while (moreToFlush) {
357*3117ece4Schristos         if (out.pos == out.size) {
358*3117ece4Schristos             return (size_t)-ZSTD_error_dstSize_tooSmall;
359*3117ece4Schristos         }
360*3117ece4Schristos         moreToFlush = ZSTD_decompressStream(dctx, &out, &in);
361*3117ece4Schristos         if (ZSTD_isError(moreToFlush)) {
362*3117ece4Schristos             return moreToFlush;
363*3117ece4Schristos         }
364*3117ece4Schristos     }
365*3117ece4Schristos     return out.pos;
366*3117ece4Schristos }
367*3117ece4Schristos 
368*3117ece4Schristos /* ================================================================= */
369*3117ece4Schristos /*      Benchmark Zstandard, mem-to-mem scenarios                    */
370*3117ece4Schristos /* ================================================================= */
371*3117ece4Schristos 
372*3117ece4Schristos int BMK_isSuccessful_benchOutcome(BMK_benchOutcome_t outcome)
373*3117ece4Schristos {
374*3117ece4Schristos     return outcome.tag == 0;
375*3117ece4Schristos }
376*3117ece4Schristos 
377*3117ece4Schristos BMK_benchResult_t BMK_extract_benchResult(BMK_benchOutcome_t outcome)
378*3117ece4Schristos {
379*3117ece4Schristos     assert(outcome.tag == 0);
380*3117ece4Schristos     return outcome.internal_never_use_directly;
381*3117ece4Schristos }
382*3117ece4Schristos 
383*3117ece4Schristos static BMK_benchOutcome_t BMK_benchOutcome_error(void)
384*3117ece4Schristos {
385*3117ece4Schristos     BMK_benchOutcome_t b;
386*3117ece4Schristos     memset(&b, 0, sizeof(b));
387*3117ece4Schristos     b.tag = 1;
388*3117ece4Schristos     return b;
389*3117ece4Schristos }
390*3117ece4Schristos 
391*3117ece4Schristos static BMK_benchOutcome_t BMK_benchOutcome_setValidResult(
392*3117ece4Schristos         BMK_benchResult_t result)
393*3117ece4Schristos {
394*3117ece4Schristos     BMK_benchOutcome_t b;
395*3117ece4Schristos     b.tag                         = 0;
396*3117ece4Schristos     b.internal_never_use_directly = result;
397*3117ece4Schristos     return b;
398*3117ece4Schristos }
399*3117ece4Schristos 
400*3117ece4Schristos /* benchMem with no allocation */
401*3117ece4Schristos static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc(
402*3117ece4Schristos         const void** srcPtrs,
403*3117ece4Schristos         size_t* srcSizes,
404*3117ece4Schristos         void** cPtrs,
405*3117ece4Schristos         size_t* cCapacities,
406*3117ece4Schristos         size_t* cSizes,
407*3117ece4Schristos         void** resPtrs,
408*3117ece4Schristos         size_t* resSizes,
409*3117ece4Schristos         void** resultBufferPtr,
410*3117ece4Schristos         void* compressedBuffer,
411*3117ece4Schristos         size_t maxCompressedSize,
412*3117ece4Schristos         BMK_timedFnState_t* timeStateCompress,
413*3117ece4Schristos         BMK_timedFnState_t* timeStateDecompress,
414*3117ece4Schristos 
415*3117ece4Schristos         const void* srcBuffer,
416*3117ece4Schristos         size_t srcSize,
417*3117ece4Schristos         const size_t* fileSizes,
418*3117ece4Schristos         unsigned nbFiles,
419*3117ece4Schristos         const int cLevel,
420*3117ece4Schristos         const ZSTD_compressionParameters* comprParams,
421*3117ece4Schristos         const void* dictBuffer,
422*3117ece4Schristos         size_t dictBufferSize,
423*3117ece4Schristos         ZSTD_CCtx* cctx,
424*3117ece4Schristos         ZSTD_DCtx* dctx,
425*3117ece4Schristos         int displayLevel,
426*3117ece4Schristos         const char* displayName,
427*3117ece4Schristos         const BMK_advancedParams_t* adv)
428*3117ece4Schristos {
429*3117ece4Schristos     size_t const blockSize =
430*3117ece4Schristos             ((adv->blockSize >= 32 && (adv->mode != BMK_decodeOnly))
431*3117ece4Schristos                      ? adv->blockSize
432*3117ece4Schristos                      : srcSize)
433*3117ece4Schristos             + (!srcSize); /* avoid div by 0 */
434*3117ece4Schristos     BMK_benchResult_t benchResult;
435*3117ece4Schristos     size_t const loadedCompressedSize = srcSize;
436*3117ece4Schristos     size_t cSize                      = 0;
437*3117ece4Schristos     double ratio                      = 0.;
438*3117ece4Schristos     U32 nbBlocks;
439*3117ece4Schristos 
440*3117ece4Schristos     assert(cctx != NULL);
441*3117ece4Schristos     assert(dctx != NULL);
442*3117ece4Schristos 
443*3117ece4Schristos     /* init */
444*3117ece4Schristos     memset(&benchResult, 0, sizeof(benchResult));
445*3117ece4Schristos     if (strlen(displayName) > 17)
446*3117ece4Schristos         displayName +=
447*3117ece4Schristos                 strlen(displayName) - 17; /* display last 17 characters */
448*3117ece4Schristos     if (adv->mode == BMK_decodeOnly) {
449*3117ece4Schristos         /* benchmark only decompression : source must be already compressed */
450*3117ece4Schristos         const char* srcPtr = (const char*)srcBuffer;
451*3117ece4Schristos         U64 totalDSize64   = 0;
452*3117ece4Schristos         U32 fileNb;
453*3117ece4Schristos         for (fileNb = 0; fileNb < nbFiles; fileNb++) {
454*3117ece4Schristos             U64 const fSize64 =
455*3117ece4Schristos                     ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
456*3117ece4Schristos             if (fSize64 == ZSTD_CONTENTSIZE_UNKNOWN) {
457*3117ece4Schristos                 RETURN_ERROR(
458*3117ece4Schristos                         32,
459*3117ece4Schristos                         BMK_benchOutcome_t,
460*3117ece4Schristos                         "Decompressed size cannot be determined: cannot benchmark");
461*3117ece4Schristos             }
462*3117ece4Schristos             if (fSize64 == ZSTD_CONTENTSIZE_ERROR) {
463*3117ece4Schristos                 RETURN_ERROR(
464*3117ece4Schristos                         32,
465*3117ece4Schristos                         BMK_benchOutcome_t,
466*3117ece4Schristos                         "Error while trying to assess decompressed size: data may be invalid");
467*3117ece4Schristos             }
468*3117ece4Schristos             totalDSize64 += fSize64;
469*3117ece4Schristos             srcPtr += fileSizes[fileNb];
470*3117ece4Schristos         }
471*3117ece4Schristos         {
472*3117ece4Schristos             size_t const decodedSize = (size_t)totalDSize64;
473*3117ece4Schristos             assert((U64)decodedSize == totalDSize64); /* check overflow */
474*3117ece4Schristos             free(*resultBufferPtr);
475*3117ece4Schristos             if (totalDSize64 > decodedSize) { /* size_t overflow */
476*3117ece4Schristos                 RETURN_ERROR(
477*3117ece4Schristos                         32,
478*3117ece4Schristos                         BMK_benchOutcome_t,
479*3117ece4Schristos                         "decompressed size is too large for local system");
480*3117ece4Schristos             }
481*3117ece4Schristos             *resultBufferPtr = malloc(decodedSize);
482*3117ece4Schristos             if (!(*resultBufferPtr)) {
483*3117ece4Schristos                 RETURN_ERROR(
484*3117ece4Schristos                         33,
485*3117ece4Schristos                         BMK_benchOutcome_t,
486*3117ece4Schristos                         "allocation error: not enough memory");
487*3117ece4Schristos             }
488*3117ece4Schristos             cSize   = srcSize;
489*3117ece4Schristos             srcSize = decodedSize;
490*3117ece4Schristos             ratio   = (double)srcSize / (double)cSize;
491*3117ece4Schristos         }
492*3117ece4Schristos     }
493*3117ece4Schristos 
494*3117ece4Schristos     /* Init data blocks  */
495*3117ece4Schristos     {
496*3117ece4Schristos         const char* srcPtr = (const char*)srcBuffer;
497*3117ece4Schristos         char* cPtr         = (char*)compressedBuffer;
498*3117ece4Schristos         char* resPtr       = (char*)(*resultBufferPtr);
499*3117ece4Schristos         U32 fileNb;
500*3117ece4Schristos         for (nbBlocks = 0, fileNb = 0; fileNb < nbFiles; fileNb++) {
501*3117ece4Schristos             size_t remaining              = fileSizes[fileNb];
502*3117ece4Schristos             U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly)
503*3117ece4Schristos                     ? 1
504*3117ece4Schristos                     : (U32)((remaining + (blockSize - 1)) / blockSize);
505*3117ece4Schristos             U32 const blockEnd            = nbBlocks + nbBlocksforThisFile;
506*3117ece4Schristos             for (; nbBlocks < blockEnd; nbBlocks++) {
507*3117ece4Schristos                 size_t const thisBlockSize = MIN(remaining, blockSize);
508*3117ece4Schristos                 srcPtrs[nbBlocks]          = srcPtr;
509*3117ece4Schristos                 srcSizes[nbBlocks]         = thisBlockSize;
510*3117ece4Schristos                 cPtrs[nbBlocks]            = cPtr;
511*3117ece4Schristos                 cCapacities[nbBlocks]      = (adv->mode == BMK_decodeOnly)
512*3117ece4Schristos                              ? thisBlockSize
513*3117ece4Schristos                              : ZSTD_compressBound(thisBlockSize);
514*3117ece4Schristos                 resPtrs[nbBlocks]          = resPtr;
515*3117ece4Schristos                 resSizes[nbBlocks]         = (adv->mode == BMK_decodeOnly)
516*3117ece4Schristos                                 ? (size_t)ZSTD_findDecompressedSize(
517*3117ece4Schristos                                 srcPtr, thisBlockSize)
518*3117ece4Schristos                                 : thisBlockSize;
519*3117ece4Schristos                 srcPtr += thisBlockSize;
520*3117ece4Schristos                 cPtr += cCapacities[nbBlocks];
521*3117ece4Schristos                 resPtr += thisBlockSize;
522*3117ece4Schristos                 remaining -= thisBlockSize;
523*3117ece4Schristos                 if (adv->mode == BMK_decodeOnly) {
524*3117ece4Schristos                     cSizes[nbBlocks]  = thisBlockSize;
525*3117ece4Schristos                     benchResult.cSize = thisBlockSize;
526*3117ece4Schristos                 }
527*3117ece4Schristos             }
528*3117ece4Schristos         }
529*3117ece4Schristos     }
530*3117ece4Schristos 
531*3117ece4Schristos     /* warming up `compressedBuffer` */
532*3117ece4Schristos     if (adv->mode == BMK_decodeOnly) {
533*3117ece4Schristos         memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
534*3117ece4Schristos     } else {
535*3117ece4Schristos         RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
536*3117ece4Schristos     }
537*3117ece4Schristos 
538*3117ece4Schristos     if (!UTIL_support_MT_measurements() && adv->nbWorkers > 1) {
539*3117ece4Schristos         OUTPUTLEVEL(
540*3117ece4Schristos                 2,
541*3117ece4Schristos                 "Warning : time measurements may be incorrect in multithreading mode... \n")
542*3117ece4Schristos     }
543*3117ece4Schristos 
544*3117ece4Schristos     /* Bench */
545*3117ece4Schristos     {
546*3117ece4Schristos         U64 const crcOrig = (adv->mode == BMK_decodeOnly)
547*3117ece4Schristos                 ? 0
548*3117ece4Schristos                 : XXH64(srcBuffer, srcSize, 0);
549*3117ece4Schristos #define NB_MARKS 4
550*3117ece4Schristos         const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
551*3117ece4Schristos         U32 markNb                  = 0;
552*3117ece4Schristos         int compressionCompleted    = (adv->mode == BMK_decodeOnly);
553*3117ece4Schristos         int decompressionCompleted  = (adv->mode == BMK_compressOnly);
554*3117ece4Schristos         BMK_benchParams_t cbp, dbp;
555*3117ece4Schristos         BMK_initCCtxArgs cctxprep;
556*3117ece4Schristos         BMK_initDCtxArgs dctxprep;
557*3117ece4Schristos 
558*3117ece4Schristos         cbp.benchFn       = local_defaultCompress; /* ZSTD_compress2 */
559*3117ece4Schristos         cbp.benchPayload  = cctx;
560*3117ece4Schristos         cbp.initFn        = local_initCCtx; /* BMK_initCCtx */
561*3117ece4Schristos         cbp.initPayload   = &cctxprep;
562*3117ece4Schristos         cbp.errorFn       = ZSTD_isError;
563*3117ece4Schristos         cbp.blockCount    = nbBlocks;
564*3117ece4Schristos         cbp.srcBuffers    = srcPtrs;
565*3117ece4Schristos         cbp.srcSizes      = srcSizes;
566*3117ece4Schristos         cbp.dstBuffers    = cPtrs;
567*3117ece4Schristos         cbp.dstCapacities = cCapacities;
568*3117ece4Schristos         cbp.blockResults  = cSizes;
569*3117ece4Schristos 
570*3117ece4Schristos         cctxprep.cctx           = cctx;
571*3117ece4Schristos         cctxprep.dictBuffer     = dictBuffer;
572*3117ece4Schristos         cctxprep.dictBufferSize = dictBufferSize;
573*3117ece4Schristos         cctxprep.cLevel         = cLevel;
574*3117ece4Schristos         cctxprep.comprParams    = comprParams;
575*3117ece4Schristos         cctxprep.adv            = adv;
576*3117ece4Schristos 
577*3117ece4Schristos         dbp.benchFn       = local_defaultDecompress;
578*3117ece4Schristos         dbp.benchPayload  = dctx;
579*3117ece4Schristos         dbp.initFn        = local_initDCtx;
580*3117ece4Schristos         dbp.initPayload   = &dctxprep;
581*3117ece4Schristos         dbp.errorFn       = ZSTD_isError;
582*3117ece4Schristos         dbp.blockCount    = nbBlocks;
583*3117ece4Schristos         dbp.srcBuffers    = (const void* const*)cPtrs;
584*3117ece4Schristos         dbp.srcSizes      = cSizes;
585*3117ece4Schristos         dbp.dstBuffers    = resPtrs;
586*3117ece4Schristos         dbp.dstCapacities = resSizes;
587*3117ece4Schristos         dbp.blockResults  = NULL;
588*3117ece4Schristos 
589*3117ece4Schristos         dctxprep.dctx           = dctx;
590*3117ece4Schristos         dctxprep.dictBuffer     = dictBuffer;
591*3117ece4Schristos         dctxprep.dictBufferSize = dictBufferSize;
592*3117ece4Schristos 
593*3117ece4Schristos         OUTPUTLEVEL(2, "\r%70s\r", ""); /* blank line */
594*3117ece4Schristos         assert(srcSize < UINT_MAX);
595*3117ece4Schristos         OUTPUTLEVEL(
596*3117ece4Schristos                 2,
597*3117ece4Schristos                 "%2s-%-17.17s :%10u -> \r",
598*3117ece4Schristos                 marks[markNb],
599*3117ece4Schristos                 displayName,
600*3117ece4Schristos                 (unsigned)srcSize);
601*3117ece4Schristos 
602*3117ece4Schristos         while (!(compressionCompleted && decompressionCompleted)) {
603*3117ece4Schristos             if (!compressionCompleted) {
604*3117ece4Schristos                 BMK_runOutcome_t const cOutcome =
605*3117ece4Schristos                         BMK_benchTimedFn(timeStateCompress, cbp);
606*3117ece4Schristos 
607*3117ece4Schristos                 if (!BMK_isSuccessful_runOutcome(cOutcome)) {
608*3117ece4Schristos                     RETURN_ERROR(30, BMK_benchOutcome_t, "compression error");
609*3117ece4Schristos                 }
610*3117ece4Schristos 
611*3117ece4Schristos                 {
612*3117ece4Schristos                     BMK_runTime_t const cResult = BMK_extract_runTime(cOutcome);
613*3117ece4Schristos                     cSize                       = cResult.sumOfReturn;
614*3117ece4Schristos                     ratio = (double)srcSize / (double)cSize;
615*3117ece4Schristos                     {
616*3117ece4Schristos                         BMK_benchResult_t newResult;
617*3117ece4Schristos                         newResult.cSpeed =
618*3117ece4Schristos                                 (U64)((double)srcSize * TIMELOOP_NANOSEC
619*3117ece4Schristos                                       / cResult.nanoSecPerRun);
620*3117ece4Schristos                         benchResult.cSize = cSize;
621*3117ece4Schristos                         if (newResult.cSpeed > benchResult.cSpeed)
622*3117ece4Schristos                             benchResult.cSpeed = newResult.cSpeed;
623*3117ece4Schristos                     }
624*3117ece4Schristos                 }
625*3117ece4Schristos 
626*3117ece4Schristos                 {
627*3117ece4Schristos                     int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
628*3117ece4Schristos                     assert(cSize < UINT_MAX);
629*3117ece4Schristos                     OUTPUTLEVEL(
630*3117ece4Schristos                             2,
631*3117ece4Schristos                             "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s \r",
632*3117ece4Schristos                             marks[markNb],
633*3117ece4Schristos                             displayName,
634*3117ece4Schristos                             (unsigned)srcSize,
635*3117ece4Schristos                             (unsigned)cSize,
636*3117ece4Schristos                             ratioAccuracy,
637*3117ece4Schristos                             ratio,
638*3117ece4Schristos                             benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1,
639*3117ece4Schristos                             (double)benchResult.cSpeed / MB_UNIT);
640*3117ece4Schristos                 }
641*3117ece4Schristos                 compressionCompleted =
642*3117ece4Schristos                         BMK_isCompleted_TimedFn(timeStateCompress);
643*3117ece4Schristos             }
644*3117ece4Schristos 
645*3117ece4Schristos             if (!decompressionCompleted) {
646*3117ece4Schristos                 BMK_runOutcome_t const dOutcome =
647*3117ece4Schristos                         BMK_benchTimedFn(timeStateDecompress, dbp);
648*3117ece4Schristos 
649*3117ece4Schristos                 if (!BMK_isSuccessful_runOutcome(dOutcome)) {
650*3117ece4Schristos                     RETURN_ERROR(30, BMK_benchOutcome_t, "decompression error");
651*3117ece4Schristos                 }
652*3117ece4Schristos 
653*3117ece4Schristos                 {
654*3117ece4Schristos                     BMK_runTime_t const dResult = BMK_extract_runTime(dOutcome);
655*3117ece4Schristos                     U64 const newDSpeed =
656*3117ece4Schristos                             (U64)((double)srcSize * TIMELOOP_NANOSEC
657*3117ece4Schristos                                   / dResult.nanoSecPerRun);
658*3117ece4Schristos                     if (newDSpeed > benchResult.dSpeed)
659*3117ece4Schristos                         benchResult.dSpeed = newDSpeed;
660*3117ece4Schristos                 }
661*3117ece4Schristos 
662*3117ece4Schristos                 {
663*3117ece4Schristos                     int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
664*3117ece4Schristos                     OUTPUTLEVEL(
665*3117ece4Schristos                             2,
666*3117ece4Schristos                             "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s, %6.1f MB/s\r",
667*3117ece4Schristos                             marks[markNb],
668*3117ece4Schristos                             displayName,
669*3117ece4Schristos                             (unsigned)srcSize,
670*3117ece4Schristos                             (unsigned)cSize,
671*3117ece4Schristos                             ratioAccuracy,
672*3117ece4Schristos                             ratio,
673*3117ece4Schristos                             benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1,
674*3117ece4Schristos                             (double)benchResult.cSpeed / MB_UNIT,
675*3117ece4Schristos                             (double)benchResult.dSpeed / MB_UNIT);
676*3117ece4Schristos                 }
677*3117ece4Schristos                 decompressionCompleted =
678*3117ece4Schristos                         BMK_isCompleted_TimedFn(timeStateDecompress);
679*3117ece4Schristos             }
680*3117ece4Schristos             markNb = (markNb + 1) % NB_MARKS;
681*3117ece4Schristos         } /* while (!(compressionCompleted && decompressionCompleted)) */
682*3117ece4Schristos 
683*3117ece4Schristos         /* CRC Checking */
684*3117ece4Schristos         {
685*3117ece4Schristos             const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
686*3117ece4Schristos             U64 const crcCheck       = XXH64(resultBuffer, srcSize, 0);
687*3117ece4Schristos             if ((adv->mode == BMK_both) && (crcOrig != crcCheck)) {
688*3117ece4Schristos                 size_t u;
689*3117ece4Schristos                 DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x   \n",
690*3117ece4Schristos                         displayName,
691*3117ece4Schristos                         (unsigned)crcOrig,
692*3117ece4Schristos                         (unsigned)crcCheck);
693*3117ece4Schristos                 for (u = 0; u < srcSize; u++) {
694*3117ece4Schristos                     if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) {
695*3117ece4Schristos                         unsigned segNb, bNb, pos;
696*3117ece4Schristos                         size_t bacc = 0;
697*3117ece4Schristos                         DISPLAY("Decoding error at pos %u ", (unsigned)u);
698*3117ece4Schristos                         for (segNb = 0; segNb < nbBlocks; segNb++) {
699*3117ece4Schristos                             if (bacc + srcSizes[segNb] > u)
700*3117ece4Schristos                                 break;
701*3117ece4Schristos                             bacc += srcSizes[segNb];
702*3117ece4Schristos                         }
703*3117ece4Schristos                         pos = (U32)(u - bacc);
704*3117ece4Schristos                         bNb = pos / (128 KB);
705*3117ece4Schristos                         DISPLAY("(sample %u, block %u, pos %u) \n",
706*3117ece4Schristos                                 segNb,
707*3117ece4Schristos                                 bNb,
708*3117ece4Schristos                                 pos);
709*3117ece4Schristos                         {
710*3117ece4Schristos                             size_t const lowest = (u > 5) ? 5 : u;
711*3117ece4Schristos                             size_t n;
712*3117ece4Schristos                             DISPLAY("origin: ");
713*3117ece4Schristos                             for (n = lowest; n > 0; n--)
714*3117ece4Schristos                                 DISPLAY("%02X ",
715*3117ece4Schristos                                         ((const BYTE*)srcBuffer)[u - n]);
716*3117ece4Schristos                             DISPLAY(" :%02X:  ", ((const BYTE*)srcBuffer)[u]);
717*3117ece4Schristos                             for (n = 1; n < 3; n++)
718*3117ece4Schristos                                 DISPLAY("%02X ",
719*3117ece4Schristos                                         ((const BYTE*)srcBuffer)[u + n]);
720*3117ece4Schristos                             DISPLAY(" \n");
721*3117ece4Schristos                             DISPLAY("decode: ");
722*3117ece4Schristos                             for (n = lowest; n > 0; n--)
723*3117ece4Schristos                                 DISPLAY("%02X ", resultBuffer[u - n]);
724*3117ece4Schristos                             DISPLAY(" :%02X:  ", resultBuffer[u]);
725*3117ece4Schristos                             for (n = 1; n < 3; n++)
726*3117ece4Schristos                                 DISPLAY("%02X ", resultBuffer[u + n]);
727*3117ece4Schristos                             DISPLAY(" \n");
728*3117ece4Schristos                         }
729*3117ece4Schristos                         break;
730*3117ece4Schristos                     }
731*3117ece4Schristos                     if (u == srcSize - 1) { /* should never happen */
732*3117ece4Schristos                         DISPLAY("no difference detected\n");
733*3117ece4Schristos                     }
734*3117ece4Schristos                 } /* for (u=0; u<srcSize; u++) */
735*3117ece4Schristos             }     /* if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) */
736*3117ece4Schristos         }         /* CRC Checking */
737*3117ece4Schristos 
738*3117ece4Schristos         if (displayLevel
739*3117ece4Schristos             == 1) { /* hidden display mode -q, used by python speed benchmark */
740*3117ece4Schristos             double const cSpeed = (double)benchResult.cSpeed / MB_UNIT;
741*3117ece4Schristos             double const dSpeed = (double)benchResult.dSpeed / MB_UNIT;
742*3117ece4Schristos             if (adv->additionalParam) {
743*3117ece4Schristos                 OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s  %s (param=%d)\n",
744*3117ece4Schristos                        cLevel,
745*3117ece4Schristos                        (int)cSize,
746*3117ece4Schristos                        ratio,
747*3117ece4Schristos                        cSpeed,
748*3117ece4Schristos                        dSpeed,
749*3117ece4Schristos                        displayName,
750*3117ece4Schristos                        adv->additionalParam);
751*3117ece4Schristos             } else {
752*3117ece4Schristos                 OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s  %s\n",
753*3117ece4Schristos                        cLevel,
754*3117ece4Schristos                        (int)cSize,
755*3117ece4Schristos                        ratio,
756*3117ece4Schristos                        cSpeed,
757*3117ece4Schristos                        dSpeed,
758*3117ece4Schristos                        displayName);
759*3117ece4Schristos             }
760*3117ece4Schristos         }
761*3117ece4Schristos 
762*3117ece4Schristos         OUTPUTLEVEL(2, "%2i#\n", cLevel);
763*3117ece4Schristos     } /* Bench */
764*3117ece4Schristos 
765*3117ece4Schristos     benchResult.cMem =
766*3117ece4Schristos             (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
767*3117ece4Schristos     return BMK_benchOutcome_setValidResult(benchResult);
768*3117ece4Schristos }
769*3117ece4Schristos 
770*3117ece4Schristos BMK_benchOutcome_t BMK_benchMemAdvanced(
771*3117ece4Schristos         const void* srcBuffer,
772*3117ece4Schristos         size_t srcSize,
773*3117ece4Schristos         void* dstBuffer,
774*3117ece4Schristos         size_t dstCapacity,
775*3117ece4Schristos         const size_t* fileSizes,
776*3117ece4Schristos         unsigned nbFiles,
777*3117ece4Schristos         int cLevel,
778*3117ece4Schristos         const ZSTD_compressionParameters* comprParams,
779*3117ece4Schristos         const void* dictBuffer,
780*3117ece4Schristos         size_t dictBufferSize,
781*3117ece4Schristos         int displayLevel,
782*3117ece4Schristos         const char* displayName,
783*3117ece4Schristos         const BMK_advancedParams_t* adv)
784*3117ece4Schristos 
785*3117ece4Schristos {
786*3117ece4Schristos     int const dstParamsError =
787*3117ece4Schristos             !dstBuffer ^ !dstCapacity; /* must be both NULL or none */
788*3117ece4Schristos 
789*3117ece4Schristos     size_t const blockSize =
790*3117ece4Schristos             ((adv->blockSize >= 32 && (adv->mode != BMK_decodeOnly))
791*3117ece4Schristos                      ? adv->blockSize
792*3117ece4Schristos                      : srcSize)
793*3117ece4Schristos             + (!srcSize) /* avoid div by 0 */;
794*3117ece4Schristos     U32 const maxNbBlocks =
795*3117ece4Schristos             (U32)((srcSize + (blockSize - 1)) / blockSize) + nbFiles;
796*3117ece4Schristos 
797*3117ece4Schristos     /* these are the blockTable parameters, just split up */
798*3117ece4Schristos     const void** const srcPtrs =
799*3117ece4Schristos             (const void**)malloc(maxNbBlocks * sizeof(void*));
800*3117ece4Schristos     size_t* const srcSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
801*3117ece4Schristos 
802*3117ece4Schristos     void** const cPtrs        = (void**)malloc(maxNbBlocks * sizeof(void*));
803*3117ece4Schristos     size_t* const cSizes      = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
804*3117ece4Schristos     size_t* const cCapacities = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
805*3117ece4Schristos 
806*3117ece4Schristos     void** const resPtrs   = (void**)malloc(maxNbBlocks * sizeof(void*));
807*3117ece4Schristos     size_t* const resSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
808*3117ece4Schristos 
809*3117ece4Schristos     BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(
810*3117ece4Schristos             adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
811*3117ece4Schristos     BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(
812*3117ece4Schristos             adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
813*3117ece4Schristos 
814*3117ece4Schristos     ZSTD_CCtx* const cctx = ZSTD_createCCtx();
815*3117ece4Schristos     ZSTD_DCtx* const dctx = ZSTD_createDCtx();
816*3117ece4Schristos 
817*3117ece4Schristos     const size_t maxCompressedSize = dstCapacity
818*3117ece4Schristos             ? dstCapacity
819*3117ece4Schristos             : ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024);
820*3117ece4Schristos 
821*3117ece4Schristos     void* const internalDstBuffer =
822*3117ece4Schristos             dstBuffer ? NULL : malloc(maxCompressedSize);
823*3117ece4Schristos     void* const compressedBuffer = dstBuffer ? dstBuffer : internalDstBuffer;
824*3117ece4Schristos 
825*3117ece4Schristos     BMK_benchOutcome_t outcome =
826*3117ece4Schristos             BMK_benchOutcome_error(); /* error by default */
827*3117ece4Schristos 
828*3117ece4Schristos     void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
829*3117ece4Schristos 
830*3117ece4Schristos     int const allocationincomplete = !srcPtrs || !srcSizes || !cPtrs || !cSizes
831*3117ece4Schristos             || !cCapacities || !resPtrs || !resSizes || !timeStateCompress
832*3117ece4Schristos             || !timeStateDecompress || !cctx || !dctx || !compressedBuffer
833*3117ece4Schristos             || !resultBuffer;
834*3117ece4Schristos 
835*3117ece4Schristos     if (!allocationincomplete && !dstParamsError) {
836*3117ece4Schristos         outcome = BMK_benchMemAdvancedNoAlloc(
837*3117ece4Schristos                 srcPtrs,
838*3117ece4Schristos                 srcSizes,
839*3117ece4Schristos                 cPtrs,
840*3117ece4Schristos                 cCapacities,
841*3117ece4Schristos                 cSizes,
842*3117ece4Schristos                 resPtrs,
843*3117ece4Schristos                 resSizes,
844*3117ece4Schristos                 &resultBuffer,
845*3117ece4Schristos                 compressedBuffer,
846*3117ece4Schristos                 maxCompressedSize,
847*3117ece4Schristos                 timeStateCompress,
848*3117ece4Schristos                 timeStateDecompress,
849*3117ece4Schristos                 srcBuffer,
850*3117ece4Schristos                 srcSize,
851*3117ece4Schristos                 fileSizes,
852*3117ece4Schristos                 nbFiles,
853*3117ece4Schristos                 cLevel,
854*3117ece4Schristos                 comprParams,
855*3117ece4Schristos                 dictBuffer,
856*3117ece4Schristos                 dictBufferSize,
857*3117ece4Schristos                 cctx,
858*3117ece4Schristos                 dctx,
859*3117ece4Schristos                 displayLevel,
860*3117ece4Schristos                 displayName,
861*3117ece4Schristos                 adv);
862*3117ece4Schristos     }
863*3117ece4Schristos 
864*3117ece4Schristos     /* clean up */
865*3117ece4Schristos     BMK_freeTimedFnState(timeStateCompress);
866*3117ece4Schristos     BMK_freeTimedFnState(timeStateDecompress);
867*3117ece4Schristos 
868*3117ece4Schristos     ZSTD_freeCCtx(cctx);
869*3117ece4Schristos     ZSTD_freeDCtx(dctx);
870*3117ece4Schristos 
871*3117ece4Schristos     free(internalDstBuffer);
872*3117ece4Schristos     free(resultBuffer);
873*3117ece4Schristos 
874*3117ece4Schristos     free((void*)srcPtrs);
875*3117ece4Schristos     free(srcSizes);
876*3117ece4Schristos     free(cPtrs);
877*3117ece4Schristos     free(cSizes);
878*3117ece4Schristos     free(cCapacities);
879*3117ece4Schristos     free(resPtrs);
880*3117ece4Schristos     free(resSizes);
881*3117ece4Schristos 
882*3117ece4Schristos     if (allocationincomplete) {
883*3117ece4Schristos         RETURN_ERROR(
884*3117ece4Schristos                 31, BMK_benchOutcome_t, "allocation error : not enough memory");
885*3117ece4Schristos     }
886*3117ece4Schristos 
887*3117ece4Schristos     if (dstParamsError) {
888*3117ece4Schristos         RETURN_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
889*3117ece4Schristos     }
890*3117ece4Schristos     return outcome;
891*3117ece4Schristos }
892*3117ece4Schristos 
893*3117ece4Schristos BMK_benchOutcome_t BMK_benchMem(
894*3117ece4Schristos         const void* srcBuffer,
895*3117ece4Schristos         size_t srcSize,
896*3117ece4Schristos         const size_t* fileSizes,
897*3117ece4Schristos         unsigned nbFiles,
898*3117ece4Schristos         int cLevel,
899*3117ece4Schristos         const ZSTD_compressionParameters* comprParams,
900*3117ece4Schristos         const void* dictBuffer,
901*3117ece4Schristos         size_t dictBufferSize,
902*3117ece4Schristos         int displayLevel,
903*3117ece4Schristos         const char* displayName)
904*3117ece4Schristos {
905*3117ece4Schristos     BMK_advancedParams_t const adv = BMK_initAdvancedParams();
906*3117ece4Schristos     return BMK_benchMemAdvanced(
907*3117ece4Schristos             srcBuffer,
908*3117ece4Schristos             srcSize,
909*3117ece4Schristos             NULL,
910*3117ece4Schristos             0,
911*3117ece4Schristos             fileSizes,
912*3117ece4Schristos             nbFiles,
913*3117ece4Schristos             cLevel,
914*3117ece4Schristos             comprParams,
915*3117ece4Schristos             dictBuffer,
916*3117ece4Schristos             dictBufferSize,
917*3117ece4Schristos             displayLevel,
918*3117ece4Schristos             displayName,
919*3117ece4Schristos             &adv);
920*3117ece4Schristos }
921*3117ece4Schristos 
922*3117ece4Schristos static BMK_benchOutcome_t BMK_benchCLevel(
923*3117ece4Schristos         const void* srcBuffer,
924*3117ece4Schristos         size_t benchedSize,
925*3117ece4Schristos         const size_t* fileSizes,
926*3117ece4Schristos         unsigned nbFiles,
927*3117ece4Schristos         int cLevel,
928*3117ece4Schristos         const ZSTD_compressionParameters* comprParams,
929*3117ece4Schristos         const void* dictBuffer,
930*3117ece4Schristos         size_t dictBufferSize,
931*3117ece4Schristos         int displayLevel,
932*3117ece4Schristos         const char* displayName,
933*3117ece4Schristos         BMK_advancedParams_t const* const adv)
934*3117ece4Schristos {
935*3117ece4Schristos     const char* pch = strrchr(displayName, '\\'); /* Windows */
936*3117ece4Schristos     if (!pch)
937*3117ece4Schristos         pch = strrchr(displayName, '/'); /* Linux */
938*3117ece4Schristos     if (pch)
939*3117ece4Schristos         displayName = pch + 1;
940*3117ece4Schristos 
941*3117ece4Schristos     if (adv->realTime) {
942*3117ece4Schristos         DISPLAYLEVEL(2, "Note : switching to real-time priority \n");
943*3117ece4Schristos         SET_REALTIME_PRIORITY;
944*3117ece4Schristos     }
945*3117ece4Schristos 
946*3117ece4Schristos     if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */
947*3117ece4Schristos         OUTPUT("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",
948*3117ece4Schristos                ZSTD_VERSION_STRING,
949*3117ece4Schristos                ZSTD_GIT_COMMIT_STRING,
950*3117ece4Schristos                (unsigned)benchedSize,
951*3117ece4Schristos                adv->nbSeconds,
952*3117ece4Schristos                (unsigned)(adv->blockSize >> 10));
953*3117ece4Schristos 
954*3117ece4Schristos     return BMK_benchMemAdvanced(
955*3117ece4Schristos             srcBuffer,
956*3117ece4Schristos             benchedSize,
957*3117ece4Schristos             NULL,
958*3117ece4Schristos             0,
959*3117ece4Schristos             fileSizes,
960*3117ece4Schristos             nbFiles,
961*3117ece4Schristos             cLevel,
962*3117ece4Schristos             comprParams,
963*3117ece4Schristos             dictBuffer,
964*3117ece4Schristos             dictBufferSize,
965*3117ece4Schristos             displayLevel,
966*3117ece4Schristos             displayName,
967*3117ece4Schristos             adv);
968*3117ece4Schristos }
969*3117ece4Schristos 
970*3117ece4Schristos int BMK_syntheticTest(
971*3117ece4Schristos         int cLevel,
972*3117ece4Schristos         double compressibility,
973*3117ece4Schristos         const ZSTD_compressionParameters* compressionParams,
974*3117ece4Schristos         int displayLevel,
975*3117ece4Schristos         const BMK_advancedParams_t* adv)
976*3117ece4Schristos {
977*3117ece4Schristos     char nameBuff[20]        = { 0 };
978*3117ece4Schristos     const char* name         = nameBuff;
979*3117ece4Schristos     size_t const benchedSize = adv->blockSize ? adv->blockSize : 10000000;
980*3117ece4Schristos     void* srcBuffer;
981*3117ece4Schristos     BMK_benchOutcome_t res;
982*3117ece4Schristos 
983*3117ece4Schristos     if (cLevel > ZSTD_maxCLevel()) {
984*3117ece4Schristos         DISPLAYLEVEL(1, "Invalid Compression Level");
985*3117ece4Schristos         return 15;
986*3117ece4Schristos     }
987*3117ece4Schristos 
988*3117ece4Schristos     /* Memory allocation */
989*3117ece4Schristos     srcBuffer = malloc(benchedSize);
990*3117ece4Schristos     if (!srcBuffer) {
991*3117ece4Schristos         DISPLAYLEVEL(1, "allocation error : not enough memory");
992*3117ece4Schristos         return 16;
993*3117ece4Schristos     }
994*3117ece4Schristos 
995*3117ece4Schristos     /* Fill input buffer */
996*3117ece4Schristos     if (compressibility < 0.0) {
997*3117ece4Schristos         LOREM_genBuffer(srcBuffer, benchedSize, 0);
998*3117ece4Schristos         name = "Lorem ipsum";
999*3117ece4Schristos     } else {
1000*3117ece4Schristos         RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
1001*3117ece4Schristos         formatString_u(
1002*3117ece4Schristos                 nameBuff,
1003*3117ece4Schristos                 sizeof(nameBuff),
1004*3117ece4Schristos                 "Synthetic %u%%",
1005*3117ece4Schristos                 (unsigned)(compressibility * 100));
1006*3117ece4Schristos     }
1007*3117ece4Schristos 
1008*3117ece4Schristos     /* Bench */
1009*3117ece4Schristos     res = BMK_benchCLevel(
1010*3117ece4Schristos             srcBuffer,
1011*3117ece4Schristos             benchedSize,
1012*3117ece4Schristos             &benchedSize /* ? */,
1013*3117ece4Schristos             1 /* ? */,
1014*3117ece4Schristos             cLevel,
1015*3117ece4Schristos             compressionParams,
1016*3117ece4Schristos             NULL,
1017*3117ece4Schristos             0, /* dictionary */
1018*3117ece4Schristos             displayLevel,
1019*3117ece4Schristos             name,
1020*3117ece4Schristos             adv);
1021*3117ece4Schristos 
1022*3117ece4Schristos     /* clean up */
1023*3117ece4Schristos     free(srcBuffer);
1024*3117ece4Schristos 
1025*3117ece4Schristos     return !BMK_isSuccessful_benchOutcome(res);
1026*3117ece4Schristos }
1027*3117ece4Schristos 
1028*3117ece4Schristos static size_t BMK_findMaxMem(U64 requiredMem)
1029*3117ece4Schristos {
1030*3117ece4Schristos     size_t const step = 64 MB;
1031*3117ece4Schristos     BYTE* testmem     = NULL;
1032*3117ece4Schristos 
1033*3117ece4Schristos     requiredMem = (((requiredMem >> 26) + 1) << 26);
1034*3117ece4Schristos     requiredMem += step;
1035*3117ece4Schristos     if (requiredMem > maxMemory)
1036*3117ece4Schristos         requiredMem = maxMemory;
1037*3117ece4Schristos 
1038*3117ece4Schristos     do {
1039*3117ece4Schristos         testmem = (BYTE*)malloc((size_t)requiredMem);
1040*3117ece4Schristos         requiredMem -= step;
1041*3117ece4Schristos     } while (!testmem && requiredMem > 0);
1042*3117ece4Schristos 
1043*3117ece4Schristos     free(testmem);
1044*3117ece4Schristos     return (size_t)(requiredMem);
1045*3117ece4Schristos }
1046*3117ece4Schristos 
1047*3117ece4Schristos /*! BMK_loadFiles() :
1048*3117ece4Schristos  *  Loads `buffer` with content of files listed within `fileNamesTable`.
1049*3117ece4Schristos  *  At most, fills `buffer` entirely. */
1050*3117ece4Schristos static int BMK_loadFiles(
1051*3117ece4Schristos         void* buffer,
1052*3117ece4Schristos         size_t bufferSize,
1053*3117ece4Schristos         size_t* fileSizes,
1054*3117ece4Schristos         const char* const* fileNamesTable,
1055*3117ece4Schristos         unsigned nbFiles,
1056*3117ece4Schristos         int displayLevel)
1057*3117ece4Schristos {
1058*3117ece4Schristos     size_t pos = 0, totalSize = 0;
1059*3117ece4Schristos     unsigned n;
1060*3117ece4Schristos     for (n = 0; n < nbFiles; n++) {
1061*3117ece4Schristos         U64 fileSize = UTIL_getFileSize(
1062*3117ece4Schristos                 fileNamesTable[n]); /* last file may be shortened */
1063*3117ece4Schristos         if (UTIL_isDirectory(fileNamesTable[n])) {
1064*3117ece4Schristos             DISPLAYLEVEL(
1065*3117ece4Schristos                     2, "Ignoring %s directory...       \n", fileNamesTable[n]);
1066*3117ece4Schristos             fileSizes[n] = 0;
1067*3117ece4Schristos             continue;
1068*3117ece4Schristos         }
1069*3117ece4Schristos         if (fileSize == UTIL_FILESIZE_UNKNOWN) {
1070*3117ece4Schristos             DISPLAYLEVEL(
1071*3117ece4Schristos                     2,
1072*3117ece4Schristos                     "Cannot evaluate size of %s, ignoring ... \n",
1073*3117ece4Schristos                     fileNamesTable[n]);
1074*3117ece4Schristos             fileSizes[n] = 0;
1075*3117ece4Schristos             continue;
1076*3117ece4Schristos         }
1077*3117ece4Schristos         {
1078*3117ece4Schristos             FILE* const f = fopen(fileNamesTable[n], "rb");
1079*3117ece4Schristos             if (f == NULL)
1080*3117ece4Schristos                 RETURN_ERROR_INT(
1081*3117ece4Schristos                         10, "impossible to open file %s", fileNamesTable[n]);
1082*3117ece4Schristos             OUTPUTLEVEL(2, "Loading %s...       \r", fileNamesTable[n]);
1083*3117ece4Schristos             if (fileSize > bufferSize - pos)
1084*3117ece4Schristos                 fileSize = bufferSize - pos,
1085*3117ece4Schristos                 nbFiles  = n; /* buffer too small - stop after this file */
1086*3117ece4Schristos             {
1087*3117ece4Schristos                 size_t const readSize =
1088*3117ece4Schristos                         fread(((char*)buffer) + pos, 1, (size_t)fileSize, f);
1089*3117ece4Schristos                 if (readSize != (size_t)fileSize)
1090*3117ece4Schristos                     RETURN_ERROR_INT(
1091*3117ece4Schristos                             11, "could not read %s", fileNamesTable[n]);
1092*3117ece4Schristos                 pos += readSize;
1093*3117ece4Schristos             }
1094*3117ece4Schristos             fileSizes[n] = (size_t)fileSize;
1095*3117ece4Schristos             totalSize += (size_t)fileSize;
1096*3117ece4Schristos             fclose(f);
1097*3117ece4Schristos         }
1098*3117ece4Schristos     }
1099*3117ece4Schristos 
1100*3117ece4Schristos     if (totalSize == 0)
1101*3117ece4Schristos         RETURN_ERROR_INT(12, "no data to bench");
1102*3117ece4Schristos     return 0;
1103*3117ece4Schristos }
1104*3117ece4Schristos 
1105*3117ece4Schristos int BMK_benchFilesAdvanced(
1106*3117ece4Schristos         const char* const* fileNamesTable,
1107*3117ece4Schristos         unsigned nbFiles,
1108*3117ece4Schristos         const char* dictFileName,
1109*3117ece4Schristos         int cLevel,
1110*3117ece4Schristos         const ZSTD_compressionParameters* compressionParams,
1111*3117ece4Schristos         int displayLevel,
1112*3117ece4Schristos         const BMK_advancedParams_t* adv)
1113*3117ece4Schristos {
1114*3117ece4Schristos     void* srcBuffer = NULL;
1115*3117ece4Schristos     size_t benchedSize;
1116*3117ece4Schristos     void* dictBuffer      = NULL;
1117*3117ece4Schristos     size_t dictBufferSize = 0;
1118*3117ece4Schristos     size_t* fileSizes     = NULL;
1119*3117ece4Schristos     BMK_benchOutcome_t res;
1120*3117ece4Schristos     U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
1121*3117ece4Schristos 
1122*3117ece4Schristos     if (!nbFiles) {
1123*3117ece4Schristos         DISPLAYLEVEL(1, "No Files to Benchmark");
1124*3117ece4Schristos         return 13;
1125*3117ece4Schristos     }
1126*3117ece4Schristos 
1127*3117ece4Schristos     if (cLevel > ZSTD_maxCLevel()) {
1128*3117ece4Schristos         DISPLAYLEVEL(1, "Invalid Compression Level");
1129*3117ece4Schristos         return 14;
1130*3117ece4Schristos     }
1131*3117ece4Schristos 
1132*3117ece4Schristos     if (totalSizeToLoad == UTIL_FILESIZE_UNKNOWN) {
1133*3117ece4Schristos         DISPLAYLEVEL(1, "Error loading files");
1134*3117ece4Schristos         return 15;
1135*3117ece4Schristos     }
1136*3117ece4Schristos 
1137*3117ece4Schristos     fileSizes = (size_t*)calloc(nbFiles, sizeof(size_t));
1138*3117ece4Schristos     if (!fileSizes) {
1139*3117ece4Schristos         DISPLAYLEVEL(1, "not enough memory for fileSizes");
1140*3117ece4Schristos         return 16;
1141*3117ece4Schristos     }
1142*3117ece4Schristos 
1143*3117ece4Schristos     /* Load dictionary */
1144*3117ece4Schristos     if (dictFileName != NULL) {
1145*3117ece4Schristos         U64 const dictFileSize = UTIL_getFileSize(dictFileName);
1146*3117ece4Schristos         if (dictFileSize == UTIL_FILESIZE_UNKNOWN) {
1147*3117ece4Schristos             DISPLAYLEVEL(
1148*3117ece4Schristos                     1,
1149*3117ece4Schristos                     "error loading %s : %s \n",
1150*3117ece4Schristos                     dictFileName,
1151*3117ece4Schristos                     strerror(errno));
1152*3117ece4Schristos             free(fileSizes);
1153*3117ece4Schristos             DISPLAYLEVEL(1, "benchmark aborted");
1154*3117ece4Schristos             return 17;
1155*3117ece4Schristos         }
1156*3117ece4Schristos         if (dictFileSize > 64 MB) {
1157*3117ece4Schristos             free(fileSizes);
1158*3117ece4Schristos             DISPLAYLEVEL(1, "dictionary file %s too large", dictFileName);
1159*3117ece4Schristos             return 18;
1160*3117ece4Schristos         }
1161*3117ece4Schristos         dictBufferSize = (size_t)dictFileSize;
1162*3117ece4Schristos         dictBuffer     = malloc(dictBufferSize);
1163*3117ece4Schristos         if (dictBuffer == NULL) {
1164*3117ece4Schristos             free(fileSizes);
1165*3117ece4Schristos             DISPLAYLEVEL(
1166*3117ece4Schristos                     1,
1167*3117ece4Schristos                     "not enough memory for dictionary (%u bytes)",
1168*3117ece4Schristos                     (unsigned)dictBufferSize);
1169*3117ece4Schristos             return 19;
1170*3117ece4Schristos         }
1171*3117ece4Schristos 
1172*3117ece4Schristos         {
1173*3117ece4Schristos             int const errorCode = BMK_loadFiles(
1174*3117ece4Schristos                     dictBuffer,
1175*3117ece4Schristos                     dictBufferSize,
1176*3117ece4Schristos                     fileSizes,
1177*3117ece4Schristos                     &dictFileName /*?*/,
1178*3117ece4Schristos                     1 /*?*/,
1179*3117ece4Schristos                     displayLevel);
1180*3117ece4Schristos             if (errorCode) {
1181*3117ece4Schristos                 res = BMK_benchOutcome_error();
1182*3117ece4Schristos                 goto _cleanUp;
1183*3117ece4Schristos             }
1184*3117ece4Schristos         }
1185*3117ece4Schristos     }
1186*3117ece4Schristos 
1187*3117ece4Schristos     /* Memory allocation & restrictions */
1188*3117ece4Schristos     benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3;
1189*3117ece4Schristos     if ((U64)benchedSize > totalSizeToLoad)
1190*3117ece4Schristos         benchedSize = (size_t)totalSizeToLoad;
1191*3117ece4Schristos     if (benchedSize < totalSizeToLoad)
1192*3117ece4Schristos         DISPLAY("Not enough memory; testing %u MB only...\n",
1193*3117ece4Schristos                 (unsigned)(benchedSize >> 20));
1194*3117ece4Schristos 
1195*3117ece4Schristos     srcBuffer = benchedSize ? malloc(benchedSize) : NULL;
1196*3117ece4Schristos     if (!srcBuffer) {
1197*3117ece4Schristos         free(dictBuffer);
1198*3117ece4Schristos         free(fileSizes);
1199*3117ece4Schristos         DISPLAYLEVEL(1, "not enough memory for srcBuffer");
1200*3117ece4Schristos         return 20;
1201*3117ece4Schristos     }
1202*3117ece4Schristos 
1203*3117ece4Schristos     /* Load input buffer */
1204*3117ece4Schristos     {
1205*3117ece4Schristos         int const errorCode = BMK_loadFiles(
1206*3117ece4Schristos                 srcBuffer,
1207*3117ece4Schristos                 benchedSize,
1208*3117ece4Schristos                 fileSizes,
1209*3117ece4Schristos                 fileNamesTable,
1210*3117ece4Schristos                 nbFiles,
1211*3117ece4Schristos                 displayLevel);
1212*3117ece4Schristos         if (errorCode) {
1213*3117ece4Schristos             res = BMK_benchOutcome_error();
1214*3117ece4Schristos             goto _cleanUp;
1215*3117ece4Schristos         }
1216*3117ece4Schristos     }
1217*3117ece4Schristos 
1218*3117ece4Schristos     /* Bench */
1219*3117ece4Schristos     {
1220*3117ece4Schristos         char mfName[20] = { 0 };
1221*3117ece4Schristos         formatString_u(mfName, sizeof(mfName), " %u files", nbFiles);
1222*3117ece4Schristos         {
1223*3117ece4Schristos             const char* const displayName =
1224*3117ece4Schristos                     (nbFiles > 1) ? mfName : fileNamesTable[0];
1225*3117ece4Schristos             res = BMK_benchCLevel(
1226*3117ece4Schristos                     srcBuffer,
1227*3117ece4Schristos                     benchedSize,
1228*3117ece4Schristos                     fileSizes,
1229*3117ece4Schristos                     nbFiles,
1230*3117ece4Schristos                     cLevel,
1231*3117ece4Schristos                     compressionParams,
1232*3117ece4Schristos                     dictBuffer,
1233*3117ece4Schristos                     dictBufferSize,
1234*3117ece4Schristos                     displayLevel,
1235*3117ece4Schristos                     displayName,
1236*3117ece4Schristos                     adv);
1237*3117ece4Schristos         }
1238*3117ece4Schristos     }
1239*3117ece4Schristos 
1240*3117ece4Schristos _cleanUp:
1241*3117ece4Schristos     free(srcBuffer);
1242*3117ece4Schristos     free(dictBuffer);
1243*3117ece4Schristos     free(fileSizes);
1244*3117ece4Schristos     return !BMK_isSuccessful_benchOutcome(res);
1245*3117ece4Schristos }
1246*3117ece4Schristos 
1247*3117ece4Schristos int BMK_benchFiles(
1248*3117ece4Schristos         const char* const* fileNamesTable,
1249*3117ece4Schristos         unsigned nbFiles,
1250*3117ece4Schristos         const char* dictFileName,
1251*3117ece4Schristos         int cLevel,
1252*3117ece4Schristos         const ZSTD_compressionParameters* compressionParams,
1253*3117ece4Schristos         int displayLevel)
1254*3117ece4Schristos {
1255*3117ece4Schristos     BMK_advancedParams_t const adv = BMK_initAdvancedParams();
1256*3117ece4Schristos     return BMK_benchFilesAdvanced(
1257*3117ece4Schristos             fileNamesTable,
1258*3117ece4Schristos             nbFiles,
1259*3117ece4Schristos             dictFileName,
1260*3117ece4Schristos             cLevel,
1261*3117ece4Schristos             compressionParams,
1262*3117ece4Schristos             displayLevel,
1263*3117ece4Schristos             &adv);
1264*3117ece4Schristos }
1265