fullbench.c 34 KB

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