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