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