blob: 9bc3628ee5fd27f8b7fe7acda1e66ba2c083a22f [file] [log] [blame]
Yann Collet32fb4072017-08-18 16:52:05 -07001/*
Elliott Hughes44aba642023-09-12 20:18:59 +00002 * Copyright (c) Meta Platforms, Inc. and affiliates.
Yann Collet4ded9e52016-08-30 10:04:33 -07003 * All rights reserved.
4 *
Yann Collet32fb4072017-08-18 16:52:05 -07005 * 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).
Yann Collet3128e032017-09-08 00:09:23 -07008 * You may select, at your option, one of the above-listed licenses.
Yann Collet4ded9e52016-08-30 10:04:33 -07009 */
Yann Collet4856a002015-01-24 01:58:16 +010010
Yann Collet4856a002015-01-24 01:58:16 +010011
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010012/* **************************************
Yann Collet500014a2017-01-19 16:59:56 -080013* Tuning parameters
14****************************************/
15#ifndef BMK_TIMETEST_DEFAULT_S /* default minimum time per test */
Elliott Hughes44aba642023-09-12 20:18:59 +000016# define BMK_TIMETEST_DEFAULT_S 3
Yann Collet500014a2017-01-19 16:59:56 -080017#endif
18
19
Yann Colletf3eca252015-10-22 15:31:46 +010020/* *************************************
Yann Collet4856a002015-01-24 01:58:16 +010021* Includes
Yann Colletf3eca252015-10-22 15:31:46 +010022***************************************/
Przemyslaw Skibinski7a8a03c2016-12-21 15:08:44 +010023#include "platform.h" /* Large Files support */
Przemyslaw Skibinski2f6ccee2016-12-21 13:23:34 +010024#include "util.h" /* UTIL_getFileSize, UTIL_sleep */
Yann Collet4856a002015-01-24 01:58:16 +010025#include <stdlib.h> /* malloc, free */
Yann Collet18434d72018-12-20 17:27:08 -080026#include <string.h> /* memset, strerror */
Yann Colletc6a64172016-12-31 03:31:26 +010027#include <stdio.h> /* fprintf, fopen */
Yann Colleted2fb6b2018-12-20 17:20:07 -080028#include <errno.h>
Yann Colletd3364aa2018-02-20 14:48:09 -080029#include <assert.h> /* assert */
inikep4c12f232016-03-29 14:52:13 +020030
Yann Collet59a71162019-04-10 12:37:03 -070031#include "timefn.h" /* UTIL_time_t */
Yann Colletd38063f2018-11-13 11:01:59 -080032#include "benchfn.h"
W. Felix Handte7dcca6b2020-05-01 16:20:40 -040033#include "../lib/common/mem.h"
W. Felix Handte4bd96a62022-01-06 00:20:49 -050034#ifndef ZSTD_STATIC_LINKING_ONLY
Yann Colletd3b7f8d2016-06-04 19:47:02 +020035#define ZSTD_STATIC_LINKING_ONLY
W. Felix Handte4bd96a62022-01-06 00:20:49 -050036#endif
W. Felix Handte7dcca6b2020-05-01 16:20:40 -040037#include "../lib/zstd.h"
inikep69fcd7c2016-04-28 12:23:33 +020038#include "datagen.h" /* RDG_genBuffer */
W. Felix Handte4bd96a62022-01-06 00:20:49 -050039#ifndef XXH_INLINE_ALL
40#define XXH_INLINE_ALL
41#endif
W. Felix Handte7dcca6b2020-05-01 16:20:40 -040042#include "../lib/common/xxhash.h"
Yann Colletd38063f2018-11-13 11:01:59 -080043#include "benchzstd.h"
Nick Terrell09149be2021-04-30 15:02:12 -070044#include "../lib/zstd_errors.h"
Yann Collet4856a002015-01-24 01:58:16 +010045
46
Yann Colletf3eca252015-10-22 15:31:46 +010047/* *************************************
Yann Collet4856a002015-01-24 01:58:16 +010048* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010049***************************************/
inikepf2f59d72016-06-22 15:42:26 +020050#ifndef ZSTD_GIT_COMMIT
inikepd7d251c2016-06-22 16:13:25 +020051# define ZSTD_GIT_COMMIT_STRING ""
52#else
53# define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
inikepf2f59d72016-06-22 15:42:26 +020054#endif
55
Yann Colletd3364aa2018-02-20 14:48:09 -080056#define TIMELOOP_MICROSEC (1*1000000ULL) /* 1 second */
57#define TIMELOOP_NANOSEC (1*1000000000ULL) /* 1 second */
58#define ACTIVEPERIOD_MICROSEC (70*TIMELOOP_MICROSEC) /* 70 seconds */
inikep83c76b42016-04-28 13:16:01 +020059#define COOLPERIOD_SEC 10
Yann Collet4856a002015-01-24 01:58:16 +010060
61#define KB *(1 <<10)
62#define MB *(1 <<20)
63#define GB *(1U<<30)
64
Yann Collet55affc02018-08-28 11:21:09 -070065#define BMK_RUNTEST_DEFAULT_MS 1000
66
Yann Collet2e45bad2018-08-23 14:21:18 -070067static const size_t maxMemory = (sizeof(size_t)==4) ?
68 /* 32-bit */ (2 GB - 64 MB) :
69 /* 64-bit */ (size_t)(1ULL << ((sizeof(size_t)*8)-31));
70
Yann Collet4856a002015-01-24 01:58:16 +010071
Yann Colletf3eca252015-10-22 15:31:46 +010072/* *************************************
Yann Colleted699e62015-12-16 02:37:24 +010073* console display
Yann Colletf3eca252015-10-22 15:31:46 +010074***************************************/
Yann Collet9750f3c2021-05-05 16:52:21 -070075#define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush(NULL); }
George Lu01d940b2018-06-11 10:59:05 -040076#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
77/* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
Yann Collet08ceda32021-09-04 00:52:44 -070078#define OUTPUT(...) { fprintf(stdout, __VA_ARGS__); fflush(NULL); }
79#define OUTPUTLEVEL(l, ...) if (displayLevel>=l) { OUTPUT(__VA_ARGS__); }
Yann Colleted699e62015-12-16 02:37:24 +010080
81
82/* *************************************
83* Exceptions
84***************************************/
85#ifndef DEBUG
George Lu3adc2172018-07-12 17:30:39 -070086# define DEBUG 0
Yann Colleted699e62015-12-16 02:37:24 +010087#endif
Yann Colletfe234bf2017-06-19 15:23:19 -070088#define DEBUGOUTPUT(...) { if (DEBUG) DISPLAY(__VA_ARGS__); }
George Lu20f4f322018-06-12 15:54:43 -040089
Yann Collet6309be62019-10-15 16:09:18 -070090#define RETURN_ERROR_INT(errorNum, ...) { \
Yann Colletfe234bf2017-06-19 15:23:19 -070091 DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
George Lu20f4f322018-06-12 15:54:43 -040092 DISPLAYLEVEL(1, "Error %i : ", errorNum); \
George Lu01d940b2018-06-11 10:59:05 -040093 DISPLAYLEVEL(1, __VA_ARGS__); \
94 DISPLAYLEVEL(1, " \n"); \
George Lu20f4f322018-06-12 15:54:43 -040095 return errorNum; \
Yann Colleted699e62015-12-16 02:37:24 +010096}
Yann Collet4856a002015-01-24 01:58:16 +010097
Yann Colletd613fd92018-12-06 19:27:37 -080098#define CHECK_Z(zf) { \
99 size_t const zerr = zf; \
100 if (ZSTD_isError(zerr)) { \
101 DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
102 DISPLAY("Error : "); \
103 DISPLAY("%s failed : %s", \
104 #zf, ZSTD_getErrorName(zerr)); \
105 DISPLAY(" \n"); \
106 exit(1); \
107 } \
108}
109
Yann Collet2e45bad2018-08-23 14:21:18 -0700110#define RETURN_ERROR(errorNum, retType, ...) { \
George Lu20f4f322018-06-12 15:54:43 -0400111 retType r; \
112 memset(&r, 0, sizeof(retType)); \
113 DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
114 DISPLAYLEVEL(1, "Error %i : ", errorNum); \
115 DISPLAYLEVEL(1, __VA_ARGS__); \
116 DISPLAYLEVEL(1, " \n"); \
Yann Collet2e45bad2018-08-23 14:21:18 -0700117 r.tag = errorNum; \
George Lu20f4f322018-06-12 15:54:43 -0400118 return r; \
119}
Yann Collet4856a002015-01-24 01:58:16 +0100120
George Lu0d1ee222018-06-15 16:21:08 -0400121
Yann Colletf3eca252015-10-22 15:31:46 +0100122/* *************************************
Yann Collet4856a002015-01-24 01:58:16 +0100123* Benchmark Parameters
Yann Colletf3eca252015-10-22 15:31:46 +0100124***************************************/
Stella Laua1f04d52017-09-01 14:52:51 -0700125
Yann Collet77e805e2018-08-21 18:19:27 -0700126BMK_advancedParams_t BMK_initAdvancedParams(void) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700127 BMK_advancedParams_t const res = {
George Lu85223462018-06-14 14:46:17 -0400128 BMK_both, /* mode */
George Lu20f4f322018-06-12 15:54:43 -0400129 BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
130 0, /* blockSize */
131 0, /* nbWorkers */
132 0, /* realTime */
George Lu20f4f322018-06-12 15:54:43 -0400133 0, /* additionalParam */
Yann Collet77e805e2018-08-21 18:19:27 -0700134 0, /* ldmFlag */
George Lu20f4f322018-06-12 15:54:43 -0400135 0, /* ldmMinMatch */
136 0, /* ldmHashLog */
George Lud6121ad2018-06-22 17:25:16 -0700137 0, /* ldmBuckSizeLog */
Nick Terrell19ca3fb2019-02-15 15:24:55 -0800138 0, /* ldmHashRateLog */
senhuang42b5c35d72021-09-20 09:04:07 -0400139 ZSTD_ps_auto, /* literalCompressionMode */
Nick Terrell46944232020-11-02 17:52:29 -0800140 0 /* useRowMatchFinder */
George Lu20f4f322018-06-12 15:54:43 -0400141 };
142 return res;
Stella Lau67d4a612017-09-02 21:10:36 -0700143}
144
Yann Collet4856a002015-01-24 01:58:16 +0100145
Yann Colletf3eca252015-10-22 15:31:46 +0100146/* ********************************************************
Yann Collet4856a002015-01-24 01:58:16 +0100147* Bench functions
Yann Colletf3eca252015-10-22 15:31:46 +0100148**********************************************************/
Yann Colletd9465012016-12-06 16:49:23 -0800149typedef struct {
150 const void* srcPtr;
Yann Collet1c00dc32015-10-21 08:22:25 +0100151 size_t srcSize;
Yann Colletd9465012016-12-06 16:49:23 -0800152 void* cPtr;
Yann Collet1c00dc32015-10-21 08:22:25 +0100153 size_t cRoom;
154 size_t cSize;
Yann Colletd9465012016-12-06 16:49:23 -0800155 void* resPtr;
Yann Collet1c00dc32015-10-21 08:22:25 +0100156 size_t resSize;
157} blockParam_t;
158
Sean Purcell42bac7f2017-04-13 15:35:05 -0700159#undef MIN
160#undef MAX
161#define MIN(a,b) ((a) < (b) ? (a) : (b))
162#define MAX(a,b) ((a) > (b) ? (a) : (b))
Yann Collet1c00dc32015-10-21 08:22:25 +0100163
Yann Colletb8701102019-01-25 15:11:50 -0800164static void
165BMK_initCCtx(ZSTD_CCtx* ctx,
166 const void* dictBuffer, size_t dictBufferSize,
167 int cLevel,
168 const ZSTD_compressionParameters* comprParams,
169 const BMK_advancedParams_t* adv)
170{
Yann Collet5c686392018-11-15 16:12:39 -0800171 ZSTD_CCtx_reset(ctx, ZSTD_reset_session_and_parameters);
George Lu20f4f322018-06-12 15:54:43 -0400172 if (adv->nbWorkers==1) {
Yann Colletd613fd92018-12-06 19:27:37 -0800173 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, 0));
George Lu20f4f322018-06-12 15:54:43 -0400174 } else {
Yann Colletd613fd92018-12-06 19:27:37 -0800175 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, adv->nbWorkers));
George Lu20f4f322018-06-12 15:54:43 -0400176 }
Yann Colletd613fd92018-12-06 19:27:37 -0800177 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, cLevel));
Nick Terrell46944232020-11-02 17:52:29 -0800178 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_useRowMatchFinder, adv->useRowMatchFinder));
Yann Colletd613fd92018-12-06 19:27:37 -0800179 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_enableLongDistanceMatching, adv->ldmFlag));
180 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmMinMatch, adv->ldmMinMatch));
181 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashLog, adv->ldmHashLog));
182 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmBucketSizeLog, adv->ldmBucketSizeLog));
183 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog));
Yann Colletb8701102019-01-25 15:11:50 -0800184 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_windowLog, (int)comprParams->windowLog));
185 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_hashLog, (int)comprParams->hashLog));
186 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_chainLog, (int)comprParams->chainLog));
187 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_searchLog, (int)comprParams->searchLog));
188 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_minMatch, (int)comprParams->minMatch));
189 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_targetLength, (int)comprParams->targetLength));
Nick Terrell19ca3fb2019-02-15 15:24:55 -0800190 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_literalCompressionMode, (int)adv->literalCompressionMode));
Yann Colleteab69222021-09-03 12:51:02 -0700191 CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_strategy, (int)comprParams->strategy));
Yann Colletd613fd92018-12-06 19:27:37 -0800192 CHECK_Z(ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize));
George Lu20f4f322018-06-12 15:54:43 -0400193}
194
Yann Collet77e805e2018-08-21 18:19:27 -0700195static void BMK_initDCtx(ZSTD_DCtx* dctx,
George Lu20f4f322018-06-12 15:54:43 -0400196 const void* dictBuffer, size_t dictBufferSize) {
Yann Colletd613fd92018-12-06 19:27:37 -0800197 CHECK_Z(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
198 CHECK_Z(ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize));
George Lu20f4f322018-06-12 15:54:43 -0400199}
200
Yann Collet2e45bad2018-08-23 14:21:18 -0700201
George Lu20f4f322018-06-12 15:54:43 -0400202typedef struct {
Yann Collet2e45bad2018-08-23 14:21:18 -0700203 ZSTD_CCtx* cctx;
George Lu20f4f322018-06-12 15:54:43 -0400204 const void* dictBuffer;
205 size_t dictBufferSize;
206 int cLevel;
207 const ZSTD_compressionParameters* comprParams;
208 const BMK_advancedParams_t* adv;
209} BMK_initCCtxArgs;
210
211static size_t local_initCCtx(void* payload) {
212 BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)payload;
Yann Collet2e45bad2018-08-23 14:21:18 -0700213 BMK_initCCtx(ag->cctx, ag->dictBuffer, ag->dictBufferSize, ag->cLevel, ag->comprParams, ag->adv);
George Lu20f4f322018-06-12 15:54:43 -0400214 return 0;
215}
216
217typedef struct {
218 ZSTD_DCtx* dctx;
219 const void* dictBuffer;
220 size_t dictBufferSize;
221} BMK_initDCtxArgs;
222
223static size_t local_initDCtx(void* payload) {
224 BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload;
225 BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize);
226 return 0;
227}
228
Yann Collet2e45bad2018-08-23 14:21:18 -0700229
230/* `addArgs` is the context */
George Lu20f4f322018-06-12 15:54:43 -0400231static size_t local_defaultCompress(
Yann Collet2e45bad2018-08-23 14:21:18 -0700232 const void* srcBuffer, size_t srcSize,
233 void* dstBuffer, size_t dstSize,
234 void* addArgs)
235{
Yann Collet2e45bad2018-08-23 14:21:18 -0700236 ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
Yann Colletd8e215c2018-11-30 11:16:26 -0800237 return ZSTD_compress2(cctx, dstBuffer, dstSize, srcBuffer, srcSize);
George Lu20f4f322018-06-12 15:54:43 -0400238}
239
Yann Collet2e45bad2018-08-23 14:21:18 -0700240/* `addArgs` is the context */
George Lu20f4f322018-06-12 15:54:43 -0400241static size_t local_defaultDecompress(
Yann Collet2e45bad2018-08-23 14:21:18 -0700242 const void* srcBuffer, size_t srcSize,
Yann Collet0c66a442018-08-28 15:47:07 -0700243 void* dstBuffer, size_t dstCapacity,
Yann Collet2e45bad2018-08-23 14:21:18 -0700244 void* addArgs)
245{
George Lu20f4f322018-06-12 15:54:43 -0400246 size_t moreToFlush = 1;
Yann Collet2e45bad2018-08-23 14:21:18 -0700247 ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs;
George Lu20f4f322018-06-12 15:54:43 -0400248 ZSTD_inBuffer in;
249 ZSTD_outBuffer out;
Yann Collet2e45bad2018-08-23 14:21:18 -0700250 in.src = srcBuffer; in.size = srcSize; in.pos = 0;
Yann Collet0c66a442018-08-28 15:47:07 -0700251 out.dst = dstBuffer; out.size = dstCapacity; out.pos = 0;
George Lu20f4f322018-06-12 15:54:43 -0400252 while (moreToFlush) {
George Lud6121ad2018-06-22 17:25:16 -0700253 if(out.pos == out.size) {
254 return (size_t)-ZSTD_error_dstSize_tooSmall;
255 }
Yann Collet34e146f2018-12-04 10:28:36 -0800256 moreToFlush = ZSTD_decompressStream(dctx, &out, &in);
George Lu20f4f322018-06-12 15:54:43 -0400257 if (ZSTD_isError(moreToFlush)) {
258 return moreToFlush;
259 }
260 }
261 return out.pos;
262
263}
264
Yann Collet2e45bad2018-08-23 14:21:18 -0700265
Yann Collet2e45bad2018-08-23 14:21:18 -0700266/* ================================================================= */
267/* Benchmark Zstandard, mem-to-mem scenarios */
268/* ================================================================= */
269
270int BMK_isSuccessful_benchOutcome(BMK_benchOutcome_t outcome)
271{
272 return outcome.tag == 0;
273}
274
275BMK_benchResult_t BMK_extract_benchResult(BMK_benchOutcome_t outcome)
276{
277 assert(outcome.tag == 0);
278 return outcome.internal_never_use_directly;
279}
280
Yann Collet6ce7b082018-08-24 15:59:57 -0700281static BMK_benchOutcome_t BMK_benchOutcome_error(void)
Yann Collet2e45bad2018-08-23 14:21:18 -0700282{
283 BMK_benchOutcome_t b;
284 memset(&b, 0, sizeof(b));
285 b.tag = 1;
286 return b;
287}
288
289static BMK_benchOutcome_t BMK_benchOutcome_setValidResult(BMK_benchResult_t result)
290{
291 BMK_benchOutcome_t b;
292 b.tag = 0;
293 b.internal_never_use_directly = result;
294 return b;
295}
296
297
298/* benchMem with no allocation */
Yann Collet8bed4012018-11-08 12:36:39 -0800299static BMK_benchOutcome_t
300BMK_benchMemAdvancedNoAlloc(
301 const void** srcPtrs, size_t* srcSizes,
302 void** cPtrs, size_t* cCapacities, size_t* cSizes,
303 void** resPtrs, size_t* resSizes,
304 void** resultBufferPtr, void* compressedBuffer,
305 size_t maxCompressedSize,
306 BMK_timedFnState_t* timeStateCompress,
307 BMK_timedFnState_t* timeStateDecompress,
Yann Collet2e45bad2018-08-23 14:21:18 -0700308
Yann Collet8bed4012018-11-08 12:36:39 -0800309 const void* srcBuffer, size_t srcSize,
310 const size_t* fileSizes, unsigned nbFiles,
311 const int cLevel,
312 const ZSTD_compressionParameters* comprParams,
313 const void* dictBuffer, size_t dictBufferSize,
314 ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
315 int displayLevel, const char* displayName,
316 const BMK_advancedParams_t* adv)
Yann Collet1c00dc32015-10-21 08:22:25 +0100317{
Yann Collet4da5bdf2018-08-23 18:04:50 -0700318 size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize); /* avoid div by 0 */
Yann Collet2e45bad2018-08-23 14:21:18 -0700319 BMK_benchResult_t benchResult;
Yann Collete63c6312016-12-06 17:46:49 -0800320 size_t const loadedCompressedSize = srcSize;
321 size_t cSize = 0;
322 double ratio = 0.;
Yann Colletde406ee2016-03-20 15:46:10 +0100323 U32 nbBlocks;
324
Yann Collet2e45bad2018-08-23 14:21:18 -0700325 assert(cctx != NULL); assert(dctx != NULL);
George Lu01d940b2018-06-11 10:59:05 -0400326
Yann Colletc776c462015-10-29 19:10:54 +0100327 /* init */
Yann Collet4da5bdf2018-08-23 18:04:50 -0700328 memset(&benchResult, 0, sizeof(benchResult));
Yann Collet2e45bad2018-08-23 14:21:18 -0700329 if (strlen(displayName)>17) displayName += strlen(displayName) - 17; /* display last 17 characters */
Elliott Hughes44aba642023-09-12 20:18:59 +0000330 if (adv->mode == BMK_decodeOnly) {
331 /* benchmark only decompression : source must be already compressed */
Yann Colletc2007382017-04-04 15:35:06 -0700332 const char* srcPtr = (const char*)srcBuffer;
333 U64 totalDSize64 = 0;
Yann Collete63c6312016-12-06 17:46:49 -0800334 U32 fileNb;
335 for (fileNb=0; fileNb<nbFiles; fileNb++) {
Sean Purcell4e709712017-02-07 13:50:09 -0800336 U64 const fSize64 = ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
Elliott Hughes44aba642023-09-12 20:18:59 +0000337 if (fSize64 == ZSTD_CONTENTSIZE_UNKNOWN) {
338 RETURN_ERROR(32, BMK_benchOutcome_t, "Decompressed size cannot be determined: cannot benchmark");
339 }
340 if (fSize64 == ZSTD_CONTENTSIZE_ERROR) {
341 RETURN_ERROR(32, BMK_benchOutcome_t, "Error while trying to assess decompressed size: data may be invalid");
342 }
Yann Colletc2007382017-04-04 15:35:06 -0700343 totalDSize64 += fSize64;
Yann Collete63c6312016-12-06 17:46:49 -0800344 srcPtr += fileSizes[fileNb];
345 }
Yann Colletc2007382017-04-04 15:35:06 -0700346 { size_t const decodedSize = (size_t)totalDSize64;
Yann Collet2e45bad2018-08-23 14:21:18 -0700347 assert((U64)decodedSize == totalDSize64); /* check overflow */
George Lu5f490342018-06-18 11:59:45 -0700348 free(*resultBufferPtr);
Elliott Hughes44aba642023-09-12 20:18:59 +0000349 if (totalDSize64 > decodedSize) { /* size_t overflow */
350 RETURN_ERROR(32, BMK_benchOutcome_t, "decompressed size is too large for local system");
351 }
George Lu5f490342018-06-18 11:59:45 -0700352 *resultBufferPtr = malloc(decodedSize);
353 if (!(*resultBufferPtr)) {
Elliott Hughes44aba642023-09-12 20:18:59 +0000354 RETURN_ERROR(33, BMK_benchOutcome_t, "allocation error: not enough memory");
George Lua8eea992018-06-19 10:58:22 -0700355 }
Yann Collete63c6312016-12-06 17:46:49 -0800356 cSize = srcSize;
357 srcSize = decodedSize;
358 ratio = (double)srcSize / (double)cSize;
Yann Collet77e805e2018-08-21 18:19:27 -0700359 }
George Lu20f4f322018-06-12 15:54:43 -0400360 }
Yann Collete63c6312016-12-06 17:46:49 -0800361
George Lu20f4f322018-06-12 15:54:43 -0400362 /* Init data blocks */
Yann Collete63c6312016-12-06 17:46:49 -0800363 { const char* srcPtr = (const char*)srcBuffer;
Yann Collet1c00dc32015-10-21 08:22:25 +0100364 char* cPtr = (char*)compressedBuffer;
George Lu5f490342018-06-18 11:59:45 -0700365 char* resPtr = (char*)(*resultBufferPtr);
Yann Collet699b14d2016-03-17 19:37:33 +0100366 U32 fileNb;
Yann Colletde406ee2016-03-20 15:46:10 +0100367 for (nbBlocks=0, fileNb=0; fileNb<nbFiles; fileNb++) {
Yann Collet70611352015-12-16 03:01:03 +0100368 size_t remaining = fileSizes[fileNb];
George Lu85223462018-06-14 14:46:17 -0400369 U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly) ? 1 : (U32)((remaining + (blockSize-1)) / blockSize);
Yann Collet699b14d2016-03-17 19:37:33 +0100370 U32 const blockEnd = nbBlocks + nbBlocksforThisFile;
Yann Colletfd416f12016-01-30 03:14:15 +0100371 for ( ; nbBlocks<blockEnd; nbBlocks++) {
Yann Colletde406ee2016-03-20 15:46:10 +0100372 size_t const thisBlockSize = MIN(remaining, blockSize);
Yann Collet2e45bad2018-08-23 14:21:18 -0700373 srcPtrs[nbBlocks] = srcPtr;
George Lu20f4f322018-06-12 15:54:43 -0400374 srcSizes[nbBlocks] = thisBlockSize;
Yann Collet2e45bad2018-08-23 14:21:18 -0700375 cPtrs[nbBlocks] = cPtr;
George Lue148db32018-07-20 14:35:09 -0700376 cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly) ? thisBlockSize : ZSTD_compressBound(thisBlockSize);
Yann Collet2e45bad2018-08-23 14:21:18 -0700377 resPtrs[nbBlocks] = resPtr;
George Lu85223462018-06-14 14:46:17 -0400378 resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly) ? (size_t) ZSTD_findDecompressedSize(srcPtr, thisBlockSize) : thisBlockSize;
Yann Colleted699e62015-12-16 02:37:24 +0100379 srcPtr += thisBlockSize;
George Lue148db32018-07-20 14:35:09 -0700380 cPtr += cCapacities[nbBlocks];
Yann Colleted699e62015-12-16 02:37:24 +0100381 resPtr += thisBlockSize;
382 remaining -= thisBlockSize;
Yann Collet3ba0d6d2018-11-13 14:15:12 -0800383 if (adv->mode == BMK_decodeOnly) {
Yann Collet9126da52018-11-08 12:47:46 -0800384 cSizes[nbBlocks] = thisBlockSize;
385 benchResult.cSize = thisBlockSize;
Yann Collet640c5b12021-09-12 01:36:18 -0700386 } } } }
Yann Collet1c00dc32015-10-21 08:22:25 +0100387
Josh Sorefa880ca22019-04-12 14:18:11 -0400388 /* warming up `compressedBuffer` */
George Lu85223462018-06-14 14:46:17 -0400389 if (adv->mode == BMK_decodeOnly) {
Yann Collet03e7e142018-03-05 13:50:07 -0800390 memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
391 } else {
392 RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
393 }
Yann Collet4856a002015-01-24 01:58:16 +0100394
Elliott Hughes44aba642023-09-12 20:18:59 +0000395 if (!UTIL_support_MT_measurements() && adv->nbWorkers > 1) {
396 OUTPUTLEVEL(2, "Warning : time measurements may be incorrect in multithreading mode... \n")
397 }
398
Yann Collet4856a002015-01-24 01:58:16 +0100399 /* Bench */
Yann Collet2e45bad2018-08-23 14:21:18 -0700400 { U64 const crcOrig = (adv->mode == BMK_decodeOnly) ? 0 : XXH64(srcBuffer, srcSize, 0);
Yann Colleta9febe82016-08-01 13:37:17 +0200401# define NB_MARKS 4
Yann Collet2e45bad2018-08-23 14:21:18 -0700402 const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
Yann Colleta9febe82016-08-01 13:37:17 +0200403 U32 markNb = 0;
Yann Collet2e45bad2018-08-23 14:21:18 -0700404 int compressionCompleted = (adv->mode == BMK_decodeOnly);
405 int decompressionCompleted = (adv->mode == BMK_compressOnly);
Yann Colletb830ccc2018-11-13 13:05:39 -0800406 BMK_benchParams_t cbp, dbp;
Yann Collet2e45bad2018-08-23 14:21:18 -0700407 BMK_initCCtxArgs cctxprep;
408 BMK_initDCtxArgs dctxprep;
Yann Colletb830ccc2018-11-13 13:05:39 -0800409
Yann Collet6309be62019-10-15 16:09:18 -0700410 cbp.benchFn = local_defaultCompress; /* ZSTD_compress2 */
Yann Colletb830ccc2018-11-13 13:05:39 -0800411 cbp.benchPayload = cctx;
Yann Collet6309be62019-10-15 16:09:18 -0700412 cbp.initFn = local_initCCtx; /* BMK_initCCtx */
Yann Colletb830ccc2018-11-13 13:05:39 -0800413 cbp.initPayload = &cctxprep;
414 cbp.errorFn = ZSTD_isError;
415 cbp.blockCount = nbBlocks;
416 cbp.srcBuffers = srcPtrs;
417 cbp.srcSizes = srcSizes;
418 cbp.dstBuffers = cPtrs;
419 cbp.dstCapacities = cCapacities;
420 cbp.blockResults = cSizes;
421
Yann Collet2e45bad2018-08-23 14:21:18 -0700422 cctxprep.cctx = cctx;
423 cctxprep.dictBuffer = dictBuffer;
424 cctxprep.dictBufferSize = dictBufferSize;
425 cctxprep.cLevel = cLevel;
426 cctxprep.comprParams = comprParams;
427 cctxprep.adv = adv;
Yann Colletb830ccc2018-11-13 13:05:39 -0800428
429 dbp.benchFn = local_defaultDecompress;
430 dbp.benchPayload = dctx;
431 dbp.initFn = local_initDCtx;
432 dbp.initPayload = &dctxprep;
433 dbp.errorFn = ZSTD_isError;
434 dbp.blockCount = nbBlocks;
435 dbp.srcBuffers = (const void* const *) cPtrs;
436 dbp.srcSizes = cSizes;
437 dbp.dstBuffers = resPtrs;
438 dbp.dstCapacities = resSizes;
439 dbp.blockResults = NULL;
440
Yann Collet2e45bad2018-08-23 14:21:18 -0700441 dctxprep.dctx = dctx;
442 dctxprep.dictBuffer = dictBuffer;
443 dctxprep.dictBufferSize = dictBufferSize;
Yann Collet4856a002015-01-24 01:58:16 +0100444
Yann Collet08ceda32021-09-04 00:52:44 -0700445 OUTPUTLEVEL(2, "\r%70s\r", ""); /* blank line */
Yann Colleteab69222021-09-03 12:51:02 -0700446 assert(srcSize < UINT_MAX);
Yann Collet08ceda32021-09-04 00:52:44 -0700447 OUTPUTLEVEL(2, "%2s-%-17.17s :%10u -> \r", marks[markNb], displayName, (unsigned)srcSize);
George Lu50d612f2018-06-25 15:01:03 -0700448
Yann Collet2e45bad2018-08-23 14:21:18 -0700449 while (!(compressionCompleted && decompressionCompleted)) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700450 if (!compressionCompleted) {
Yann Colletb830ccc2018-11-13 13:05:39 -0800451 BMK_runOutcome_t const cOutcome = BMK_benchTimedFn( timeStateCompress, cbp);
Yann Collet2e45bad2018-08-23 14:21:18 -0700452
Yann Collet2279f3d2018-08-24 17:28:38 -0700453 if (!BMK_isSuccessful_runOutcome(cOutcome)) {
Elliott Hughes44aba642023-09-12 20:18:59 +0000454 RETURN_ERROR(30, BMK_benchOutcome_t, "compression error");
George Lu50d612f2018-06-25 15:01:03 -0700455 }
456
Yann Collet2279f3d2018-08-24 17:28:38 -0700457 { BMK_runTime_t const cResult = BMK_extract_runTime(cOutcome);
Yann Collet4da5bdf2018-08-23 18:04:50 -0700458 cSize = cResult.sumOfReturn;
Yann Colleteab69222021-09-03 12:51:02 -0700459 ratio = (double)srcSize / (double)cSize;
Yann Collet4da5bdf2018-08-23 18:04:50 -0700460 { BMK_benchResult_t newResult;
Yann Colletb8701102019-01-25 15:11:50 -0800461 newResult.cSpeed = (U64)((double)srcSize * TIMELOOP_NANOSEC / cResult.nanoSecPerRun);
Yann Collet4da5bdf2018-08-23 18:04:50 -0700462 benchResult.cSize = cSize;
463 if (newResult.cSpeed > benchResult.cSpeed)
464 benchResult.cSpeed = newResult.cSpeed;
465 } }
George Lu5f490342018-06-18 11:59:45 -0700466
Yann Collet2e45bad2018-08-23 14:21:18 -0700467 { int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
Yann Colleteab69222021-09-03 12:51:02 -0700468 assert(cSize < UINT_MAX);
Yann Collet23dd28d2021-10-26 23:23:30 -0700469 OUTPUTLEVEL(2, "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s \r",
Yann Collet4da5bdf2018-08-23 18:04:50 -0700470 marks[markNb], displayName,
Yann Colleteab69222021-09-03 12:51:02 -0700471 (unsigned)srcSize, (unsigned)cSize,
Yann Collet2e45bad2018-08-23 14:21:18 -0700472 ratioAccuracy, ratio,
Yann Collet23dd28d2021-10-26 23:23:30 -0700473 benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT);
George Lua8eea992018-06-19 10:58:22 -0700474 }
Yann Collet01dcd0f2018-08-26 21:30:18 -0700475 compressionCompleted = BMK_isCompleted_TimedFn(timeStateCompress);
Yann Collet2e45bad2018-08-23 14:21:18 -0700476 }
George Lue89f1fb2018-08-14 14:44:47 -0700477
Yann Collet2e45bad2018-08-23 14:21:18 -0700478 if(!decompressionCompleted) {
Yann Colletb830ccc2018-11-13 13:05:39 -0800479 BMK_runOutcome_t const dOutcome = BMK_benchTimedFn(timeStateDecompress, dbp);
Yann Collet2e45bad2018-08-23 14:21:18 -0700480
Yann Collet2279f3d2018-08-24 17:28:38 -0700481 if(!BMK_isSuccessful_runOutcome(dOutcome)) {
Elliott Hughes44aba642023-09-12 20:18:59 +0000482 RETURN_ERROR(30, BMK_benchOutcome_t, "decompression error");
Yann Collet2e45bad2018-08-23 14:21:18 -0700483 }
484
Yann Collet2279f3d2018-08-24 17:28:38 -0700485 { BMK_runTime_t const dResult = BMK_extract_runTime(dOutcome);
Yann Colletb8701102019-01-25 15:11:50 -0800486 U64 const newDSpeed = (U64)((double)srcSize * TIMELOOP_NANOSEC / dResult.nanoSecPerRun);
Yann Collet4da5bdf2018-08-23 18:04:50 -0700487 if (newDSpeed > benchResult.dSpeed)
488 benchResult.dSpeed = newDSpeed;
489 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700490
491 { int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
Yann Collet23dd28d2021-10-26 23:23:30 -0700492 OUTPUTLEVEL(2, "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s, %6.1f MB/s\r",
Yann Collet4da5bdf2018-08-23 18:04:50 -0700493 marks[markNb], displayName,
Yann Colleteab69222021-09-03 12:51:02 -0700494 (unsigned)srcSize, (unsigned)cSize,
Yann Collet2e45bad2018-08-23 14:21:18 -0700495 ratioAccuracy, ratio,
Yann Collet23dd28d2021-10-26 23:23:30 -0700496 benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT,
Yann Collet4da5bdf2018-08-23 18:04:50 -0700497 (double)benchResult.dSpeed / MB_UNIT);
George Lua8eea992018-06-19 10:58:22 -0700498 }
Yann Collet01dcd0f2018-08-26 21:30:18 -0700499 decompressionCompleted = BMK_isCompleted_TimedFn(timeStateDecompress);
Yann Colletdaebc7f2017-11-18 15:54:32 -0800500 }
Yann Collet8bed4012018-11-08 12:36:39 -0800501 markNb = (markNb+1) % NB_MARKS;
Yann Collet4da5bdf2018-08-23 18:04:50 -0700502 } /* while (!(compressionCompleted && decompressionCompleted)) */
George Lu20f4f322018-06-12 15:54:43 -0400503
504 /* CRC Checking */
Yann Collet2e45bad2018-08-23 14:21:18 -0700505 { const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
George Lu5f490342018-06-18 11:59:45 -0700506 U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
George Lu85223462018-06-14 14:46:17 -0400507 if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) {
George Lu20f4f322018-06-12 15:54:43 -0400508 size_t u;
Yann Collet8bed4012018-11-08 12:36:39 -0800509 DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n",
510 displayName, (unsigned)crcOrig, (unsigned)crcCheck);
George Lu20f4f322018-06-12 15:54:43 -0400511 for (u=0; u<srcSize; u++) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700512 if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) {
Yann Colletededcfc2018-12-21 16:19:44 -0800513 unsigned segNb, bNb, pos;
George Lu20f4f322018-06-12 15:54:43 -0400514 size_t bacc = 0;
Yann Colletededcfc2018-12-21 16:19:44 -0800515 DISPLAY("Decoding error at pos %u ", (unsigned)u);
George Lu20f4f322018-06-12 15:54:43 -0400516 for (segNb = 0; segNb < nbBlocks; segNb++) {
517 if (bacc + srcSizes[segNb] > u) break;
518 bacc += srcSizes[segNb];
519 }
520 pos = (U32)(u - bacc);
521 bNb = pos / (128 KB);
522 DISPLAY("(sample %u, block %u, pos %u) \n", segNb, bNb, pos);
Yann Colletb8701102019-01-25 15:11:50 -0800523 { size_t const lowest = (u>5) ? 5 : u;
524 size_t n;
George Lu20f4f322018-06-12 15:54:43 -0400525 DISPLAY("origin: ");
Yann Colletb8701102019-01-25 15:11:50 -0800526 for (n=lowest; n>0; n--)
527 DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u-n]);
George Lu20f4f322018-06-12 15:54:43 -0400528 DISPLAY(" :%02X: ", ((const BYTE*)srcBuffer)[u]);
Yann Colletb8701102019-01-25 15:11:50 -0800529 for (n=1; n<3; n++)
530 DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
George Lu20f4f322018-06-12 15:54:43 -0400531 DISPLAY(" \n");
532 DISPLAY("decode: ");
W. Felix Handteab8aa492021-08-17 11:31:15 -0400533 for (n=lowest; n>0; n--)
Yann Colletb8701102019-01-25 15:11:50 -0800534 DISPLAY("%02X ", resultBuffer[u-n]);
Yann Collet2e45bad2018-08-23 14:21:18 -0700535 DISPLAY(" :%02X: ", resultBuffer[u]);
Yann Colletb8701102019-01-25 15:11:50 -0800536 for (n=1; n<3; n++)
537 DISPLAY("%02X ", resultBuffer[u+n]);
George Lu20f4f322018-06-12 15:54:43 -0400538 DISPLAY(" \n");
539 }
540 break;
541 }
542 if (u==srcSize-1) { /* should never happen */
543 DISPLAY("no difference detected\n");
Yann Collet77e805e2018-08-21 18:19:27 -0700544 }
Yann Collet6309be62019-10-15 16:09:18 -0700545 } /* for (u=0; u<srcSize; u++) */
546 } /* if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) */
George Lu20f4f322018-06-12 15:54:43 -0400547 } /* CRC Checking */
548
Yann Collet2e45bad2018-08-23 14:21:18 -0700549 if (displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
Yann Collet1f9ec132018-08-23 16:03:30 -0700550 double const cSpeed = (double)benchResult.cSpeed / MB_UNIT;
551 double const dSpeed = (double)benchResult.dSpeed / MB_UNIT;
Yann Collet2e45bad2018-08-23 14:21:18 -0700552 if (adv->additionalParam) {
Yann Collet08ceda32021-09-04 00:52:44 -0700553 OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, adv->additionalParam);
Yann Collet2e45bad2018-08-23 14:21:18 -0700554 } else {
Yann Collet08ceda32021-09-04 00:52:44 -0700555 OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName);
Yann Collet2e45bad2018-08-23 14:21:18 -0700556 }
George Luab26f242018-06-21 11:16:53 -0700557 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700558
Yann Collet08ceda32021-09-04 00:52:44 -0700559 OUTPUTLEVEL(2, "%2i#\n", cLevel);
George Lu85223462018-06-14 14:46:17 -0400560 } /* Bench */
Yann Collet2e45bad2018-08-23 14:21:18 -0700561
562 benchResult.cMem = (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
563 return BMK_benchOutcome_setValidResult(benchResult);
George Lua8eea992018-06-19 10:58:22 -0700564}
Yann Collet4856a002015-01-24 01:58:16 +0100565
Yann Collet2e45bad2018-08-23 14:21:18 -0700566BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
Yann Collet77e805e2018-08-21 18:19:27 -0700567 void* dstBuffer, size_t dstCapacity,
George Lua8eea992018-06-19 10:58:22 -0700568 const size_t* fileSizes, unsigned nbFiles,
Yann Collet6ce7b082018-08-24 15:59:57 -0700569 int cLevel, const ZSTD_compressionParameters* comprParams,
George Lua8eea992018-06-19 10:58:22 -0700570 const void* dictBuffer, size_t dictBufferSize,
George Lua8eea992018-06-19 10:58:22 -0700571 int displayLevel, const char* displayName, const BMK_advancedParams_t* adv)
572
573{
Yann Collet2e45bad2018-08-23 14:21:18 -0700574 int const dstParamsError = !dstBuffer ^ !dstCapacity; /* must be both NULL or none */
575
George Lua8eea992018-06-19 10:58:22 -0700576 size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ;
577 U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles;
578
579 /* these are the blockTable parameters, just split up */
George Ludd270b22018-07-27 08:49:25 -0700580 const void ** const srcPtrs = (const void**)malloc(maxNbBlocks * sizeof(void*));
581 size_t* const srcSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
George Lua8eea992018-06-19 10:58:22 -0700582
George Lue148db32018-07-20 14:35:09 -0700583
George Ludd270b22018-07-27 08:49:25 -0700584 void ** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
585 size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
586 size_t* const cCapacities = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
George Lua8eea992018-06-19 10:58:22 -0700587
George Ludd270b22018-07-27 08:49:25 -0700588 void ** const resPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
589 size_t* const resSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
George Lua8eea992018-06-19 10:58:22 -0700590
Yann Collet55affc02018-08-28 11:21:09 -0700591 BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
592 BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
George Lud6121ad2018-06-22 17:25:16 -0700593
Yann Collet2e45bad2018-08-23 14:21:18 -0700594 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
595 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
George Lubfe83922018-08-09 12:07:57 -0700596
George Lu5f490342018-06-18 11:59:45 -0700597 const size_t maxCompressedSize = dstCapacity ? dstCapacity : ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024);
George Ludd270b22018-07-27 08:49:25 -0700598
599 void* const internalDstBuffer = dstBuffer ? NULL : malloc(maxCompressedSize);
600 void* const compressedBuffer = dstBuffer ? dstBuffer : internalDstBuffer;
601
Yann Collet2e45bad2018-08-23 14:21:18 -0700602 BMK_benchOutcome_t outcome = BMK_benchOutcome_error(); /* error by default */
George Lue89f1fb2018-08-14 14:44:47 -0700603
604 void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
605
Elliott Hughes44aba642023-09-12 20:18:59 +0000606 int const allocationincomplete = !srcPtrs || !srcSizes || !cPtrs ||
Yann Collet77e805e2018-08-21 18:19:27 -0700607 !cSizes || !cCapacities || !resPtrs || !resSizes ||
Yann Collet2e45bad2018-08-23 14:21:18 -0700608 !timeStateCompress || !timeStateDecompress ||
609 !cctx || !dctx ||
610 !compressedBuffer || !resultBuffer;
George Lu5f490342018-06-18 11:59:45 -0700611
George Lu5f490342018-06-18 11:59:45 -0700612
Yann Collet2e45bad2018-08-23 14:21:18 -0700613 if (!allocationincomplete && !dstParamsError) {
614 outcome = BMK_benchMemAdvancedNoAlloc(srcPtrs, srcSizes,
615 cPtrs, cCapacities, cSizes,
616 resPtrs, resSizes,
617 &resultBuffer,
618 compressedBuffer, maxCompressedSize,
619 timeStateCompress, timeStateDecompress,
620 srcBuffer, srcSize,
621 fileSizes, nbFiles,
622 cLevel, comprParams,
623 dictBuffer, dictBufferSize,
624 cctx, dctx,
625 displayLevel, displayName, adv);
George Lua8eea992018-06-19 10:58:22 -0700626 }
Yann Collet77e805e2018-08-21 18:19:27 -0700627
Yann Colleted699e62015-12-16 02:37:24 +0100628 /* clean up */
Yann Collet77e805e2018-08-21 18:19:27 -0700629 BMK_freeTimedFnState(timeStateCompress);
630 BMK_freeTimedFnState(timeStateDecompress);
631
Yann Collet2e45bad2018-08-23 14:21:18 -0700632 ZSTD_freeCCtx(cctx);
George Lubfe83922018-08-09 12:07:57 -0700633 ZSTD_freeDCtx(dctx);
634
George Ludd270b22018-07-27 08:49:25 -0700635 free(internalDstBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100636 free(resultBuffer);
George Lu20f4f322018-06-12 15:54:43 -0400637
Yann Collet77e805e2018-08-21 18:19:27 -0700638 free((void*)srcPtrs);
639 free(srcSizes);
640 free(cPtrs);
George Lu20f4f322018-06-12 15:54:43 -0400641 free(cSizes);
George Lue148db32018-07-20 14:35:09 -0700642 free(cCapacities);
George Lu20f4f322018-06-12 15:54:43 -0400643 free(resPtrs);
644 free(resSizes);
645
George Lua8eea992018-06-19 10:58:22 -0700646 if(allocationincomplete) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700647 RETURN_ERROR(31, BMK_benchOutcome_t, "allocation error : not enough memory");
George Lua8eea992018-06-19 10:58:22 -0700648 }
Yann Collet77e805e2018-08-21 18:19:27 -0700649
Yann Collet2e45bad2018-08-23 14:21:18 -0700650 if(dstParamsError) {
651 RETURN_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
George Ludd270b22018-07-27 08:49:25 -0700652 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700653 return outcome;
Yann Collet4856a002015-01-24 01:58:16 +0100654}
655
Yann Collet2e45bad2018-08-23 14:21:18 -0700656BMK_benchOutcome_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
George Lu20f4f322018-06-12 15:54:43 -0400657 const size_t* fileSizes, unsigned nbFiles,
Yann Collet2e45bad2018-08-23 14:21:18 -0700658 int cLevel, const ZSTD_compressionParameters* comprParams,
George Lu20f4f322018-06-12 15:54:43 -0400659 const void* dictBuffer, size_t dictBufferSize,
George Lu20f4f322018-06-12 15:54:43 -0400660 int displayLevel, const char* displayName) {
661
Yann Collet2e45bad2018-08-23 14:21:18 -0700662 BMK_advancedParams_t const adv = BMK_initAdvancedParams();
George Lu20f4f322018-06-12 15:54:43 -0400663 return BMK_benchMemAdvanced(srcBuffer, srcSize,
George Lu5f490342018-06-18 11:59:45 -0700664 NULL, 0,
George Lu20f4f322018-06-12 15:54:43 -0400665 fileSizes, nbFiles,
666 cLevel, comprParams,
667 dictBuffer, dictBufferSize,
George Lu20f4f322018-06-12 15:54:43 -0400668 displayLevel, displayName, &adv);
669}
670
Yann Collet2e45bad2018-08-23 14:21:18 -0700671static BMK_benchOutcome_t BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
672 const size_t* fileSizes, unsigned nbFiles,
673 int cLevel, const ZSTD_compressionParameters* comprParams,
674 const void* dictBuffer, size_t dictBufferSize,
675 int displayLevel, const char* displayName,
676 BMK_advancedParams_t const * const adv)
677{
678 const char* pch = strrchr(displayName, '\\'); /* Windows */
679 if (!pch) pch = strrchr(displayName, '/'); /* Linux */
680 if (pch) displayName = pch+1;
681
682 if (adv->realTime) {
683 DISPLAYLEVEL(2, "Note : switching to real-time priority \n");
684 SET_REALTIME_PRIORITY;
685 }
686
687 if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */
Yann Collet08ceda32021-09-04 00:52:44 -0700688 OUTPUT("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",
Yann Collet2e45bad2018-08-23 14:21:18 -0700689 ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING,
Yann Colletededcfc2018-12-21 16:19:44 -0800690 (unsigned)benchedSize, adv->nbSeconds, (unsigned)(adv->blockSize>>10));
Yann Collet2e45bad2018-08-23 14:21:18 -0700691
692 return BMK_benchMemAdvanced(srcBuffer, benchedSize,
693 NULL, 0,
694 fileSizes, nbFiles,
695 cLevel, comprParams,
696 dictBuffer, dictBufferSize,
697 displayLevel, displayName, adv);
698}
699
Elliott Hughes44aba642023-09-12 20:18:59 +0000700int BMK_syntheticTest(int cLevel, double compressibility,
701 const ZSTD_compressionParameters* compressionParams,
702 int displayLevel, const BMK_advancedParams_t* adv)
Yann Collet2e45bad2018-08-23 14:21:18 -0700703{
704 char name[20] = {0};
705 size_t const benchedSize = 10000000;
706 void* srcBuffer;
707 BMK_benchOutcome_t res;
708
709 if (cLevel > ZSTD_maxCLevel()) {
Elliott Hughes44aba642023-09-12 20:18:59 +0000710 DISPLAYLEVEL(1, "Invalid Compression Level");
711 return 15;
Yann Collet2e45bad2018-08-23 14:21:18 -0700712 }
713
714 /* Memory allocation */
715 srcBuffer = malloc(benchedSize);
Elliott Hughes44aba642023-09-12 20:18:59 +0000716 if (!srcBuffer) {
717 DISPLAYLEVEL(1, "allocation error : not enough memory");
718 return 16;
719 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700720
721 /* Fill input buffer */
722 RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
723
724 /* Bench */
725 snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));
726 res = BMK_benchCLevel(srcBuffer, benchedSize,
727 &benchedSize /* ? */, 1 /* ? */,
728 cLevel, compressionParams,
729 NULL, 0, /* dictionary */
730 displayLevel, name, adv);
731
732 /* clean up */
733 free(srcBuffer);
734
Elliott Hughes44aba642023-09-12 20:18:59 +0000735 return !BMK_isSuccessful_benchOutcome(res);
Yann Collet2e45bad2018-08-23 14:21:18 -0700736}
737
738
739
Yann Collet4856a002015-01-24 01:58:16 +0100740static size_t BMK_findMaxMem(U64 requiredMem)
741{
Yann Colletde406ee2016-03-20 15:46:10 +0100742 size_t const step = 64 MB;
Yann Collet4856a002015-01-24 01:58:16 +0100743 BYTE* testmem = NULL;
744
745 requiredMem = (((requiredMem >> 26) + 1) << 26);
Yann Colletde406ee2016-03-20 15:46:10 +0100746 requiredMem += step;
Yann Collet050efba2015-11-03 09:49:30 +0100747 if (requiredMem > maxMemory) requiredMem = maxMemory;
Yann Collet4856a002015-01-24 01:58:16 +0100748
Yann Colletde406ee2016-03-20 15:46:10 +0100749 do {
Yann Collet4856a002015-01-24 01:58:16 +0100750 testmem = (BYTE*)malloc((size_t)requiredMem);
Yann Colletde406ee2016-03-20 15:46:10 +0100751 requiredMem -= step;
George Lue89f1fb2018-08-14 14:44:47 -0700752 } while (!testmem && requiredMem > 0);
Yann Colletde406ee2016-03-20 15:46:10 +0100753
Yann Collet4856a002015-01-24 01:58:16 +0100754 free(testmem);
Yann Colletde406ee2016-03-20 15:46:10 +0100755 return (size_t)(requiredMem);
Yann Collet4856a002015-01-24 01:58:16 +0100756}
757
Yann Colleta5b66e32016-03-26 01:48:27 +0100758/*! BMK_loadFiles() :
Yann Collet6a9b41b2018-03-11 19:56:48 -0700759 * Loads `buffer` with content of files listed within `fileNamesTable`.
760 * At most, fills `buffer` entirely. */
George Lu20f4f322018-06-12 15:54:43 -0400761static int BMK_loadFiles(void* buffer, size_t bufferSize,
Yann Collet4086b282018-08-30 11:02:08 -0700762 size_t* fileSizes,
763 const char* const * fileNamesTable, unsigned nbFiles,
764 int displayLevel)
Yann Colleted699e62015-12-16 02:37:24 +0100765{
inikepc0d5f4e2016-04-13 10:48:04 +0200766 size_t pos = 0, totalSize = 0;
Yann Collet699b14d2016-03-17 19:37:33 +0100767 unsigned n;
Yann Colletfd416f12016-01-30 03:14:15 +0100768 for (n=0; n<nbFiles; n++) {
Yann Collet6309be62019-10-15 16:09:18 -0700769 U64 fileSize = UTIL_getFileSize(fileNamesTable[n]); /* last file may be shortened */
inikep69fcd7c2016-04-28 12:23:33 +0200770 if (UTIL_isDirectory(fileNamesTable[n])) {
George Lu01d940b2018-06-11 10:59:05 -0400771 DISPLAYLEVEL(2, "Ignoring %s directory... \n", fileNamesTable[n]);
inikepbab43172016-04-29 15:19:40 +0200772 fileSizes[n] = 0;
inikepc0d5f4e2016-04-13 10:48:04 +0200773 continue;
774 }
Yann Collet18b79532017-10-17 16:14:25 -0700775 if (fileSize == UTIL_FILESIZE_UNKNOWN) {
George Lu01d940b2018-06-11 10:59:05 -0400776 DISPLAYLEVEL(2, "Cannot evaluate size of %s, ignoring ... \n", fileNamesTable[n]);
Yann Collet18b79532017-10-17 16:14:25 -0700777 fileSizes[n] = 0;
778 continue;
779 }
Yann Collet6309be62019-10-15 16:09:18 -0700780 { FILE* const f = fopen(fileNamesTable[n], "rb");
781 if (f==NULL) RETURN_ERROR_INT(10, "impossible to open file %s", fileNamesTable[n]);
Yann Collet08ceda32021-09-04 00:52:44 -0700782 OUTPUTLEVEL(2, "Loading %s... \r", fileNamesTable[n]);
Yann Collet6309be62019-10-15 16:09:18 -0700783 if (fileSize > bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n; /* buffer too small - stop after this file */
784 { size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f);
785 if (readSize != (size_t)fileSize) RETURN_ERROR_INT(11, "could not read %s", fileNamesTable[n]);
786 pos += readSize;
787 }
788 fileSizes[n] = (size_t)fileSize;
789 totalSize += (size_t)fileSize;
790 fclose(f);
791 } }
Yann Collet6f9c0562016-05-01 10:26:30 +0200792
Yann Collet6309be62019-10-15 16:09:18 -0700793 if (totalSize == 0) RETURN_ERROR_INT(12, "no data to bench");
George Lu20f4f322018-06-12 15:54:43 -0400794 return 0;
Yann Colleted699e62015-12-16 02:37:24 +0100795}
796
Elliott Hughes44aba642023-09-12 20:18:59 +0000797int BMK_benchFilesAdvanced(
Yann Collet2e45bad2018-08-23 14:21:18 -0700798 const char* const * fileNamesTable, unsigned nbFiles,
799 const char* dictFileName, int cLevel,
800 const ZSTD_compressionParameters* compressionParams,
801 int displayLevel, const BMK_advancedParams_t* adv)
Yann Colleted699e62015-12-16 02:37:24 +0100802{
George Lud6121ad2018-06-22 17:25:16 -0700803 void* srcBuffer = NULL;
Yann Colleted699e62015-12-16 02:37:24 +0100804 size_t benchedSize;
Yann Collet31683c02015-12-18 01:26:48 +0100805 void* dictBuffer = NULL;
806 size_t dictBufferSize = 0;
George Lud6121ad2018-06-22 17:25:16 -0700807 size_t* fileSizes = NULL;
Yann Colletc3a4baa2018-08-24 21:38:09 -0700808 BMK_benchOutcome_t res;
Yann Collete162ace2016-05-20 11:24:35 +0200809 U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
Yann Colleted699e62015-12-16 02:37:24 +0100810
Yann Collet2e45bad2018-08-23 14:21:18 -0700811 if (!nbFiles) {
Elliott Hughes44aba642023-09-12 20:18:59 +0000812 DISPLAYLEVEL(1, "No Files to Benchmark");
813 return 13;
George Lua8eea992018-06-19 10:58:22 -0700814 }
Yann Collet31683c02015-12-18 01:26:48 +0100815
George Lua8eea992018-06-19 10:58:22 -0700816 if (cLevel > ZSTD_maxCLevel()) {
Elliott Hughes44aba642023-09-12 20:18:59 +0000817 DISPLAYLEVEL(1, "Invalid Compression Level");
818 return 14;
George Lua8eea992018-06-19 10:58:22 -0700819 }
820
senhuang42dce48f52021-08-23 19:10:16 -0400821 if (totalSizeToLoad == UTIL_FILESIZE_UNKNOWN) {
Elliott Hughes44aba642023-09-12 20:18:59 +0000822 DISPLAYLEVEL(1, "Error loading files");
823 return 15;
senhuang42dce48f52021-08-23 19:10:16 -0400824 }
825
George Lua8eea992018-06-19 10:58:22 -0700826 fileSizes = (size_t*)calloc(nbFiles, sizeof(size_t));
Elliott Hughes44aba642023-09-12 20:18:59 +0000827 if (!fileSizes) {
828 DISPLAYLEVEL(1, "not enough memory for fileSizes");
829 return 16;
830 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700831
Yann Collet31683c02015-12-18 01:26:48 +0100832 /* Load dictionary */
Yann Colletfd416f12016-01-30 03:14:15 +0100833 if (dictFileName != NULL) {
Yann Collet18b79532017-10-17 16:14:25 -0700834 U64 const dictFileSize = UTIL_getFileSize(dictFileName);
Yann Colleted2fb6b2018-12-20 17:20:07 -0800835 if (dictFileSize == UTIL_FILESIZE_UNKNOWN) {
836 DISPLAYLEVEL(1, "error loading %s : %s \n", dictFileName, strerror(errno));
837 free(fileSizes);
Elliott Hughes44aba642023-09-12 20:18:59 +0000838 DISPLAYLEVEL(1, "benchmark aborted");
839 return 17;
Yann Colleted2fb6b2018-12-20 17:20:07 -0800840 }
George Lua8eea992018-06-19 10:58:22 -0700841 if (dictFileSize > 64 MB) {
842 free(fileSizes);
Elliott Hughes44aba642023-09-12 20:18:59 +0000843 DISPLAYLEVEL(1, "dictionary file %s too large", dictFileName);
844 return 18;
George Lua8eea992018-06-19 10:58:22 -0700845 }
Yann Collet31683c02015-12-18 01:26:48 +0100846 dictBufferSize = (size_t)dictFileSize;
847 dictBuffer = malloc(dictBufferSize);
George Lua8eea992018-06-19 10:58:22 -0700848 if (dictBuffer==NULL) {
849 free(fileSizes);
Elliott Hughes44aba642023-09-12 20:18:59 +0000850 DISPLAYLEVEL(1, "not enough memory for dictionary (%u bytes)",
Yann Colletededcfc2018-12-21 16:19:44 -0800851 (unsigned)dictBufferSize);
Elliott Hughes44aba642023-09-12 20:18:59 +0000852 return 19;
George Lua8eea992018-06-19 10:58:22 -0700853 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700854
855 { int const errorCode = BMK_loadFiles(dictBuffer, dictBufferSize,
856 fileSizes, &dictFileName /*?*/,
857 1 /*?*/, displayLevel);
858 if (errorCode) {
859 res = BMK_benchOutcome_error();
George Lud6121ad2018-06-22 17:25:16 -0700860 goto _cleanUp;
Yann Collet2e45bad2018-08-23 14:21:18 -0700861 } }
Yann Collet31683c02015-12-18 01:26:48 +0100862 }
863
Yann Colleted699e62015-12-16 02:37:24 +0100864 /* Memory allocation & restrictions */
865 benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3;
866 if ((U64)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad;
867 if (benchedSize < totalSizeToLoad)
Yann Colletededcfc2018-12-21 16:19:44 -0800868 DISPLAY("Not enough memory; testing %u MB only...\n", (unsigned)(benchedSize >> 20));
George Lue89f1fb2018-08-14 14:44:47 -0700869
870 srcBuffer = benchedSize ? malloc(benchedSize) : NULL;
George Lua8eea992018-06-19 10:58:22 -0700871 if (!srcBuffer) {
872 free(dictBuffer);
873 free(fileSizes);
Elliott Hughes44aba642023-09-12 20:18:59 +0000874 DISPLAYLEVEL(1, "not enough memory for srcBuffer");
875 return 20;
George Lua8eea992018-06-19 10:58:22 -0700876 }
Yann Colleted699e62015-12-16 02:37:24 +0100877
878 /* Load input buffer */
Yann Collet2e45bad2018-08-23 14:21:18 -0700879 { int const errorCode = BMK_loadFiles(srcBuffer, benchedSize,
880 fileSizes, fileNamesTable, nbFiles,
881 displayLevel);
882 if (errorCode) {
883 res = BMK_benchOutcome_error();
George Lud6121ad2018-06-22 17:25:16 -0700884 goto _cleanUp;
Yann Collet2e45bad2018-08-23 14:21:18 -0700885 } }
886
Yann Colleted699e62015-12-16 02:37:24 +0100887 /* Bench */
Yann Collet2e45bad2018-08-23 14:21:18 -0700888 { char mfName[20] = {0};
Yann Colletd898fb72017-11-17 00:22:55 -0800889 snprintf (mfName, sizeof(mfName), " %u files", nbFiles);
Yann Collet2e45bad2018-08-23 14:21:18 -0700890 { const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
Yann Collet77e805e2018-08-21 18:19:27 -0700891 res = BMK_benchCLevel(srcBuffer, benchedSize,
Yann Collet2e45bad2018-08-23 14:21:18 -0700892 fileSizes, nbFiles,
893 cLevel, compressionParams,
894 dictBuffer, dictBufferSize,
895 displayLevel, displayName,
896 adv);
Yann Colletd898fb72017-11-17 00:22:55 -0800897 } }
Yann Collet4856a002015-01-24 01:58:16 +0100898
George Lud6121ad2018-06-22 17:25:16 -0700899_cleanUp:
Yann Collet4856a002015-01-24 01:58:16 +0100900 free(srcBuffer);
Yann Collet31683c02015-12-18 01:26:48 +0100901 free(dictBuffer);
Yann Collet70611352015-12-16 03:01:03 +0100902 free(fileSizes);
Elliott Hughes44aba642023-09-12 20:18:59 +0000903 return !BMK_isSuccessful_benchOutcome(res);
Yann Collet4856a002015-01-24 01:58:16 +0100904}
905
906
Elliott Hughes44aba642023-09-12 20:18:59 +0000907int BMK_benchFiles(const char* const * fileNamesTable, unsigned nbFiles,
Yann Collet2e45bad2018-08-23 14:21:18 -0700908 const char* dictFileName,
909 int cLevel, const ZSTD_compressionParameters* compressionParams,
910 int displayLevel)
Yann Collet4856a002015-01-24 01:58:16 +0100911{
Yann Collet2e45bad2018-08-23 14:21:18 -0700912 BMK_advancedParams_t const adv = BMK_initAdvancedParams();
George Lu0d1ee222018-06-15 16:21:08 -0400913 return BMK_benchFilesAdvanced(fileNamesTable, nbFiles, dictFileName, cLevel, compressionParams, displayLevel, &adv);
Yann Collet4856a002015-01-24 01:58:16 +0100914}