benchzstd.c 42 KB

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