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