benchzstd.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281
  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. * Tuning parameters
  12. ****************************************/
  13. #ifndef BMK_TIMETEST_DEFAULT_S /* default minimum time per test */
  14. # define BMK_TIMETEST_DEFAULT_S 3
  15. #endif
  16. /* *************************************
  17. * Includes
  18. ***************************************/
  19. /* this must be included first */
  20. #include "platform.h" /* Large Files support, compiler specifics */
  21. /* then following system includes */
  22. #include <assert.h> /* assert */
  23. #include <errno.h>
  24. #include <stdio.h> /* fprintf, fopen */
  25. #include <stdlib.h> /* malloc, free */
  26. #include <string.h> /* memset, strerror */
  27. #include "util.h" /* UTIL_getFileSize, UTIL_sleep */
  28. #include "../lib/common/mem.h"
  29. #include "benchfn.h"
  30. #include "timefn.h" /* UTIL_time_t */
  31. #ifndef ZSTD_STATIC_LINKING_ONLY
  32. # define ZSTD_STATIC_LINKING_ONLY
  33. #endif
  34. #include "../lib/zstd.h"
  35. #include "datagen.h" /* RDG_genBuffer */
  36. #include "lorem.h" /* LOREM_genBuffer */
  37. #ifndef XXH_INLINE_ALL
  38. # define XXH_INLINE_ALL
  39. #endif
  40. #include <contrib/libs/xxhash/xxhash.h>
  41. #include "../lib/zstd_errors.h"
  42. #include "benchzstd.h"
  43. /* *************************************
  44. * Constants
  45. ***************************************/
  46. #ifndef ZSTD_GIT_COMMIT
  47. # define ZSTD_GIT_COMMIT_STRING ""
  48. #else
  49. # define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
  50. #endif
  51. #define TIMELOOP_MICROSEC (1 * 1000000ULL) /* 1 second */
  52. #define TIMELOOP_NANOSEC (1 * 1000000000ULL) /* 1 second */
  53. #define ACTIVEPERIOD_MICROSEC (70 * TIMELOOP_MICROSEC) /* 70 seconds */
  54. #define COOLPERIOD_SEC 10
  55. #define KB *(1 << 10)
  56. #define MB *(1 << 20)
  57. #define GB *(1U << 30)
  58. #define BMK_RUNTEST_DEFAULT_MS 1000
  59. static const size_t maxMemory = (sizeof(size_t) == 4)
  60. ?
  61. /* 32-bit */ (2 GB - 64 MB)
  62. :
  63. /* 64-bit */ (size_t)(1ULL << ((sizeof(size_t) * 8) - 31));
  64. /* *************************************
  65. * console display
  66. ***************************************/
  67. #define DISPLAY(...) \
  68. { \
  69. fprintf(stderr, __VA_ARGS__); \
  70. fflush(NULL); \
  71. }
  72. #define DISPLAYLEVEL(l, ...) \
  73. if (displayLevel >= l) { \
  74. DISPLAY(__VA_ARGS__); \
  75. }
  76. /* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : +
  77. * progression; 4 : + information */
  78. #define OUTPUT(...) \
  79. { \
  80. fprintf(stdout, __VA_ARGS__); \
  81. fflush(NULL); \
  82. }
  83. #define OUTPUTLEVEL(l, ...) \
  84. if (displayLevel >= l) { \
  85. OUTPUT(__VA_ARGS__); \
  86. }
  87. /* *************************************
  88. * Exceptions
  89. ***************************************/
  90. #ifndef DEBUG
  91. # define DEBUG 0
  92. #endif
  93. #define DEBUGOUTPUT(...) \
  94. { \
  95. if (DEBUG) \
  96. DISPLAY(__VA_ARGS__); \
  97. }
  98. #define RETURN_ERROR_INT(errorNum, ...) \
  99. { \
  100. DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
  101. DISPLAYLEVEL(1, "Error %i : ", errorNum); \
  102. DISPLAYLEVEL(1, __VA_ARGS__); \
  103. DISPLAYLEVEL(1, " \n"); \
  104. return errorNum; \
  105. }
  106. #define CHECK_Z(zf) \
  107. { \
  108. size_t const zerr = zf; \
  109. if (ZSTD_isError(zerr)) { \
  110. DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
  111. DISPLAY("Error : "); \
  112. DISPLAY("%s failed : %s", #zf, ZSTD_getErrorName(zerr)); \
  113. DISPLAY(" \n"); \
  114. exit(1); \
  115. } \
  116. }
  117. #define RETURN_ERROR(errorNum, retType, ...) \
  118. { \
  119. retType r; \
  120. memset(&r, 0, sizeof(retType)); \
  121. DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
  122. DISPLAYLEVEL(1, "Error %i : ", errorNum); \
  123. DISPLAYLEVEL(1, __VA_ARGS__); \
  124. DISPLAYLEVEL(1, " \n"); \
  125. r.tag = errorNum; \
  126. return r; \
  127. }
  128. static size_t uintSize(unsigned value)
  129. {
  130. size_t size = 1;
  131. while (value >= 10) {
  132. size++;
  133. value /= 10;
  134. }
  135. return size;
  136. }
  137. /* Note: presume @buffer is large enough */
  138. static void writeUint_varLen(char* buffer, size_t capacity, unsigned value)
  139. {
  140. int endPos = (int)uintSize(value) - 1;
  141. assert(uintSize(value) >= 1);
  142. assert(uintSize(value) < capacity); (void)capacity;
  143. while (endPos >= 0) {
  144. char c = '0' + (char)(value % 10);
  145. buffer[endPos--] = c;
  146. value /= 10;
  147. }
  148. }
  149. /* replacement for snprintf(), which is not supported by C89.
  150. * sprintf() would be the supported one, but it's labelled unsafe:
  151. * modern static analyzer will flag sprintf() as dangerous, making it unusable.
  152. * formatString_u() replaces snprintf() for the specific case where there is only one %u argument */
  153. static int formatString_u(char* buffer, size_t buffer_size, const char* formatString, unsigned int value)
  154. {
  155. size_t const valueSize = uintSize(value);
  156. size_t written = 0;
  157. int i;
  158. for (i = 0; formatString[i] != '\0' && written < buffer_size - 1; i++) {
  159. if (formatString[i] != '%') {
  160. buffer[written++] = formatString[i];
  161. continue;
  162. }
  163. i++;
  164. if (formatString[i] == 'u') {
  165. if (written + valueSize >= buffer_size) abort(); /* buffer not large enough */
  166. writeUint_varLen(buffer + written, buffer_size - written, value);
  167. written += valueSize;
  168. } else if (formatString[i] == '%') { /* Check for escaped percent sign */
  169. buffer[written++] = '%';
  170. } else {
  171. abort(); /* unsupported format */
  172. }
  173. }
  174. if (written < buffer_size) {
  175. buffer[written] = '\0';
  176. } else {
  177. abort(); /* buffer not large enough */
  178. }
  179. return (int)written;
  180. }
  181. /* *************************************
  182. * Benchmark Parameters
  183. ***************************************/
  184. BMK_advancedParams_t BMK_initAdvancedParams(void)
  185. {
  186. BMK_advancedParams_t const res = {
  187. BMK_both, /* mode */
  188. BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
  189. 0, /* blockSize */
  190. 0, /* targetCBlockSize */
  191. 0, /* nbWorkers */
  192. 0, /* realTime */
  193. 0, /* additionalParam */
  194. 0, /* ldmFlag */
  195. 0, /* ldmMinMatch */
  196. 0, /* ldmHashLog */
  197. 0, /* ldmBuckSizeLog */
  198. 0, /* ldmHashRateLog */
  199. ZSTD_ps_auto, /* literalCompressionMode */
  200. 0 /* useRowMatchFinder */
  201. };
  202. return res;
  203. }
  204. /* ********************************************************
  205. * Bench functions
  206. **********************************************************/
  207. typedef struct {
  208. const void* srcPtr;
  209. size_t srcSize;
  210. void* cPtr;
  211. size_t cRoom;
  212. size_t cSize;
  213. void* resPtr;
  214. size_t resSize;
  215. } blockParam_t;
  216. #undef MIN
  217. #undef MAX
  218. #define MIN(a, b) ((a) < (b) ? (a) : (b))
  219. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  220. static void BMK_initCCtx(
  221. ZSTD_CCtx* ctx,
  222. const void* dictBuffer,
  223. size_t dictBufferSize,
  224. int cLevel,
  225. const ZSTD_compressionParameters* comprParams,
  226. const BMK_advancedParams_t* adv)
  227. {
  228. ZSTD_CCtx_reset(ctx, ZSTD_reset_session_and_parameters);
  229. if (adv->nbWorkers == 1) {
  230. CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, 0));
  231. } else {
  232. CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, adv->nbWorkers));
  233. }
  234. CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, cLevel));
  235. CHECK_Z(ZSTD_CCtx_setParameter(
  236. ctx, ZSTD_c_useRowMatchFinder, adv->useRowMatchFinder));
  237. CHECK_Z(ZSTD_CCtx_setParameter(
  238. ctx, ZSTD_c_enableLongDistanceMatching, adv->ldmFlag));
  239. CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmMinMatch, adv->ldmMinMatch));
  240. CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashLog, adv->ldmHashLog));
  241. CHECK_Z(ZSTD_CCtx_setParameter(
  242. ctx, ZSTD_c_ldmBucketSizeLog, adv->ldmBucketSizeLog));
  243. CHECK_Z(ZSTD_CCtx_setParameter(
  244. ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog));
  245. CHECK_Z(ZSTD_CCtx_setParameter(
  246. ctx, ZSTD_c_windowLog, (int)comprParams->windowLog));
  247. CHECK_Z(ZSTD_CCtx_setParameter(
  248. ctx, ZSTD_c_hashLog, (int)comprParams->hashLog));
  249. CHECK_Z(ZSTD_CCtx_setParameter(
  250. ctx, ZSTD_c_chainLog, (int)comprParams->chainLog));
  251. CHECK_Z(ZSTD_CCtx_setParameter(
  252. ctx, ZSTD_c_searchLog, (int)comprParams->searchLog));
  253. CHECK_Z(ZSTD_CCtx_setParameter(
  254. ctx, ZSTD_c_minMatch, (int)comprParams->minMatch));
  255. CHECK_Z(ZSTD_CCtx_setParameter(
  256. ctx, ZSTD_c_targetLength, (int)comprParams->targetLength));
  257. CHECK_Z(ZSTD_CCtx_setParameter(
  258. ctx,
  259. ZSTD_c_literalCompressionMode,
  260. (int)adv->literalCompressionMode));
  261. CHECK_Z(ZSTD_CCtx_setParameter(
  262. ctx, ZSTD_c_strategy, (int)comprParams->strategy));
  263. CHECK_Z(ZSTD_CCtx_setParameter(
  264. ctx, ZSTD_c_targetCBlockSize, (int)adv->targetCBlockSize));
  265. CHECK_Z(ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize));
  266. }
  267. static void
  268. BMK_initDCtx(ZSTD_DCtx* dctx, const void* dictBuffer, size_t dictBufferSize)
  269. {
  270. CHECK_Z(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
  271. CHECK_Z(ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize));
  272. }
  273. typedef struct {
  274. ZSTD_CCtx* cctx;
  275. const void* dictBuffer;
  276. size_t dictBufferSize;
  277. int cLevel;
  278. const ZSTD_compressionParameters* comprParams;
  279. const BMK_advancedParams_t* adv;
  280. } BMK_initCCtxArgs;
  281. static size_t local_initCCtx(void* payload)
  282. {
  283. BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)payload;
  284. BMK_initCCtx(
  285. ag->cctx,
  286. ag->dictBuffer,
  287. ag->dictBufferSize,
  288. ag->cLevel,
  289. ag->comprParams,
  290. ag->adv);
  291. return 0;
  292. }
  293. typedef struct {
  294. ZSTD_DCtx* dctx;
  295. const void* dictBuffer;
  296. size_t dictBufferSize;
  297. } BMK_initDCtxArgs;
  298. static size_t local_initDCtx(void* payload)
  299. {
  300. BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload;
  301. BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize);
  302. return 0;
  303. }
  304. /* `addArgs` is the context */
  305. static size_t local_defaultCompress(
  306. const void* srcBuffer,
  307. size_t srcSize,
  308. void* dstBuffer,
  309. size_t dstSize,
  310. void* addArgs)
  311. {
  312. ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
  313. return ZSTD_compress2(cctx, dstBuffer, dstSize, srcBuffer, srcSize);
  314. }
  315. /* `addArgs` is the context */
  316. static size_t local_defaultDecompress(
  317. const void* srcBuffer,
  318. size_t srcSize,
  319. void* dstBuffer,
  320. size_t dstCapacity,
  321. void* addArgs)
  322. {
  323. size_t moreToFlush = 1;
  324. ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs;
  325. ZSTD_inBuffer in;
  326. ZSTD_outBuffer out;
  327. in.src = srcBuffer;
  328. in.size = srcSize;
  329. in.pos = 0;
  330. out.dst = dstBuffer;
  331. out.size = dstCapacity;
  332. out.pos = 0;
  333. while (moreToFlush) {
  334. if (out.pos == out.size) {
  335. return (size_t)-ZSTD_error_dstSize_tooSmall;
  336. }
  337. moreToFlush = ZSTD_decompressStream(dctx, &out, &in);
  338. if (ZSTD_isError(moreToFlush)) {
  339. return moreToFlush;
  340. }
  341. }
  342. return out.pos;
  343. }
  344. /* ================================================================= */
  345. /* Benchmark Zstandard, mem-to-mem scenarios */
  346. /* ================================================================= */
  347. int BMK_isSuccessful_benchOutcome(BMK_benchOutcome_t outcome)
  348. {
  349. return outcome.tag == 0;
  350. }
  351. BMK_benchResult_t BMK_extract_benchResult(BMK_benchOutcome_t outcome)
  352. {
  353. assert(outcome.tag == 0);
  354. return outcome.internal_never_use_directly;
  355. }
  356. static BMK_benchOutcome_t BMK_benchOutcome_error(void)
  357. {
  358. BMK_benchOutcome_t b;
  359. memset(&b, 0, sizeof(b));
  360. b.tag = 1;
  361. return b;
  362. }
  363. static BMK_benchOutcome_t BMK_benchOutcome_setValidResult(
  364. BMK_benchResult_t result)
  365. {
  366. BMK_benchOutcome_t b;
  367. b.tag = 0;
  368. b.internal_never_use_directly = result;
  369. return b;
  370. }
  371. /* benchMem with no allocation */
  372. static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc(
  373. const void** srcPtrs,
  374. size_t* srcSizes,
  375. void** cPtrs,
  376. size_t* cCapacities,
  377. size_t* cSizes,
  378. void** resPtrs,
  379. size_t* resSizes,
  380. void** resultBufferPtr,
  381. void* compressedBuffer,
  382. size_t maxCompressedSize,
  383. BMK_timedFnState_t* timeStateCompress,
  384. BMK_timedFnState_t* timeStateDecompress,
  385. const void* srcBuffer,
  386. size_t srcSize,
  387. const size_t* fileSizes,
  388. unsigned nbFiles,
  389. const int cLevel,
  390. const ZSTD_compressionParameters* comprParams,
  391. const void* dictBuffer,
  392. size_t dictBufferSize,
  393. ZSTD_CCtx* cctx,
  394. ZSTD_DCtx* dctx,
  395. int displayLevel,
  396. const char* displayName,
  397. const BMK_advancedParams_t* adv)
  398. {
  399. size_t const blockSize =
  400. ((adv->blockSize >= 32 && (adv->mode != BMK_decodeOnly))
  401. ? adv->blockSize
  402. : srcSize)
  403. + (!srcSize); /* avoid div by 0 */
  404. BMK_benchResult_t benchResult;
  405. size_t const loadedCompressedSize = srcSize;
  406. size_t cSize = 0;
  407. double ratio = 0.;
  408. U32 nbBlocks;
  409. assert(cctx != NULL);
  410. assert(dctx != NULL);
  411. /* init */
  412. memset(&benchResult, 0, sizeof(benchResult));
  413. if (strlen(displayName) > 17)
  414. displayName +=
  415. strlen(displayName) - 17; /* display last 17 characters */
  416. if (adv->mode == BMK_decodeOnly) {
  417. /* benchmark only decompression : source must be already compressed */
  418. const char* srcPtr = (const char*)srcBuffer;
  419. U64 totalDSize64 = 0;
  420. U32 fileNb;
  421. for (fileNb = 0; fileNb < nbFiles; fileNb++) {
  422. U64 const fSize64 =
  423. ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
  424. if (fSize64 == ZSTD_CONTENTSIZE_UNKNOWN) {
  425. RETURN_ERROR(
  426. 32,
  427. BMK_benchOutcome_t,
  428. "Decompressed size cannot be determined: cannot benchmark");
  429. }
  430. if (fSize64 == ZSTD_CONTENTSIZE_ERROR) {
  431. RETURN_ERROR(
  432. 32,
  433. BMK_benchOutcome_t,
  434. "Error while trying to assess decompressed size: data may be invalid");
  435. }
  436. totalDSize64 += fSize64;
  437. srcPtr += fileSizes[fileNb];
  438. }
  439. {
  440. size_t const decodedSize = (size_t)totalDSize64;
  441. assert((U64)decodedSize == totalDSize64); /* check overflow */
  442. free(*resultBufferPtr);
  443. if (totalDSize64 > decodedSize) { /* size_t overflow */
  444. RETURN_ERROR(
  445. 32,
  446. BMK_benchOutcome_t,
  447. "decompressed size is too large for local system");
  448. }
  449. *resultBufferPtr = malloc(decodedSize);
  450. if (!(*resultBufferPtr)) {
  451. RETURN_ERROR(
  452. 33,
  453. BMK_benchOutcome_t,
  454. "allocation error: not enough memory");
  455. }
  456. cSize = srcSize;
  457. srcSize = decodedSize;
  458. ratio = (double)srcSize / (double)cSize;
  459. }
  460. }
  461. /* Init data blocks */
  462. {
  463. const char* srcPtr = (const char*)srcBuffer;
  464. char* cPtr = (char*)compressedBuffer;
  465. char* resPtr = (char*)(*resultBufferPtr);
  466. U32 fileNb;
  467. for (nbBlocks = 0, fileNb = 0; fileNb < nbFiles; fileNb++) {
  468. size_t remaining = fileSizes[fileNb];
  469. U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly)
  470. ? 1
  471. : (U32)((remaining + (blockSize - 1)) / blockSize);
  472. U32 const blockEnd = nbBlocks + nbBlocksforThisFile;
  473. for (; nbBlocks < blockEnd; nbBlocks++) {
  474. size_t const thisBlockSize = MIN(remaining, blockSize);
  475. srcPtrs[nbBlocks] = srcPtr;
  476. srcSizes[nbBlocks] = thisBlockSize;
  477. cPtrs[nbBlocks] = cPtr;
  478. cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly)
  479. ? thisBlockSize
  480. : ZSTD_compressBound(thisBlockSize);
  481. resPtrs[nbBlocks] = resPtr;
  482. resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly)
  483. ? (size_t)ZSTD_findDecompressedSize(
  484. srcPtr, thisBlockSize)
  485. : thisBlockSize;
  486. srcPtr += thisBlockSize;
  487. cPtr += cCapacities[nbBlocks];
  488. resPtr += thisBlockSize;
  489. remaining -= thisBlockSize;
  490. if (adv->mode == BMK_decodeOnly) {
  491. cSizes[nbBlocks] = thisBlockSize;
  492. benchResult.cSize = thisBlockSize;
  493. }
  494. }
  495. }
  496. }
  497. /* warming up `compressedBuffer` */
  498. if (adv->mode == BMK_decodeOnly) {
  499. memcpy(compressedBuffer, srcBuffer, loadedCompressedSize);
  500. } else {
  501. RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.50, 1);
  502. }
  503. if (!UTIL_support_MT_measurements() && adv->nbWorkers > 1) {
  504. OUTPUTLEVEL(
  505. 2,
  506. "Warning : time measurements may be incorrect in multithreading mode... \n")
  507. }
  508. /* Bench */
  509. {
  510. U64 const crcOrig = (adv->mode == BMK_decodeOnly)
  511. ? 0
  512. : XXH64(srcBuffer, srcSize, 0);
  513. #define NB_MARKS 4
  514. const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
  515. U32 markNb = 0;
  516. int compressionCompleted = (adv->mode == BMK_decodeOnly);
  517. int decompressionCompleted = (adv->mode == BMK_compressOnly);
  518. BMK_benchParams_t cbp, dbp;
  519. BMK_initCCtxArgs cctxprep;
  520. BMK_initDCtxArgs dctxprep;
  521. cbp.benchFn = local_defaultCompress; /* ZSTD_compress2 */
  522. cbp.benchPayload = cctx;
  523. cbp.initFn = local_initCCtx; /* BMK_initCCtx */
  524. cbp.initPayload = &cctxprep;
  525. cbp.errorFn = ZSTD_isError;
  526. cbp.blockCount = nbBlocks;
  527. cbp.srcBuffers = srcPtrs;
  528. cbp.srcSizes = srcSizes;
  529. cbp.dstBuffers = cPtrs;
  530. cbp.dstCapacities = cCapacities;
  531. cbp.blockResults = cSizes;
  532. cctxprep.cctx = cctx;
  533. cctxprep.dictBuffer = dictBuffer;
  534. cctxprep.dictBufferSize = dictBufferSize;
  535. cctxprep.cLevel = cLevel;
  536. cctxprep.comprParams = comprParams;
  537. cctxprep.adv = adv;
  538. dbp.benchFn = local_defaultDecompress;
  539. dbp.benchPayload = dctx;
  540. dbp.initFn = local_initDCtx;
  541. dbp.initPayload = &dctxprep;
  542. dbp.errorFn = ZSTD_isError;
  543. dbp.blockCount = nbBlocks;
  544. dbp.srcBuffers = (const void* const*)cPtrs;
  545. dbp.srcSizes = cSizes;
  546. dbp.dstBuffers = resPtrs;
  547. dbp.dstCapacities = resSizes;
  548. dbp.blockResults = NULL;
  549. dctxprep.dctx = dctx;
  550. dctxprep.dictBuffer = dictBuffer;
  551. dctxprep.dictBufferSize = dictBufferSize;
  552. OUTPUTLEVEL(2, "\r%70s\r", ""); /* blank line */
  553. assert(srcSize < UINT_MAX);
  554. OUTPUTLEVEL(
  555. 2,
  556. "%2s-%-17.17s :%10u -> \r",
  557. marks[markNb],
  558. displayName,
  559. (unsigned)srcSize);
  560. while (!(compressionCompleted && decompressionCompleted)) {
  561. if (!compressionCompleted) {
  562. BMK_runOutcome_t const cOutcome =
  563. BMK_benchTimedFn(timeStateCompress, cbp);
  564. if (!BMK_isSuccessful_runOutcome(cOutcome)) {
  565. RETURN_ERROR(30, BMK_benchOutcome_t, "compression error");
  566. }
  567. {
  568. BMK_runTime_t const cResult = BMK_extract_runTime(cOutcome);
  569. cSize = cResult.sumOfReturn;
  570. ratio = (double)srcSize / (double)cSize;
  571. {
  572. BMK_benchResult_t newResult;
  573. newResult.cSpeed =
  574. (U64)((double)srcSize * TIMELOOP_NANOSEC
  575. / cResult.nanoSecPerRun);
  576. benchResult.cSize = cSize;
  577. if (newResult.cSpeed > benchResult.cSpeed)
  578. benchResult.cSpeed = newResult.cSpeed;
  579. }
  580. }
  581. {
  582. int const ratioDigits = 1 + (ratio < 100.) + (ratio < 10.);
  583. assert(cSize < UINT_MAX);
  584. OUTPUTLEVEL(
  585. 2,
  586. "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s \r",
  587. marks[markNb],
  588. displayName,
  589. (unsigned)srcSize,
  590. (unsigned)cSize,
  591. ratioDigits,
  592. ratio,
  593. benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1,
  594. (double)benchResult.cSpeed / MB_UNIT);
  595. }
  596. compressionCompleted =
  597. BMK_isCompleted_TimedFn(timeStateCompress);
  598. }
  599. if (!decompressionCompleted) {
  600. BMK_runOutcome_t const dOutcome =
  601. BMK_benchTimedFn(timeStateDecompress, dbp);
  602. if (!BMK_isSuccessful_runOutcome(dOutcome)) {
  603. RETURN_ERROR(30, BMK_benchOutcome_t, "decompression error");
  604. }
  605. {
  606. BMK_runTime_t const dResult = BMK_extract_runTime(dOutcome);
  607. U64 const newDSpeed =
  608. (U64)((double)srcSize * TIMELOOP_NANOSEC
  609. / dResult.nanoSecPerRun);
  610. if (newDSpeed > benchResult.dSpeed)
  611. benchResult.dSpeed = newDSpeed;
  612. }
  613. {
  614. int const ratioDigits = 1 + (ratio < 100.) + (ratio < 10.);
  615. OUTPUTLEVEL(
  616. 2,
  617. "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s, %6.1f MB/s\r",
  618. marks[markNb],
  619. displayName,
  620. (unsigned)srcSize,
  621. (unsigned)cSize,
  622. ratioDigits,
  623. ratio,
  624. benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1,
  625. (double)benchResult.cSpeed / MB_UNIT,
  626. (double)benchResult.dSpeed / MB_UNIT);
  627. }
  628. decompressionCompleted =
  629. BMK_isCompleted_TimedFn(timeStateDecompress);
  630. }
  631. markNb = (markNb + 1) % NB_MARKS;
  632. } /* while (!(compressionCompleted && decompressionCompleted)) */
  633. /* CRC Checking */
  634. {
  635. const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
  636. U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
  637. if ((adv->mode == BMK_both) && (crcOrig != crcCheck)) {
  638. size_t u;
  639. DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n",
  640. displayName,
  641. (unsigned)crcOrig,
  642. (unsigned)crcCheck);
  643. for (u = 0; u < srcSize; u++) {
  644. if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) {
  645. unsigned segNb, bNb, pos;
  646. size_t bacc = 0;
  647. DISPLAY("Decoding error at pos %u ", (unsigned)u);
  648. for (segNb = 0; segNb < nbBlocks; segNb++) {
  649. if (bacc + srcSizes[segNb] > u)
  650. break;
  651. bacc += srcSizes[segNb];
  652. }
  653. pos = (U32)(u - bacc);
  654. bNb = pos / (128 KB);
  655. DISPLAY("(sample %u, block %u, pos %u) \n",
  656. segNb,
  657. bNb,
  658. pos);
  659. {
  660. size_t const lowest = (u > 5) ? 5 : u;
  661. size_t n;
  662. DISPLAY("origin: ");
  663. for (n = lowest; n > 0; n--)
  664. DISPLAY("%02X ",
  665. ((const BYTE*)srcBuffer)[u - n]);
  666. DISPLAY(" :%02X: ", ((const BYTE*)srcBuffer)[u]);
  667. for (n = 1; n < 3; n++)
  668. DISPLAY("%02X ",
  669. ((const BYTE*)srcBuffer)[u + n]);
  670. DISPLAY(" \n");
  671. DISPLAY("decode: ");
  672. for (n = lowest; n > 0; n--)
  673. DISPLAY("%02X ", resultBuffer[u - n]);
  674. DISPLAY(" :%02X: ", resultBuffer[u]);
  675. for (n = 1; n < 3; n++)
  676. DISPLAY("%02X ", resultBuffer[u + n]);
  677. DISPLAY(" \n");
  678. }
  679. break;
  680. }
  681. if (u == srcSize - 1) { /* should never happen */
  682. DISPLAY("no difference detected\n");
  683. }
  684. } /* for (u=0; u<srcSize; u++) */
  685. } /* if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) */
  686. } /* CRC Checking */
  687. if (displayLevel
  688. == 1) { /* hidden display mode -q, used by python speed benchmark */
  689. double const cSpeed = (double)benchResult.cSpeed / MB_UNIT;
  690. double const dSpeed = (double)benchResult.dSpeed / MB_UNIT;
  691. if (adv->additionalParam) {
  692. OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n",
  693. cLevel,
  694. (int)cSize,
  695. ratio,
  696. cSpeed,
  697. dSpeed,
  698. displayName,
  699. adv->additionalParam);
  700. } else {
  701. OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n",
  702. cLevel,
  703. (int)cSize,
  704. ratio,
  705. cSpeed,
  706. dSpeed,
  707. displayName);
  708. }
  709. }
  710. OUTPUTLEVEL(2, "%2i#\n", cLevel);
  711. } /* Bench */
  712. benchResult.cMem =
  713. (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
  714. return BMK_benchOutcome_setValidResult(benchResult);
  715. }
  716. BMK_benchOutcome_t BMK_benchMemAdvanced(
  717. const void* srcBuffer,
  718. size_t srcSize,
  719. void* dstBuffer,
  720. size_t dstCapacity,
  721. const size_t* fileSizes,
  722. unsigned nbFiles,
  723. int cLevel,
  724. const ZSTD_compressionParameters* comprParams,
  725. const void* dictBuffer,
  726. size_t dictBufferSize,
  727. int displayLevel,
  728. const char* displayName,
  729. const BMK_advancedParams_t* adv)
  730. {
  731. int const dstParamsError =
  732. !dstBuffer ^ !dstCapacity; /* must be both NULL or none */
  733. size_t const blockSize =
  734. ((adv->blockSize >= 32 && (adv->mode != BMK_decodeOnly))
  735. ? adv->blockSize
  736. : srcSize)
  737. + (!srcSize) /* avoid div by 0 */;
  738. U32 const maxNbBlocks =
  739. (U32)((srcSize + (blockSize - 1)) / blockSize) + nbFiles;
  740. /* these are the blockTable parameters, just split up */
  741. const void** const srcPtrs =
  742. (const void**)malloc(maxNbBlocks * sizeof(void*));
  743. size_t* const srcSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
  744. void** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
  745. size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
  746. size_t* const cCapacities = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
  747. void** const resPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
  748. size_t* const resSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
  749. BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(
  750. adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
  751. BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(
  752. adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
  753. ZSTD_CCtx* const cctx = ZSTD_createCCtx();
  754. ZSTD_DCtx* const dctx = ZSTD_createDCtx();
  755. const size_t maxCompressedSize = dstCapacity
  756. ? dstCapacity
  757. : ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024);
  758. void* const internalDstBuffer =
  759. dstBuffer ? NULL : malloc(maxCompressedSize);
  760. void* const compressedBuffer = dstBuffer ? dstBuffer : internalDstBuffer;
  761. BMK_benchOutcome_t outcome =
  762. BMK_benchOutcome_error(); /* error by default */
  763. void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
  764. int const allocationincomplete = !srcPtrs || !srcSizes || !cPtrs || !cSizes
  765. || !cCapacities || !resPtrs || !resSizes || !timeStateCompress
  766. || !timeStateDecompress || !cctx || !dctx || !compressedBuffer
  767. || !resultBuffer;
  768. if (!allocationincomplete && !dstParamsError) {
  769. outcome = BMK_benchMemAdvancedNoAlloc(
  770. srcPtrs,
  771. srcSizes,
  772. cPtrs,
  773. cCapacities,
  774. cSizes,
  775. resPtrs,
  776. resSizes,
  777. &resultBuffer,
  778. compressedBuffer,
  779. maxCompressedSize,
  780. timeStateCompress,
  781. timeStateDecompress,
  782. srcBuffer,
  783. srcSize,
  784. fileSizes,
  785. nbFiles,
  786. cLevel,
  787. comprParams,
  788. dictBuffer,
  789. dictBufferSize,
  790. cctx,
  791. dctx,
  792. displayLevel,
  793. displayName,
  794. adv);
  795. }
  796. /* clean up */
  797. BMK_freeTimedFnState(timeStateCompress);
  798. BMK_freeTimedFnState(timeStateDecompress);
  799. ZSTD_freeCCtx(cctx);
  800. ZSTD_freeDCtx(dctx);
  801. free(internalDstBuffer);
  802. free(resultBuffer);
  803. free((void*)srcPtrs);
  804. free(srcSizes);
  805. free(cPtrs);
  806. free(cSizes);
  807. free(cCapacities);
  808. free(resPtrs);
  809. free(resSizes);
  810. if (allocationincomplete) {
  811. RETURN_ERROR(
  812. 31, BMK_benchOutcome_t, "allocation error : not enough memory");
  813. }
  814. if (dstParamsError) {
  815. RETURN_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
  816. }
  817. return outcome;
  818. }
  819. BMK_benchOutcome_t BMK_benchMem(
  820. const void* srcBuffer,
  821. size_t srcSize,
  822. const size_t* fileSizes,
  823. unsigned nbFiles,
  824. int cLevel,
  825. const ZSTD_compressionParameters* comprParams,
  826. const void* dictBuffer,
  827. size_t dictBufferSize,
  828. int displayLevel,
  829. const char* displayName)
  830. {
  831. BMK_advancedParams_t const adv = BMK_initAdvancedParams();
  832. return BMK_benchMemAdvanced(
  833. srcBuffer,
  834. srcSize,
  835. NULL,
  836. 0,
  837. fileSizes,
  838. nbFiles,
  839. cLevel,
  840. comprParams,
  841. dictBuffer,
  842. dictBufferSize,
  843. displayLevel,
  844. displayName,
  845. &adv);
  846. }
  847. /* @return: 0 on success, !0 if error */
  848. static int BMK_benchCLevels(
  849. const void* srcBuffer,
  850. size_t benchedSize,
  851. const size_t* fileSizes,
  852. unsigned nbFiles,
  853. int startCLevel, int endCLevel,
  854. const ZSTD_compressionParameters* comprParams,
  855. const void* dictBuffer,
  856. size_t dictBufferSize,
  857. int displayLevel,
  858. const char* displayName,
  859. BMK_advancedParams_t const* const adv)
  860. {
  861. int level;
  862. const char* pch = strrchr(displayName, '\\'); /* Windows */
  863. if (!pch)
  864. pch = strrchr(displayName, '/'); /* Linux */
  865. if (pch)
  866. displayName = pch + 1;
  867. if (endCLevel > ZSTD_maxCLevel()) {
  868. DISPLAYLEVEL(1, "Invalid Compression Level \n");
  869. return 15;
  870. }
  871. if (endCLevel < startCLevel) {
  872. DISPLAYLEVEL(1, "Invalid Compression Level Range \n");
  873. return 15;
  874. }
  875. if (adv->realTime) {
  876. DISPLAYLEVEL(2, "Note : switching to real-time priority \n");
  877. SET_REALTIME_PRIORITY;
  878. }
  879. if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */
  880. OUTPUT("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",
  881. ZSTD_VERSION_STRING,
  882. ZSTD_GIT_COMMIT_STRING,
  883. (unsigned)benchedSize,
  884. adv->nbSeconds,
  885. (unsigned)(adv->blockSize >> 10));
  886. for (level = startCLevel; level <= endCLevel; level++) {
  887. BMK_benchOutcome_t res = BMK_benchMemAdvanced(
  888. srcBuffer,
  889. benchedSize,
  890. NULL,
  891. 0,
  892. fileSizes,
  893. nbFiles,
  894. level,
  895. comprParams,
  896. dictBuffer,
  897. dictBufferSize,
  898. displayLevel,
  899. displayName,
  900. adv);
  901. if (!BMK_isSuccessful_benchOutcome(res)) return 1;
  902. }
  903. return 0;
  904. }
  905. int BMK_syntheticTest(
  906. double compressibility,
  907. int startingCLevel, int endCLevel,
  908. const ZSTD_compressionParameters* compressionParams,
  909. int displayLevel,
  910. const BMK_advancedParams_t* adv)
  911. {
  912. char nameBuff[20] = { 0 };
  913. const char* name = nameBuff;
  914. size_t const benchedSize = adv->blockSize ? adv->blockSize : 10000000;
  915. /* Memory allocation */
  916. void* const srcBuffer = malloc(benchedSize);
  917. if (!srcBuffer) {
  918. DISPLAYLEVEL(1, "allocation error : not enough memory \n");
  919. return 16;
  920. }
  921. /* Fill input buffer */
  922. if (compressibility < 0.0) {
  923. LOREM_genBuffer(srcBuffer, benchedSize, 0);
  924. name = "Lorem ipsum";
  925. } else {
  926. RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
  927. formatString_u(
  928. nameBuff,
  929. sizeof(nameBuff),
  930. "Synthetic %u%%",
  931. (unsigned)(compressibility * 100));
  932. }
  933. /* Bench */
  934. { int res = BMK_benchCLevels(
  935. srcBuffer,
  936. benchedSize,
  937. &benchedSize,
  938. 1,
  939. startingCLevel, endCLevel,
  940. compressionParams,
  941. NULL,
  942. 0, /* dictionary */
  943. displayLevel,
  944. name,
  945. adv);
  946. free(srcBuffer);
  947. return res;
  948. }
  949. }
  950. static size_t BMK_findMaxMem(U64 requiredMem)
  951. {
  952. size_t const step = 64 MB;
  953. BYTE* testmem = NULL;
  954. requiredMem = (((requiredMem >> 26) + 1) << 26);
  955. requiredMem += step;
  956. if (requiredMem > maxMemory)
  957. requiredMem = maxMemory;
  958. do {
  959. testmem = (BYTE*)malloc((size_t)requiredMem);
  960. requiredMem -= step;
  961. } while (!testmem && requiredMem > 0);
  962. free(testmem);
  963. return (size_t)(requiredMem);
  964. }
  965. /*! BMK_loadFiles() :
  966. * Loads `buffer` with content of files listed within `fileNamesTable`.
  967. * At most, fills `buffer` entirely. */
  968. static int BMK_loadFiles(
  969. void* buffer,
  970. size_t bufferSize,
  971. size_t* fileSizes,
  972. const char* const* fileNamesTable,
  973. unsigned nbFiles,
  974. int displayLevel)
  975. {
  976. size_t pos = 0, totalSize = 0;
  977. unsigned n;
  978. for (n = 0; n < nbFiles; n++) {
  979. const char* const filename = fileNamesTable[n];
  980. U64 fileSize = UTIL_getFileSize(
  981. filename); /* last file may be shortened */
  982. if (UTIL_isDirectory(filename)) {
  983. DISPLAYLEVEL(
  984. 2, "Ignoring %s directory... \n", filename);
  985. fileSizes[n] = 0;
  986. continue;
  987. }
  988. if (fileSize == UTIL_FILESIZE_UNKNOWN) {
  989. DISPLAYLEVEL(
  990. 2,
  991. "Cannot evaluate size of %s, ignoring ... \n",
  992. filename);
  993. fileSizes[n] = 0;
  994. continue;
  995. }
  996. if (fileSize > bufferSize - pos) {
  997. /* buffer too small - limit quantity loaded */
  998. fileSize = bufferSize - pos;
  999. nbFiles = n; /* stop after this file */
  1000. }
  1001. { FILE* const f = fopen(filename, "rb");
  1002. if (f == NULL) {
  1003. RETURN_ERROR_INT(
  1004. 10, "cannot open file %s", filename);
  1005. }
  1006. OUTPUTLEVEL(2, "Loading %s... \r", filename);
  1007. { size_t const readSize =
  1008. fread(((char*)buffer) + pos, 1, (size_t)fileSize, f);
  1009. if (readSize != (size_t)fileSize) {
  1010. fclose(f);
  1011. RETURN_ERROR_INT(
  1012. 11, "invalid read %s", filename);
  1013. }
  1014. pos += readSize;
  1015. }
  1016. fileSizes[n] = (size_t)fileSize;
  1017. totalSize += (size_t)fileSize;
  1018. fclose(f);
  1019. }
  1020. }
  1021. if (totalSize == 0)
  1022. RETURN_ERROR_INT(12, "no data to bench");
  1023. return 0;
  1024. }
  1025. int BMK_benchFilesAdvanced(
  1026. const char* const* fileNamesTable,
  1027. unsigned nbFiles,
  1028. const char* dictFileName,
  1029. int startCLevel, int endCLevel,
  1030. const ZSTD_compressionParameters* compressionParams,
  1031. int displayLevel,
  1032. const BMK_advancedParams_t* adv)
  1033. {
  1034. void* srcBuffer = NULL;
  1035. size_t benchedSize;
  1036. void* dictBuffer = NULL;
  1037. size_t dictBufferSize = 0;
  1038. size_t* fileSizes = NULL;
  1039. int res = 1;
  1040. U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
  1041. if (!nbFiles) {
  1042. DISPLAYLEVEL(1, "No Files to Benchmark");
  1043. return 13;
  1044. }
  1045. if (endCLevel > ZSTD_maxCLevel()) {
  1046. DISPLAYLEVEL(1, "Invalid Compression Level");
  1047. return 14;
  1048. }
  1049. if (totalSizeToLoad == UTIL_FILESIZE_UNKNOWN) {
  1050. DISPLAYLEVEL(1, "Error loading files");
  1051. return 15;
  1052. }
  1053. fileSizes = (size_t*)calloc(nbFiles, sizeof(size_t));
  1054. if (!fileSizes) {
  1055. DISPLAYLEVEL(1, "not enough memory for fileSizes");
  1056. return 16;
  1057. }
  1058. /* Load dictionary */
  1059. if (dictFileName != NULL) {
  1060. U64 const dictFileSize = UTIL_getFileSize(dictFileName);
  1061. if (dictFileSize == UTIL_FILESIZE_UNKNOWN) {
  1062. DISPLAYLEVEL(
  1063. 1,
  1064. "error loading %s : %s \n",
  1065. dictFileName,
  1066. strerror(errno));
  1067. free(fileSizes);
  1068. DISPLAYLEVEL(1, "benchmark aborted");
  1069. return 17;
  1070. }
  1071. if (dictFileSize > 64 MB) {
  1072. free(fileSizes);
  1073. DISPLAYLEVEL(1, "dictionary file %s too large", dictFileName);
  1074. return 18;
  1075. }
  1076. dictBufferSize = (size_t)dictFileSize;
  1077. dictBuffer = malloc(dictBufferSize);
  1078. if (dictBuffer == NULL) {
  1079. free(fileSizes);
  1080. DISPLAYLEVEL(
  1081. 1,
  1082. "not enough memory for dictionary (%u bytes)",
  1083. (unsigned)dictBufferSize);
  1084. return 19;
  1085. }
  1086. {
  1087. int const errorCode = BMK_loadFiles(
  1088. dictBuffer,
  1089. dictBufferSize,
  1090. fileSizes,
  1091. &dictFileName /*?*/,
  1092. 1 /*?*/,
  1093. displayLevel);
  1094. if (errorCode) {
  1095. goto _cleanUp;
  1096. }
  1097. }
  1098. }
  1099. /* Memory allocation & restrictions */
  1100. benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3;
  1101. if ((U64)benchedSize > totalSizeToLoad)
  1102. benchedSize = (size_t)totalSizeToLoad;
  1103. if (benchedSize < totalSizeToLoad)
  1104. DISPLAY("Not enough memory; testing %u MB only...\n",
  1105. (unsigned)(benchedSize >> 20));
  1106. srcBuffer = benchedSize ? malloc(benchedSize) : NULL;
  1107. if (!srcBuffer) {
  1108. free(dictBuffer);
  1109. free(fileSizes);
  1110. DISPLAYLEVEL(1, "not enough memory for srcBuffer");
  1111. return 20;
  1112. }
  1113. /* Load input buffer */
  1114. {
  1115. int const errorCode = BMK_loadFiles(
  1116. srcBuffer,
  1117. benchedSize,
  1118. fileSizes,
  1119. fileNamesTable,
  1120. nbFiles,
  1121. displayLevel);
  1122. if (errorCode) {
  1123. goto _cleanUp;
  1124. }
  1125. }
  1126. /* Bench */
  1127. {
  1128. char mfName[20] = { 0 };
  1129. formatString_u(mfName, sizeof(mfName), " %u files", nbFiles);
  1130. { const char* const displayName =
  1131. (nbFiles > 1) ? mfName : fileNamesTable[0];
  1132. res = BMK_benchCLevels(
  1133. srcBuffer,
  1134. benchedSize,
  1135. fileSizes,
  1136. nbFiles,
  1137. startCLevel, endCLevel,
  1138. compressionParams,
  1139. dictBuffer,
  1140. dictBufferSize,
  1141. displayLevel,
  1142. displayName,
  1143. adv);
  1144. }
  1145. }
  1146. _cleanUp:
  1147. free(srcBuffer);
  1148. free(dictBuffer);
  1149. free(fileSizes);
  1150. return res;
  1151. }
  1152. int BMK_benchFiles(
  1153. const char* const* fileNamesTable,
  1154. unsigned nbFiles,
  1155. const char* dictFileName,
  1156. int cLevel,
  1157. const ZSTD_compressionParameters* compressionParams,
  1158. int displayLevel)
  1159. {
  1160. BMK_advancedParams_t const adv = BMK_initAdvancedParams();
  1161. return BMK_benchFilesAdvanced(
  1162. fileNamesTable,
  1163. nbFiles,
  1164. dictFileName,
  1165. cLevel, cLevel,
  1166. compressionParams,
  1167. displayLevel,
  1168. &adv);
  1169. }