fullbench.c revision 1.1.1.2 1 /*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
8 * You may select, at your option, one of the above-listed licenses.
9 */
10
11
12 /*_************************************
13 * Includes
14 **************************************/
15 #define _CRT_SECURE_NO_WARNINGS /* disable Visual warning that it doesn't like fopen() */
16 #define ZSTD_DISABLE_DEPRECATE_WARNINGS /* No deprecation warnings, we still bench some deprecated functions */
17 #include <limits.h>
18 #include "util.h" /* Compiler options, UTIL_GetFileSize */
19 #include <stdlib.h> /* malloc */
20 #include <stdio.h> /* fprintf, fopen, ftello64 */
21 #include <assert.h>
22
23 #include "mem.h" /* U32 */
24 #include "compress/zstd_compress_internal.h"
25 #ifndef ZSTD_DLL_IMPORT
26 #include "zstd_internal.h" /* ZSTD_decodeSeqHeaders, ZSTD_blockHeaderSize, ZSTD_getcBlockSize, blockType_e, KB, MB */
27 #include "decompress/zstd_decompress_internal.h" /* ZSTD_DCtx struct */
28 #else
29 #define KB *(1 <<10)
30 #define MB *(1 <<20)
31 #define GB *(1U<<30)
32 typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e;
33 #endif
34 #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressBegin, ZSTD_compressContinue, etc. */
35 #include "zstd.h" /* ZSTD_versionString */
36 #include "util.h" /* time functions */
37 #include "datagen.h"
38 #include "lorem.h"
39 #include "benchfn.h" /* CustomBench */
40 #include "benchzstd.h" /* MB_UNIT */
41
42 /*_************************************
43 * Constants
44 **************************************/
45 #define PROGRAM_DESCRIPTION "Zstandard speed analyzer"
46 #define AUTHOR "Yann Collet"
47 #define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", PROGRAM_DESCRIPTION, ZSTD_versionString(), (int)(sizeof(void*)*8), AUTHOR, __DATE__
48
49 #define NBLOOPS 6
50 #define TIMELOOP_S 2
51
52 #define MAX_MEM (1984 MB)
53
54 #define DEFAULT_CLEVEL 1
55
56 #define COMPRESSIBILITY_DEFAULT (-1.0)
57 static const size_t kSampleSizeDefault = 10000000;
58
59 #define TIMELOOP_NANOSEC (1*1000000000ULL) /* 1 second */
60
61
62 /*_************************************
63 * Macros
64 **************************************/
65 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
66
67 #define CONTROL(c) { if (!(c)) { abort(); } } /* like assert(), but cannot be disabled */
68
69
70 /*_************************************
71 * Benchmark Parameters
72 **************************************/
73 static unsigned g_nbIterations = NBLOOPS;
74
75
76 /*_*******************************************************
77 * Private functions
78 *********************************************************/
79 static size_t BMK_findMaxMem(U64 requiredMem)
80 {
81 size_t const step = 64 MB;
82 void* testmem = NULL;
83
84 requiredMem = (((requiredMem >> 26) + 1) << 26);
85 if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
86
87 requiredMem += step;
88 do {
89 testmem = malloc ((size_t)requiredMem);
90 requiredMem -= step;
91 } while (!testmem);
92
93 free (testmem);
94 return (size_t) requiredMem;
95 }
96
97
98 /*_*******************************************************
99 * Benchmark wrappers
100 *********************************************************/
101
102 static ZSTD_CCtx* g_zcc = NULL;
103 static size_t
104 local_ZSTD_compress(const void* src, size_t srcSize,
105 void* dst, size_t dstSize,
106 void* payload)
107 {
108 ZSTD_parameters p;
109 ZSTD_frameParameters f = { 1 /* contentSizeHeader*/, 0, 0 };
110 p.fParams = f;
111 p.cParams = *(ZSTD_compressionParameters*)payload;
112 return ZSTD_compress_advanced (g_zcc, dst, dstSize, src, srcSize, NULL ,0, p);
113 }
114
115 static size_t
116 local_ZSTD_compress_freshCCtx(const void* src, size_t srcSize,
117 void* dst, size_t dstSize,
118 void* payload)
119 {
120 ZSTD_parameters p;
121 ZSTD_frameParameters f = { 1 /* contentSizeHeader*/, 0, 0 };
122 p.fParams = f;
123 p.cParams = *(ZSTD_compressionParameters*)payload;
124 if (g_zcc != NULL) ZSTD_freeCCtx(g_zcc);
125 g_zcc = ZSTD_createCCtx();
126 assert(g_zcc != NULL);
127 { size_t const r = ZSTD_compress_advanced (g_zcc, dst, dstSize, src, srcSize, NULL ,0, p);
128 ZSTD_freeCCtx(g_zcc);
129 g_zcc = NULL;
130 return r;
131 }
132 }
133
134 typedef struct {
135 void* prepBuffer;
136 size_t prepSize;
137 void* dst;
138 size_t dstCapacity;
139 size_t fixedOrigSize; /* optional, 0 means "no modification" */
140 } PrepResult;
141 #define PREPRESULT_INIT { NULL, 0, NULL, 0, 0 }
142
143 static PrepResult prepDecompress(const void* src, size_t srcSize, int cLevel)
144 {
145 size_t prepCapacity = ZSTD_compressBound(srcSize);
146 void* prepBuffer = malloc(prepCapacity);
147 size_t cSize = ZSTD_compress(prepBuffer, prepCapacity, src, srcSize, cLevel);
148 void* dst = malloc(srcSize);
149 PrepResult r = PREPRESULT_INIT;
150 assert(dst != NULL);
151 r.prepBuffer = prepBuffer;
152 r.prepSize = cSize;
153 r.dst = dst;
154 r.dstCapacity = srcSize;
155 return r;
156 }
157
158 static size_t local_ZSTD_decompress(const void* src, size_t srcSize,
159 void* dst, size_t dstSize,
160 void* unused)
161 {
162 (void)unused;
163 return ZSTD_decompress(dst, dstSize, src, srcSize);
164 }
165
166 static ZSTD_DCtx* g_zdc = NULL; /* will be initialized within benchMem */
167 static size_t local_ZSTD_decompressDCtx(const void* src, size_t srcSize,
168 void* dst, size_t dstSize,
169 void* unused)
170 {
171 (void)unused;
172 return ZSTD_decompressDCtx(g_zdc, dst, dstSize, src, srcSize);
173 }
174
175 #ifndef ZSTD_DLL_IMPORT
176
177 static PrepResult prepLiterals(const void* src, size_t srcSize, int cLevel)
178 {
179 PrepResult r = PREPRESULT_INIT;
180 size_t dstCapacity = srcSize;
181 void* dst = malloc(dstCapacity);
182 void* prepBuffer;
183 size_t prepSize = ZSTD_compress(dst, dstCapacity, src, srcSize, cLevel);
184 size_t frameHeaderSize = ZSTD_frameHeaderSize(dst, ZSTD_FRAMEHEADERSIZE_PREFIX(ZSTD_f_zstd1));
185 CONTROL(!ZSTD_isError(frameHeaderSize));
186 /* check block is compressible, hence contains a literals section */
187 { blockProperties_t bp;
188 ZSTD_getcBlockSize((char*)dst+frameHeaderSize, dstCapacity, &bp); /* Get 1st block type */
189 if (bp.blockType != bt_compressed) {
190 DISPLAY("no compressed literals\n");
191 return r;
192 } }
193 { size_t const skippedSize = frameHeaderSize + ZSTD_blockHeaderSize;
194 prepSize -= skippedSize;
195 prepBuffer = malloc(prepSize);
196 CONTROL(prepBuffer != NULL);
197 memmove(prepBuffer, (char*)dst+skippedSize, prepSize);
198 }
199 ZSTD_decompressBegin(g_zdc);
200 r.prepBuffer = prepBuffer;
201 r.prepSize = prepSize;
202 r.dst = dst;
203 r.dstCapacity = dstCapacity;
204 r.fixedOrigSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */
205 return r;
206 }
207
208 extern size_t ZSTD_decodeLiteralsBlock_wrapper(ZSTD_DCtx* dctx,
209 const void* src, size_t srcSize,
210 void* dst, size_t dstCapacity);
211 static size_t
212 local_ZSTD_decodeLiteralsBlock(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* unused)
213 {
214 (void)unused;
215 return ZSTD_decodeLiteralsBlock_wrapper(g_zdc, src, srcSize, dst, dstCapacity);
216 }
217
218 FORCE_NOINLINE size_t ZSTD_decodeLiteralsHeader(ZSTD_DCtx* dctx, void const* src, size_t srcSize)
219 {
220 RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, "");
221 {
222 BYTE const* istart = (BYTE const*)src;
223 SymbolEncodingType_e const litEncType = (SymbolEncodingType_e)(istart[0] & 3);
224 if (litEncType == set_compressed) {
225 RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3");
226 {
227 size_t lhSize, litSize, litCSize;
228 U32 const lhlCode = (istart[0] >> 2) & 3;
229 U32 const lhc = MEM_readLE32(istart);
230 int const flags = ZSTD_DCtx_get_bmi2(dctx) ? HUF_flags_bmi2 : 0;
231 switch(lhlCode)
232 {
233 case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */
234 /* 2 - 2 - 10 - 10 */
235 lhSize = 3;
236 litSize = (lhc >> 4) & 0x3FF;
237 litCSize = (lhc >> 14) & 0x3FF;
238 break;
239 case 2:
240 /* 2 - 2 - 14 - 14 */
241 lhSize = 4;
242 litSize = (lhc >> 4) & 0x3FFF;
243 litCSize = lhc >> 18;
244 break;
245 case 3:
246 /* 2 - 2 - 18 - 18 */
247 lhSize = 5;
248 litSize = (lhc >> 4) & 0x3FFFF;
249 litCSize = (lhc >> 22) + ((size_t)istart[4] << 10);
250 break;
251 }
252 RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, "");
253 RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, "");
254 #ifndef HUF_FORCE_DECOMPRESS_X2
255 return HUF_readDTableX1_wksp(
256 dctx->entropy.hufTable,
257 istart+lhSize, litCSize,
258 dctx->workspace, sizeof(dctx->workspace),
259 flags);
260 #else
261 return HUF_readDTableX2_wksp(
262 dctx->entropy.hufTable,
263 istart+lhSize, litCSize,
264 dctx->workspace, sizeof(dctx->workspace), flags);
265 #endif
266 }
267 }
268 }
269 return 0;
270 }
271
272 static size_t
273 local_ZSTD_decodeLiteralsHeader(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* unused)
274 {
275 (void)dst; (void)dstCapacity; (void)unused;
276 return ZSTD_decodeLiteralsHeader(g_zdc, src, srcSize);
277 }
278
279 static PrepResult prepSequences1stBlock(const void* src, size_t srcSize, int cLevel)
280 {
281 PrepResult r = PREPRESULT_INIT;
282 size_t const dstCapacity = srcSize;
283 void* dst = malloc(dstCapacity);
284 const BYTE* ip = dst;
285 const BYTE* iend;
286 { size_t const cSize = ZSTD_compress(dst, dstCapacity, src, srcSize, cLevel);
287 CONTROL(cSize > ZSTD_FRAMEHEADERSIZE_PREFIX(ZSTD_f_zstd1));
288 }
289 /* Skip frame Header */
290 { size_t const frameHeaderSize = ZSTD_frameHeaderSize(dst, ZSTD_FRAMEHEADERSIZE_PREFIX(ZSTD_f_zstd1));
291 CONTROL(!ZSTD_isError(frameHeaderSize));
292 ip += frameHeaderSize;
293 }
294 /* Find end of block */
295 { blockProperties_t bp;
296 size_t const cBlockSize = ZSTD_getcBlockSize(ip, dstCapacity, &bp); /* Get 1st block type */
297 if (bp.blockType != bt_compressed) {
298 DISPLAY("no compressed sequences\n");
299 return r;
300 }
301 iend = ip + ZSTD_blockHeaderSize + cBlockSize; /* End of first block */
302 }
303 ip += ZSTD_blockHeaderSize; /* skip block header */
304 ZSTD_decompressBegin(g_zdc);
305 CONTROL(iend > ip);
306 ip += ZSTD_decodeLiteralsBlock_wrapper(g_zdc, ip, (size_t)(iend-ip), dst, dstCapacity); /* skip literal segment */
307 r.prepSize = (size_t)(iend-ip);
308 r.prepBuffer = malloc(r.prepSize);
309 CONTROL(r.prepBuffer != NULL);
310 memmove(r.prepBuffer, ip, r.prepSize); /* copy rest of block (it starts by SeqHeader) */
311 r.dst = dst;
312 r.dstCapacity = dstCapacity;
313 r.fixedOrigSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */
314 return r;
315 }
316
317 static size_t
318 local_ZSTD_decodeSeqHeaders(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* unused)
319 {
320 int nbSeq;
321 (void)unused; (void)dst; (void)dstCapacity;
322 return ZSTD_decodeSeqHeaders(g_zdc, &nbSeq, src, srcSize);
323 }
324
325 #endif
326
327 static ZSTD_CStream* g_cstream= NULL;
328 static size_t
329 local_ZSTD_compressStream(const void* src, size_t srcSize,
330 void* dst, size_t dstCapacity,
331 void* payload)
332 {
333 ZSTD_outBuffer buffOut;
334 ZSTD_inBuffer buffIn;
335 ZSTD_parameters p;
336 ZSTD_frameParameters f = {1 /* contentSizeHeader*/, 0, 0};
337 p.fParams = f;
338 p.cParams = *(ZSTD_compressionParameters*)payload;
339 ZSTD_initCStream_advanced(g_cstream, NULL, 0, p, ZSTD_CONTENTSIZE_UNKNOWN);
340 buffOut.dst = dst;
341 buffOut.size = dstCapacity;
342 buffOut.pos = 0;
343 buffIn.src = src;
344 buffIn.size = srcSize;
345 buffIn.pos = 0;
346 ZSTD_compressStream(g_cstream, &buffOut, &buffIn);
347 ZSTD_endStream(g_cstream, &buffOut);
348 return buffOut.pos;
349 }
350
351 static size_t
352 local_ZSTD_compressStream_freshCCtx(const void* src, size_t srcSize,
353 void* dst, size_t dstCapacity,
354 void* payload)
355 {
356 if (g_cstream != NULL) ZSTD_freeCCtx(g_cstream);
357 g_cstream = ZSTD_createCCtx();
358 assert(g_cstream != NULL);
359
360 { size_t const r = local_ZSTD_compressStream(src, srcSize, dst, dstCapacity, payload);
361 ZSTD_freeCCtx(g_cstream);
362 g_cstream = NULL;
363 return r;
364 }
365 }
366
367 static size_t
368 local_ZSTD_compress2(const void* src, size_t srcSize,
369 void* dst, size_t dstCapacity,
370 void* payload)
371 {
372 (void)payload;
373 return ZSTD_compress2(g_cstream, dst, dstCapacity, src, srcSize);
374 }
375
376 static size_t
377 local_ZSTD_compressStream2_end(const void* src, size_t srcSize,
378 void* dst, size_t dstCapacity,
379 void* payload)
380 {
381 ZSTD_outBuffer buffOut;
382 ZSTD_inBuffer buffIn;
383 (void)payload;
384 buffOut.dst = dst;
385 buffOut.size = dstCapacity;
386 buffOut.pos = 0;
387 buffIn.src = src;
388 buffIn.size = srcSize;
389 buffIn.pos = 0;
390 ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_end);
391 return buffOut.pos;
392 }
393
394 static size_t
395 local_ZSTD_compressStream2_continue(const void* src, size_t srcSize,
396 void* dst, size_t dstCapacity,
397 void* payload)
398 {
399 ZSTD_outBuffer buffOut;
400 ZSTD_inBuffer buffIn;
401 (void)payload;
402 buffOut.dst = dst;
403 buffOut.size = dstCapacity;
404 buffOut.pos = 0;
405 buffIn.src = src;
406 buffIn.size = srcSize;
407 buffIn.pos = 0;
408 ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_continue);
409 ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_end);
410 return buffOut.pos;
411 }
412
413 static size_t
414 local_ZSTD_compress_generic_T2_end(const void* src, size_t srcSize,
415 void* dst, size_t dstCapacity,
416 void* payload)
417 {
418 (void)payload;
419 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_nbWorkers, 2);
420 return ZSTD_compress2(g_cstream, dst, dstCapacity, src, srcSize);
421 }
422
423 static size_t
424 local_ZSTD_compress_generic_T2_continue(const void* src, size_t srcSize,
425 void* dst, size_t dstCapacity,
426 void* payload)
427 {
428 ZSTD_outBuffer buffOut;
429 ZSTD_inBuffer buffIn;
430 (void)payload;
431 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_nbWorkers, 2);
432 buffOut.dst = dst;
433 buffOut.size = dstCapacity;
434 buffOut.pos = 0;
435 buffIn.src = src;
436 buffIn.size = srcSize;
437 buffIn.pos = 0;
438 ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_continue);
439 while(ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_end)) {}
440 return buffOut.pos;
441 }
442
443 static ZSTD_DStream* g_dstream= NULL;
444 static size_t
445 local_ZSTD_decompressStream(const void* src, size_t srcSize,
446 void* dst, size_t dstCapacity,
447 void* unused)
448 {
449 ZSTD_outBuffer buffOut;
450 ZSTD_inBuffer buffIn;
451 (void)unused;
452 ZSTD_initDStream(g_dstream);
453 buffOut.dst = dst;
454 buffOut.size = dstCapacity;
455 buffOut.pos = 0;
456 buffIn.src = src;
457 buffIn.size = srcSize;
458 buffIn.pos = 0;
459 ZSTD_decompressStream(g_dstream, &buffOut, &buffIn);
460 return buffOut.pos;
461 }
462
463 static size_t local_ZSTD_compressContinue(const void* src, size_t srcSize,
464 void* dst, size_t dstCapacity,
465 void* payload)
466 {
467 ZSTD_parameters p;
468 ZSTD_frameParameters f = { 1 /* contentSizeHeader*/, 0, 0 };
469 p.fParams = f;
470 p.cParams = *(ZSTD_compressionParameters*)payload;
471 ZSTD_compressBegin_advanced(g_zcc, NULL, 0, p, srcSize);
472 return ZSTD_compressEnd(g_zcc, dst, dstCapacity, src, srcSize);
473 }
474
475 #define FIRST_BLOCK_SIZE 8
476 static size_t
477 local_ZSTD_compressContinue_extDict(const void* src, size_t srcSize,
478 void* dst, size_t dstCapacity,
479 void* payload)
480 {
481 BYTE firstBlockBuf[FIRST_BLOCK_SIZE];
482
483 ZSTD_parameters p;
484 ZSTD_frameParameters const f = { 1, 0, 0 };
485 p.fParams = f;
486 p.cParams = *(ZSTD_compressionParameters*)payload;
487 ZSTD_compressBegin_advanced(g_zcc, NULL, 0, p, srcSize);
488 memcpy(firstBlockBuf, src, FIRST_BLOCK_SIZE);
489
490 { size_t const compressResult = ZSTD_compressContinue(g_zcc,
491 dst, dstCapacity,
492 firstBlockBuf, FIRST_BLOCK_SIZE);
493 if (ZSTD_isError(compressResult)) {
494 DISPLAY("local_ZSTD_compressContinue_extDict error : %s\n",
495 ZSTD_getErrorName(compressResult));
496 return compressResult;
497 }
498 dst = (BYTE*)dst + compressResult;
499 dstCapacity -= compressResult;
500 }
501 return ZSTD_compressEnd(g_zcc, dst, dstCapacity,
502 (const BYTE*)src + FIRST_BLOCK_SIZE,
503 srcSize - FIRST_BLOCK_SIZE);
504 }
505
506 static size_t local_ZSTD_decompressContinue(const void* src, size_t srcSize,
507 void* dst, size_t dstCapacity,
508 void* unused)
509 {
510 size_t regeneratedSize = 0;
511 const BYTE* ip = (const BYTE*)src;
512 const BYTE* const iend = ip + srcSize;
513 BYTE* op = (BYTE*)dst;
514 size_t remainingCapacity = dstCapacity;
515
516 (void)unused;
517 ZSTD_decompressBegin(g_zdc);
518 while (ip < iend) {
519 size_t const iSize = ZSTD_nextSrcSizeToDecompress(g_zdc);
520 size_t const decodedSize = ZSTD_decompressContinue(g_zdc, op, remainingCapacity, ip, iSize);
521 ip += iSize;
522 regeneratedSize += decodedSize;
523 op += decodedSize;
524 remainingCapacity -= decodedSize;
525 }
526
527 return regeneratedSize;
528 }
529
530 static PrepResult prepSequences(const void* src, size_t srcSize, int cLevel)
531 {
532 PrepResult r = PREPRESULT_INIT;
533 size_t const dstCapacity = ZSTD_compressBound(srcSize);
534 void* const dst = malloc(dstCapacity);
535 size_t const prepCapacity = dstCapacity * 4;
536 void* prepBuffer = malloc(prepCapacity);
537 void* sequencesStart = (char*)prepBuffer + 2*sizeof(unsigned);
538 ZSTD_Sequence* const seqs = sequencesStart;
539 size_t const seqsCapacity = prepCapacity / sizeof(ZSTD_Sequence);
540 size_t nbSeqs;
541 ZSTD_CCtx_reset(g_zcc, ZSTD_reset_session_and_parameters);
542 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_compressionLevel, cLevel);
543 nbSeqs = ZSTD_generateSequences(g_zcc, seqs, seqsCapacity, src, srcSize);
544 CONTROL(srcSize < UINT_MAX);
545 MEM_write32(prepBuffer, (U32)srcSize);
546 MEM_write32((char*)prepBuffer+4, (U32)nbSeqs);
547 memcpy(seqs + nbSeqs, src, srcSize);
548 r.prepBuffer = prepBuffer;
549 r.prepSize = 8 + sizeof(ZSTD_Sequence)*nbSeqs + srcSize;
550 r.dst = dst;
551 r.dstCapacity = dstCapacity;
552 return r;
553 }
554
555 static size_t local_compressSequences(const void* input, size_t inputSize,
556 void* dst, size_t dstCapacity,
557 void* payload)
558 {
559 const char* ip = input;
560 size_t srcSize = MEM_read32(ip);
561 size_t nbSeqs = MEM_read32(ip+=4);
562 const ZSTD_Sequence* seqs = (const ZSTD_Sequence*)(const void*)(ip+=4);
563 const void* src = (ip+=nbSeqs * sizeof(ZSTD_Sequence));
564 ZSTD_CCtx_reset(g_zcc, ZSTD_reset_session_and_parameters);
565 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters);
566 assert(8 + nbSeqs * sizeof(ZSTD_Sequence) + srcSize == inputSize); (void)inputSize;
567 (void)payload;
568
569 return ZSTD_compressSequences(g_zcc, dst, dstCapacity, seqs, nbSeqs, src, srcSize);
570 }
571
572 static PrepResult prepSequencesAndLiterals(const void* src, size_t srcSize, int cLevel)
573 {
574 PrepResult r = PREPRESULT_INIT;
575 size_t const dstCapacity = ZSTD_compressBound(srcSize);
576 void* const dst = malloc(dstCapacity);
577 size_t const prepCapacity = dstCapacity * 4;
578 void* prepBuffer = malloc(prepCapacity);
579 void* sequencesStart = (char*)prepBuffer + 3*sizeof(unsigned);
580 ZSTD_Sequence* const seqs = sequencesStart;
581 size_t const seqsCapacity = prepCapacity / sizeof(ZSTD_Sequence);
582 size_t nbSeqs;
583 ZSTD_CCtx_reset(g_zcc, ZSTD_reset_session_and_parameters);
584 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_compressionLevel, cLevel);
585 nbSeqs = ZSTD_generateSequences(g_zcc, seqs, seqsCapacity, src, srcSize);
586 CONTROL(srcSize < UINT_MAX);
587 MEM_write32(prepBuffer, (U32)srcSize);
588 MEM_write32((char*)prepBuffer+4, (U32)nbSeqs);
589 /* copy literals */
590 { char* const litStart = (char*)(seqs + nbSeqs);
591 size_t nbLiterals = 0;
592 const char* ip = src;
593 size_t n;
594 for (n=0; n<nbSeqs; n++) {
595 size_t const litSize = seqs[n].litLength;
596 memcpy(litStart + nbLiterals, ip, litSize);
597 ip += litSize + seqs[n].matchLength;
598 nbLiterals += litSize;
599 }
600 MEM_write32((char*)prepBuffer+8, (U32)nbLiterals);
601 r.prepBuffer = prepBuffer;
602 r.prepSize = 12 + sizeof(ZSTD_Sequence)*nbSeqs + nbLiterals;
603 r.dst = dst;
604 r.dstCapacity = dstCapacity;
605 }
606 return r;
607 }
608
609 static size_t
610 local_compressSequencesAndLiterals(const void* input, size_t inputSize,
611 void* dst, size_t dstCapacity,
612 void* payload)
613 {
614 const char* ip = input;
615 size_t decompressedSize = MEM_read32(ip);
616 size_t nbSeqs = MEM_read32(ip+=4);
617 size_t nbLiterals = MEM_read32(ip+=4);
618 const ZSTD_Sequence* seqs = (const ZSTD_Sequence*)(const void*)(ip+=4);
619 const void* literals = (ip+=nbSeqs * sizeof(ZSTD_Sequence));
620 ZSTD_CCtx_reset(g_zcc, ZSTD_reset_session_and_parameters);
621 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters);
622 # if 0 /* for tests */
623 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_repcodeResolution, ZSTD_ps_enable);
624 #endif
625 assert(12 + nbSeqs * sizeof(ZSTD_Sequence) + nbLiterals == inputSize); (void)inputSize;
626 (void)payload;
627
628 return ZSTD_compressSequencesAndLiterals(g_zcc, dst, dstCapacity, seqs, nbSeqs, literals, nbLiterals, nbLiterals + 8, decompressedSize);
629 }
630
631 static PrepResult prepConvertSequences(const void* src, size_t srcSize, int cLevel)
632 {
633 PrepResult r = PREPRESULT_INIT;
634 size_t const prepCapacity = srcSize * 4;
635 void* prepBuffer = malloc(prepCapacity);
636 void* sequencesStart = (char*)prepBuffer + 2*sizeof(unsigned);
637 ZSTD_Sequence* const seqs = sequencesStart;
638 size_t const seqsCapacity = prepCapacity / sizeof(ZSTD_Sequence);
639 size_t totalNbSeqs, nbSeqs, blockSize=0;
640 ZSTD_CCtx_reset(g_zcc, ZSTD_reset_session_and_parameters);
641 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_compressionLevel, cLevel);
642 totalNbSeqs = ZSTD_generateSequences(g_zcc, seqs, seqsCapacity, src, srcSize);
643 CONTROL(!ZSTD_isError(totalNbSeqs));
644 /* find nb sequences in first block */
645 { size_t n;
646 for (n=0; n<totalNbSeqs; n++) {
647 if (seqs[n].matchLength == 0) break;
648 blockSize += seqs[n].litLength + seqs[n].matchLength;
649 }
650 blockSize += seqs[n].litLength;
651 nbSeqs = n+1;
652 #if 0
653 printf("found %zu sequences representing a first block of size %zu\n", nbSeqs, blockSize);
654 #endif
655 }
656 /* generate benchmarked input */
657 CONTROL(blockSize < UINT_MAX);
658 MEM_write32(prepBuffer, (U32)blockSize);
659 MEM_write32((char*)prepBuffer+4, (U32)nbSeqs);
660 memcpy(seqs + nbSeqs, src, srcSize);
661 r.prepBuffer = prepBuffer;
662 r.prepSize = 8 + sizeof(ZSTD_Sequence) * nbSeqs;
663 r.fixedOrigSize = blockSize;
664 return r;
665 }
666
667 static size_t
668 local_convertSequences(const void* input, size_t inputSize,
669 void* dst, size_t dstCapacity,
670 void* payload)
671 {
672 const char* ip = input;
673 size_t const blockSize = MEM_read32(ip);
674 size_t const nbSeqs = MEM_read32(ip+=4);
675 const ZSTD_Sequence* seqs = (const ZSTD_Sequence*)(const void*)(ip+=4);
676 ZSTD_CCtx_reset(g_zcc, ZSTD_reset_session_and_parameters);
677 ZSTD_resetSeqStore(&g_zcc->seqStore);
678 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters);
679 # if 0 /* for tests */
680 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_repcodeResolution, ZSTD_ps_enable);
681 #endif
682 assert(8 + nbSeqs * sizeof(ZSTD_Sequence) == inputSize); (void)inputSize;
683 (void)dst; (void)dstCapacity;
684 (void)payload; (void)blockSize;
685
686 (void)ZSTD_convertBlockSequences(g_zcc, seqs, nbSeqs, 0);
687 return nbSeqs;
688 }
689
690 static size_t
691 check_compressedSequences(const void* compressed, size_t cSize, const void* orig, size_t origSize)
692 {
693 size_t decSize;
694 int diff;
695 void* decompressed = malloc(origSize);
696 if (decompressed == NULL) return 2;
697
698 decSize = ZSTD_decompress(decompressed, origSize, compressed, cSize);
699 if (decSize != origSize) { free(decompressed); DISPLAY("ZSTD_decompress failed (%u) ", (unsigned)decSize); return 1; }
700
701 diff = memcmp(decompressed, orig, origSize);
702 if (diff) { free(decompressed); return 1; }
703
704 free(decompressed);
705 return 0;
706 }
707
708 static size_t
709 local_get1BlockSummary(const void* input, size_t inputSize,
710 void* dst, size_t dstCapacity,
711 void* payload)
712 {
713 const char* ip = input;
714 size_t const blockSize = MEM_read32(ip);
715 size_t const nbSeqs = MEM_read32(ip+=4);
716 const ZSTD_Sequence* seqs = (const ZSTD_Sequence*)(const void*)(ip+=4);
717 ZSTD_CCtx_reset(g_zcc, ZSTD_reset_session_and_parameters);
718 ZSTD_resetSeqStore(&g_zcc->seqStore);
719 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_blockDelimiters, ZSTD_sf_explicitBlockDelimiters);
720 assert(8 + nbSeqs * sizeof(ZSTD_Sequence) == inputSize); (void)inputSize;
721 (void)dst; (void)dstCapacity;
722 (void)payload; (void)blockSize;
723
724 (void)ZSTD_get1BlockSummary(seqs, nbSeqs);
725 return nbSeqs;
726 }
727
728 static PrepResult prepCopy(const void* src, size_t srcSize, int cLevel)
729 {
730 PrepResult r = PREPRESULT_INIT;
731 (void)cLevel;
732 r.prepSize = srcSize;
733 r.prepBuffer = malloc(srcSize);
734 CONTROL(r.prepBuffer != NULL);
735 memcpy(r.prepBuffer, src, srcSize);
736 r.dstCapacity = ZSTD_compressBound(srcSize);
737 r.dst = malloc(r.dstCapacity);
738 CONTROL(r.dst != NULL);
739 return r;
740 }
741
742 static PrepResult prepShorterDstCapacity(const void* src, size_t srcSize, int cLevel)
743 {
744 PrepResult r = prepCopy(src, srcSize, cLevel);
745 assert(r.dstCapacity > 1);
746 r.dstCapacity -= 1;
747 return r;
748 }
749
750 /*_*******************************************************
751 * List of Scenarios
752 *********************************************************/
753
754 /* if PrepFunction_f returns PrepResult.prepBuffSize == 0, benchmarking is cancelled */
755 typedef PrepResult (*PrepFunction_f)(const void* src, size_t srcSize, int cLevel);
756 typedef size_t (*BenchedFunction_f)(const void* src, size_t srcSize, void* dst, size_t dstSize, void* opaque);
757 /* must return 0, otherwise verification is considered failed */
758 typedef size_t (*VerifFunction_f)(const void* processed, size_t procSize, const void* input, size_t inputSize);
759
760 typedef struct {
761 const char* name;
762 PrepFunction_f preparation_f;
763 BenchedFunction_f benched_f;
764 VerifFunction_f verif_f; /* optional */
765 } BenchScenario;
766
767 static BenchScenario kScenarios[] = {
768 { "compress", NULL, local_ZSTD_compress, check_compressedSequences },
769 { "decompress", prepDecompress, local_ZSTD_decompress, NULL },
770 { "compress_freshCCtx", NULL, local_ZSTD_compress_freshCCtx, check_compressedSequences },
771 { "decompressDCtx", prepDecompress, local_ZSTD_decompressDCtx, NULL },
772 { "compressContinue", NULL, local_ZSTD_compressContinue, check_compressedSequences },
773 { "compressContinue_extDict", NULL, local_ZSTD_compressContinue_extDict, NULL },
774 { "decompressContinue", prepDecompress, local_ZSTD_decompressContinue, NULL },
775 { "compressStream", NULL, local_ZSTD_compressStream, check_compressedSequences },
776 { "compressStream_freshCCtx", NULL, local_ZSTD_compressStream_freshCCtx, check_compressedSequences },
777 { "decompressStream", prepDecompress, local_ZSTD_decompressStream, NULL },
778 { "compress2", NULL, local_ZSTD_compress2, check_compressedSequences },
779 { "compressStream2, end", NULL, local_ZSTD_compressStream2_end, check_compressedSequences },
780 { "compressStream2, end & short", prepShorterDstCapacity, local_ZSTD_compressStream2_end, check_compressedSequences },
781 { "compressStream2, continue", NULL, local_ZSTD_compressStream2_continue, check_compressedSequences },
782 { "compressStream2, -T2, continue", NULL, local_ZSTD_compress_generic_T2_continue, check_compressedSequences },
783 { "compressStream2, -T2, end", NULL, local_ZSTD_compress_generic_T2_end, check_compressedSequences },
784 { "compressSequences", prepSequences, local_compressSequences, check_compressedSequences },
785 { "compressSequencesAndLiterals", prepSequencesAndLiterals, local_compressSequencesAndLiterals, check_compressedSequences },
786 { "convertSequences (1st block)", prepConvertSequences, local_convertSequences, NULL },
787 { "get1BlockSummary (1st block)", prepConvertSequences, local_get1BlockSummary, NULL },
788 #ifndef ZSTD_DLL_IMPORT
789 { "decodeLiteralsHeader (1st block)", prepLiterals, local_ZSTD_decodeLiteralsHeader, NULL },
790 { "decodeLiteralsBlock (1st block)", prepLiterals, local_ZSTD_decodeLiteralsBlock, NULL },
791 { "decodeSeqHeaders (1st block)", prepSequences1stBlock, local_ZSTD_decodeSeqHeaders, NULL },
792 #endif
793 };
794 #define NB_SCENARIOS (sizeof(kScenarios) / sizeof(kScenarios[0]))
795
796 /*_*******************************************************
797 * Bench loop
798 *********************************************************/
799 static int benchMem(unsigned scenarioID,
800 const void* origSrc, size_t origSrcSize,
801 int cLevel, ZSTD_compressionParameters cparams)
802 {
803 size_t dstCapacity = 0;
804 void* dst = NULL;
805 void* prepBuff = NULL;
806 size_t prepBuffSize = 0;
807 void* payload;
808 const char* benchName;
809 BMK_benchFn_t benchFunction;
810 PrepFunction_f prep_f;
811 VerifFunction_f verif_f;
812 int errorcode = 0;
813
814 if (scenarioID >= NB_SCENARIOS) return 0; /* scenario doesn't exist */
815
816 benchName = kScenarios[scenarioID].name;
817 benchFunction = kScenarios[scenarioID].benched_f;
818 prep_f = kScenarios[scenarioID].preparation_f;
819 verif_f = kScenarios[scenarioID].verif_f;
820 if (prep_f == NULL) prep_f = prepCopy; /* default */
821
822 /* Initialization */
823 if (g_zcc==NULL) g_zcc = ZSTD_createCCtx();
824 if (g_zdc==NULL) g_zdc = ZSTD_createDCtx();
825 if (g_cstream==NULL) g_cstream = ZSTD_createCStream();
826 if (g_dstream==NULL) g_dstream = ZSTD_createDStream();
827
828 /* DISPLAY("params: cLevel %d, wlog %d hlog %d clog %d slog %d mml %d tlen %d strat %d \n",
829 cLevel, cparams->windowLog, cparams->hashLog, cparams->chainLog, cparams->searchLog,
830 cparams->minMatch, cparams->targetLength, cparams->strategy); */
831
832 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_compressionLevel, cLevel);
833 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_windowLog, (int)cparams.windowLog);
834 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_hashLog, (int)cparams.hashLog);
835 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_chainLog, (int)cparams.chainLog);
836 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_searchLog, (int)cparams.searchLog);
837 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_minMatch, (int)cparams.minMatch);
838 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_targetLength, (int)cparams.targetLength);
839 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_strategy, (int)cparams.strategy);
840
841 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_compressionLevel, cLevel);
842 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_windowLog, (int)cparams.windowLog);
843 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_hashLog, (int)cparams.hashLog);
844 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_chainLog, (int)cparams.chainLog);
845 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_searchLog, (int)cparams.searchLog);
846 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_minMatch, (int)cparams.minMatch);
847 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_targetLength, (int)cparams.targetLength);
848 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_strategy, (int)cparams.strategy);
849
850 /* Preparation */
851 payload = &cparams;
852 { PrepResult pr = prep_f(origSrc, origSrcSize, cLevel);
853 dst = pr.dst;
854 dstCapacity = pr.dstCapacity;
855 prepBuff = pr.prepBuffer;
856 prepBuffSize = pr.prepSize;
857 if (pr.fixedOrigSize) origSrcSize = pr.fixedOrigSize;
858 }
859 if (prepBuffSize==0) goto _cleanOut; /* failed preparation */
860
861 /* warming up dstBuff */
862 { size_t i; for (i=0; i<dstCapacity; i++) ((BYTE*)dst)[i]=(BYTE)i; }
863
864 /* benchmark loop */
865 { BMK_timedFnState_t* const tfs = BMK_createTimedFnState(g_nbIterations * 1000, 1000);
866 void* const avoidStrictAliasingPtr = &dst;
867 const void* prepSrc = prepBuff;
868 BMK_benchParams_t bp;
869 BMK_runTime_t bestResult;
870 bestResult.sumOfReturn = 0;
871 bestResult.nanoSecPerRun = (double)TIMELOOP_NANOSEC * 2000000000; /* hopefully large enough : must be larger than any potential measurement */
872 CONTROL(tfs != NULL);
873
874 bp.benchFn = benchFunction;
875 bp.benchPayload = payload;
876 bp.initFn = NULL;
877 bp.initPayload = NULL;
878 bp.errorFn = ZSTD_isError;
879 bp.blockCount = 1;
880 bp.srcBuffers = &prepSrc;
881 bp.srcSizes = &prepBuffSize;
882 bp.dstBuffers = (void* const*) avoidStrictAliasingPtr; /* circumvent strict aliasing warning on gcc-8,
883 * because gcc considers that `void* const *` and `void**` are 2 different types */
884 bp.dstCapacities = &dstCapacity;
885 bp.blockResults = NULL;
886
887 for (;;) {
888 BMK_runOutcome_t const bOutcome = BMK_benchTimedFn(tfs, bp);
889
890 if (!BMK_isSuccessful_runOutcome(bOutcome)) {
891 DISPLAY("ERROR: Scenario %u: %s \n", scenarioID, ZSTD_getErrorName(BMK_extract_errorResult(bOutcome)));
892 errorcode = 1;
893 goto _cleanOut;
894 }
895
896 { BMK_runTime_t const newResult = BMK_extract_runTime(bOutcome);
897 if (newResult.nanoSecPerRun < bestResult.nanoSecPerRun )
898 bestResult.nanoSecPerRun = newResult.nanoSecPerRun;
899 DISPLAY("\r%2u#%-31.31s:%8.1f MB/s (%8u) ",
900 scenarioID, benchName,
901 (double)origSrcSize * TIMELOOP_NANOSEC / bestResult.nanoSecPerRun / MB_UNIT,
902 (unsigned)newResult.sumOfReturn );
903
904 if (verif_f) {
905 size_t const vRes = verif_f(dst, newResult.sumOfReturn, origSrc, origSrcSize);
906 if (vRes) {
907 DISPLAY(" validation failed ! (%u)\n", (unsigned)vRes);
908 break;
909 }
910 }
911 }
912
913 if ( BMK_isCompleted_TimedFn(tfs) ) break;
914 }
915 BMK_freeTimedFnState(tfs);
916 }
917 DISPLAY("\n");
918
919 _cleanOut:
920 free(prepBuff);
921 free(dst);
922 ZSTD_freeCCtx(g_zcc); g_zcc=NULL;
923 ZSTD_freeDCtx(g_zdc); g_zdc=NULL;
924 ZSTD_freeCStream(g_cstream); g_cstream=NULL;
925 ZSTD_freeDStream(g_dstream); g_dstream=NULL;
926 return errorcode;
927 }
928
929
930 #define BENCH_ALL_SCENARIOS 999
931 /*
932 * if @compressibility < 0.0, use Lorem Ipsum generator
933 * otherwise, @compressibility is expected to be between 0.0 and 1.0
934 * if scenarioID == BENCH_ALL_SCENARIOS, all scenarios will be run on the sample
935 */
936 static int benchSample(U32 scenarioID,
937 size_t benchedSize, double compressibility,
938 int cLevel, ZSTD_compressionParameters cparams)
939 {
940 /* Allocation */
941 void* const origBuff = malloc(benchedSize);
942 if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); return 12; }
943
944 /* Fill buffer */
945 if (compressibility < 0.0) {
946 LOREM_genBuffer(origBuff, benchedSize, 0);
947 } else {
948 RDG_genBuffer(origBuff, benchedSize, compressibility, 0.0, 0);
949
950 }
951
952 /* bench */
953 DISPLAY("\r%70s\r", "");
954 DISPLAY(" Sample %u bytes : \n", (unsigned)benchedSize);
955 if (scenarioID == BENCH_ALL_SCENARIOS) {
956 for (scenarioID=0; scenarioID<100; scenarioID++) {
957 benchMem(scenarioID, origBuff, benchedSize, cLevel, cparams);
958 }
959 } else {
960 benchMem(scenarioID, origBuff, benchedSize, cLevel, cparams);
961 }
962
963 free(origBuff);
964 return 0;
965 }
966
967
968 static int benchFiles(U32 scenarioID,
969 const char** fileNamesTable, const int nbFiles,
970 int cLevel, ZSTD_compressionParameters cparams)
971 {
972 /* Loop for each file */
973 int fileIdx;
974 for (fileIdx=0; fileIdx<nbFiles; fileIdx++) {
975 const char* const inFileName = fileNamesTable[fileIdx];
976 FILE* const inFile = fopen( inFileName, "rb" );
977 size_t benchedSize;
978
979 /* Check file existence */
980 if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; }
981
982 /* Memory allocation & restrictions */
983 { U64 const inFileSize = UTIL_getFileSize(inFileName);
984 if (inFileSize == UTIL_FILESIZE_UNKNOWN) {
985 DISPLAY( "Cannot measure size of %s\n", inFileName);
986 fclose(inFile);
987 return 11;
988 }
989 benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
990 if ((U64)benchedSize > inFileSize)
991 benchedSize = (size_t)inFileSize;
992 if ((U64)benchedSize < inFileSize) {
993 DISPLAY("Not enough memory for '%s' full size; testing %u MB only... \n",
994 inFileName, (unsigned)(benchedSize>>20));
995 } }
996
997 /* Alloc */
998 { void* const origBuff = malloc(benchedSize);
999 if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); fclose(inFile); return 12; }
1000
1001 /* Fill input buffer */
1002 DISPLAY("Loading %s... \r", inFileName);
1003 { size_t const readSize = fread(origBuff, 1, benchedSize, inFile);
1004 fclose(inFile);
1005 if (readSize != benchedSize) {
1006 DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
1007 free(origBuff);
1008 return 13;
1009 } }
1010
1011 /* bench */
1012 DISPLAY("\r%70s\r", ""); /* blank line */
1013 DISPLAY(" %s : \n", inFileName);
1014 if (scenarioID == BENCH_ALL_SCENARIOS) {
1015 for (scenarioID=0; scenarioID<100; scenarioID++) {
1016 benchMem(scenarioID, origBuff, benchedSize, cLevel, cparams);
1017 }
1018 } else {
1019 benchMem(scenarioID, origBuff, benchedSize, cLevel, cparams);
1020 }
1021
1022 free(origBuff);
1023 } }
1024
1025 return 0;
1026 }
1027
1028
1029
1030 /*_*******************************************************
1031 * Argument Parsing
1032 *********************************************************/
1033
1034 #define ERROR_OUT(msg) { DISPLAY("%s \n", msg); exit(1); }
1035
1036 static unsigned readU32FromChar(const char** stringPtr)
1037 {
1038 const char errorMsg[] = "error: numeric value too large";
1039 unsigned result = 0;
1040 while ((**stringPtr >='0') && (**stringPtr <='9')) {
1041 unsigned const max = (((unsigned)(-1)) / 10) - 1;
1042 if (result > max) ERROR_OUT(errorMsg);
1043 result *= 10;
1044 result += (unsigned)(**stringPtr - '0');
1045 (*stringPtr)++ ;
1046 }
1047 if ((**stringPtr=='K') || (**stringPtr=='M')) {
1048 unsigned const maxK = ((unsigned)(-1)) >> 10;
1049 if (result > maxK) ERROR_OUT(errorMsg);
1050 result <<= 10;
1051 if (**stringPtr=='M') {
1052 if (result > maxK) ERROR_OUT(errorMsg);
1053 result <<= 10;
1054 }
1055 (*stringPtr)++; /* skip `K` or `M` */
1056 if (**stringPtr=='i') (*stringPtr)++;
1057 if (**stringPtr=='B') (*stringPtr)++;
1058 }
1059 return result;
1060 }
1061
1062 static int longCommandWArg(const char** stringPtr, const char* longCommand)
1063 {
1064 size_t const comSize = strlen(longCommand);
1065 int const result = !strncmp(*stringPtr, longCommand, comSize);
1066 if (result) *stringPtr += comSize;
1067 return result;
1068 }
1069
1070
1071 /*_*******************************************************
1072 * Command line
1073 *********************************************************/
1074
1075 static int usage(const char* exename)
1076 {
1077 DISPLAY( "Usage :\n");
1078 DISPLAY( " %s [arg] file1 file2 ... fileX\n", exename);
1079 DISPLAY( "Arguments :\n");
1080 DISPLAY( " -H/-h : Help (this text + advanced options)\n");
1081 return 0;
1082 }
1083
1084 static int usage_advanced(const char* exename)
1085 {
1086 usage(exename);
1087 DISPLAY( "\nAdvanced options :\n");
1088 DISPLAY( " -b# : test only function # \n");
1089 DISPLAY( " -l# : benchmark functions at that compression level (default : %i)\n", DEFAULT_CLEVEL);
1090 DISPLAY( "--zstd= : custom parameter selection. Format same as zstdcli \n");
1091 DISPLAY( " -P# : sample compressibility (default : %.1f%%)\n", COMPRESSIBILITY_DEFAULT * 100);
1092 DISPLAY( " -B# : sample size (default : %u)\n", (unsigned)kSampleSizeDefault);
1093 DISPLAY( " -i# : iteration loops [1-9](default : %i)\n", NBLOOPS);
1094 return 0;
1095 }
1096
1097 static int badusage(const char* exename)
1098 {
1099 DISPLAY("Wrong parameters\n");
1100 usage(exename);
1101 return 1;
1102 }
1103
1104 int main(int argc, const char** argv)
1105 {
1106 int argNb, filenamesStart=0, result;
1107 const char* const exename = argv[0];
1108 const char* input_filename = NULL;
1109 U32 scenarioID = BENCH_ALL_SCENARIOS, main_pause = 0;
1110 int cLevel = DEFAULT_CLEVEL;
1111 ZSTD_compressionParameters cparams = ZSTD_getCParams(cLevel, 0, 0);
1112 size_t sampleSize = kSampleSizeDefault;
1113 double compressibility = COMPRESSIBILITY_DEFAULT;
1114
1115 DISPLAY(WELCOME_MESSAGE);
1116 if (argc<1) return badusage(exename);
1117
1118 for (argNb=1; argNb<argc; argNb++) {
1119 const char* argument = argv[argNb];
1120 CONTROL(argument != NULL);
1121
1122 if (longCommandWArg(&argument, "--zstd=")) {
1123 for ( ; ;) {
1124 if (longCommandWArg(&argument, "windowLog=") || longCommandWArg(&argument, "wlog=")) { cparams.windowLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
1125 if (longCommandWArg(&argument, "chainLog=") || longCommandWArg(&argument, "clog=")) { cparams.chainLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
1126 if (longCommandWArg(&argument, "hashLog=") || longCommandWArg(&argument, "hlog=")) { cparams.hashLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
1127 if (longCommandWArg(&argument, "searchLog=") || longCommandWArg(&argument, "slog=")) { cparams.searchLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
1128 if (longCommandWArg(&argument, "minMatch=") || longCommandWArg(&argument, "mml=")) { cparams.minMatch = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
1129 if (longCommandWArg(&argument, "targetLength=") || longCommandWArg(&argument, "tlen=")) { cparams.targetLength = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; }
1130 if (longCommandWArg(&argument, "strategy=") || longCommandWArg(&argument, "strat=")) { cparams.strategy = (ZSTD_strategy)(readU32FromChar(&argument)); if (argument[0]==',') { argument++; continue; } else break; }
1131 if (longCommandWArg(&argument, "level=") || longCommandWArg(&argument, "lvl=")) { cLevel = (int)readU32FromChar(&argument); cparams = ZSTD_getCParams(cLevel, 0, 0); if (argument[0]==',') { argument++; continue; } else break; }
1132 DISPLAY("invalid compression parameter \n");
1133 return 1;
1134 }
1135
1136 /* check end of string */
1137 if (argument[0] != 0) {
1138 DISPLAY("invalid --zstd= format \n");
1139 return 1;
1140 } else {
1141 continue;
1142 }
1143
1144 } else if (argument[0]=='-') { /* Commands (note : aggregated commands are allowed) */
1145 argument++;
1146 while (argument[0]!=0) {
1147
1148 switch(argument[0])
1149 {
1150 /* Display help on usage */
1151 case 'h':
1152 case 'H': return usage_advanced(exename);
1153
1154 /* Pause at the end (hidden option) */
1155 case 'p': main_pause = 1; break;
1156
1157 /* Select specific algorithm to bench */
1158 case 'b':
1159 argument++;
1160 scenarioID = readU32FromChar(&argument);
1161 break;
1162
1163 /* Select compression level to use */
1164 case 'l':
1165 argument++;
1166 cLevel = (int)readU32FromChar(&argument);
1167 cparams = ZSTD_getCParams(cLevel, 0, 0);
1168 break;
1169
1170 /* Select compressibility of synthetic sample */
1171 case 'P':
1172 argument++;
1173 compressibility = (double)readU32FromChar(&argument) / 100.;
1174 break;
1175
1176 /* Select size of synthetic sample */
1177 case 'B':
1178 argument++;
1179 sampleSize = (size_t)readU32FromChar(&argument);
1180 break;
1181
1182 /* Modify Nb Iterations */
1183 case 'i':
1184 argument++;
1185 g_nbIterations = readU32FromChar(&argument);
1186 break;
1187
1188 /* Unknown command */
1189 default : return badusage(exename);
1190 }
1191 }
1192 continue;
1193 }
1194
1195 /* first provided filename is input */
1196 if (!input_filename) { input_filename=argument; filenamesStart=argNb; continue; }
1197 }
1198
1199
1200
1201 if (filenamesStart==0) /* no input file */
1202 result = benchSample(scenarioID, sampleSize, compressibility, cLevel, cparams);
1203 else
1204 result = benchFiles(scenarioID, argv+filenamesStart, argc-filenamesStart, cLevel, cparams);
1205
1206 if (main_pause) { int unused; printf("press enter...\n"); unused = getchar(); (void)unused; }
1207
1208 return result;
1209 }
1210