blob: 6738fe952d4848462be790c6069225bbac522fa3 [file] [log] [blame]
Yann Collet32fb4072017-08-18 16:52:05 -07001/*
Yann Collet4ded9e52016-08-30 10:04:33 -07002 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * 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 */
16#define BMK_TIMETEST_DEFAULT_S 3
17#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 */
26#include <string.h> /* memset */
Yann Colletc6a64172016-12-31 03:31:26 +010027#include <stdio.h> /* fprintf, fopen */
Yann Colletd3364aa2018-02-20 14:48:09 -080028#include <assert.h> /* assert */
inikep4c12f232016-03-29 14:52:13 +020029
Yann Colletd38063f2018-11-13 11:01:59 -080030#include "benchfn.h"
Yann Colletf3eca252015-10-22 15:31:46 +010031#include "mem.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020032#define ZSTD_STATIC_LINKING_ONLY
33#include "zstd.h"
inikep69fcd7c2016-04-28 12:23:33 +020034#include "datagen.h" /* RDG_genBuffer */
Yann Collet4856a002015-01-24 01:58:16 +010035#include "xxhash.h"
Yann Colletd38063f2018-11-13 11:01:59 -080036#include "benchzstd.h"
George Lud6121ad2018-06-22 17:25:16 -070037#include "zstd_errors.h"
Yann Collet4856a002015-01-24 01:58:16 +010038
39
Yann Colletf3eca252015-10-22 15:31:46 +010040/* *************************************
Yann Collet4856a002015-01-24 01:58:16 +010041* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010042***************************************/
inikepf2f59d72016-06-22 15:42:26 +020043#ifndef ZSTD_GIT_COMMIT
inikepd7d251c2016-06-22 16:13:25 +020044# define ZSTD_GIT_COMMIT_STRING ""
45#else
46# define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
inikepf2f59d72016-06-22 15:42:26 +020047#endif
48
Yann Colletd3364aa2018-02-20 14:48:09 -080049#define TIMELOOP_MICROSEC (1*1000000ULL) /* 1 second */
50#define TIMELOOP_NANOSEC (1*1000000000ULL) /* 1 second */
51#define ACTIVEPERIOD_MICROSEC (70*TIMELOOP_MICROSEC) /* 70 seconds */
inikep83c76b42016-04-28 13:16:01 +020052#define COOLPERIOD_SEC 10
Yann Collet4856a002015-01-24 01:58:16 +010053
54#define KB *(1 <<10)
55#define MB *(1 <<20)
56#define GB *(1U<<30)
57
Yann Collet55affc02018-08-28 11:21:09 -070058#define BMK_RUNTEST_DEFAULT_MS 1000
59
Yann Collet2e45bad2018-08-23 14:21:18 -070060static const size_t maxMemory = (sizeof(size_t)==4) ?
61 /* 32-bit */ (2 GB - 64 MB) :
62 /* 64-bit */ (size_t)(1ULL << ((sizeof(size_t)*8)-31));
63
Yann Collet4856a002015-01-24 01:58:16 +010064
Yann Colletf3eca252015-10-22 15:31:46 +010065/* *************************************
Yann Colleted699e62015-12-16 02:37:24 +010066* console display
Yann Colletf3eca252015-10-22 15:31:46 +010067***************************************/
Yann Colleted699e62015-12-16 02:37:24 +010068#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
George Lu01d940b2018-06-11 10:59:05 -040069#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
70/* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
Yann Colleted699e62015-12-16 02:37:24 +010071
Nick Terrell9a2f6f42017-11-29 19:11:12 -080072static const U64 g_refreshRate = SEC_TO_MICRO / 6;
73static UTIL_time_t g_displayClock = UTIL_TIME_INITIALIZER;
74
George Lu01d940b2018-06-11 10:59:05 -040075#define DISPLAYUPDATE(l, ...) { if (displayLevel>=l) { \
76 if ((UTIL_clockSpanMicro(g_displayClock) > g_refreshRate) || (displayLevel>=4)) \
Nick Terrell9a2f6f42017-11-29 19:11:12 -080077 { g_displayClock = UTIL_getTime(); DISPLAY(__VA_ARGS__); \
George Lu01d940b2018-06-11 10:59:05 -040078 if (displayLevel>=4) fflush(stderr); } } }
Yann Colletbf2bc112016-08-02 23:48:13 +020079
Yann Colleted699e62015-12-16 02:37:24 +010080
81/* *************************************
82* Exceptions
83***************************************/
84#ifndef DEBUG
George Lu3adc2172018-07-12 17:30:39 -070085# define DEBUG 0
Yann Colleted699e62015-12-16 02:37:24 +010086#endif
Yann Colletfe234bf2017-06-19 15:23:19 -070087#define DEBUGOUTPUT(...) { if (DEBUG) DISPLAY(__VA_ARGS__); }
George Lu20f4f322018-06-12 15:54:43 -040088
89#define EXM_THROW_INT(errorNum, ...) { \
Yann Colletfe234bf2017-06-19 15:23:19 -070090 DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
George Lu20f4f322018-06-12 15:54:43 -040091 DISPLAYLEVEL(1, "Error %i : ", errorNum); \
George Lu01d940b2018-06-11 10:59:05 -040092 DISPLAYLEVEL(1, __VA_ARGS__); \
93 DISPLAYLEVEL(1, " \n"); \
George Lu20f4f322018-06-12 15:54:43 -040094 return errorNum; \
Yann Colleted699e62015-12-16 02:37:24 +010095}
Yann Collet4856a002015-01-24 01:58:16 +010096
Yann Collet2e45bad2018-08-23 14:21:18 -070097#define RETURN_ERROR(errorNum, retType, ...) { \
George Lu20f4f322018-06-12 15:54:43 -040098 retType r; \
99 memset(&r, 0, sizeof(retType)); \
100 DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
101 DISPLAYLEVEL(1, "Error %i : ", errorNum); \
102 DISPLAYLEVEL(1, __VA_ARGS__); \
103 DISPLAYLEVEL(1, " \n"); \
Yann Collet2e45bad2018-08-23 14:21:18 -0700104 r.tag = errorNum; \
George Lu20f4f322018-06-12 15:54:43 -0400105 return r; \
106}
Yann Collet4856a002015-01-24 01:58:16 +0100107
George Lu0d1ee222018-06-15 16:21:08 -0400108/* error without displaying */
Yann Collet2e45bad2018-08-23 14:21:18 -0700109#define RETURN_QUIET_ERROR(errorNum, retType, ...) { \
George Lu0d1ee222018-06-15 16:21:08 -0400110 retType r; \
111 memset(&r, 0, sizeof(retType)); \
112 DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
George Lud6121ad2018-06-22 17:25:16 -0700113 DEBUGOUTPUT("Error %i : ", errorNum); \
114 DEBUGOUTPUT(__VA_ARGS__); \
115 DEBUGOUTPUT(" \n"); \
Yann Collet2e45bad2018-08-23 14:21:18 -0700116 r.tag = errorNum; \
George Lu0d1ee222018-06-15 16:21:08 -0400117 return r; \
118}
119
Yann Colletf3eca252015-10-22 15:31:46 +0100120/* *************************************
Yann Collet4856a002015-01-24 01:58:16 +0100121* Benchmark Parameters
Yann Colletf3eca252015-10-22 15:31:46 +0100122***************************************/
Stella Laua1f04d52017-09-01 14:52:51 -0700123
Yann Collet77e805e2018-08-21 18:19:27 -0700124BMK_advancedParams_t BMK_initAdvancedParams(void) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700125 BMK_advancedParams_t const res = {
George Lu85223462018-06-14 14:46:17 -0400126 BMK_both, /* mode */
George Lu20f4f322018-06-12 15:54:43 -0400127 BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
128 0, /* blockSize */
129 0, /* nbWorkers */
130 0, /* realTime */
George Lu20f4f322018-06-12 15:54:43 -0400131 0, /* additionalParam */
Yann Collet77e805e2018-08-21 18:19:27 -0700132 0, /* ldmFlag */
George Lu20f4f322018-06-12 15:54:43 -0400133 0, /* ldmMinMatch */
134 0, /* ldmHashLog */
George Lud6121ad2018-06-22 17:25:16 -0700135 0, /* ldmBuckSizeLog */
136 0 /* ldmHashEveryLog */
George Lu20f4f322018-06-12 15:54:43 -0400137 };
138 return res;
Stella Lau67d4a612017-09-02 21:10:36 -0700139}
140
Yann Collet4856a002015-01-24 01:58:16 +0100141
Yann Colletf3eca252015-10-22 15:31:46 +0100142/* ********************************************************
Yann Collet4856a002015-01-24 01:58:16 +0100143* Bench functions
Yann Colletf3eca252015-10-22 15:31:46 +0100144**********************************************************/
Yann Colletd9465012016-12-06 16:49:23 -0800145typedef struct {
146 const void* srcPtr;
Yann Collet1c00dc32015-10-21 08:22:25 +0100147 size_t srcSize;
Yann Colletd9465012016-12-06 16:49:23 -0800148 void* cPtr;
Yann Collet1c00dc32015-10-21 08:22:25 +0100149 size_t cRoom;
150 size_t cSize;
Yann Colletd9465012016-12-06 16:49:23 -0800151 void* resPtr;
Yann Collet1c00dc32015-10-21 08:22:25 +0100152 size_t resSize;
153} blockParam_t;
154
Sean Purcell42bac7f2017-04-13 15:35:05 -0700155#undef MIN
156#undef MAX
157#define MIN(a,b) ((a) < (b) ? (a) : (b))
158#define MAX(a,b) ((a) > (b) ? (a) : (b))
Yann Collet1c00dc32015-10-21 08:22:25 +0100159
Yann Collet77e805e2018-08-21 18:19:27 -0700160static void BMK_initCCtx(ZSTD_CCtx* ctx,
161 const void* dictBuffer, size_t dictBufferSize, int cLevel,
George Lu20f4f322018-06-12 15:54:43 -0400162 const ZSTD_compressionParameters* comprParams, const BMK_advancedParams_t* adv) {
George Lue148db32018-07-20 14:35:09 -0700163 ZSTD_CCtx_reset(ctx);
164 ZSTD_CCtx_resetParameters(ctx);
George Lu20f4f322018-06-12 15:54:43 -0400165 if (adv->nbWorkers==1) {
166 ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbWorkers, 0);
167 } else {
168 ZSTD_CCtx_setParameter(ctx, ZSTD_p_nbWorkers, adv->nbWorkers);
169 }
170 ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionLevel, cLevel);
171 ZSTD_CCtx_setParameter(ctx, ZSTD_p_enableLongDistanceMatching, adv->ldmFlag);
172 ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmMinMatch, adv->ldmMinMatch);
173 ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashLog, adv->ldmHashLog);
George Lud6121ad2018-06-22 17:25:16 -0700174 ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmBucketSizeLog, adv->ldmBucketSizeLog);
175 ZSTD_CCtx_setParameter(ctx, ZSTD_p_ldmHashEveryLog, adv->ldmHashEveryLog);
George Lu20f4f322018-06-12 15:54:43 -0400176 ZSTD_CCtx_setParameter(ctx, ZSTD_p_windowLog, comprParams->windowLog);
177 ZSTD_CCtx_setParameter(ctx, ZSTD_p_hashLog, comprParams->hashLog);
178 ZSTD_CCtx_setParameter(ctx, ZSTD_p_chainLog, comprParams->chainLog);
179 ZSTD_CCtx_setParameter(ctx, ZSTD_p_searchLog, comprParams->searchLog);
180 ZSTD_CCtx_setParameter(ctx, ZSTD_p_minMatch, comprParams->searchLength);
181 ZSTD_CCtx_setParameter(ctx, ZSTD_p_targetLength, comprParams->targetLength);
George Lu7b5b3d72018-07-16 16:16:31 -0700182 ZSTD_CCtx_setParameter(ctx, ZSTD_p_compressionStrategy, comprParams->strategy);
George Lu20f4f322018-06-12 15:54:43 -0400183 ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize);
184}
185
Yann Collet77e805e2018-08-21 18:19:27 -0700186static void BMK_initDCtx(ZSTD_DCtx* dctx,
George Lu20f4f322018-06-12 15:54:43 -0400187 const void* dictBuffer, size_t dictBufferSize) {
George Lue148db32018-07-20 14:35:09 -0700188 ZSTD_DCtx_reset(dctx);
George Lu20f4f322018-06-12 15:54:43 -0400189 ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize);
190}
191
Yann Collet2e45bad2018-08-23 14:21:18 -0700192
George Lu20f4f322018-06-12 15:54:43 -0400193typedef struct {
Yann Collet2e45bad2018-08-23 14:21:18 -0700194 ZSTD_CCtx* cctx;
George Lu20f4f322018-06-12 15:54:43 -0400195 const void* dictBuffer;
196 size_t dictBufferSize;
197 int cLevel;
198 const ZSTD_compressionParameters* comprParams;
199 const BMK_advancedParams_t* adv;
200} BMK_initCCtxArgs;
201
202static size_t local_initCCtx(void* payload) {
203 BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)payload;
Yann Collet2e45bad2018-08-23 14:21:18 -0700204 BMK_initCCtx(ag->cctx, ag->dictBuffer, ag->dictBufferSize, ag->cLevel, ag->comprParams, ag->adv);
George Lu20f4f322018-06-12 15:54:43 -0400205 return 0;
206}
207
208typedef struct {
209 ZSTD_DCtx* dctx;
210 const void* dictBuffer;
211 size_t dictBufferSize;
212} BMK_initDCtxArgs;
213
214static size_t local_initDCtx(void* payload) {
215 BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload;
216 BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize);
217 return 0;
218}
219
Yann Collet2e45bad2018-08-23 14:21:18 -0700220
221/* `addArgs` is the context */
George Lu20f4f322018-06-12 15:54:43 -0400222static size_t local_defaultCompress(
Yann Collet2e45bad2018-08-23 14:21:18 -0700223 const void* srcBuffer, size_t srcSize,
224 void* dstBuffer, size_t dstSize,
225 void* addArgs)
226{
George Lu20f4f322018-06-12 15:54:43 -0400227 size_t moreToFlush = 1;
Yann Collet2e45bad2018-08-23 14:21:18 -0700228 ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
George Lu20f4f322018-06-12 15:54:43 -0400229 ZSTD_inBuffer in;
230 ZSTD_outBuffer out;
Yann Collet2e45bad2018-08-23 14:21:18 -0700231 in.src = srcBuffer; in.size = srcSize; in.pos = 0;
232 out.dst = dstBuffer; out.size = dstSize; out.pos = 0;
George Lu20f4f322018-06-12 15:54:43 -0400233 while (moreToFlush) {
George Lud6121ad2018-06-22 17:25:16 -0700234 if(out.pos == out.size) {
235 return (size_t)-ZSTD_error_dstSize_tooSmall;
236 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700237 moreToFlush = ZSTD_compress_generic(cctx, &out, &in, ZSTD_e_end);
George Lu20f4f322018-06-12 15:54:43 -0400238 if (ZSTD_isError(moreToFlush)) {
239 return moreToFlush;
240 }
241 }
242 return out.pos;
243}
244
Yann Collet2e45bad2018-08-23 14:21:18 -0700245/* `addArgs` is the context */
George Lu20f4f322018-06-12 15:54:43 -0400246static size_t local_defaultDecompress(
Yann Collet2e45bad2018-08-23 14:21:18 -0700247 const void* srcBuffer, size_t srcSize,
Yann Collet0c66a442018-08-28 15:47:07 -0700248 void* dstBuffer, size_t dstCapacity,
Yann Collet2e45bad2018-08-23 14:21:18 -0700249 void* addArgs)
250{
George Lu20f4f322018-06-12 15:54:43 -0400251 size_t moreToFlush = 1;
Yann Collet2e45bad2018-08-23 14:21:18 -0700252 ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs;
George Lu20f4f322018-06-12 15:54:43 -0400253 ZSTD_inBuffer in;
254 ZSTD_outBuffer out;
Yann Collet2e45bad2018-08-23 14:21:18 -0700255 in.src = srcBuffer; in.size = srcSize; in.pos = 0;
Yann Collet0c66a442018-08-28 15:47:07 -0700256 out.dst = dstBuffer; out.size = dstCapacity; out.pos = 0;
George Lu20f4f322018-06-12 15:54:43 -0400257 while (moreToFlush) {
George Lud6121ad2018-06-22 17:25:16 -0700258 if(out.pos == out.size) {
259 return (size_t)-ZSTD_error_dstSize_tooSmall;
260 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700261 moreToFlush = ZSTD_decompress_generic(dctx, &out, &in);
George Lu20f4f322018-06-12 15:54:43 -0400262 if (ZSTD_isError(moreToFlush)) {
263 return moreToFlush;
264 }
265 }
266 return out.pos;
267
268}
269
Yann Collet2e45bad2018-08-23 14:21:18 -0700270
Yann Collet2e45bad2018-08-23 14:21:18 -0700271/* ================================================================= */
272/* Benchmark Zstandard, mem-to-mem scenarios */
273/* ================================================================= */
274
275int BMK_isSuccessful_benchOutcome(BMK_benchOutcome_t outcome)
276{
277 return outcome.tag == 0;
278}
279
280BMK_benchResult_t BMK_extract_benchResult(BMK_benchOutcome_t outcome)
281{
282 assert(outcome.tag == 0);
283 return outcome.internal_never_use_directly;
284}
285
Yann Collet6ce7b082018-08-24 15:59:57 -0700286static BMK_benchOutcome_t BMK_benchOutcome_error(void)
Yann Collet2e45bad2018-08-23 14:21:18 -0700287{
288 BMK_benchOutcome_t b;
289 memset(&b, 0, sizeof(b));
290 b.tag = 1;
291 return b;
292}
293
294static BMK_benchOutcome_t BMK_benchOutcome_setValidResult(BMK_benchResult_t result)
295{
296 BMK_benchOutcome_t b;
297 b.tag = 0;
298 b.internal_never_use_directly = result;
299 return b;
300}
301
302
303/* benchMem with no allocation */
Yann Collet8bed4012018-11-08 12:36:39 -0800304static BMK_benchOutcome_t
305BMK_benchMemAdvancedNoAlloc(
306 const void** srcPtrs, size_t* srcSizes,
307 void** cPtrs, size_t* cCapacities, size_t* cSizes,
308 void** resPtrs, size_t* resSizes,
309 void** resultBufferPtr, void* compressedBuffer,
310 size_t maxCompressedSize,
311 BMK_timedFnState_t* timeStateCompress,
312 BMK_timedFnState_t* timeStateDecompress,
Yann Collet2e45bad2018-08-23 14:21:18 -0700313
Yann Collet8bed4012018-11-08 12:36:39 -0800314 const void* srcBuffer, size_t srcSize,
315 const size_t* fileSizes, unsigned nbFiles,
316 const int cLevel,
317 const ZSTD_compressionParameters* comprParams,
318 const void* dictBuffer, size_t dictBufferSize,
319 ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
320 int displayLevel, const char* displayName,
321 const BMK_advancedParams_t* adv)
Yann Collet1c00dc32015-10-21 08:22:25 +0100322{
Yann Collet4da5bdf2018-08-23 18:04:50 -0700323 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 -0700324 BMK_benchResult_t benchResult;
Yann Collete63c6312016-12-06 17:46:49 -0800325 size_t const loadedCompressedSize = srcSize;
326 size_t cSize = 0;
327 double ratio = 0.;
Yann Colletde406ee2016-03-20 15:46:10 +0100328 U32 nbBlocks;
329
Yann Collet2e45bad2018-08-23 14:21:18 -0700330 assert(cctx != NULL); assert(dctx != NULL);
George Lu01d940b2018-06-11 10:59:05 -0400331
Yann Colletc776c462015-10-29 19:10:54 +0100332 /* init */
Yann Collet4da5bdf2018-08-23 18:04:50 -0700333 memset(&benchResult, 0, sizeof(benchResult));
Yann Collet2e45bad2018-08-23 14:21:18 -0700334 if (strlen(displayName)>17) displayName += strlen(displayName) - 17; /* display last 17 characters */
George Lu85223462018-06-14 14:46:17 -0400335 if (adv->mode == BMK_decodeOnly) { /* benchmark only decompression : source must be already compressed */
Yann Colletc2007382017-04-04 15:35:06 -0700336 const char* srcPtr = (const char*)srcBuffer;
337 U64 totalDSize64 = 0;
Yann Collete63c6312016-12-06 17:46:49 -0800338 U32 fileNb;
339 for (fileNb=0; fileNb<nbFiles; fileNb++) {
Sean Purcell4e709712017-02-07 13:50:09 -0800340 U64 const fSize64 = ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
Yann Collet2e45bad2018-08-23 14:21:18 -0700341 if (fSize64==0) RETURN_ERROR(32, BMK_benchOutcome_t, "Impossible to determine original size ");
Yann Colletc2007382017-04-04 15:35:06 -0700342 totalDSize64 += fSize64;
Yann Collete63c6312016-12-06 17:46:49 -0800343 srcPtr += fileSizes[fileNb];
344 }
Yann Colletc2007382017-04-04 15:35:06 -0700345 { size_t const decodedSize = (size_t)totalDSize64;
Yann Collet2e45bad2018-08-23 14:21:18 -0700346 assert((U64)decodedSize == totalDSize64); /* check overflow */
George Lu5f490342018-06-18 11:59:45 -0700347 free(*resultBufferPtr);
George Lu5f490342018-06-18 11:59:45 -0700348 *resultBufferPtr = malloc(decodedSize);
349 if (!(*resultBufferPtr)) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700350 RETURN_ERROR(33, BMK_benchOutcome_t, "not enough memory");
George Lua8eea992018-06-19 10:58:22 -0700351 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700352 if (totalDSize64 > decodedSize) { /* size_t overflow */
Yann Collet77e805e2018-08-21 18:19:27 -0700353 free(*resultBufferPtr);
Yann Collet2e45bad2018-08-23 14:21:18 -0700354 RETURN_ERROR(32, BMK_benchOutcome_t, "original size is too large");
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 Collet9126da52018-11-08 12:47:46 -0800383 if (BMK_decodeOnly) {
384 assert(nbBlocks==0);
385 cSizes[nbBlocks] = thisBlockSize;
386 benchResult.cSize = thisBlockSize;
387 }
Yann Collet77e805e2018-08-21 18:19:27 -0700388 }
389 }
George Lu20f4f322018-06-12 15:54:43 -0400390 }
Yann Collet1c00dc32015-10-21 08:22:25 +0100391
Yann Collet2e45bad2018-08-23 14:21:18 -0700392 /* warmimg up `compressedBuffer` */
George Lu85223462018-06-14 14:46:17 -0400393 if (adv->mode == BMK_decodeOnly) {
Yann Collet03e7e142018-03-05 13:50:07 -0800394 memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
395 } else {
396 RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
397 }
Yann Collet4856a002015-01-24 01:58:16 +0100398
399 /* 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);
406 BMK_initCCtxArgs cctxprep;
407 BMK_initDCtxArgs dctxprep;
408 cctxprep.cctx = cctx;
409 cctxprep.dictBuffer = dictBuffer;
410 cctxprep.dictBufferSize = dictBufferSize;
411 cctxprep.cLevel = cLevel;
412 cctxprep.comprParams = comprParams;
413 cctxprep.adv = adv;
414 dctxprep.dctx = dctx;
415 dctxprep.dictBuffer = dictBuffer;
416 dctxprep.dictBufferSize = dictBufferSize;
Yann Collet4856a002015-01-24 01:58:16 +0100417
Yann Collet2e45bad2018-08-23 14:21:18 -0700418 DISPLAYLEVEL(2, "\r%70s\r", ""); /* blank line */
George Lu50d612f2018-06-25 15:01:03 -0700419 DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->\r", marks[markNb], displayName, (U32)srcSize);
George Lu50d612f2018-06-25 15:01:03 -0700420
Yann Collet2e45bad2018-08-23 14:21:18 -0700421 while (!(compressionCompleted && decompressionCompleted)) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700422 if (!compressionCompleted) {
Yann Collet2279f3d2018-08-24 17:28:38 -0700423 BMK_runOutcome_t const cOutcome =
Yann Collet01dcd0f2018-08-26 21:30:18 -0700424 BMK_benchTimedFn( timeStateCompress,
425 &local_defaultCompress, cctx,
426 &local_initCCtx, &cctxprep,
Yann Colletd38063f2018-11-13 11:01:59 -0800427 ZSTD_isError,
Yann Collet01dcd0f2018-08-26 21:30:18 -0700428 nbBlocks,
429 srcPtrs, srcSizes,
430 cPtrs, cCapacities,
431 cSizes);
Yann Collet2e45bad2018-08-23 14:21:18 -0700432
Yann Collet2279f3d2018-08-24 17:28:38 -0700433 if (!BMK_isSuccessful_runOutcome(cOutcome)) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700434 return BMK_benchOutcome_error();
George Lu50d612f2018-06-25 15:01:03 -0700435 }
436
Yann Collet2279f3d2018-08-24 17:28:38 -0700437 { BMK_runTime_t const cResult = BMK_extract_runTime(cOutcome);
Yann Collet4da5bdf2018-08-23 18:04:50 -0700438 cSize = cResult.sumOfReturn;
439 ratio = (double)srcSize / cSize;
440 { BMK_benchResult_t newResult;
441 newResult.cSpeed = ((U64)srcSize * TIMELOOP_NANOSEC / cResult.nanoSecPerRun);
442 benchResult.cSize = cSize;
443 if (newResult.cSpeed > benchResult.cSpeed)
444 benchResult.cSpeed = newResult.cSpeed;
445 } }
George Lu5f490342018-06-18 11:59:45 -0700446
Yann Collet2e45bad2018-08-23 14:21:18 -0700447 { int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
Yann Collet2e45bad2018-08-23 14:21:18 -0700448 DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s\r",
Yann Collet4da5bdf2018-08-23 18:04:50 -0700449 marks[markNb], displayName,
450 (U32)srcSize, (U32)cSize,
Yann Collet2e45bad2018-08-23 14:21:18 -0700451 ratioAccuracy, ratio,
Yann Collet1f9ec132018-08-23 16:03:30 -0700452 benchResult.cSpeed < (10 MB) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT);
George Lua8eea992018-06-19 10:58:22 -0700453 }
Yann Collet01dcd0f2018-08-26 21:30:18 -0700454 compressionCompleted = BMK_isCompleted_TimedFn(timeStateCompress);
Yann Collet2e45bad2018-08-23 14:21:18 -0700455 }
George Lue89f1fb2018-08-14 14:44:47 -0700456
Yann Collet2e45bad2018-08-23 14:21:18 -0700457 if(!decompressionCompleted) {
Yann Collet2279f3d2018-08-24 17:28:38 -0700458 BMK_runOutcome_t const dOutcome =
Yann Collet01dcd0f2018-08-26 21:30:18 -0700459 BMK_benchTimedFn(timeStateDecompress,
460 &local_defaultDecompress, dctx,
461 &local_initDCtx, &dctxprep,
Yann Colletd38063f2018-11-13 11:01:59 -0800462 ZSTD_isError,
Yann Collet01dcd0f2018-08-26 21:30:18 -0700463 nbBlocks,
464 (const void *const *)cPtrs, cSizes,
465 resPtrs, resSizes,
466 NULL);
Yann Collet2e45bad2018-08-23 14:21:18 -0700467
Yann Collet2279f3d2018-08-24 17:28:38 -0700468 if(!BMK_isSuccessful_runOutcome(dOutcome)) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700469 return BMK_benchOutcome_error();
470 }
471
Yann Collet2279f3d2018-08-24 17:28:38 -0700472 { BMK_runTime_t const dResult = BMK_extract_runTime(dOutcome);
Yann Collet4da5bdf2018-08-23 18:04:50 -0700473 U64 const newDSpeed = (srcSize * TIMELOOP_NANOSEC / dResult.nanoSecPerRun);
474 if (newDSpeed > benchResult.dSpeed)
475 benchResult.dSpeed = newDSpeed;
476 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700477
478 { int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
Yann Collet2e45bad2018-08-23 14:21:18 -0700479 DISPLAYLEVEL(2, "%2s-%-17.17s :%10u ->%10u (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
Yann Collet4da5bdf2018-08-23 18:04:50 -0700480 marks[markNb], displayName,
481 (U32)srcSize, (U32)benchResult.cSize,
Yann Collet2e45bad2018-08-23 14:21:18 -0700482 ratioAccuracy, ratio,
Yann Collet1f9ec132018-08-23 16:03:30 -0700483 benchResult.cSpeed < (10 MB) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT,
Yann Collet4da5bdf2018-08-23 18:04:50 -0700484 (double)benchResult.dSpeed / MB_UNIT);
George Lua8eea992018-06-19 10:58:22 -0700485 }
Yann Collet01dcd0f2018-08-26 21:30:18 -0700486 decompressionCompleted = BMK_isCompleted_TimedFn(timeStateDecompress);
Yann Colletdaebc7f2017-11-18 15:54:32 -0800487 }
Yann Collet8bed4012018-11-08 12:36:39 -0800488 markNb = (markNb+1) % NB_MARKS;
Yann Collet4da5bdf2018-08-23 18:04:50 -0700489 } /* while (!(compressionCompleted && decompressionCompleted)) */
George Lu20f4f322018-06-12 15:54:43 -0400490
491 /* CRC Checking */
Yann Collet2e45bad2018-08-23 14:21:18 -0700492 { const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
George Lu5f490342018-06-18 11:59:45 -0700493 U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
George Lu85223462018-06-14 14:46:17 -0400494 if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) {
George Lu20f4f322018-06-12 15:54:43 -0400495 size_t u;
Yann Collet8bed4012018-11-08 12:36:39 -0800496 DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n",
497 displayName, (unsigned)crcOrig, (unsigned)crcCheck);
George Lu20f4f322018-06-12 15:54:43 -0400498 for (u=0; u<srcSize; u++) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700499 if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) {
George Lu20f4f322018-06-12 15:54:43 -0400500 U32 segNb, bNb, pos;
501 size_t bacc = 0;
502 DISPLAY("Decoding error at pos %u ", (U32)u);
503 for (segNb = 0; segNb < nbBlocks; segNb++) {
504 if (bacc + srcSizes[segNb] > u) break;
505 bacc += srcSizes[segNb];
506 }
507 pos = (U32)(u - bacc);
508 bNb = pos / (128 KB);
509 DISPLAY("(sample %u, block %u, pos %u) \n", segNb, bNb, pos);
510 if (u>5) {
511 int n;
512 DISPLAY("origin: ");
513 for (n=-5; n<0; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
514 DISPLAY(" :%02X: ", ((const BYTE*)srcBuffer)[u]);
515 for (n=1; n<3; n++) DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
516 DISPLAY(" \n");
517 DISPLAY("decode: ");
Yann Collet2e45bad2018-08-23 14:21:18 -0700518 for (n=-5; n<0; n++) DISPLAY("%02X ", resultBuffer[u+n]);
519 DISPLAY(" :%02X: ", resultBuffer[u]);
520 for (n=1; n<3; n++) DISPLAY("%02X ", resultBuffer[u+n]);
George Lu20f4f322018-06-12 15:54:43 -0400521 DISPLAY(" \n");
522 }
523 break;
524 }
525 if (u==srcSize-1) { /* should never happen */
526 DISPLAY("no difference detected\n");
Yann Collet77e805e2018-08-21 18:19:27 -0700527 }
George Lu20f4f322018-06-12 15:54:43 -0400528 }
Yann Collet77e805e2018-08-21 18:19:27 -0700529 }
George Lu20f4f322018-06-12 15:54:43 -0400530 } /* CRC Checking */
531
Yann Collet2e45bad2018-08-23 14:21:18 -0700532 if (displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
Yann Collet1f9ec132018-08-23 16:03:30 -0700533 double const cSpeed = (double)benchResult.cSpeed / MB_UNIT;
534 double const dSpeed = (double)benchResult.dSpeed / MB_UNIT;
Yann Collet2e45bad2018-08-23 14:21:18 -0700535 if (adv->additionalParam) {
536 DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, adv->additionalParam);
537 } else {
538 DISPLAY("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName);
539 }
George Luab26f242018-06-21 11:16:53 -0700540 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700541
542 DISPLAYLEVEL(2, "%2i#\n", cLevel);
George Lu85223462018-06-14 14:46:17 -0400543 } /* Bench */
Yann Collet2e45bad2018-08-23 14:21:18 -0700544
545 benchResult.cMem = (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
546 return BMK_benchOutcome_setValidResult(benchResult);
George Lua8eea992018-06-19 10:58:22 -0700547}
Yann Collet4856a002015-01-24 01:58:16 +0100548
Yann Collet2e45bad2018-08-23 14:21:18 -0700549BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
Yann Collet77e805e2018-08-21 18:19:27 -0700550 void* dstBuffer, size_t dstCapacity,
George Lua8eea992018-06-19 10:58:22 -0700551 const size_t* fileSizes, unsigned nbFiles,
Yann Collet6ce7b082018-08-24 15:59:57 -0700552 int cLevel, const ZSTD_compressionParameters* comprParams,
George Lua8eea992018-06-19 10:58:22 -0700553 const void* dictBuffer, size_t dictBufferSize,
George Lua8eea992018-06-19 10:58:22 -0700554 int displayLevel, const char* displayName, const BMK_advancedParams_t* adv)
555
556{
Yann Collet2e45bad2018-08-23 14:21:18 -0700557 int const dstParamsError = !dstBuffer ^ !dstCapacity; /* must be both NULL or none */
558
George Lua8eea992018-06-19 10:58:22 -0700559 size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ;
560 U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles;
561
562 /* these are the blockTable parameters, just split up */
George Ludd270b22018-07-27 08:49:25 -0700563 const void ** const srcPtrs = (const void**)malloc(maxNbBlocks * sizeof(void*));
564 size_t* const srcSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
George Lua8eea992018-06-19 10:58:22 -0700565
George Lue148db32018-07-20 14:35:09 -0700566
George Ludd270b22018-07-27 08:49:25 -0700567 void ** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
568 size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
569 size_t* const cCapacities = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
George Lua8eea992018-06-19 10:58:22 -0700570
George Ludd270b22018-07-27 08:49:25 -0700571 void ** const resPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
572 size_t* const resSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
George Lua8eea992018-06-19 10:58:22 -0700573
Yann Collet55affc02018-08-28 11:21:09 -0700574 BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
575 BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
George Lud6121ad2018-06-22 17:25:16 -0700576
Yann Collet2e45bad2018-08-23 14:21:18 -0700577 ZSTD_CCtx* const cctx = ZSTD_createCCtx();
578 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
George Lubfe83922018-08-09 12:07:57 -0700579
George Lu5f490342018-06-18 11:59:45 -0700580 const size_t maxCompressedSize = dstCapacity ? dstCapacity : ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024);
George Ludd270b22018-07-27 08:49:25 -0700581
582 void* const internalDstBuffer = dstBuffer ? NULL : malloc(maxCompressedSize);
583 void* const compressedBuffer = dstBuffer ? dstBuffer : internalDstBuffer;
584
Yann Collet2e45bad2018-08-23 14:21:18 -0700585 BMK_benchOutcome_t outcome = BMK_benchOutcome_error(); /* error by default */
George Lue89f1fb2018-08-14 14:44:47 -0700586
587 void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
588
Yann Collet77e805e2018-08-21 18:19:27 -0700589 int allocationincomplete = !srcPtrs || !srcSizes || !cPtrs ||
590 !cSizes || !cCapacities || !resPtrs || !resSizes ||
Yann Collet2e45bad2018-08-23 14:21:18 -0700591 !timeStateCompress || !timeStateDecompress ||
592 !cctx || !dctx ||
593 !compressedBuffer || !resultBuffer;
George Lu5f490342018-06-18 11:59:45 -0700594
George Lu5f490342018-06-18 11:59:45 -0700595
Yann Collet2e45bad2018-08-23 14:21:18 -0700596 if (!allocationincomplete && !dstParamsError) {
597 outcome = BMK_benchMemAdvancedNoAlloc(srcPtrs, srcSizes,
598 cPtrs, cCapacities, cSizes,
599 resPtrs, resSizes,
600 &resultBuffer,
601 compressedBuffer, maxCompressedSize,
602 timeStateCompress, timeStateDecompress,
603 srcBuffer, srcSize,
604 fileSizes, nbFiles,
605 cLevel, comprParams,
606 dictBuffer, dictBufferSize,
607 cctx, dctx,
608 displayLevel, displayName, adv);
George Lua8eea992018-06-19 10:58:22 -0700609 }
Yann Collet77e805e2018-08-21 18:19:27 -0700610
Yann Colleted699e62015-12-16 02:37:24 +0100611 /* clean up */
Yann Collet77e805e2018-08-21 18:19:27 -0700612 BMK_freeTimedFnState(timeStateCompress);
613 BMK_freeTimedFnState(timeStateDecompress);
614
Yann Collet2e45bad2018-08-23 14:21:18 -0700615 ZSTD_freeCCtx(cctx);
George Lubfe83922018-08-09 12:07:57 -0700616 ZSTD_freeDCtx(dctx);
617
George Ludd270b22018-07-27 08:49:25 -0700618 free(internalDstBuffer);
Yann Collet4856a002015-01-24 01:58:16 +0100619 free(resultBuffer);
George Lu20f4f322018-06-12 15:54:43 -0400620
Yann Collet77e805e2018-08-21 18:19:27 -0700621 free((void*)srcPtrs);
622 free(srcSizes);
623 free(cPtrs);
George Lu20f4f322018-06-12 15:54:43 -0400624 free(cSizes);
George Lue148db32018-07-20 14:35:09 -0700625 free(cCapacities);
George Lu20f4f322018-06-12 15:54:43 -0400626 free(resPtrs);
627 free(resSizes);
628
George Lua8eea992018-06-19 10:58:22 -0700629 if(allocationincomplete) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700630 RETURN_ERROR(31, BMK_benchOutcome_t, "allocation error : not enough memory");
George Lua8eea992018-06-19 10:58:22 -0700631 }
Yann Collet77e805e2018-08-21 18:19:27 -0700632
Yann Collet2e45bad2018-08-23 14:21:18 -0700633 if(dstParamsError) {
634 RETURN_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
George Ludd270b22018-07-27 08:49:25 -0700635 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700636 return outcome;
Yann Collet4856a002015-01-24 01:58:16 +0100637}
638
Yann Collet2e45bad2018-08-23 14:21:18 -0700639BMK_benchOutcome_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
George Lu20f4f322018-06-12 15:54:43 -0400640 const size_t* fileSizes, unsigned nbFiles,
Yann Collet2e45bad2018-08-23 14:21:18 -0700641 int cLevel, const ZSTD_compressionParameters* comprParams,
George Lu20f4f322018-06-12 15:54:43 -0400642 const void* dictBuffer, size_t dictBufferSize,
George Lu20f4f322018-06-12 15:54:43 -0400643 int displayLevel, const char* displayName) {
644
Yann Collet2e45bad2018-08-23 14:21:18 -0700645 BMK_advancedParams_t const adv = BMK_initAdvancedParams();
George Lu20f4f322018-06-12 15:54:43 -0400646 return BMK_benchMemAdvanced(srcBuffer, srcSize,
George Lu5f490342018-06-18 11:59:45 -0700647 NULL, 0,
George Lu20f4f322018-06-12 15:54:43 -0400648 fileSizes, nbFiles,
649 cLevel, comprParams,
650 dictBuffer, dictBufferSize,
George Lu20f4f322018-06-12 15:54:43 -0400651 displayLevel, displayName, &adv);
652}
653
Yann Collet2e45bad2018-08-23 14:21:18 -0700654static BMK_benchOutcome_t BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
655 const size_t* fileSizes, unsigned nbFiles,
656 int cLevel, const ZSTD_compressionParameters* comprParams,
657 const void* dictBuffer, size_t dictBufferSize,
658 int displayLevel, const char* displayName,
659 BMK_advancedParams_t const * const adv)
660{
661 const char* pch = strrchr(displayName, '\\'); /* Windows */
662 if (!pch) pch = strrchr(displayName, '/'); /* Linux */
663 if (pch) displayName = pch+1;
664
665 if (adv->realTime) {
666 DISPLAYLEVEL(2, "Note : switching to real-time priority \n");
667 SET_REALTIME_PRIORITY;
668 }
669
670 if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */
671 DISPLAY("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",
672 ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING,
673 (U32)benchedSize, adv->nbSeconds, (U32)(adv->blockSize>>10));
674
675 return BMK_benchMemAdvanced(srcBuffer, benchedSize,
676 NULL, 0,
677 fileSizes, nbFiles,
678 cLevel, comprParams,
679 dictBuffer, dictBufferSize,
680 displayLevel, displayName, adv);
681}
682
683BMK_benchOutcome_t BMK_syntheticTest(int cLevel, double compressibility,
684 const ZSTD_compressionParameters* compressionParams,
685 int displayLevel, const BMK_advancedParams_t* adv)
686{
687 char name[20] = {0};
688 size_t const benchedSize = 10000000;
689 void* srcBuffer;
690 BMK_benchOutcome_t res;
691
692 if (cLevel > ZSTD_maxCLevel()) {
693 RETURN_ERROR(15, BMK_benchOutcome_t, "Invalid Compression Level");
694 }
695
696 /* Memory allocation */
697 srcBuffer = malloc(benchedSize);
698 if (!srcBuffer) RETURN_ERROR(21, BMK_benchOutcome_t, "not enough memory");
699
700 /* Fill input buffer */
701 RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
702
703 /* Bench */
704 snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));
705 res = BMK_benchCLevel(srcBuffer, benchedSize,
706 &benchedSize /* ? */, 1 /* ? */,
707 cLevel, compressionParams,
708 NULL, 0, /* dictionary */
709 displayLevel, name, adv);
710
711 /* clean up */
712 free(srcBuffer);
713
714 return res;
715}
716
717
718
Yann Collet4856a002015-01-24 01:58:16 +0100719static size_t BMK_findMaxMem(U64 requiredMem)
720{
Yann Colletde406ee2016-03-20 15:46:10 +0100721 size_t const step = 64 MB;
Yann Collet4856a002015-01-24 01:58:16 +0100722 BYTE* testmem = NULL;
723
724 requiredMem = (((requiredMem >> 26) + 1) << 26);
Yann Colletde406ee2016-03-20 15:46:10 +0100725 requiredMem += step;
Yann Collet050efba2015-11-03 09:49:30 +0100726 if (requiredMem > maxMemory) requiredMem = maxMemory;
Yann Collet4856a002015-01-24 01:58:16 +0100727
Yann Colletde406ee2016-03-20 15:46:10 +0100728 do {
Yann Collet4856a002015-01-24 01:58:16 +0100729 testmem = (BYTE*)malloc((size_t)requiredMem);
Yann Colletde406ee2016-03-20 15:46:10 +0100730 requiredMem -= step;
George Lue89f1fb2018-08-14 14:44:47 -0700731 } while (!testmem && requiredMem > 0);
Yann Colletde406ee2016-03-20 15:46:10 +0100732
Yann Collet4856a002015-01-24 01:58:16 +0100733 free(testmem);
Yann Colletde406ee2016-03-20 15:46:10 +0100734 return (size_t)(requiredMem);
Yann Collet4856a002015-01-24 01:58:16 +0100735}
736
Yann Colleta5b66e32016-03-26 01:48:27 +0100737/*! BMK_loadFiles() :
Yann Collet6a9b41b2018-03-11 19:56:48 -0700738 * Loads `buffer` with content of files listed within `fileNamesTable`.
739 * At most, fills `buffer` entirely. */
George Lu20f4f322018-06-12 15:54:43 -0400740static int BMK_loadFiles(void* buffer, size_t bufferSize,
Yann Collet4086b282018-08-30 11:02:08 -0700741 size_t* fileSizes,
742 const char* const * fileNamesTable, unsigned nbFiles,
743 int displayLevel)
Yann Colleted699e62015-12-16 02:37:24 +0100744{
inikepc0d5f4e2016-04-13 10:48:04 +0200745 size_t pos = 0, totalSize = 0;
Yann Collet699b14d2016-03-17 19:37:33 +0100746 unsigned n;
Yann Colletfd416f12016-01-30 03:14:15 +0100747 for (n=0; n<nbFiles; n++) {
Yann Collete162ace2016-05-20 11:24:35 +0200748 FILE* f;
inikep69fcd7c2016-04-28 12:23:33 +0200749 U64 fileSize = UTIL_getFileSize(fileNamesTable[n]);
750 if (UTIL_isDirectory(fileNamesTable[n])) {
George Lu01d940b2018-06-11 10:59:05 -0400751 DISPLAYLEVEL(2, "Ignoring %s directory... \n", fileNamesTable[n]);
inikepbab43172016-04-29 15:19:40 +0200752 fileSizes[n] = 0;
inikepc0d5f4e2016-04-13 10:48:04 +0200753 continue;
754 }
Yann Collet18b79532017-10-17 16:14:25 -0700755 if (fileSize == UTIL_FILESIZE_UNKNOWN) {
George Lu01d940b2018-06-11 10:59:05 -0400756 DISPLAYLEVEL(2, "Cannot evaluate size of %s, ignoring ... \n", fileNamesTable[n]);
Yann Collet18b79532017-10-17 16:14:25 -0700757 fileSizes[n] = 0;
758 continue;
759 }
inikepea4ee3e2016-04-25 13:09:06 +0200760 f = fopen(fileNamesTable[n], "rb");
George Lu20f4f322018-06-12 15:54:43 -0400761 if (f==NULL) EXM_THROW_INT(10, "impossible to open file %s", fileNamesTable[n]);
Yann Colletbf2bc112016-08-02 23:48:13 +0200762 DISPLAYUPDATE(2, "Loading %s... \r", fileNamesTable[n]);
Yann Colleta5b66e32016-03-26 01:48:27 +0100763 if (fileSize > bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n; /* buffer too small - stop after this file */
Yann Collet4086b282018-08-30 11:02:08 -0700764 { size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f);
765 if (readSize != (size_t)fileSize) EXM_THROW_INT(11, "could not read %s", fileNamesTable[n]);
766 pos += readSize;
767 }
Yann Colleta52c98d2015-12-16 03:12:31 +0100768 fileSizes[n] = (size_t)fileSize;
inikepc0d5f4e2016-04-13 10:48:04 +0200769 totalSize += (size_t)fileSize;
Yann Colleted699e62015-12-16 02:37:24 +0100770 fclose(f);
771 }
Yann Collet6f9c0562016-05-01 10:26:30 +0200772
George Lu20f4f322018-06-12 15:54:43 -0400773 if (totalSize == 0) EXM_THROW_INT(12, "no data to bench");
774 return 0;
Yann Colleted699e62015-12-16 02:37:24 +0100775}
776
Yann Collet2e45bad2018-08-23 14:21:18 -0700777BMK_benchOutcome_t BMK_benchFilesAdvanced(
778 const char* const * fileNamesTable, unsigned nbFiles,
779 const char* dictFileName, int cLevel,
780 const ZSTD_compressionParameters* compressionParams,
781 int displayLevel, const BMK_advancedParams_t* adv)
Yann Colleted699e62015-12-16 02:37:24 +0100782{
George Lud6121ad2018-06-22 17:25:16 -0700783 void* srcBuffer = NULL;
Yann Colleted699e62015-12-16 02:37:24 +0100784 size_t benchedSize;
Yann Collet31683c02015-12-18 01:26:48 +0100785 void* dictBuffer = NULL;
786 size_t dictBufferSize = 0;
George Lud6121ad2018-06-22 17:25:16 -0700787 size_t* fileSizes = NULL;
Yann Colletc3a4baa2018-08-24 21:38:09 -0700788 BMK_benchOutcome_t res;
Yann Collete162ace2016-05-20 11:24:35 +0200789 U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
Yann Colleted699e62015-12-16 02:37:24 +0100790
Yann Collet2e45bad2018-08-23 14:21:18 -0700791 if (!nbFiles) {
792 RETURN_ERROR(14, BMK_benchOutcome_t, "No Files to Benchmark");
George Lua8eea992018-06-19 10:58:22 -0700793 }
Yann Collet31683c02015-12-18 01:26:48 +0100794
George Lua8eea992018-06-19 10:58:22 -0700795 if (cLevel > ZSTD_maxCLevel()) {
Yann Collet2e45bad2018-08-23 14:21:18 -0700796 RETURN_ERROR(15, BMK_benchOutcome_t, "Invalid Compression Level");
George Lua8eea992018-06-19 10:58:22 -0700797 }
798
799 fileSizes = (size_t*)calloc(nbFiles, sizeof(size_t));
Yann Collet2e45bad2018-08-23 14:21:18 -0700800 if (!fileSizes) RETURN_ERROR(12, BMK_benchOutcome_t, "not enough memory for fileSizes");
801
Yann Collet31683c02015-12-18 01:26:48 +0100802 /* Load dictionary */
Yann Colletfd416f12016-01-30 03:14:15 +0100803 if (dictFileName != NULL) {
Yann Collet18b79532017-10-17 16:14:25 -0700804 U64 const dictFileSize = UTIL_getFileSize(dictFileName);
George Lua8eea992018-06-19 10:58:22 -0700805 if (dictFileSize > 64 MB) {
806 free(fileSizes);
Yann Collet2e45bad2018-08-23 14:21:18 -0700807 RETURN_ERROR(10, BMK_benchOutcome_t, "dictionary file %s too large", dictFileName);
George Lua8eea992018-06-19 10:58:22 -0700808 }
Yann Collet31683c02015-12-18 01:26:48 +0100809 dictBufferSize = (size_t)dictFileSize;
810 dictBuffer = malloc(dictBufferSize);
George Lua8eea992018-06-19 10:58:22 -0700811 if (dictBuffer==NULL) {
812 free(fileSizes);
Yann Collet2e45bad2018-08-23 14:21:18 -0700813 RETURN_ERROR(11, BMK_benchOutcome_t, "not enough memory for dictionary (%u bytes)",
Yann Collet18b79532017-10-17 16:14:25 -0700814 (U32)dictBufferSize);
George Lua8eea992018-06-19 10:58:22 -0700815 }
Yann Collet2e45bad2018-08-23 14:21:18 -0700816
817 { int const errorCode = BMK_loadFiles(dictBuffer, dictBufferSize,
818 fileSizes, &dictFileName /*?*/,
819 1 /*?*/, displayLevel);
820 if (errorCode) {
821 res = BMK_benchOutcome_error();
George Lud6121ad2018-06-22 17:25:16 -0700822 goto _cleanUp;
Yann Collet2e45bad2018-08-23 14:21:18 -0700823 } }
Yann Collet31683c02015-12-18 01:26:48 +0100824 }
825
Yann Colleted699e62015-12-16 02:37:24 +0100826 /* Memory allocation & restrictions */
827 benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3;
828 if ((U64)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad;
829 if (benchedSize < totalSizeToLoad)
830 DISPLAY("Not enough memory; testing %u MB only...\n", (U32)(benchedSize >> 20));
George Lue89f1fb2018-08-14 14:44:47 -0700831
832 srcBuffer = benchedSize ? malloc(benchedSize) : NULL;
George Lua8eea992018-06-19 10:58:22 -0700833 if (!srcBuffer) {
834 free(dictBuffer);
835 free(fileSizes);
Yann Collet2e45bad2018-08-23 14:21:18 -0700836 RETURN_ERROR(12, BMK_benchOutcome_t, "not enough memory");
George Lua8eea992018-06-19 10:58:22 -0700837 }
Yann Colleted699e62015-12-16 02:37:24 +0100838
839 /* Load input buffer */
Yann Collet2e45bad2018-08-23 14:21:18 -0700840 { int const errorCode = BMK_loadFiles(srcBuffer, benchedSize,
841 fileSizes, fileNamesTable, nbFiles,
842 displayLevel);
843 if (errorCode) {
844 res = BMK_benchOutcome_error();
George Lud6121ad2018-06-22 17:25:16 -0700845 goto _cleanUp;
Yann Collet2e45bad2018-08-23 14:21:18 -0700846 } }
847
Yann Colleted699e62015-12-16 02:37:24 +0100848 /* Bench */
Yann Collet2e45bad2018-08-23 14:21:18 -0700849 { char mfName[20] = {0};
Yann Colletd898fb72017-11-17 00:22:55 -0800850 snprintf (mfName, sizeof(mfName), " %u files", nbFiles);
Yann Collet2e45bad2018-08-23 14:21:18 -0700851 { const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
Yann Collet77e805e2018-08-21 18:19:27 -0700852 res = BMK_benchCLevel(srcBuffer, benchedSize,
Yann Collet2e45bad2018-08-23 14:21:18 -0700853 fileSizes, nbFiles,
854 cLevel, compressionParams,
855 dictBuffer, dictBufferSize,
856 displayLevel, displayName,
857 adv);
Yann Colletd898fb72017-11-17 00:22:55 -0800858 } }
Yann Collet4856a002015-01-24 01:58:16 +0100859
George Lud6121ad2018-06-22 17:25:16 -0700860_cleanUp:
Yann Collet4856a002015-01-24 01:58:16 +0100861 free(srcBuffer);
Yann Collet31683c02015-12-18 01:26:48 +0100862 free(dictBuffer);
Yann Collet70611352015-12-16 03:01:03 +0100863 free(fileSizes);
George Lu20f4f322018-06-12 15:54:43 -0400864 return res;
Yann Collet4856a002015-01-24 01:58:16 +0100865}
866
867
Yann Collet2e45bad2018-08-23 14:21:18 -0700868BMK_benchOutcome_t BMK_benchFiles(
869 const char* const * fileNamesTable, unsigned nbFiles,
870 const char* dictFileName,
871 int cLevel, const ZSTD_compressionParameters* compressionParams,
872 int displayLevel)
Yann Collet4856a002015-01-24 01:58:16 +0100873{
Yann Collet2e45bad2018-08-23 14:21:18 -0700874 BMK_advancedParams_t const adv = BMK_initAdvancedParams();
George Lu0d1ee222018-06-15 16:21:08 -0400875 return BMK_benchFilesAdvanced(fileNamesTable, nbFiles, dictFileName, cLevel, compressionParams, displayLevel, &adv);
Yann Collet4856a002015-01-24 01:58:16 +0100876}