fullbench.c 35 KB

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