blob: 5eabcba2b60b44ae9f901fda594c436e647da96b [file] [log] [blame]
Yann Collet4ded9e52016-08-30 10:04:33 -07001/**
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
Yann Colletfd9d6b82015-10-26 00:06:36 +01009
Yann Colletfd9d6b82015-10-26 00:06:36 +010010
Yann Collet70e8c382016-02-10 13:37:52 +010011/*-************************************
12* Dependencies
Yann Colletfd9d6b82015-10-26 00:06:36 +010013**************************************/
Yann Collet158e7702016-07-13 16:45:24 +020014#include "util.h" /* Compiler options, UTIL_GetFileSize */
15#include <stdlib.h> /* malloc */
16#include <stdio.h> /* fprintf, fopen, ftello64 */
17#include <string.h> /* strcmp */
18#include <math.h> /* log */
19#include <time.h> /* clock_t */
Yann Colletfd9d6b82015-10-26 00:06:36 +010020
21#include "mem.h"
Yann Collet3ae543c2016-07-11 03:12:17 +020022#define ZSTD_STATIC_LINKING_ONLY /* ZSTD_parameters, ZSTD_estimateCCtxSize */
Yann Colletd3b7f8d2016-06-04 19:47:02 +020023#include "zstd.h"
Yann Colletfd9d6b82015-10-26 00:06:36 +010024#include "datagen.h"
25#include "xxhash.h"
Yann Colletfd9d6b82015-10-26 00:06:36 +010026
27
Yann Collet70e8c382016-02-10 13:37:52 +010028/*-************************************
Yann Colletfd9d6b82015-10-26 00:06:36 +010029* Constants
30**************************************/
inikepd5ff2c32016-04-28 14:40:45 +020031#define PROGRAM_DESCRIPTION "ZSTD parameters tester"
Yann Colletfd9d6b82015-10-26 00:06:36 +010032#define AUTHOR "Yann Collet"
Yann Collet45f84ab2016-05-20 12:34:40 +020033#define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", PROGRAM_DESCRIPTION, ZSTD_VERSION_STRING, (int)(sizeof(void*)*8), AUTHOR, __DATE__
Yann Colletfd9d6b82015-10-26 00:06:36 +010034
35
36#define KB *(1<<10)
37#define MB *(1<<20)
Yann Collet49cc9b72015-11-27 17:52:57 +010038#define GB *(1ULL<<30)
Yann Colletfd9d6b82015-10-26 00:06:36 +010039
Yann Colletb2ad30c2015-10-26 02:45:19 +010040#define NBLOOPS 2
Yann Collet158e7702016-07-13 16:45:24 +020041#define TIMELOOP (2 * CLOCKS_PER_SEC)
Yann Colletfd9d6b82015-10-26 00:06:36 +010042
Yann Collet70e8c382016-02-10 13:37:52 +010043#define NB_LEVELS_TRACKED 30
44
Yann Collet49cc9b72015-11-27 17:52:57 +010045static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t)(1ULL << ((sizeof(size_t)*8)-31));
Yann Colletfd9d6b82015-10-26 00:06:36 +010046
47#define COMPRESSIBILITY_DEFAULT 0.50
48static const size_t sampleSize = 10000000;
49
Yann Collet158e7702016-07-13 16:45:24 +020050static const U32 g_grillDuration_s = 60000; /* about 16 hours */
51static const clock_t g_maxParamTime = 15 * CLOCKS_PER_SEC;
52static const clock_t g_maxVariationTime = 60 * CLOCKS_PER_SEC;
Yann Collet2c6992e2015-10-27 12:18:00 +010053static const int g_maxNbVariations = 64;
Yann Colletfd9d6b82015-10-26 00:06:36 +010054
Yann Collet09116c22015-11-27 17:46:14 +010055
Yann Collet70e8c382016-02-10 13:37:52 +010056/*-************************************
Yann Colletfd9d6b82015-10-26 00:06:36 +010057* Macros
58**************************************/
59#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
60
61
Yann Collet70e8c382016-02-10 13:37:52 +010062/*-************************************
Yann Colletfd9d6b82015-10-26 00:06:36 +010063* Benchmark Parameters
64**************************************/
Yann Collet4b100f42015-10-30 15:49:48 +010065static U32 g_nbIterations = NBLOOPS;
Yann Colletfd9d6b82015-10-26 00:06:36 +010066static double g_compressibility = COMPRESSIBILITY_DEFAULT;
67static U32 g_blockSize = 0;
Yann Collet786f5b52015-10-26 15:45:58 +010068static U32 g_rand = 1;
Yann Collet8b91abe2015-10-27 02:59:12 +010069static U32 g_singleRun = 0;
Yann Collet2c6992e2015-10-27 12:18:00 +010070static U32 g_target = 0;
Yann Colletb315bc82015-10-27 13:12:25 +010071static U32 g_noSeed = 0;
Yann Collet51d50042016-03-30 20:42:19 +020072static ZSTD_compressionParameters g_params = { 0, 0, 0, 0, 0, 0, ZSTD_greedy };
Yann Colletfd9d6b82015-10-26 00:06:36 +010073
74void BMK_SetNbIterations(int nbLoops)
75{
Yann Collet4b100f42015-10-30 15:49:48 +010076 g_nbIterations = nbLoops;
77 DISPLAY("- %u iterations -\n", g_nbIterations);
Yann Colletfd9d6b82015-10-26 00:06:36 +010078}
79
80
Yann Collet70e8c382016-02-10 13:37:52 +010081/*-*******************************************************
Yann Colletfd9d6b82015-10-26 00:06:36 +010082* Private functions
83*********************************************************/
84
Yann Collet158e7702016-07-13 16:45:24 +020085static clock_t BMK_clockSpan(clock_t cStart) { return clock() - cStart; } /* works even if overflow ; max span ~ 30 mn */
Yann Colletfd9d6b82015-10-26 00:06:36 +010086
Yann Collet158e7702016-07-13 16:45:24 +020087static U32 BMK_timeSpan(time_t tStart) { return (U32)difftime(time(NULL), tStart); } /* accuracy in seconds only, span can be multiple years */
Yann Colletfd9d6b82015-10-26 00:06:36 +010088
89
90static size_t BMK_findMaxMem(U64 requiredMem)
91{
Yann Collet158e7702016-07-13 16:45:24 +020092 size_t const step = 64 MB;
93 void* testmem = NULL;
Yann Colletfd9d6b82015-10-26 00:06:36 +010094
95 requiredMem = (((requiredMem >> 26) + 1) << 26);
Yann Collet49cc9b72015-11-27 17:52:57 +010096 if (requiredMem > maxMemory) requiredMem = maxMemory;
Yann Colletfd9d6b82015-10-26 00:06:36 +010097
98 requiredMem += 2*step;
Yann Collet70e8c382016-02-10 13:37:52 +010099 while (!testmem) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100100 requiredMem -= step;
Yann Collet158e7702016-07-13 16:45:24 +0200101 testmem = malloc ((size_t)requiredMem);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100102 }
103
104 free (testmem);
105 return (size_t) (requiredMem - step);
106}
107
108
Yann Colletfd9d6b82015-10-26 00:06:36 +0100109# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
110U32 FUZ_rand(U32* src)
111{
112 const U32 prime1 = 2654435761U;
113 const U32 prime2 = 2246822519U;
114 U32 rand32 = *src;
115 rand32 *= prime1;
116 rand32 += prime2;
117 rand32 = FUZ_rotl32(rand32, 13);
118 *src = rand32;
119 return rand32 >> 5;
120}
121
122
Yann Collet70e8c382016-02-10 13:37:52 +0100123/*-*******************************************************
Yann Colletfd9d6b82015-10-26 00:06:36 +0100124* Bench functions
125*********************************************************/
126typedef struct {
127 size_t cSize;
Yann Collet158e7702016-07-13 16:45:24 +0200128 double cSpeed;
129 double dSpeed;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100130} BMK_result_t;
131
132typedef struct
133{
134 const char* srcPtr;
135 size_t srcSize;
136 char* cPtr;
137 size_t cRoom;
138 size_t cSize;
139 char* resPtr;
140 size_t resSize;
141} blockParam_t;
142
143
144#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
Yann Colletb315bc82015-10-27 13:12:25 +0100145
Yann Colletfd9d6b82015-10-26 00:06:36 +0100146static size_t BMK_benchParam(BMK_result_t* resultPtr,
147 const void* srcBuffer, size_t srcSize,
Yann Collet5be2dd22015-11-11 13:43:58 +0100148 ZSTD_CCtx* ctx,
Yann Collet51d50042016-03-30 20:42:19 +0200149 const ZSTD_compressionParameters cParams)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100150{
151 const size_t blockSize = g_blockSize ? g_blockSize : srcSize;
152 const U32 nbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize);
153 blockParam_t* const blockTable = (blockParam_t*) malloc(nbBlocks * sizeof(blockParam_t));
154 const size_t maxCompressedSize = (size_t)nbBlocks * ZSTD_compressBound(blockSize);
155 void* const compressedBuffer = malloc(maxCompressedSize);
156 void* const resultBuffer = malloc(srcSize);
Yann Collet51d50042016-03-30 20:42:19 +0200157 ZSTD_parameters params;
158 U32 Wlog = cParams.windowLog;
Yann Collet8a57b922016-04-04 13:49:18 +0200159 U32 Clog = cParams.chainLog;
Yann Collet51d50042016-03-30 20:42:19 +0200160 U32 Hlog = cParams.hashLog;
161 U32 Slog = cParams.searchLog;
162 U32 Slength = cParams.searchLength;
163 U32 Tlength = cParams.targetLength;
164 ZSTD_strategy strat = cParams.strategy;
Yann Colletbe2010e2015-10-31 12:57:14 +0100165 char name[30] = { 0 };
Yann Colletfd9d6b82015-10-26 00:06:36 +0100166 U64 crcOrig;
167
168 /* Memory allocation & restrictions */
Yann Collet70e8c382016-02-10 13:37:52 +0100169 snprintf(name, 30, "Sw%02uc%02uh%02us%02ul%1ut%03uS%1u", Wlog, Clog, Hlog, Slog, Slength, Tlength, strat);
170 if (!compressedBuffer || !resultBuffer || !blockTable) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100171 DISPLAY("\nError: not enough memory!\n");
172 free(compressedBuffer);
173 free(resultBuffer);
174 free(blockTable);
175 return 12;
176 }
177
178 /* Calculating input Checksum */
179 crcOrig = XXH64(srcBuffer, srcSize, 0);
180
181 /* Init blockTable data */
182 {
183 U32 i;
184 size_t remaining = srcSize;
185 const char* srcPtr = (const char*)srcBuffer;
186 char* cPtr = (char*)compressedBuffer;
187 char* resPtr = (char*)resultBuffer;
Yann Collet70e8c382016-02-10 13:37:52 +0100188 for (i=0; i<nbBlocks; i++) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100189 size_t thisBlockSize = MIN(remaining, blockSize);
190 blockTable[i].srcPtr = srcPtr;
191 blockTable[i].cPtr = cPtr;
192 blockTable[i].resPtr = resPtr;
193 blockTable[i].srcSize = thisBlockSize;
194 blockTable[i].cRoom = ZSTD_compressBound(thisBlockSize);
195 srcPtr += thisBlockSize;
196 cPtr += blockTable[i].cRoom;
197 resPtr += thisBlockSize;
198 remaining -= thisBlockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100199 } }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100200
201 /* warmimg up memory */
202 RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.10, 1);
203
204 /* Bench */
Yann Collet158e7702016-07-13 16:45:24 +0200205 { U32 loopNb;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100206 size_t cSize = 0;
207 double fastestC = 100000000., fastestD = 100000000.;
208 double ratio = 0.;
209 U64 crcCheck = 0;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200210 clock_t const benchStart = clock();
Yann Colletfd9d6b82015-10-26 00:06:36 +0100211
212 DISPLAY("\r%79s\r", "");
Yann Collet3ae543c2016-07-11 03:12:17 +0200213 memset(&params, 0, sizeof(params));
Yann Collet51d50042016-03-30 20:42:19 +0200214 params.cParams = cParams;
Yann Collet70e8c382016-02-10 13:37:52 +0100215 for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100216 int nbLoops;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100217 U32 blockNb;
Yann Collet158e7702016-07-13 16:45:24 +0200218 clock_t roundStart, roundClock;
Yann Collet786f5b52015-10-26 15:45:58 +0100219
Yann Collet158e7702016-07-13 16:45:24 +0200220 { clock_t const benchTime = BMK_clockSpan(benchStart);
221 if (benchTime > g_maxParamTime) break; }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100222
223 /* Compression */
Yann Collet59d70632015-11-04 12:05:27 +0100224 DISPLAY("\r%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100225 memset(compressedBuffer, 0xE5, maxCompressedSize);
226
227 nbLoops = 0;
Yann Collet158e7702016-07-13 16:45:24 +0200228 roundStart = clock();
229 while (clock() == roundStart);
230 roundStart = clock();
231 while (BMK_clockSpan(roundStart) < TIMELOOP) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100232 for (blockNb=0; blockNb<nbBlocks; blockNb++)
Yann Collet5be2dd22015-11-11 13:43:58 +0100233 blockTable[blockNb].cSize = ZSTD_compress_advanced(ctx,
Yann Collet786f5b52015-10-26 15:45:58 +0100234 blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,
235 blockTable[blockNb].srcPtr, blockTable[blockNb].srcSize,
Yann Collet31683c02015-12-18 01:26:48 +0100236 NULL, 0,
Yann Collet786f5b52015-10-26 15:45:58 +0100237 params);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100238 nbLoops++;
239 }
Yann Collet158e7702016-07-13 16:45:24 +0200240 roundClock = BMK_clockSpan(roundStart);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100241
242 cSize = 0;
243 for (blockNb=0; blockNb<nbBlocks; blockNb++)
244 cSize += blockTable[blockNb].cSize;
Yann Collet158e7702016-07-13 16:45:24 +0200245 if ((double)roundClock < fastestC * CLOCKS_PER_SEC * nbLoops) fastestC = ((double)roundClock / CLOCKS_PER_SEC) / nbLoops;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100246 ratio = (double)srcSize / (double)cSize;
Yann Collet59d70632015-11-04 12:05:27 +0100247 DISPLAY("\r");
Yann Colletbe2010e2015-10-31 12:57:14 +0100248 DISPLAY("%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
Yann Collet158e7702016-07-13 16:45:24 +0200249 DISPLAY(" %9u (%4.3f),%7.1f MB/s", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100250 resultPtr->cSize = cSize;
Yann Collet158e7702016-07-13 16:45:24 +0200251 resultPtr->cSpeed = (double)srcSize / fastestC;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100252
253#if 1
254 /* Decompression */
255 memset(resultBuffer, 0xD6, srcSize);
256
257 nbLoops = 0;
Yann Collet158e7702016-07-13 16:45:24 +0200258 roundStart = clock();
259 while (clock() == roundStart);
260 roundStart = clock();
261 for ( ; BMK_clockSpan(roundStart) < TIMELOOP; nbLoops++) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100262 for (blockNb=0; blockNb<nbBlocks; blockNb++)
263 blockTable[blockNb].resSize = ZSTD_decompress(blockTable[blockNb].resPtr, blockTable[blockNb].srcSize,
264 blockTable[blockNb].cPtr, blockTable[blockNb].cSize);
265 }
Yann Collet158e7702016-07-13 16:45:24 +0200266 roundClock = BMK_clockSpan(roundStart);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100267
Yann Collet158e7702016-07-13 16:45:24 +0200268 if ((double)roundClock < fastestD * CLOCKS_PER_SEC * nbLoops) fastestD = ((double)roundClock / CLOCKS_PER_SEC) / nbLoops;
Yann Collet59d70632015-11-04 12:05:27 +0100269 DISPLAY("\r");
Yann Colletbe2010e2015-10-31 12:57:14 +0100270 DISPLAY("%1u-%s : %9u -> ", loopNb, name, (U32)srcSize);
Yann Collet158e7702016-07-13 16:45:24 +0200271 DISPLAY("%9u (%4.3f),%7.1f MB/s, ", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.);
272 DISPLAY("%7.1f MB/s", (double)srcSize / fastestD / 1000000.);
273 resultPtr->dSpeed = (double)srcSize / fastestD;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100274
275 /* CRC Checking */
276 crcCheck = XXH64(resultBuffer, srcSize, 0);
Yann Collet70e8c382016-02-10 13:37:52 +0100277 if (crcOrig!=crcCheck) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100278 unsigned u;
279 unsigned eBlockSize = (unsigned)(MIN(65536*2, blockSize));
280 DISPLAY("\n!!! WARNING !!! Invalid Checksum : %x != %x\n", (unsigned)crcOrig, (unsigned)crcCheck);
Yann Collet70e8c382016-02-10 13:37:52 +0100281 for (u=0; u<srcSize; u++) {
282 if (((const BYTE*)srcBuffer)[u] != ((BYTE*)resultBuffer)[u]) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100283 printf("Decoding error at pos %u (block %u, pos %u) \n", u, u / eBlockSize, u % eBlockSize);
284 break;
Yann Collet70e8c382016-02-10 13:37:52 +0100285 } }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100286 break;
287 }
288#endif
Yann Collet70e8c382016-02-10 13:37:52 +0100289 } }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100290
291 /* End cleaning */
Yann Collet59d70632015-11-04 12:05:27 +0100292 DISPLAY("\r");
Yann Colletfd9d6b82015-10-26 00:06:36 +0100293 free(compressedBuffer);
294 free(resultBuffer);
295 return 0;
296}
297
Yann Collet59d70632015-11-04 12:05:27 +0100298
Yann Collet5be2dd22015-11-11 13:43:58 +0100299const char* g_stratName[] = { "ZSTD_fast ",
Yann Colleta43a8542016-07-12 13:42:10 +0200300 "ZSTD_dfast ",
Yann Collet5be2dd22015-11-11 13:43:58 +0100301 "ZSTD_greedy ",
302 "ZSTD_lazy ",
303 "ZSTD_lazy2 ",
Yann Collet70e8c382016-02-10 13:37:52 +0100304 "ZSTD_btlazy2",
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200305 "ZSTD_btopt ",
306 "ZSTD_btopt2 "};
Yann Colletfd9d6b82015-10-26 00:06:36 +0100307
Yann Collet51d50042016-03-30 20:42:19 +0200308static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_compressionParameters params, size_t srcSize)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100309{
310 DISPLAY("\r%79s\r", "");
Yann Collet51d50042016-03-30 20:42:19 +0200311 fprintf(f," {%3u,%3u,%3u,%3u,%3u,%3u, %s }, ",
Yann Collet8a57b922016-04-04 13:49:18 +0200312 params.windowLog, params.chainLog, params.hashLog, params.searchLog, params.searchLength,
Yann Colletbd828d92016-02-11 04:38:55 +0100313 params.targetLength, g_stratName[(U32)(params.strategy)]);
Yann Collet786f5b52015-10-26 15:45:58 +0100314 fprintf(f,
Yann Collet35644872015-11-02 16:14:46 +0100315 "/* level %2u */ /* R:%5.3f at %5.1f MB/s - %5.1f MB/s */\n",
Yann Collet158e7702016-07-13 16:45:24 +0200316 cLevel, (double)srcSize / result.cSize, result.cSpeed / 1000000., result.dSpeed / 1000000.);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100317}
318
319
Yann Collet158e7702016-07-13 16:45:24 +0200320static double g_cSpeedTarget[NB_LEVELS_TRACKED] = { 0. }; /* NB_LEVELS_TRACKED : checked at main() */
Yann Colletb2ad30c2015-10-26 02:45:19 +0100321
Yann Colletfd9d6b82015-10-26 00:06:36 +0100322typedef struct {
323 BMK_result_t result;
Yann Collet51d50042016-03-30 20:42:19 +0200324 ZSTD_compressionParameters params;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100325} winnerInfo_t;
326
Yann Collet8b91abe2015-10-27 02:59:12 +0100327static void BMK_printWinners2(FILE* f, const winnerInfo_t* winners, size_t srcSize)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100328{
Yann Collet41105342016-07-27 15:09:11 +0200329 int cLevel;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100330
Yann Collet09116c22015-11-27 17:46:14 +0100331 fprintf(f, "\n /* Proposed configurations : */ \n");
Yann Collet51d50042016-03-30 20:42:19 +0200332 fprintf(f, " /* W, C, H, S, L, T, strat */ \n");
Yann Colletfd9d6b82015-10-26 00:06:36 +0100333
Yann Collet70e8c382016-02-10 13:37:52 +0100334 for (cLevel=0; cLevel <= ZSTD_maxCLevel(); cLevel++)
Yann Collet786f5b52015-10-26 15:45:58 +0100335 BMK_printWinner(f, cLevel, winners[cLevel].result, winners[cLevel].params, srcSize);
336}
337
Yann Collet8b91abe2015-10-27 02:59:12 +0100338
339static void BMK_printWinners(FILE* f, const winnerInfo_t* winners, size_t srcSize)
340{
341 fseek(f, 0, SEEK_SET);
342 BMK_printWinners2(f, winners, srcSize);
Yann Collet10ba1832015-10-28 14:05:37 +0100343 fflush(f);
Yann Collet8b91abe2015-10-27 02:59:12 +0100344 BMK_printWinners2(stdout, winners, srcSize);
345}
346
Yann Collet51d50042016-03-30 20:42:19 +0200347static int BMK_seed(winnerInfo_t* winners, const ZSTD_compressionParameters params,
Yann Collet786f5b52015-10-26 15:45:58 +0100348 const void* srcBuffer, size_t srcSize,
Yann Collet5be2dd22015-11-11 13:43:58 +0100349 ZSTD_CCtx* ctx)
Yann Collet786f5b52015-10-26 15:45:58 +0100350{
351 BMK_result_t testResult;
352 int better = 0;
Yann Collet41105342016-07-27 15:09:11 +0200353 int cLevel;
Yann Collet786f5b52015-10-26 15:45:58 +0100354
355 BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params);
356
Yann Collet70e8c382016-02-10 13:37:52 +0100357 for (cLevel = 1; cLevel <= ZSTD_maxCLevel(); cLevel++) {
Yann Collet81e49e62015-10-28 15:56:48 +0100358 if (testResult.cSpeed < g_cSpeedTarget[cLevel])
359 continue; /* not fast enough for this level */
Yann Collet70e8c382016-02-10 13:37:52 +0100360 if (winners[cLevel].result.cSize==0) {
Yann Collet81e49e62015-10-28 15:56:48 +0100361 /* first solution for this cLevel */
362 winners[cLevel].result = testResult;
363 winners[cLevel].params = params;
364 BMK_printWinner(stdout, cLevel, testResult, params, srcSize);
365 better = 1;
366 continue;
367 }
Yann Collet1077bb82015-10-28 12:32:25 +0100368
Yann Collet70e8c382016-02-10 13:37:52 +0100369 if ((double)testResult.cSize <= ((double)winners[cLevel].result.cSize * (1. + (0.02 / cLevel))) ) {
Yann Collet1077bb82015-10-28 12:32:25 +0100370 /* Validate solution is "good enough" */
Yann Collet81e49e62015-10-28 15:56:48 +0100371 double W_ratio = (double)srcSize / testResult.cSize;
372 double O_ratio = (double)srcSize / winners[cLevel].result.cSize;
373 double W_ratioNote = log (W_ratio);
374 double O_ratioNote = log (O_ratio);
Yann Collet1077bb82015-10-28 12:32:25 +0100375 size_t W_DMemUsed = (1 << params.windowLog) + (16 KB);
376 size_t O_DMemUsed = (1 << winners[cLevel].params.windowLog) + (16 KB);
Yann Collet76c5c2a2015-10-28 19:07:05 +0100377 double W_DMemUsed_note = W_ratioNote * ( 40 + 9*cLevel) - log((double)W_DMemUsed);
378 double O_DMemUsed_note = O_ratioNote * ( 40 + 9*cLevel) - log((double)O_DMemUsed);
Yann Collet1077bb82015-10-28 12:32:25 +0100379
Yann Collete20d5cf2016-07-14 20:46:24 +0200380 size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize(params);
381 size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize(winners[cLevel].params);
Yann Collet81e49e62015-10-28 15:56:48 +0100382 double W_CMemUsed_note = W_ratioNote * ( 50 + 13*cLevel) - log((double)W_CMemUsed);
383 double O_CMemUsed_note = O_ratioNote * ( 50 + 13*cLevel) - log((double)O_CMemUsed);
Yann Collet1077bb82015-10-28 12:32:25 +0100384
Yann Collet158e7702016-07-13 16:45:24 +0200385 double W_CSpeed_note = W_ratioNote * ( 30 + 10*cLevel) + log(testResult.cSpeed);
386 double O_CSpeed_note = O_ratioNote * ( 30 + 10*cLevel) + log(winners[cLevel].result.cSpeed);
Yann Collet10ba1832015-10-28 14:05:37 +0100387
Yann Collet158e7702016-07-13 16:45:24 +0200388 double W_DSpeed_note = W_ratioNote * ( 20 + 2*cLevel) + log(testResult.dSpeed);
389 double O_DSpeed_note = O_ratioNote * ( 20 + 2*cLevel) + log(winners[cLevel].result.dSpeed);
Yann Collet10ba1832015-10-28 14:05:37 +0100390
Yann Collet70e8c382016-02-10 13:37:52 +0100391 if (W_DMemUsed_note < O_DMemUsed_note) {
Yann Collet81e49e62015-10-28 15:56:48 +0100392 /* uses too much Decompression memory for too little benefit */
393 if (W_ratio > O_ratio)
394 DISPLAY ("Decompression Memory : %5.3f @ %4.1f MB vs %5.3f @ %4.1f MB : not enough for level %i\n",
395 W_ratio, (double)(W_DMemUsed) / 1024 / 1024,
396 O_ratio, (double)(O_DMemUsed) / 1024 / 1024, cLevel);
397 continue;
398 }
Yann Collet70e8c382016-02-10 13:37:52 +0100399 if (W_CMemUsed_note < O_CMemUsed_note) {
Yann Collet81e49e62015-10-28 15:56:48 +0100400 /* uses too much memory for compression for too little benefit */
401 if (W_ratio > O_ratio)
402 DISPLAY ("Compression Memory : %5.3f @ %4.1f MB vs %5.3f @ %4.1f MB : not enough for level %i\n",
403 W_ratio, (double)(W_CMemUsed) / 1024 / 1024,
404 O_ratio, (double)(O_CMemUsed) / 1024 / 1024, cLevel);
405 continue;
406 }
Yann Collet70e8c382016-02-10 13:37:52 +0100407 if (W_CSpeed_note < O_CSpeed_note ) {
Yann Collet81e49e62015-10-28 15:56:48 +0100408 /* too large compression speed difference for the compression benefit */
409 if (W_ratio > O_ratio)
410 DISPLAY ("Compression Speed : %5.3f @ %4.1f MB/s vs %5.3f @ %4.1f MB/s : not enough for level %i\n",
Yann Collet158e7702016-07-13 16:45:24 +0200411 W_ratio, testResult.cSpeed / 1000000,
412 O_ratio, winners[cLevel].result.cSpeed / 1000000., cLevel);
Yann Collet81e49e62015-10-28 15:56:48 +0100413 continue;
414 }
Yann Collet70e8c382016-02-10 13:37:52 +0100415 if (W_DSpeed_note < O_DSpeed_note ) {
Yann Collet81e49e62015-10-28 15:56:48 +0100416 /* too large decompression speed difference for the compression benefit */
417 if (W_ratio > O_ratio)
418 DISPLAY ("Decompression Speed : %5.3f @ %4.1f MB/s vs %5.3f @ %4.1f MB/s : not enough for level %i\n",
Yann Collet158e7702016-07-13 16:45:24 +0200419 W_ratio, testResult.dSpeed / 1000000.,
420 O_ratio, winners[cLevel].result.dSpeed / 1000000., cLevel);
Yann Collet81e49e62015-10-28 15:56:48 +0100421 continue;
422 }
423
424 if (W_ratio < O_ratio)
425 DISPLAY("Solution %4.3f selected over %4.3f at level %i, due to better secondary statistics \n", W_ratio, O_ratio, cLevel);
426
427 winners[cLevel].result = testResult;
428 winners[cLevel].params = params;
429 BMK_printWinner(stdout, cLevel, testResult, params, srcSize);
Yann Collet1077bb82015-10-28 12:32:25 +0100430
Yann Collet786f5b52015-10-26 15:45:58 +0100431 better = 1;
Yann Collet70e8c382016-02-10 13:37:52 +0100432 } }
Yann Collet786f5b52015-10-26 15:45:58 +0100433
434 return better;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100435}
436
Yann Colletfd9d6b82015-10-26 00:06:36 +0100437
Yann Collet7ccff592015-11-09 12:07:44 +0100438/* nullified useless params, to ensure count stats */
Yann Collet51d50042016-03-30 20:42:19 +0200439static ZSTD_compressionParameters* sanitizeParams(ZSTD_compressionParameters params)
Yann Collet7ccff592015-11-09 12:07:44 +0100440{
441 g_params = params;
Yann Collet5be2dd22015-11-11 13:43:58 +0100442 if (params.strategy == ZSTD_fast)
Yann Collet8a57b922016-04-04 13:49:18 +0200443 g_params.chainLog = 0, g_params.searchLog = 0;
Yann Collet650a8772016-07-13 11:49:05 +0200444 if (params.strategy == ZSTD_dfast)
445 g_params.searchLog = 0;
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200446 if (params.strategy != ZSTD_btopt && params.strategy != ZSTD_btopt2)
Yann Colletbd828d92016-02-11 04:38:55 +0100447 g_params.targetLength = 0;
Yann Collet7ccff592015-11-09 12:07:44 +0100448 return &g_params;
449}
450
Yann Collet09116c22015-11-27 17:46:14 +0100451
Yann Collet51d50042016-03-30 20:42:19 +0200452static void paramVariation(ZSTD_compressionParameters* ptr)
Yann Collet09116c22015-11-27 17:46:14 +0100453{
Yann Collet51d50042016-03-30 20:42:19 +0200454 ZSTD_compressionParameters p;
455 U32 validated = 0;
456 while (!validated) {
457 U32 nbChanges = (FUZ_rand(&g_rand) & 3) + 1;
458 p = *ptr;
459 for ( ; nbChanges ; nbChanges--) {
460 const U32 changeID = FUZ_rand(&g_rand) % 14;
461 switch(changeID)
462 {
463 case 0:
Yann Collet8a57b922016-04-04 13:49:18 +0200464 p.chainLog++; break;
Yann Collet51d50042016-03-30 20:42:19 +0200465 case 1:
Yann Collet8a57b922016-04-04 13:49:18 +0200466 p.chainLog--; break;
Yann Collet51d50042016-03-30 20:42:19 +0200467 case 2:
468 p.hashLog++; break;
469 case 3:
470 p.hashLog--; break;
471 case 4:
472 p.searchLog++; break;
473 case 5:
474 p.searchLog--; break;
475 case 6:
476 p.windowLog++; break;
477 case 7:
478 p.windowLog--; break;
479 case 8:
480 p.searchLength++; break;
481 case 9:
482 p.searchLength--; break;
483 case 10:
484 p.strategy = (ZSTD_strategy)(((U32)p.strategy)+1); break;
485 case 11:
486 p.strategy = (ZSTD_strategy)(((U32)p.strategy)-1); break;
487 case 12:
488 p.targetLength *= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break;
489 case 13:
490 p.targetLength /= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break;
491 }
Yann Collet09116c22015-11-27 17:46:14 +0100492 }
Yann Collet51d50042016-03-30 20:42:19 +0200493 validated = !ZSTD_isError(ZSTD_checkCParams(p));
Yann Collet09116c22015-11-27 17:46:14 +0100494 }
Yann Collet51d50042016-03-30 20:42:19 +0200495 *ptr = p;
Yann Collet09116c22015-11-27 17:46:14 +0100496}
497
498
Yann Collet6d2c9e62015-11-09 11:39:48 +0100499#define PARAMTABLELOG 25
500#define PARAMTABLESIZE (1<<PARAMTABLELOG)
501#define PARAMTABLEMASK (PARAMTABLESIZE-1)
502static BYTE g_alreadyTested[PARAMTABLESIZE] = {0}; /* init to zero */
Yann Collet786f5b52015-10-26 15:45:58 +0100503
504#define NB_TESTS_PLAYED(p) \
Yann Collet7ccff592015-11-09 12:07:44 +0100505 g_alreadyTested[(XXH64(sanitizeParams(p), sizeof(p), 0) >> 3) & PARAMTABLEMASK]
Yann Collet786f5b52015-10-26 15:45:58 +0100506
507
Yann Collet6d2c9e62015-11-09 11:39:48 +0100508#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
509
Yann Collet786f5b52015-10-26 15:45:58 +0100510static void playAround(FILE* f, winnerInfo_t* winners,
Yann Collet51d50042016-03-30 20:42:19 +0200511 ZSTD_compressionParameters params,
Yann Colletfd9d6b82015-10-26 00:06:36 +0100512 const void* srcBuffer, size_t srcSize,
Yann Collet5be2dd22015-11-11 13:43:58 +0100513 ZSTD_CCtx* ctx)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100514{
Yann Collet786f5b52015-10-26 15:45:58 +0100515 int nbVariations = 0;
Yann Collet158e7702016-07-13 16:45:24 +0200516 clock_t const clockStart = clock();
Yann Colletb315bc82015-10-27 13:12:25 +0100517
Yann Collet158e7702016-07-13 16:45:24 +0200518 while (BMK_clockSpan(clockStart) < g_maxVariationTime) {
Yann Collet51d50042016-03-30 20:42:19 +0200519 ZSTD_compressionParameters p = params;
Yann Collet09116c22015-11-27 17:46:14 +0100520
Yann Collet786f5b52015-10-26 15:45:58 +0100521 if (nbVariations++ > g_maxNbVariations) break;
Yann Collet09116c22015-11-27 17:46:14 +0100522 paramVariation(&p);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100523
Yann Collet786f5b52015-10-26 15:45:58 +0100524 /* exclude faster if already played params */
Yann Collet21f96932015-11-01 14:32:59 +0100525 if (FUZ_rand(&g_rand) & ((1 << NB_TESTS_PLAYED(p))-1))
526 continue;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100527
Yann Collet786f5b52015-10-26 15:45:58 +0100528 /* test */
529 NB_TESTS_PLAYED(p)++;
530 if (!BMK_seed(winners, p, srcBuffer, srcSize, ctx)) continue;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100531
Yann Collet786f5b52015-10-26 15:45:58 +0100532 /* improvement found => search more */
533 BMK_printWinners(f, winners, srcSize);
534 playAround(f, winners, p, srcBuffer, srcSize, ctx);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100535 }
536
537}
538
Yann Collet786f5b52015-10-26 15:45:58 +0100539
Yann Colleteb700432016-06-01 18:59:55 +0200540static ZSTD_compressionParameters randomParams(void)
Yann Collet09116c22015-11-27 17:46:14 +0100541{
Yann Colleteb700432016-06-01 18:59:55 +0200542 ZSTD_compressionParameters p;
Yann Collet51d50042016-03-30 20:42:19 +0200543 U32 validated = 0;
Yann Collet51d50042016-03-30 20:42:19 +0200544 while (!validated) {
Yann Collet09116c22015-11-27 17:46:14 +0100545 /* totally random entry */
Yann Colleteb700432016-06-01 18:59:55 +0200546 p.chainLog = FUZ_rand(&g_rand) % (ZSTD_CHAINLOG_MAX+1 - ZSTD_CHAINLOG_MIN) + ZSTD_CHAINLOG_MIN;
547 p.hashLog = FUZ_rand(&g_rand) % (ZSTD_HASHLOG_MAX+1 - ZSTD_HASHLOG_MIN) + ZSTD_HASHLOG_MIN;
548 p.searchLog = FUZ_rand(&g_rand) % (ZSTD_SEARCHLOG_MAX+1 - ZSTD_SEARCHLOG_MIN) + ZSTD_SEARCHLOG_MIN;
549 p.windowLog = FUZ_rand(&g_rand) % (ZSTD_WINDOWLOG_MAX+1 - ZSTD_WINDOWLOG_MIN) + ZSTD_WINDOWLOG_MIN;
550 p.searchLength=FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN) + ZSTD_SEARCHLENGTH_MIN;
551 p.targetLength=FUZ_rand(&g_rand) % (ZSTD_TARGETLENGTH_MAX+1 - ZSTD_TARGETLENGTH_MIN) + ZSTD_TARGETLENGTH_MIN;
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200552 p.strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_btopt2 +1));
Yann Colleteb700432016-06-01 18:59:55 +0200553 validated = !ZSTD_isError(ZSTD_checkCParams(p));
Yann Collet09116c22015-11-27 17:46:14 +0100554 }
Yann Colleteb700432016-06-01 18:59:55 +0200555 return p;
Yann Collet09116c22015-11-27 17:46:14 +0100556}
557
Yann Collet786f5b52015-10-26 15:45:58 +0100558static void BMK_selectRandomStart(
559 FILE* f, winnerInfo_t* winners,
560 const void* srcBuffer, size_t srcSize,
Yann Collet5be2dd22015-11-11 13:43:58 +0100561 ZSTD_CCtx* ctx)
Yann Collet786f5b52015-10-26 15:45:58 +0100562{
Yann Colleteb700432016-06-01 18:59:55 +0200563 U32 const id = (FUZ_rand(&g_rand) % (ZSTD_maxCLevel()+1));
Yann Collet70e8c382016-02-10 13:37:52 +0100564 if ((id==0) || (winners[id].params.windowLog==0)) {
Yann Collet786f5b52015-10-26 15:45:58 +0100565 /* totally random entry */
Yann Colleteb700432016-06-01 18:59:55 +0200566 ZSTD_compressionParameters const p = ZSTD_adjustCParams(randomParams(), srcSize, 0);
Yann Collet786f5b52015-10-26 15:45:58 +0100567 playAround(f, winners, p, srcBuffer, srcSize, ctx);
568 }
569 else
570 playAround(f, winners, winners[id].params, srcBuffer, srcSize, ctx);
571}
572
573
Yann Colletfd9d6b82015-10-26 00:06:36 +0100574static void BMK_benchMem(void* srcBuffer, size_t srcSize)
575{
Yann Colleta43a8542016-07-12 13:42:10 +0200576 ZSTD_CCtx* const ctx = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200577 ZSTD_compressionParameters params;
Yann Collet70e8c382016-02-10 13:37:52 +0100578 winnerInfo_t winners[NB_LEVELS_TRACKED];
Yann Collet158e7702016-07-13 16:45:24 +0200579 const char* const rfName = "grillResults.txt";
Yann Colleta43a8542016-07-12 13:42:10 +0200580 FILE* const f = fopen(rfName, "w");
Yann Collet43e0cd52015-11-09 16:38:17 +0100581 const size_t blockSize = g_blockSize ? g_blockSize : srcSize;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100582
Yann Collet158e7702016-07-13 16:45:24 +0200583 /* init */
584 if (ctx==NULL) { DISPLAY("ZSTD_createCCtx() failed \n"); exit(1); }
585 memset(winners, 0, sizeof(winners));
586 if (f==NULL) { DISPLAY("error opening %s \n", rfName); exit(1); }
587
Yann Collet70e8c382016-02-10 13:37:52 +0100588 if (g_singleRun) {
Yann Collet1077bb82015-10-28 12:32:25 +0100589 BMK_result_t testResult;
Yann Colleteb700432016-06-01 18:59:55 +0200590 g_params = ZSTD_adjustCParams(g_params, srcSize, 0);
Yann Collet8b91abe2015-10-27 02:59:12 +0100591 BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, g_params);
592 DISPLAY("\n");
593 return;
594 }
595
Yann Collet2c6992e2015-10-27 12:18:00 +0100596 if (g_target)
Yann Collet158e7702016-07-13 16:45:24 +0200597 g_cSpeedTarget[1] = g_target * 1000000;
Yann Collet70e8c382016-02-10 13:37:52 +0100598 else {
Yann Colletf12c1302015-11-05 18:16:59 +0100599 /* baseline config for level 1 */
Yann Collet1077bb82015-10-28 12:32:25 +0100600 BMK_result_t testResult;
Yann Collet51d50042016-03-30 20:42:19 +0200601 params = ZSTD_getCParams(1, blockSize, 0);
Yann Collet2c6992e2015-10-27 12:18:00 +0100602 BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params);
Yann Collet158e7702016-07-13 16:45:24 +0200603 g_cSpeedTarget[1] = (testResult.cSpeed * 31) / 32;
Yann Collet2c6992e2015-10-27 12:18:00 +0100604 }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100605
Yann Colletf12c1302015-11-05 18:16:59 +0100606 /* establish speed objectives (relative to level 1) */
Yann Collet41105342016-07-27 15:09:11 +0200607 { int i;
608 for (i=2; i<=ZSTD_maxCLevel(); i++)
609 g_cSpeedTarget[i] = (g_cSpeedTarget[i-1] * 25) / 32;
Yann Collet158e7702016-07-13 16:45:24 +0200610 }
Yann Collet786f5b52015-10-26 15:45:58 +0100611
612 /* populate initial solution */
Yann Colleta43a8542016-07-12 13:42:10 +0200613 { const int maxSeeds = g_noSeed ? 1 : ZSTD_maxCLevel();
614 int i;
615 for (i=0; i<=maxSeeds; i++) {
Yann Collet51d50042016-03-30 20:42:19 +0200616 params = ZSTD_getCParams(i, blockSize, 0);
Yann Colletb315bc82015-10-27 13:12:25 +0100617 BMK_seed(winners, params, srcBuffer, srcSize, ctx);
Yann Colleta43a8542016-07-12 13:42:10 +0200618 } }
Yann Collet786f5b52015-10-26 15:45:58 +0100619 BMK_printWinners(f, winners, srcSize);
620
621 /* start tests */
Yann Collet158e7702016-07-13 16:45:24 +0200622 { const time_t grillStart = time(NULL);
Yann Collet70e8c382016-02-10 13:37:52 +0100623 do {
Yann Collet786f5b52015-10-26 15:45:58 +0100624 BMK_selectRandomStart(f, winners, srcBuffer, srcSize, ctx);
Yann Collet158e7702016-07-13 16:45:24 +0200625 } while (BMK_timeSpan(grillStart) < g_grillDuration_s);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100626 }
627
Yann Colletfd9d6b82015-10-26 00:06:36 +0100628 /* end summary */
Yann Collet786f5b52015-10-26 15:45:58 +0100629 BMK_printWinners(f, winners, srcSize);
Yann Collet2c6992e2015-10-27 12:18:00 +0100630 DISPLAY("grillParams operations completed \n");
Yann Colletfd9d6b82015-10-26 00:06:36 +0100631
632 /* clean up*/
Yann Collet786f5b52015-10-26 15:45:58 +0100633 fclose(f);
Yann Collet5be2dd22015-11-11 13:43:58 +0100634 ZSTD_freeCCtx(ctx);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100635}
636
637
638static int benchSample(void)
639{
Yann Collet70e8c382016-02-10 13:37:52 +0100640 void* origBuff;
Yann Colleta43a8542016-07-12 13:42:10 +0200641 size_t const benchedSize = sampleSize;
642 const char* const name = "Sample 10MiB";
Yann Colletfd9d6b82015-10-26 00:06:36 +0100643
644 /* Allocation */
Yann Collet70e8c382016-02-10 13:37:52 +0100645 origBuff = malloc(benchedSize);
646 if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); return 12; }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100647
648 /* Fill buffer */
649 RDG_genBuffer(origBuff, benchedSize, g_compressibility, 0.0, 0);
650
651 /* bench */
652 DISPLAY("\r%79s\r", "");
653 DISPLAY("using %s %i%%: \n", name, (int)(g_compressibility*100));
654 BMK_benchMem(origBuff, benchedSize);
655
656 free(origBuff);
657 return 0;
658}
659
660
Yann Colleta43a8542016-07-12 13:42:10 +0200661int benchFiles(const char** fileNamesTable, int nbFiles)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100662{
663 int fileIdx=0;
664
665 /* Loop for each file */
Yann Collet70e8c382016-02-10 13:37:52 +0100666 while (fileIdx<nbFiles) {
Yann Colleta43a8542016-07-12 13:42:10 +0200667 const char* const inFileName = fileNamesTable[fileIdx++];
668 FILE* const inFile = fopen( inFileName, "rb" );
669 U64 const inFileSize = UTIL_getFileSize(inFileName);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100670 size_t benchedSize;
Yann Colleta43a8542016-07-12 13:42:10 +0200671 void* origBuff;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100672
673 /* Check file existence */
Yann Collet70e8c382016-02-10 13:37:52 +0100674 if (inFile==NULL) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100675 DISPLAY( "Pb opening %s\n", inFileName);
676 return 11;
677 }
678
Yann Colleta43a8542016-07-12 13:42:10 +0200679 /* Memory allocation */
Yann Collet70e8c382016-02-10 13:37:52 +0100680 benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100681 if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
682 if (benchedSize < inFileSize)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100683 DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
Yann Colleta43a8542016-07-12 13:42:10 +0200684 origBuff = malloc(benchedSize);
685 if (origBuff==NULL) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100686 DISPLAY("\nError: not enough memory!\n");
687 fclose(inFile);
688 return 12;
689 }
690
691 /* Fill input buffer */
692 DISPLAY("Loading %s... \r", inFileName);
Yann Colleta43a8542016-07-12 13:42:10 +0200693 { size_t const readSize = fread(origBuff, 1, benchedSize, inFile);
694 fclose(inFile);
695 if(readSize != benchedSize) {
696 DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
697 free(origBuff);
698 return 13;
699 } }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100700
701 /* bench */
702 DISPLAY("\r%79s\r", "");
703 DISPLAY("using %s : \n", inFileName);
704 BMK_benchMem(origBuff, benchedSize);
Yann Colleta43a8542016-07-12 13:42:10 +0200705
706 /* clean */
707 free(origBuff);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100708 }
709
710 return 0;
711}
712
713
Yann Collet696c4d72016-07-13 13:11:08 +0200714int optimizeForSize(const char* inFileName, U32 targetSpeed)
Yann Collet09116c22015-11-27 17:46:14 +0100715{
Yann Collet696c4d72016-07-13 13:11:08 +0200716 FILE* const inFile = fopen( inFileName, "rb" );
717 U64 const inFileSize = UTIL_getFileSize(inFileName);
718 size_t benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
719 void* origBuff;
Yann Collet09116c22015-11-27 17:46:14 +0100720
Yann Collet696c4d72016-07-13 13:11:08 +0200721 /* Init */
722 if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; }
Yann Collet09116c22015-11-27 17:46:14 +0100723
724 /* Memory allocation & restrictions */
Yann Collet09116c22015-11-27 17:46:14 +0100725 if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
726 if (benchedSize < inFileSize)
Yann Collet09116c22015-11-27 17:46:14 +0100727 DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
Yann Collet09116c22015-11-27 17:46:14 +0100728
729 /* Alloc */
Yann Collet696c4d72016-07-13 13:11:08 +0200730 origBuff = malloc(benchedSize);
Yann Collet70e8c382016-02-10 13:37:52 +0100731 if(!origBuff) {
Yann Collet09116c22015-11-27 17:46:14 +0100732 DISPLAY("\nError: not enough memory!\n");
733 fclose(inFile);
734 return 12;
735 }
736
737 /* Fill input buffer */
738 DISPLAY("Loading %s... \r", inFileName);
Yann Collet696c4d72016-07-13 13:11:08 +0200739 { size_t const readSize = fread(origBuff, 1, benchedSize, inFile);
740 fclose(inFile);
741 if(readSize != benchedSize) {
742 DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
743 free(origBuff);
744 return 13;
745 } }
Yann Collet09116c22015-11-27 17:46:14 +0100746
747 /* bench */
748 DISPLAY("\r%79s\r", "");
Yann Collet696c4d72016-07-13 13:11:08 +0200749 DISPLAY("optimizing for %s - limit speed %u MB/s \n", inFileName, targetSpeed);
750 targetSpeed *= 1000;
Yann Collet09116c22015-11-27 17:46:14 +0100751
Yann Collet696c4d72016-07-13 13:11:08 +0200752 { ZSTD_CCtx* const ctx = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200753 ZSTD_compressionParameters params;
Yann Collet09116c22015-11-27 17:46:14 +0100754 winnerInfo_t winner;
755 BMK_result_t candidate;
Yann Collet7fe531e2015-11-29 02:38:09 +0100756 const size_t blockSize = g_blockSize ? g_blockSize : benchedSize;
Yann Collet09116c22015-11-27 17:46:14 +0100757
758 /* init */
Yann Collet696c4d72016-07-13 13:11:08 +0200759 if (ctx==NULL) { DISPLAY("\n ZSTD_createCCtx error \n"); free(origBuff); return 14;}
Yann Collet09116c22015-11-27 17:46:14 +0100760 memset(&winner, 0, sizeof(winner));
761 winner.result.cSize = (size_t)(-1);
762
763 /* find best solution from default params */
Yann Colleta43a8542016-07-12 13:42:10 +0200764 { const int maxSeeds = g_noSeed ? 1 : ZSTD_maxCLevel();
Yann Collet696c4d72016-07-13 13:11:08 +0200765 int i;
Yann Collet70e8c382016-02-10 13:37:52 +0100766 for (i=1; i<=maxSeeds; i++) {
Yann Collet51d50042016-03-30 20:42:19 +0200767 params = ZSTD_getCParams(i, blockSize, 0);
Yann Collet7fe531e2015-11-29 02:38:09 +0100768 BMK_benchParam(&candidate, origBuff, benchedSize, ctx, params);
Yann Collet696c4d72016-07-13 13:11:08 +0200769 if (candidate.cSpeed < targetSpeed)
770 break;
Yann Collet09116c22015-11-27 17:46:14 +0100771 if ( (candidate.cSize < winner.result.cSize)
Yann Collet696c4d72016-07-13 13:11:08 +0200772 | ((candidate.cSize == winner.result.cSize) & (candidate.cSpeed > winner.result.cSpeed)) )
Yann Collet09116c22015-11-27 17:46:14 +0100773 {
774 winner.params = params;
775 winner.result = candidate;
Yann Collet7fe531e2015-11-29 02:38:09 +0100776 BMK_printWinner(stdout, i, winner.result, winner.params, benchedSize);
Yann Collet70e8c382016-02-10 13:37:52 +0100777 } }
Yann Collet09116c22015-11-27 17:46:14 +0100778 }
Yann Collet7fe531e2015-11-29 02:38:09 +0100779 BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
Yann Collet09116c22015-11-27 17:46:14 +0100780
781 /* start tests */
Yann Collet158e7702016-07-13 16:45:24 +0200782 { time_t const grillStart = time(NULL);
Yann Collet70e8c382016-02-10 13:37:52 +0100783 do {
Yann Collet09116c22015-11-27 17:46:14 +0100784 params = winner.params;
785 paramVariation(&params);
Yann Collet696c4d72016-07-13 13:11:08 +0200786 if ((FUZ_rand(&g_rand) & 15) == 3) params = randomParams();
Yann Collet09116c22015-11-27 17:46:14 +0100787
788 /* exclude faster if already played set of params */
789 if (FUZ_rand(&g_rand) & ((1 << NB_TESTS_PLAYED(params))-1)) continue;
790
791 /* test */
792 NB_TESTS_PLAYED(params)++;
Yann Collet7fe531e2015-11-29 02:38:09 +0100793 BMK_benchParam(&candidate, origBuff, benchedSize, ctx, params);
Yann Collet09116c22015-11-27 17:46:14 +0100794
795 /* improvement found => new winner */
Yann Collet696c4d72016-07-13 13:11:08 +0200796 if ( (candidate.cSpeed > targetSpeed)
797 & ( (candidate.cSize < winner.result.cSize)
798 | ((candidate.cSize == winner.result.cSize) & (candidate.cSpeed > winner.result.cSpeed)) ) )
799 {
Yann Collet09116c22015-11-27 17:46:14 +0100800 winner.params = params;
801 winner.result = candidate;
Yann Collet7fe531e2015-11-29 02:38:09 +0100802 BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
Yann Collet09116c22015-11-27 17:46:14 +0100803 }
Yann Collet158e7702016-07-13 16:45:24 +0200804 } while (BMK_timeSpan(grillStart) < g_grillDuration_s);
Yann Collet09116c22015-11-27 17:46:14 +0100805 }
806
807 /* end summary */
Yann Collet7fe531e2015-11-29 02:38:09 +0100808 BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
Yann Collet09116c22015-11-27 17:46:14 +0100809 DISPLAY("grillParams size - optimizer completed \n");
810
811 /* clean up*/
812 ZSTD_freeCCtx(ctx);
813 }
814
Yann Collet696c4d72016-07-13 13:11:08 +0200815 free(origBuff);
Yann Collet09116c22015-11-27 17:46:14 +0100816 return 0;
817}
818
819
Yann Colleta43a8542016-07-12 13:42:10 +0200820static int usage(const char* exename)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100821{
822 DISPLAY( "Usage :\n");
823 DISPLAY( " %s [arg] file\n", exename);
824 DISPLAY( "Arguments :\n");
Yann Colletb5d2a0c2015-11-23 17:10:19 +0100825 DISPLAY( " file : path to the file used as reference (if none, generates a compressible sample)\n");
Yann Colletfd9d6b82015-10-26 00:06:36 +0100826 DISPLAY( " -H/-h : Help (this text + advanced options)\n");
827 return 0;
828}
829
Yann Collet04b12d82016-02-11 06:23:24 +0100830static int usage_advanced(void)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100831{
832 DISPLAY( "\nAdvanced options :\n");
Yann Colleta43a8542016-07-12 13:42:10 +0200833 DISPLAY( " -T# : set level 1 speed objective \n");
834 DISPLAY( " -B# : cut input into blocks of size # (default : single block) \n");
835 DISPLAY( " -i# : iteration loops [1-9](default : %i) \n", NBLOOPS);
Yann Collet696c4d72016-07-13 13:11:08 +0200836 DISPLAY( " -O# : find Optimized parameters for # target speed (default : 0) \n");
Yann Colleta43a8542016-07-12 13:42:10 +0200837 DISPLAY( " -S : Single run \n");
838 DISPLAY( " -P# : generated sample compressibility (default : %.1f%%) \n", COMPRESSIBILITY_DEFAULT * 100);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100839 return 0;
840}
841
Yann Colleta43a8542016-07-12 13:42:10 +0200842static int badusage(const char* exename)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100843{
844 DISPLAY("Wrong parameters\n");
845 usage(exename);
Yann Collet8b91abe2015-10-27 02:59:12 +0100846 return 1;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100847}
848
Yann Colleta43a8542016-07-12 13:42:10 +0200849int main(int argc, const char** argv)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100850{
851 int i,
852 filenamesStart=0,
853 result;
Yann Colleta43a8542016-07-12 13:42:10 +0200854 const char* exename=argv[0];
855 const char* input_filename=0;
Yann Collet09116c22015-11-27 17:46:14 +0100856 U32 optimizer = 0;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100857 U32 main_pause = 0;
Yann Collet696c4d72016-07-13 13:11:08 +0200858 U32 targetSpeed = 0;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100859
Yann Collet70e8c382016-02-10 13:37:52 +0100860 /* checks */
861 if (NB_LEVELS_TRACKED <= ZSTD_maxCLevel()) {
862 DISPLAY("Error : NB_LEVELS_TRACKED <= ZSTD_maxCLevel() \n");
863 exit(1);
864 }
865
Yann Colletfd9d6b82015-10-26 00:06:36 +0100866 /* Welcome message */
867 DISPLAY(WELCOME_MESSAGE);
868
869 if (argc<1) { badusage(exename); return 1; }
870
Yann Collet0dbf2872016-04-08 02:02:12 +0200871 for(i=1; i<argc; i++) {
Yann Colleta43a8542016-07-12 13:42:10 +0200872 const char* argument = argv[i];
Yann Colletfd9d6b82015-10-26 00:06:36 +0100873
Yann Colletb315bc82015-10-27 13:12:25 +0100874 if(!argument) continue; /* Protection if argument empty */
875
876 if(!strcmp(argument,"--no-seed")) { g_noSeed = 1; continue; }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100877
Yann Collet786f5b52015-10-26 15:45:58 +0100878 /* Decode command (note : aggregated commands are allowed) */
Yann Collet70e8c382016-02-10 13:37:52 +0100879 if (argument[0]=='-') {
Yann Collet8b91abe2015-10-27 02:59:12 +0100880 argument++;
881
Yann Collet70e8c382016-02-10 13:37:52 +0100882 while (argument[0]!=0) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100883
884 switch(argument[0])
885 {
886 /* Display help on usage */
887 case 'h' :
888 case 'H': usage(exename); usage_advanced(); return 0;
889
890 /* Pause at the end (hidden option) */
Yann Collet8b91abe2015-10-27 02:59:12 +0100891 case 'p': main_pause = 1; argument++; break;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100892
893 /* Modify Nb Iterations */
894 case 'i':
Yann Collet8b91abe2015-10-27 02:59:12 +0100895 argument++;
Yann Collet696c4d72016-07-13 13:11:08 +0200896 if ((argument[0] >='0') & (argument[0] <='9'))
Yann Collet4b100f42015-10-30 15:49:48 +0100897 g_nbIterations = *argument++ - '0';
Yann Colletfd9d6b82015-10-26 00:06:36 +0100898 break;
899
900 /* Sample compressibility (when no file provided) */
901 case 'P':
Yann Collet8b91abe2015-10-27 02:59:12 +0100902 argument++;
Yann Collet0dbf2872016-04-08 02:02:12 +0200903 { U32 proba32 = 0;
Yann Collet696c4d72016-07-13 13:11:08 +0200904 while ((argument[0]>= '0') & (argument[0]<= '9'))
Yann Collet0dbf2872016-04-08 02:02:12 +0200905 proba32 = (proba32*10) + (*argument++ - '0');
Yann Colletfd9d6b82015-10-26 00:06:36 +0100906 g_compressibility = (double)proba32 / 100.;
907 }
908 break;
909
Yann Collet09116c22015-11-27 17:46:14 +0100910 case 'O':
911 argument++;
912 optimizer=1;
Yann Collet696c4d72016-07-13 13:11:08 +0200913 targetSpeed = 0;
914 while ((*argument >= '0') & (*argument <= '9'))
915 targetSpeed = (targetSpeed*10) + (*argument++ - '0');
Yann Collet09116c22015-11-27 17:46:14 +0100916 break;
917
Yann Collet8b91abe2015-10-27 02:59:12 +0100918 /* Run Single conf */
919 case 'S':
Yann Collet4b100f42015-10-30 15:49:48 +0100920 g_singleRun = 1;
921 argument++;
Yann Collet51d50042016-03-30 20:42:19 +0200922 g_params = ZSTD_getCParams(2, g_blockSize, 0);
Yann Collet70e8c382016-02-10 13:37:52 +0100923 for ( ; ; ) {
Yann Collet4b100f42015-10-30 15:49:48 +0100924 switch(*argument)
925 {
926 case 'w':
927 g_params.windowLog = 0;
928 argument++;
929 while ((*argument>= '0') && (*argument<='9'))
930 g_params.windowLog *= 10, g_params.windowLog += *argument++ - '0';
931 continue;
932 case 'c':
Yann Collet8a57b922016-04-04 13:49:18 +0200933 g_params.chainLog = 0;
Yann Collet4b100f42015-10-30 15:49:48 +0100934 argument++;
935 while ((*argument>= '0') && (*argument<='9'))
Yann Collet8a57b922016-04-04 13:49:18 +0200936 g_params.chainLog *= 10, g_params.chainLog += *argument++ - '0';
Yann Collet4b100f42015-10-30 15:49:48 +0100937 continue;
938 case 'h':
939 g_params.hashLog = 0;
940 argument++;
941 while ((*argument>= '0') && (*argument<='9'))
942 g_params.hashLog *= 10, g_params.hashLog += *argument++ - '0';
943 continue;
944 case 's':
945 g_params.searchLog = 0;
946 argument++;
947 while ((*argument>= '0') && (*argument<='9'))
948 g_params.searchLog *= 10, g_params.searchLog += *argument++ - '0';
949 continue;
Yann Collet9b11b462015-11-01 12:40:22 +0100950 case 'l': /* search length */
Yann Collet4b100f42015-10-30 15:49:48 +0100951 g_params.searchLength = 0;
952 argument++;
953 while ((*argument>= '0') && (*argument<='9'))
954 g_params.searchLength *= 10, g_params.searchLength += *argument++ - '0';
955 continue;
Yann Collet04b12d82016-02-11 06:23:24 +0100956 case 't': /* target length */
957 g_params.targetLength = 0;
Yann Collet9b11b462015-11-01 12:40:22 +0100958 argument++;
Yann Collet04b12d82016-02-11 06:23:24 +0100959 while ((*argument>= '0') && (*argument<='9'))
960 g_params.targetLength *= 10, g_params.targetLength += *argument++ - '0';
961 continue;
962 case 'S': /* strategy */
963 argument++;
964 while ((*argument>= '0') && (*argument<='9'))
965 g_params.strategy = (ZSTD_strategy)(*argument++ - '0');
Yann Collet9b11b462015-11-01 12:40:22 +0100966 continue;
Yann Collet4b100f42015-10-30 15:49:48 +0100967 case 'L':
Yann Collet0dbf2872016-04-08 02:02:12 +0200968 { int cLevel = 0;
Yann Collet4b100f42015-10-30 15:49:48 +0100969 argument++;
970 while ((*argument>= '0') && (*argument<='9'))
971 cLevel *= 10, cLevel += *argument++ - '0';
Yann Collet51d50042016-03-30 20:42:19 +0200972 g_params = ZSTD_getCParams(cLevel, g_blockSize, 0);
Yann Collet4b100f42015-10-30 15:49:48 +0100973 continue;
974 }
975 default : ;
976 }
Yann Collet8b91abe2015-10-27 02:59:12 +0100977 break;
978 }
Yann Collet4b100f42015-10-30 15:49:48 +0100979 break;
Yann Collet8b91abe2015-10-27 02:59:12 +0100980
Yann Colletf12c1302015-11-05 18:16:59 +0100981 /* target level1 speed objective, in MB/s */
Yann Collet2c6992e2015-10-27 12:18:00 +0100982 case 'T':
983 argument++;
984 g_target = 0;
Yann Collet0dbf2872016-04-08 02:02:12 +0200985 while ((*argument >= '0') && (*argument <= '9'))
986 g_target = (g_target*10) + (*argument++ - '0');
Yann Collet2c6992e2015-10-27 12:18:00 +0100987 break;
988
989 /* cut input into blocks */
990 case 'B':
Yann Collet0dbf2872016-04-08 02:02:12 +0200991 g_blockSize = 0;
992 argument++;
Yann Collet696c4d72016-07-13 13:11:08 +0200993 while ((*argument >='0') & (*argument <='9'))
Yann Collet0dbf2872016-04-08 02:02:12 +0200994 g_blockSize = (g_blockSize*10) + (*argument++ - '0');
995 if (*argument=='K') g_blockSize<<=10, argument++; /* allows using KB notation */
996 if (*argument=='M') g_blockSize<<=20, argument++;
997 if (*argument=='B') argument++;
998 DISPLAY("using %u KB block size \n", g_blockSize>>10);
Yann Collet2c6992e2015-10-27 12:18:00 +0100999 break;
1000
Yann Colletfd9d6b82015-10-26 00:06:36 +01001001 /* Unknown command */
Yann Collet8b91abe2015-10-27 02:59:12 +01001002 default : return badusage(exename);
Yann Colletfd9d6b82015-10-26 00:06:36 +01001003 }
1004 }
1005 continue;
Yann Collet0dbf2872016-04-08 02:02:12 +02001006 } /* if (argument[0]=='-') */
Yann Colletfd9d6b82015-10-26 00:06:36 +01001007
1008 /* first provided filename is input */
1009 if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
1010 }
1011
Yann Colletfd9d6b82015-10-26 00:06:36 +01001012 if (filenamesStart==0)
1013 result = benchSample();
Yann Collet70e8c382016-02-10 13:37:52 +01001014 else {
Yann Collet00fd7a22015-11-28 16:03:22 +01001015 if (optimizer)
Yann Collet696c4d72016-07-13 13:11:08 +02001016 result = optimizeForSize(input_filename, targetSpeed);
Yann Collet00fd7a22015-11-28 16:03:22 +01001017 else
1018 result = benchFiles(argv+filenamesStart, argc-filenamesStart);
1019 }
Yann Colletfd9d6b82015-10-26 00:06:36 +01001020
1021 if (main_pause) { int unused; printf("press enter...\n"); unused = getchar(); (void)unused; }
1022
1023 return result;
1024}