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 ZSTD_DISABLE_DEPRECATE_WARNINGS /* No deprecation warnings, we still bench some deprecated functions */ 16 #include "util.h" /* Compiler options, UTIL_GetFileSize */ 17 #include <stdlib.h> /* malloc */ 18 #include <stdio.h> /* fprintf, fopen, ftello64 */ 19 #include <assert.h> 20 21 #include "timefn.h" /* UTIL_clockSpanNano, UTIL_getTime */ 22 #include "mem.h" /* U32 */ 23 #ifndef ZSTD_DLL_IMPORT 24 #include "zstd_internal.h" /* ZSTD_decodeSeqHeaders, ZSTD_blockHeaderSize, ZSTD_getcBlockSize, blockType_e, KB, MB */ 25 #include "decompress/zstd_decompress_internal.h" /* ZSTD_DCtx struct */ 26 #else 27 #define KB *(1 <<10) 28 #define MB *(1 <<20) 29 #define GB *(1U<<30) 30 typedef enum { bt_raw, bt_rle, bt_compressed, bt_reserved } blockType_e; 31 #endif 32 #define ZSTD_STATIC_LINKING_ONLY /* ZSTD_compressBegin, ZSTD_compressContinue, etc. */ 33 #include "zstd.h" /* ZSTD_versionString */ 34 #include "util.h" /* time functions */ 35 #include "datagen.h" 36 #include "benchfn.h" /* CustomBench */ 37 #include "benchzstd.h" /* MB_UNIT */ 38 39 40 /*_************************************ 41 * Constants 42 **************************************/ 43 #define PROGRAM_DESCRIPTION "Zstandard speed analyzer" 44 #define AUTHOR "Yann Collet" 45 #define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", PROGRAM_DESCRIPTION, ZSTD_versionString(), (int)(sizeof(void*)*8), AUTHOR, __DATE__ 46 47 #define NBLOOPS 6 48 #define TIMELOOP_S 2 49 50 #define MAX_MEM (1984 MB) 51 52 #define DEFAULT_CLEVEL 1 53 54 #define COMPRESSIBILITY_DEFAULT 0.50 55 static const size_t kSampleSizeDefault = 10000000; 56 57 #define TIMELOOP_NANOSEC (1*1000000000ULL) /* 1 second */ 58 59 60 /*_************************************ 61 * Macros 62 **************************************/ 63 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) 64 65 #define CONTROL(c) { if (!(c)) { abort(); } } /* like assert(), but cannot be disabled */ 66 67 /*_************************************ 68 * Benchmark Parameters 69 **************************************/ 70 static unsigned g_nbIterations = NBLOOPS; 71 72 73 /*_******************************************************* 74 * Private functions 75 *********************************************************/ 76 static size_t BMK_findMaxMem(U64 requiredMem) 77 { 78 size_t const step = 64 MB; 79 void* testmem = NULL; 80 81 requiredMem = (((requiredMem >> 26) + 1) << 26); 82 if (requiredMem > MAX_MEM) requiredMem = MAX_MEM; 83 84 requiredMem += step; 85 do { 86 testmem = malloc ((size_t)requiredMem); 87 requiredMem -= step; 88 } while (!testmem); 89 90 free (testmem); 91 return (size_t) requiredMem; 92 } 93 94 95 /*_******************************************************* 96 * Benchmark wrappers 97 *********************************************************/ 98 99 static ZSTD_CCtx* g_zcc = NULL; 100 101 static size_t 102 local_ZSTD_compress(const void* src, size_t srcSize, 103 void* dst, size_t dstSize, 104 void* payload) 105 { 106 ZSTD_parameters p; 107 ZSTD_frameParameters f = { 1 /* contentSizeHeader*/, 0, 0 }; 108 p.fParams = f; 109 p.cParams = *(ZSTD_compressionParameters*)payload; 110 return ZSTD_compress_advanced (g_zcc, dst, dstSize, src, srcSize, NULL ,0, p); 111 } 112 113 static size_t 114 local_ZSTD_compress_freshCCtx(const void* src, size_t srcSize, 115 void* dst, size_t dstSize, 116 void* payload) 117 { 118 ZSTD_parameters p; 119 ZSTD_frameParameters f = { 1 /* contentSizeHeader*/, 0, 0 }; 120 p.fParams = f; 121 p.cParams = *(ZSTD_compressionParameters*)payload; 122 if (g_zcc != NULL) ZSTD_freeCCtx(g_zcc); 123 g_zcc = ZSTD_createCCtx(); 124 assert(g_zcc != NULL); 125 { size_t const r = ZSTD_compress_advanced (g_zcc, dst, dstSize, src, srcSize, NULL ,0, p); 126 ZSTD_freeCCtx(g_zcc); 127 g_zcc = NULL; 128 return r; 129 } 130 } 131 132 static size_t g_cSize = 0; 133 static size_t local_ZSTD_decompress(const void* src, size_t srcSize, 134 void* dst, size_t dstSize, 135 void* buff2) 136 { 137 (void)src; (void)srcSize; 138 return ZSTD_decompress(dst, dstSize, buff2, g_cSize); 139 } 140 141 static ZSTD_DCtx* g_zdc = NULL; /* will be initialized within benchMem */ 142 static size_t local_ZSTD_decompressDCtx(const void* src, size_t srcSize, 143 void* dst, size_t dstSize, 144 void* buff2) 145 { 146 (void)src; (void)srcSize; 147 return ZSTD_decompressDCtx(g_zdc, dst, dstSize, buff2, g_cSize); 148 } 149 150 #ifndef ZSTD_DLL_IMPORT 151 152 extern size_t ZSTD_decodeLiteralsBlock_wrapper(ZSTD_DCtx* dctx, 153 const void* src, size_t srcSize, 154 void* dst, size_t dstCapacity); 155 static size_t local_ZSTD_decodeLiteralsBlock(const void* src, size_t srcSize, void* dst, size_t dstSize, void* buff2) 156 { 157 (void)src; (void)srcSize; (void)dst; (void)dstSize; 158 return ZSTD_decodeLiteralsBlock_wrapper(g_zdc, buff2, g_cSize, dst, dstSize); 159 } 160 161 static size_t local_ZSTD_decodeSeqHeaders(const void* src, size_t srcSize, void* dst, size_t dstSize, void* buff2) 162 { 163 int nbSeq; 164 (void)src; (void)srcSize; (void)dst; (void)dstSize; 165 return ZSTD_decodeSeqHeaders(g_zdc, &nbSeq, buff2, g_cSize); 166 } 167 168 FORCE_NOINLINE size_t ZSTD_decodeLiteralsHeader(ZSTD_DCtx* dctx, void const* src, size_t srcSize) 169 { 170 RETURN_ERROR_IF(srcSize < MIN_CBLOCK_SIZE, corruption_detected, ""); 171 { 172 BYTE const* istart = (BYTE const*)src; 173 symbolEncodingType_e const litEncType = (symbolEncodingType_e)(istart[0] & 3); 174 if (litEncType == set_compressed) { 175 RETURN_ERROR_IF(srcSize < 5, corruption_detected, "srcSize >= MIN_CBLOCK_SIZE == 3; here we need up to 5 for case 3"); 176 { 177 size_t lhSize, litSize, litCSize; 178 U32 const lhlCode = (istart[0] >> 2) & 3; 179 U32 const lhc = MEM_readLE32(istart); 180 int const flags = ZSTD_DCtx_get_bmi2(dctx) ? HUF_flags_bmi2 : 0; 181 switch(lhlCode) 182 { 183 case 0: case 1: default: /* note : default is impossible, since lhlCode into [0..3] */ 184 /* 2 - 2 - 10 - 10 */ 185 lhSize = 3; 186 litSize = (lhc >> 4) & 0x3FF; 187 litCSize = (lhc >> 14) & 0x3FF; 188 break; 189 case 2: 190 /* 2 - 2 - 14 - 14 */ 191 lhSize = 4; 192 litSize = (lhc >> 4) & 0x3FFF; 193 litCSize = lhc >> 18; 194 break; 195 case 3: 196 /* 2 - 2 - 18 - 18 */ 197 lhSize = 5; 198 litSize = (lhc >> 4) & 0x3FFFF; 199 litCSize = (lhc >> 22) + ((size_t)istart[4] << 10); 200 break; 201 } 202 RETURN_ERROR_IF(litSize > ZSTD_BLOCKSIZE_MAX, corruption_detected, ""); 203 RETURN_ERROR_IF(litCSize + lhSize > srcSize, corruption_detected, ""); 204 #ifndef HUF_FORCE_DECOMPRESS_X2 205 return HUF_readDTableX1_wksp( 206 dctx->entropy.hufTable, 207 istart+lhSize, litCSize, 208 dctx->workspace, sizeof(dctx->workspace), 209 flags); 210 #else 211 return HUF_readDTableX2_wksp( 212 dctx->entropy.hufTable, 213 istart+lhSize, litCSize, 214 dctx->workspace, sizeof(dctx->workspace), flags); 215 #endif 216 } 217 } 218 } 219 return 0; 220 } 221 222 static size_t local_ZSTD_decodeLiteralsHeader(const void* src, size_t srcSize, void* dst, size_t dstSize, void* buff2) 223 { 224 (void)dst, (void)dstSize, (void)src, (void)srcSize; 225 return ZSTD_decodeLiteralsHeader(g_zdc, buff2, g_cSize); 226 } 227 #endif 228 229 static ZSTD_CStream* g_cstream= NULL; 230 static size_t 231 local_ZSTD_compressStream(const void* src, size_t srcSize, 232 void* dst, size_t dstCapacity, 233 void* payload) 234 { 235 ZSTD_outBuffer buffOut; 236 ZSTD_inBuffer buffIn; 237 ZSTD_parameters p; 238 ZSTD_frameParameters f = {1 /* contentSizeHeader*/, 0, 0}; 239 p.fParams = f; 240 p.cParams = *(ZSTD_compressionParameters*)payload; 241 ZSTD_initCStream_advanced(g_cstream, NULL, 0, p, ZSTD_CONTENTSIZE_UNKNOWN); 242 buffOut.dst = dst; 243 buffOut.size = dstCapacity; 244 buffOut.pos = 0; 245 buffIn.src = src; 246 buffIn.size = srcSize; 247 buffIn.pos = 0; 248 ZSTD_compressStream(g_cstream, &buffOut, &buffIn); 249 ZSTD_endStream(g_cstream, &buffOut); 250 return buffOut.pos; 251 } 252 253 static size_t 254 local_ZSTD_compressStream_freshCCtx(const void* src, size_t srcSize, 255 void* dst, size_t dstCapacity, 256 void* payload) 257 { 258 if (g_cstream != NULL) ZSTD_freeCCtx(g_cstream); 259 g_cstream = ZSTD_createCCtx(); 260 assert(g_cstream != NULL); 261 262 { size_t const r = local_ZSTD_compressStream(src, srcSize, dst, dstCapacity, payload); 263 ZSTD_freeCCtx(g_cstream); 264 g_cstream = NULL; 265 return r; 266 } 267 } 268 269 static size_t 270 local_ZSTD_compress2(const void* src, size_t srcSize, 271 void* dst, size_t dstCapacity, 272 void* payload) 273 { 274 (void)payload; 275 return ZSTD_compress2(g_cstream, dst, dstCapacity, src, srcSize); 276 } 277 278 static size_t 279 local_ZSTD_compressStream2_end(const void* src, size_t srcSize, 280 void* dst, size_t dstCapacity, 281 void* payload) 282 { 283 ZSTD_outBuffer buffOut; 284 ZSTD_inBuffer buffIn; 285 (void)payload; 286 buffOut.dst = dst; 287 buffOut.size = dstCapacity; 288 buffOut.pos = 0; 289 buffIn.src = src; 290 buffIn.size = srcSize; 291 buffIn.pos = 0; 292 ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_end); 293 return buffOut.pos; 294 } 295 296 static size_t 297 local_ZSTD_compressStream2_continue(const void* src, size_t srcSize, 298 void* dst, size_t dstCapacity, 299 void* payload) 300 { 301 ZSTD_outBuffer buffOut; 302 ZSTD_inBuffer buffIn; 303 (void)payload; 304 buffOut.dst = dst; 305 buffOut.size = dstCapacity; 306 buffOut.pos = 0; 307 buffIn.src = src; 308 buffIn.size = srcSize; 309 buffIn.pos = 0; 310 ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_continue); 311 ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_end); 312 return buffOut.pos; 313 } 314 315 static size_t 316 local_ZSTD_compress_generic_T2_end(const void* src, size_t srcSize, 317 void* dst, size_t dstCapacity, 318 void* payload) 319 { 320 (void)payload; 321 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_nbWorkers, 2); 322 return ZSTD_compress2(g_cstream, dst, dstCapacity, src, srcSize); 323 } 324 325 static size_t 326 local_ZSTD_compress_generic_T2_continue(const void* src, size_t srcSize, 327 void* dst, size_t dstCapacity, 328 void* payload) 329 { 330 ZSTD_outBuffer buffOut; 331 ZSTD_inBuffer buffIn; 332 (void)payload; 333 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_nbWorkers, 2); 334 buffOut.dst = dst; 335 buffOut.size = dstCapacity; 336 buffOut.pos = 0; 337 buffIn.src = src; 338 buffIn.size = srcSize; 339 buffIn.pos = 0; 340 ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_continue); 341 while(ZSTD_compressStream2(g_cstream, &buffOut, &buffIn, ZSTD_e_end)) {} 342 return buffOut.pos; 343 } 344 345 static ZSTD_DStream* g_dstream= NULL; 346 static size_t 347 local_ZSTD_decompressStream(const void* src, size_t srcSize, 348 void* dst, size_t dstCapacity, 349 void* buff2) 350 { 351 ZSTD_outBuffer buffOut; 352 ZSTD_inBuffer buffIn; 353 (void)src; (void)srcSize; 354 ZSTD_initDStream(g_dstream); 355 buffOut.dst = dst; 356 buffOut.size = dstCapacity; 357 buffOut.pos = 0; 358 buffIn.src = buff2; 359 buffIn.size = g_cSize; 360 buffIn.pos = 0; 361 ZSTD_decompressStream(g_dstream, &buffOut, &buffIn); 362 return buffOut.pos; 363 } 364 365 #ifndef ZSTD_DLL_IMPORT 366 static size_t local_ZSTD_compressContinue(const void* src, size_t srcSize, 367 void* dst, size_t dstCapacity, 368 void* payload) 369 { 370 ZSTD_parameters p; 371 ZSTD_frameParameters f = { 1 /* contentSizeHeader*/, 0, 0 }; 372 p.fParams = f; 373 p.cParams = *(ZSTD_compressionParameters*)payload; 374 ZSTD_compressBegin_advanced(g_zcc, NULL, 0, p, srcSize); 375 return ZSTD_compressEnd(g_zcc, dst, dstCapacity, src, srcSize); 376 } 377 378 #define FIRST_BLOCK_SIZE 8 379 static size_t 380 local_ZSTD_compressContinue_extDict(const void* src, size_t srcSize, 381 void* dst, size_t dstCapacity, 382 void* payload) 383 { 384 BYTE firstBlockBuf[FIRST_BLOCK_SIZE]; 385 386 ZSTD_parameters p; 387 ZSTD_frameParameters const f = { 1, 0, 0 }; 388 p.fParams = f; 389 p.cParams = *(ZSTD_compressionParameters*)payload; 390 ZSTD_compressBegin_advanced(g_zcc, NULL, 0, p, srcSize); 391 memcpy(firstBlockBuf, src, FIRST_BLOCK_SIZE); 392 393 { size_t const compressResult = ZSTD_compressContinue(g_zcc, 394 dst, dstCapacity, 395 firstBlockBuf, FIRST_BLOCK_SIZE); 396 if (ZSTD_isError(compressResult)) { 397 DISPLAY("local_ZSTD_compressContinue_extDict error : %s\n", 398 ZSTD_getErrorName(compressResult)); 399 return compressResult; 400 } 401 dst = (BYTE*)dst + compressResult; 402 dstCapacity -= compressResult; 403 } 404 return ZSTD_compressEnd(g_zcc, dst, dstCapacity, 405 (const BYTE*)src + FIRST_BLOCK_SIZE, 406 srcSize - FIRST_BLOCK_SIZE); 407 } 408 409 static size_t local_ZSTD_decompressContinue(const void* src, size_t srcSize, 410 void* dst, size_t dstCapacity, 411 void* buff2) 412 { 413 size_t regeneratedSize = 0; 414 const BYTE* ip = (const BYTE*)buff2; 415 const BYTE* const iend = ip + g_cSize; 416 BYTE* op = (BYTE*)dst; 417 size_t remainingCapacity = dstCapacity; 418 419 (void)src; (void)srcSize; /* unused */ 420 ZSTD_decompressBegin(g_zdc); 421 while (ip < iend) { 422 size_t const iSize = ZSTD_nextSrcSizeToDecompress(g_zdc); 423 size_t const decodedSize = ZSTD_decompressContinue(g_zdc, op, remainingCapacity, ip, iSize); 424 ip += iSize; 425 regeneratedSize += decodedSize; 426 op += decodedSize; 427 remainingCapacity -= decodedSize; 428 } 429 430 return regeneratedSize; 431 } 432 #endif 433 434 435 /*_******************************************************* 436 * Bench functions 437 *********************************************************/ 438 static int benchMem(unsigned benchNb, 439 const void* src, size_t srcSize, 440 int cLevel, ZSTD_compressionParameters cparams) 441 { 442 size_t dstBuffSize = ZSTD_compressBound(srcSize); 443 BYTE* dstBuff; 444 void* dstBuff2; 445 void* payload; 446 const char* benchName; 447 BMK_benchFn_t benchFunction; 448 int errorcode = 0; 449 450 /* Selection */ 451 switch(benchNb) 452 { 453 case 1: 454 benchFunction = local_ZSTD_compress; benchName = "compress"; 455 break; 456 case 2: 457 benchFunction = local_ZSTD_decompress; benchName = "decompress"; 458 break; 459 case 3: 460 benchFunction = local_ZSTD_compress_freshCCtx; benchName = "compress_freshCCtx"; 461 break; 462 case 4: 463 benchFunction = local_ZSTD_decompressDCtx; benchName = "decompressDCtx"; 464 break; 465 #ifndef ZSTD_DLL_IMPORT 466 case 11: 467 benchFunction = local_ZSTD_compressContinue; benchName = "compressContinue"; 468 break; 469 case 12: 470 benchFunction = local_ZSTD_compressContinue_extDict; benchName = "compressContinue_extDict"; 471 break; 472 case 13: 473 benchFunction = local_ZSTD_decompressContinue; benchName = "decompressContinue"; 474 break; 475 case 30: 476 benchFunction = local_ZSTD_decodeLiteralsHeader; benchName = "decodeLiteralsHeader"; 477 break; 478 case 31: 479 benchFunction = local_ZSTD_decodeLiteralsBlock; benchName = "decodeLiteralsBlock"; 480 break; 481 case 32: 482 benchFunction = local_ZSTD_decodeSeqHeaders; benchName = "decodeSeqHeaders"; 483 break; 484 #endif 485 case 41: 486 benchFunction = local_ZSTD_compressStream; benchName = "compressStream"; 487 break; 488 case 42: 489 benchFunction = local_ZSTD_decompressStream; benchName = "decompressStream"; 490 break; 491 case 43: 492 benchFunction = local_ZSTD_compressStream_freshCCtx; benchName = "compressStream_freshCCtx"; 493 break; 494 case 50: 495 benchFunction = local_ZSTD_compress2; benchName = "compress2"; 496 break; 497 case 51: 498 benchFunction = local_ZSTD_compressStream2_end; benchName = "compressStream2, end"; 499 break; 500 case 52: 501 benchFunction = local_ZSTD_compressStream2_end; benchName = "compressStream2, end & short"; 502 break; 503 case 53: 504 benchFunction = local_ZSTD_compressStream2_continue; benchName = "compressStream2, continue"; 505 break; 506 case 61: 507 benchFunction = local_ZSTD_compress_generic_T2_continue; benchName = "compress_generic, -T2, continue"; 508 break; 509 case 62: 510 benchFunction = local_ZSTD_compress_generic_T2_end; benchName = "compress_generic, -T2, end"; 511 break; 512 default : 513 return 0; 514 } 515 516 /* Allocation */ 517 dstBuff = (BYTE*)malloc(dstBuffSize); 518 dstBuff2 = malloc(dstBuffSize); 519 if ((!dstBuff) || (!dstBuff2)) { 520 DISPLAY("\nError: not enough memory!\n"); 521 free(dstBuff); free(dstBuff2); 522 return 12; 523 } 524 payload = dstBuff2; 525 if (g_zcc==NULL) g_zcc = ZSTD_createCCtx(); 526 if (g_zdc==NULL) g_zdc = ZSTD_createDCtx(); 527 if (g_cstream==NULL) g_cstream = ZSTD_createCStream(); 528 if (g_dstream==NULL) g_dstream = ZSTD_createDStream(); 529 530 /* DISPLAY("params: cLevel %d, wlog %d hlog %d clog %d slog %d mml %d tlen %d strat %d \n", 531 cLevel, cparams->windowLog, cparams->hashLog, cparams->chainLog, cparams->searchLog, 532 cparams->minMatch, cparams->targetLength, cparams->strategy); */ 533 534 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_compressionLevel, cLevel); 535 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_windowLog, (int)cparams.windowLog); 536 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_hashLog, (int)cparams.hashLog); 537 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_chainLog, (int)cparams.chainLog); 538 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_searchLog, (int)cparams.searchLog); 539 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_minMatch, (int)cparams.minMatch); 540 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_targetLength, (int)cparams.targetLength); 541 ZSTD_CCtx_setParameter(g_zcc, ZSTD_c_strategy, cparams.strategy); 542 543 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_compressionLevel, cLevel); 544 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_windowLog, (int)cparams.windowLog); 545 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_hashLog, (int)cparams.hashLog); 546 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_chainLog, (int)cparams.chainLog); 547 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_searchLog, (int)cparams.searchLog); 548 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_minMatch, (int)cparams.minMatch); 549 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_targetLength, (int)cparams.targetLength); 550 ZSTD_CCtx_setParameter(g_cstream, ZSTD_c_strategy, cparams.strategy); 551 552 /* Preparation */ 553 switch(benchNb) 554 { 555 case 1: 556 payload = &cparams; 557 break; 558 case 2: 559 g_cSize = ZSTD_compress(dstBuff2, dstBuffSize, src, srcSize, cLevel); 560 break; 561 case 3: 562 payload = &cparams; 563 break; 564 case 4: 565 g_cSize = ZSTD_compress(dstBuff2, dstBuffSize, src, srcSize, cLevel); 566 break; 567 #ifndef ZSTD_DLL_IMPORT 568 case 11: 569 payload = &cparams; 570 break; 571 case 12: 572 payload = &cparams; 573 break; 574 case 13 : 575 g_cSize = ZSTD_compress(dstBuff2, dstBuffSize, src, srcSize, cLevel); 576 break; 577 case 30: /* ZSTD_decodeLiteralsHeader */ 578 /* fall-through */ 579 case 31: /* ZSTD_decodeLiteralsBlock : starts literals block in dstBuff2 */ 580 { size_t frameHeaderSize; 581 g_cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, cLevel); 582 frameHeaderSize = ZSTD_frameHeaderSize(dstBuff, ZSTD_FRAMEHEADERSIZE_PREFIX(ZSTD_f_zstd1)); 583 CONTROL(!ZSTD_isError(frameHeaderSize)); 584 /* check block is compressible, hence contains a literals section */ 585 { blockProperties_t bp; 586 ZSTD_getcBlockSize(dstBuff+frameHeaderSize, dstBuffSize, &bp); /* Get 1st block type */ 587 if (bp.blockType != bt_compressed) { 588 DISPLAY("ZSTD_decodeLiteralsBlock : impossible to test on this sample (not compressible)\n"); 589 goto _cleanOut; 590 } } 591 { size_t const skippedSize = frameHeaderSize + ZSTD_blockHeaderSize; 592 memcpy(dstBuff2, dstBuff+skippedSize, g_cSize-skippedSize); 593 } 594 srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */ 595 ZSTD_decompressBegin(g_zdc); 596 break; 597 } 598 case 32: /* ZSTD_decodeSeqHeaders */ 599 { blockProperties_t bp; 600 const BYTE* ip = dstBuff; 601 const BYTE* iend; 602 { size_t const cSize = ZSTD_compress(dstBuff, dstBuffSize, src, srcSize, cLevel); 603 CONTROL(cSize > ZSTD_FRAMEHEADERSIZE_PREFIX(ZSTD_f_zstd1)); 604 } 605 /* Skip frame Header */ 606 { size_t const frameHeaderSize = ZSTD_frameHeaderSize(dstBuff, ZSTD_FRAMEHEADERSIZE_PREFIX(ZSTD_f_zstd1)); 607 CONTROL(!ZSTD_isError(frameHeaderSize)); 608 ip += frameHeaderSize; 609 } 610 /* Find end of block */ 611 { size_t const cBlockSize = ZSTD_getcBlockSize(ip, dstBuffSize, &bp); /* Get 1st block type */ 612 if (bp.blockType != bt_compressed) { 613 DISPLAY("ZSTD_decodeSeqHeaders : impossible to test on this sample (not compressible)\n"); 614 goto _cleanOut; 615 } 616 iend = ip + ZSTD_blockHeaderSize + cBlockSize; /* End of first block */ 617 } 618 ip += ZSTD_blockHeaderSize; /* skip block header */ 619 ZSTD_decompressBegin(g_zdc); 620 CONTROL(iend > ip); 621 ip += ZSTD_decodeLiteralsBlock_wrapper(g_zdc, ip, (size_t)(iend-ip), dstBuff, dstBuffSize); /* skip literal segment */ 622 g_cSize = (size_t)(iend-ip); 623 memcpy(dstBuff2, ip, g_cSize); /* copy rest of block (it starts by SeqHeader) */ 624 srcSize = srcSize > 128 KB ? 128 KB : srcSize; /* speed relative to block */ 625 break; 626 } 627 #else 628 case 31: 629 goto _cleanOut; 630 #endif 631 case 41 : 632 payload = &cparams; 633 break; 634 case 42 : 635 g_cSize = ZSTD_compress(payload, dstBuffSize, src, srcSize, cLevel); 636 break; 637 case 43 : 638 payload = &cparams; 639 break; 640 641 case 52 : 642 /* compressStream2, short dstCapacity */ 643 dstBuffSize--; 644 break; 645 646 /* test functions */ 647 /* convention: test functions have ID > 100 */ 648 649 default : ; 650 } 651 652 /* warming up dstBuff */ 653 { size_t i; for (i=0; i<dstBuffSize; i++) dstBuff[i]=(BYTE)i; } 654 655 /* benchmark loop */ 656 { BMK_timedFnState_t* const tfs = BMK_createTimedFnState(g_nbIterations * 1000, 1000); 657 void* const avoidStrictAliasingPtr = &dstBuff; 658 BMK_benchParams_t bp; 659 BMK_runTime_t bestResult; 660 bestResult.sumOfReturn = 0; 661 bestResult.nanoSecPerRun = (double)TIMELOOP_NANOSEC * 2000000000; /* hopefully large enough : must be larger than any potential measurement */ 662 CONTROL(tfs != NULL); 663 664 bp.benchFn = benchFunction; 665 bp.benchPayload = payload; 666 bp.initFn = NULL; 667 bp.initPayload = NULL; 668 bp.errorFn = ZSTD_isError; 669 bp.blockCount = 1; 670 bp.srcBuffers = &src; 671 bp.srcSizes = &srcSize; 672 bp.dstBuffers = (void* const*) avoidStrictAliasingPtr; /* circumvent strict aliasing warning on gcc-8, 673 * because gcc considers that `void* const *` and `void**` are 2 different types */ 674 bp.dstCapacities = &dstBuffSize; 675 bp.blockResults = NULL; 676 677 for (;;) { 678 BMK_runOutcome_t const bOutcome = BMK_benchTimedFn(tfs, bp); 679 680 if (!BMK_isSuccessful_runOutcome(bOutcome)) { 681 DISPLAY("ERROR benchmarking function ! ! \n"); 682 errorcode = 1; 683 goto _cleanOut; 684 } 685 686 { BMK_runTime_t const newResult = BMK_extract_runTime(bOutcome); 687 if (newResult.nanoSecPerRun < bestResult.nanoSecPerRun ) 688 bestResult.nanoSecPerRun = newResult.nanoSecPerRun; 689 DISPLAY("\r%2u#%-29.29s:%8.1f MB/s (%8u) ", 690 benchNb, benchName, 691 (double)srcSize * TIMELOOP_NANOSEC / bestResult.nanoSecPerRun / MB_UNIT, 692 (unsigned)newResult.sumOfReturn ); 693 } 694 695 if ( BMK_isCompleted_TimedFn(tfs) ) break; 696 } 697 BMK_freeTimedFnState(tfs); 698 } 699 DISPLAY("\n"); 700 701 _cleanOut: 702 free(dstBuff); 703 free(dstBuff2); 704 ZSTD_freeCCtx(g_zcc); g_zcc=NULL; 705 ZSTD_freeDCtx(g_zdc); g_zdc=NULL; 706 ZSTD_freeCStream(g_cstream); g_cstream=NULL; 707 ZSTD_freeDStream(g_dstream); g_dstream=NULL; 708 return errorcode; 709 } 710 711 712 static int benchSample(U32 benchNb, 713 size_t benchedSize, double compressibility, 714 int cLevel, ZSTD_compressionParameters cparams) 715 { 716 /* Allocation */ 717 void* const origBuff = malloc(benchedSize); 718 if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); return 12; } 719 720 /* Fill buffer */ 721 RDG_genBuffer(origBuff, benchedSize, compressibility, 0.0, 0); 722 723 /* bench */ 724 DISPLAY("\r%70s\r", ""); 725 DISPLAY(" Sample %u bytes : \n", (unsigned)benchedSize); 726 if (benchNb) { 727 benchMem(benchNb, origBuff, benchedSize, cLevel, cparams); 728 } else { /* 0 == run all tests */ 729 for (benchNb=0; benchNb<100; benchNb++) { 730 benchMem(benchNb, origBuff, benchedSize, cLevel, cparams); 731 } } 732 733 free(origBuff); 734 return 0; 735 } 736 737 738 static int benchFiles(U32 benchNb, 739 const char** fileNamesTable, const int nbFiles, 740 int cLevel, ZSTD_compressionParameters cparams) 741 { 742 /* Loop for each file */ 743 int fileIdx; 744 for (fileIdx=0; fileIdx<nbFiles; fileIdx++) { 745 const char* const inFileName = fileNamesTable[fileIdx]; 746 FILE* const inFile = fopen( inFileName, "rb" ); 747 size_t benchedSize; 748 749 /* Check file existence */ 750 if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; } 751 752 /* Memory allocation & restrictions */ 753 { U64 const inFileSize = UTIL_getFileSize(inFileName); 754 if (inFileSize == UTIL_FILESIZE_UNKNOWN) { 755 DISPLAY( "Cannot measure size of %s\n", inFileName); 756 fclose(inFile); 757 return 11; 758 } 759 benchedSize = BMK_findMaxMem(inFileSize*3) / 3; 760 if ((U64)benchedSize > inFileSize) 761 benchedSize = (size_t)inFileSize; 762 if ((U64)benchedSize < inFileSize) { 763 DISPLAY("Not enough memory for '%s' full size; testing %u MB only... \n", 764 inFileName, (unsigned)(benchedSize>>20)); 765 } } 766 767 /* Alloc */ 768 { void* const origBuff = malloc(benchedSize); 769 if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); fclose(inFile); return 12; } 770 771 /* Fill input buffer */ 772 DISPLAY("Loading %s... \r", inFileName); 773 { size_t const readSize = fread(origBuff, 1, benchedSize, inFile); 774 fclose(inFile); 775 if (readSize != benchedSize) { 776 DISPLAY("\nError: problem reading file '%s' !! \n", inFileName); 777 free(origBuff); 778 return 13; 779 } } 780 781 /* bench */ 782 DISPLAY("\r%70s\r", ""); /* blank line */ 783 DISPLAY(" %s : \n", inFileName); 784 if (benchNb) { 785 benchMem(benchNb, origBuff, benchedSize, cLevel, cparams); 786 } else { 787 for (benchNb=0; benchNb<100; benchNb++) { 788 benchMem(benchNb, origBuff, benchedSize, cLevel, cparams); 789 } 790 benchNb = 0; 791 } 792 793 free(origBuff); 794 } } 795 796 return 0; 797 } 798 799 800 801 /*_******************************************************* 802 * Argument Parsing 803 *********************************************************/ 804 805 #define ERROR_OUT(msg) { DISPLAY("%s \n", msg); exit(1); } 806 807 static unsigned readU32FromChar(const char** stringPtr) 808 { 809 const char errorMsg[] = "error: numeric value too large"; 810 unsigned result = 0; 811 while ((**stringPtr >='0') && (**stringPtr <='9')) { 812 unsigned const max = (((unsigned)(-1)) / 10) - 1; 813 if (result > max) ERROR_OUT(errorMsg); 814 result *= 10; 815 result += (unsigned)(**stringPtr - '0'); 816 (*stringPtr)++ ; 817 } 818 if ((**stringPtr=='K') || (**stringPtr=='M')) { 819 unsigned const maxK = ((unsigned)(-1)) >> 10; 820 if (result > maxK) ERROR_OUT(errorMsg); 821 result <<= 10; 822 if (**stringPtr=='M') { 823 if (result > maxK) ERROR_OUT(errorMsg); 824 result <<= 10; 825 } 826 (*stringPtr)++; /* skip `K` or `M` */ 827 if (**stringPtr=='i') (*stringPtr)++; 828 if (**stringPtr=='B') (*stringPtr)++; 829 } 830 return result; 831 } 832 833 static int longCommandWArg(const char** stringPtr, const char* longCommand) 834 { 835 size_t const comSize = strlen(longCommand); 836 int const result = !strncmp(*stringPtr, longCommand, comSize); 837 if (result) *stringPtr += comSize; 838 return result; 839 } 840 841 842 /*_******************************************************* 843 * Command line 844 *********************************************************/ 845 846 static int usage(const char* exename) 847 { 848 DISPLAY( "Usage :\n"); 849 DISPLAY( " %s [arg] file1 file2 ... fileX\n", exename); 850 DISPLAY( "Arguments :\n"); 851 DISPLAY( " -H/-h : Help (this text + advanced options)\n"); 852 return 0; 853 } 854 855 static int usage_advanced(const char* exename) 856 { 857 usage(exename); 858 DISPLAY( "\nAdvanced options :\n"); 859 DISPLAY( " -b# : test only function # \n"); 860 DISPLAY( " -l# : benchmark functions at that compression level (default : %i)\n", DEFAULT_CLEVEL); 861 DISPLAY( "--zstd= : custom parameter selection. Format same as zstdcli \n"); 862 DISPLAY( " -P# : sample compressibility (default : %.1f%%)\n", COMPRESSIBILITY_DEFAULT * 100); 863 DISPLAY( " -B# : sample size (default : %u)\n", (unsigned)kSampleSizeDefault); 864 DISPLAY( " -i# : iteration loops [1-9](default : %i)\n", NBLOOPS); 865 return 0; 866 } 867 868 static int badusage(const char* exename) 869 { 870 DISPLAY("Wrong parameters\n"); 871 usage(exename); 872 return 1; 873 } 874 875 int main(int argc, const char** argv) 876 { 877 int argNb, filenamesStart=0, result; 878 const char* const exename = argv[0]; 879 const char* input_filename = NULL; 880 U32 benchNb = 0, main_pause = 0; 881 int cLevel = DEFAULT_CLEVEL; 882 ZSTD_compressionParameters cparams = ZSTD_getCParams(cLevel, 0, 0); 883 size_t sampleSize = kSampleSizeDefault; 884 double compressibility = COMPRESSIBILITY_DEFAULT; 885 886 DISPLAY(WELCOME_MESSAGE); 887 if (argc<1) return badusage(exename); 888 889 for (argNb=1; argNb<argc; argNb++) { 890 const char* argument = argv[argNb]; 891 CONTROL(argument != NULL); 892 893 if (longCommandWArg(&argument, "--zstd=")) { 894 for ( ; ;) { 895 if (longCommandWArg(&argument, "windowLog=") || longCommandWArg(&argument, "wlog=")) { cparams.windowLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; } 896 if (longCommandWArg(&argument, "chainLog=") || longCommandWArg(&argument, "clog=")) { cparams.chainLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; } 897 if (longCommandWArg(&argument, "hashLog=") || longCommandWArg(&argument, "hlog=")) { cparams.hashLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; } 898 if (longCommandWArg(&argument, "searchLog=") || longCommandWArg(&argument, "slog=")) { cparams.searchLog = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; } 899 if (longCommandWArg(&argument, "minMatch=") || longCommandWArg(&argument, "mml=")) { cparams.minMatch = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; } 900 if (longCommandWArg(&argument, "targetLength=") || longCommandWArg(&argument, "tlen=")) { cparams.targetLength = readU32FromChar(&argument); if (argument[0]==',') { argument++; continue; } else break; } 901 if (longCommandWArg(&argument, "strategy=") || longCommandWArg(&argument, "strat=")) { cparams.strategy = (ZSTD_strategy)(readU32FromChar(&argument)); if (argument[0]==',') { argument++; continue; } else break; } 902 if (longCommandWArg(&argument, "level=") || longCommandWArg(&argument, "lvl=")) { cLevel = (int)readU32FromChar(&argument); cparams = ZSTD_getCParams(cLevel, 0, 0); if (argument[0]==',') { argument++; continue; } else break; } 903 DISPLAY("invalid compression parameter \n"); 904 return 1; 905 } 906 907 /* check end of string */ 908 if (argument[0] != 0) { 909 DISPLAY("invalid --zstd= format \n"); 910 return 1; 911 } else { 912 continue; 913 } 914 915 } else if (argument[0]=='-') { /* Commands (note : aggregated commands are allowed) */ 916 argument++; 917 while (argument[0]!=0) { 918 919 switch(argument[0]) 920 { 921 /* Display help on usage */ 922 case 'h': 923 case 'H': return usage_advanced(exename); 924 925 /* Pause at the end (hidden option) */ 926 case 'p': main_pause = 1; break; 927 928 /* Select specific algorithm to bench */ 929 case 'b': 930 argument++; 931 benchNb = readU32FromChar(&argument); 932 break; 933 934 /* Select compression level to use */ 935 case 'l': 936 argument++; 937 cLevel = (int)readU32FromChar(&argument); 938 cparams = ZSTD_getCParams(cLevel, 0, 0); 939 break; 940 941 /* Select compressibility of synthetic sample */ 942 case 'P': 943 argument++; 944 compressibility = (double)readU32FromChar(&argument) / 100.; 945 break; 946 947 /* Select size of synthetic sample */ 948 case 'B': 949 argument++; 950 sampleSize = (size_t)readU32FromChar(&argument); 951 break; 952 953 /* Modify Nb Iterations */ 954 case 'i': 955 argument++; 956 g_nbIterations = readU32FromChar(&argument); 957 break; 958 959 /* Unknown command */ 960 default : return badusage(exename); 961 } 962 } 963 continue; 964 } 965 966 /* first provided filename is input */ 967 if (!input_filename) { input_filename=argument; filenamesStart=argNb; continue; } 968 } 969 970 971 972 if (filenamesStart==0) /* no input file */ 973 result = benchSample(benchNb, sampleSize, compressibility, cLevel, cparams); 974 else 975 result = benchFiles(benchNb, argv+filenamesStart, argc-filenamesStart, cLevel, cparams); 976 977 if (main_pause) { int unused; printf("press enter...\n"); unused = getchar(); (void)unused; } 978 979 return result; 980 } 981