blob: 1185c664980f85249b37eb9d3e9c5cb88cca3c8c [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 Collet83d0c762017-05-15 17:15:46 -070041#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 Collet83d0c762017-05-15 17:15:46 -070050static const double g_grillDuration_s = 90000; /* about 24 hours */
Yann Collet158e7702016-07-13 16:45:24 +020051static 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
Yann Collet4f818182017-04-17 17:57:35 -070061#undef MIN
62#undef MAX
63#define MIN(a,b) ( (a) < (b) ? (a) : (b) )
64#define MAX(a,b) ( (a) > (b) ? (a) : (b) )
65
Yann Colletfd9d6b82015-10-26 00:06:36 +010066
Yann Collet70e8c382016-02-10 13:37:52 +010067/*-************************************
Yann Colletfd9d6b82015-10-26 00:06:36 +010068* Benchmark Parameters
69**************************************/
Yann Collet4b100f42015-10-30 15:49:48 +010070static U32 g_nbIterations = NBLOOPS;
Yann Colletfd9d6b82015-10-26 00:06:36 +010071static double g_compressibility = COMPRESSIBILITY_DEFAULT;
72static U32 g_blockSize = 0;
Yann Collet786f5b52015-10-26 15:45:58 +010073static U32 g_rand = 1;
Yann Collet8b91abe2015-10-27 02:59:12 +010074static U32 g_singleRun = 0;
Yann Collet2c6992e2015-10-27 12:18:00 +010075static U32 g_target = 0;
Yann Colletb315bc82015-10-27 13:12:25 +010076static U32 g_noSeed = 0;
Yann Collet51d50042016-03-30 20:42:19 +020077static ZSTD_compressionParameters g_params = { 0, 0, 0, 0, 0, 0, ZSTD_greedy };
Yann Colletfd9d6b82015-10-26 00:06:36 +010078
79void BMK_SetNbIterations(int nbLoops)
80{
Yann Collet4b100f42015-10-30 15:49:48 +010081 g_nbIterations = nbLoops;
82 DISPLAY("- %u iterations -\n", g_nbIterations);
Yann Colletfd9d6b82015-10-26 00:06:36 +010083}
84
85
Yann Collet70e8c382016-02-10 13:37:52 +010086/*-*******************************************************
Yann Colletfd9d6b82015-10-26 00:06:36 +010087* Private functions
88*********************************************************/
89
Yann Collet83d0c762017-05-15 17:15:46 -070090/* works even if overflow ; max span ~ 30 mn */
91static clock_t BMK_clockSpan(clock_t cStart) { return clock() - cStart; }
Yann Colletfd9d6b82015-10-26 00:06:36 +010092
Yann Collet83d0c762017-05-15 17:15:46 -070093/* accuracy in seconds only, span can be multiple years */
94static double BMK_timeSpan(time_t tStart) { return difftime(time(NULL), tStart); }
Yann Colletfd9d6b82015-10-26 00:06:36 +010095
96
97static size_t BMK_findMaxMem(U64 requiredMem)
98{
Yann Collet158e7702016-07-13 16:45:24 +020099 size_t const step = 64 MB;
100 void* testmem = NULL;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100101
102 requiredMem = (((requiredMem >> 26) + 1) << 26);
Yann Collet49cc9b72015-11-27 17:52:57 +0100103 if (requiredMem > maxMemory) requiredMem = maxMemory;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100104
105 requiredMem += 2*step;
Yann Collet70e8c382016-02-10 13:37:52 +0100106 while (!testmem) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100107 requiredMem -= step;
Yann Collet158e7702016-07-13 16:45:24 +0200108 testmem = malloc ((size_t)requiredMem);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100109 }
110
111 free (testmem);
112 return (size_t) (requiredMem - step);
113}
114
115
Yann Colletc2007382017-04-04 15:35:06 -0700116static U32 FUZ_rotl32(U32 x, U32 r)
117{
118 return ((x << r) | (x >> (32 - r)));
119}
120
Yann Colletfd9d6b82015-10-26 00:06:36 +0100121U32 FUZ_rand(U32* src)
122{
123 const U32 prime1 = 2654435761U;
124 const U32 prime2 = 2246822519U;
125 U32 rand32 = *src;
126 rand32 *= prime1;
127 rand32 += prime2;
128 rand32 = FUZ_rotl32(rand32, 13);
129 *src = rand32;
130 return rand32 >> 5;
131}
132
133
Yann Collet70e8c382016-02-10 13:37:52 +0100134/*-*******************************************************
Yann Colletfd9d6b82015-10-26 00:06:36 +0100135* Bench functions
136*********************************************************/
137typedef struct {
138 size_t cSize;
Yann Collet2724f252017-04-04 16:31:17 -0700139 double cSpeed; /* bytes / sec */
Yann Collet158e7702016-07-13 16:45:24 +0200140 double dSpeed;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100141} BMK_result_t;
142
143typedef struct
144{
145 const char* srcPtr;
146 size_t srcSize;
147 char* cPtr;
148 size_t cRoom;
149 size_t cSize;
150 char* resPtr;
151 size_t resSize;
152} blockParam_t;
153
154
Yann Colletfd9d6b82015-10-26 00:06:36 +0100155static size_t BMK_benchParam(BMK_result_t* resultPtr,
156 const void* srcBuffer, size_t srcSize,
Yann Collet5be2dd22015-11-11 13:43:58 +0100157 ZSTD_CCtx* ctx,
Yann Collet51d50042016-03-30 20:42:19 +0200158 const ZSTD_compressionParameters cParams)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100159{
160 const size_t blockSize = g_blockSize ? g_blockSize : srcSize;
161 const U32 nbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize);
162 blockParam_t* const blockTable = (blockParam_t*) malloc(nbBlocks * sizeof(blockParam_t));
163 const size_t maxCompressedSize = (size_t)nbBlocks * ZSTD_compressBound(blockSize);
164 void* const compressedBuffer = malloc(maxCompressedSize);
165 void* const resultBuffer = malloc(srcSize);
Yann Collet51d50042016-03-30 20:42:19 +0200166 ZSTD_parameters params;
167 U32 Wlog = cParams.windowLog;
Yann Collet8a57b922016-04-04 13:49:18 +0200168 U32 Clog = cParams.chainLog;
Yann Collet51d50042016-03-30 20:42:19 +0200169 U32 Hlog = cParams.hashLog;
170 U32 Slog = cParams.searchLog;
171 U32 Slength = cParams.searchLength;
172 U32 Tlength = cParams.targetLength;
173 ZSTD_strategy strat = cParams.strategy;
Yann Colletbe2010e2015-10-31 12:57:14 +0100174 char name[30] = { 0 };
Yann Colletfd9d6b82015-10-26 00:06:36 +0100175 U64 crcOrig;
176
Yann Collet89b32f32017-04-04 16:41:11 -0700177 /* init result for early exit */
178 resultPtr->cSize = srcSize;
179 resultPtr->cSpeed = 0.;
180 resultPtr->dSpeed = 0.;
181
Yann Colletfd9d6b82015-10-26 00:06:36 +0100182 /* Memory allocation & restrictions */
Yann Collet70e8c382016-02-10 13:37:52 +0100183 snprintf(name, 30, "Sw%02uc%02uh%02us%02ul%1ut%03uS%1u", Wlog, Clog, Hlog, Slog, Slength, Tlength, strat);
184 if (!compressedBuffer || !resultBuffer || !blockTable) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100185 DISPLAY("\nError: not enough memory!\n");
186 free(compressedBuffer);
187 free(resultBuffer);
188 free(blockTable);
189 return 12;
190 }
191
192 /* Calculating input Checksum */
193 crcOrig = XXH64(srcBuffer, srcSize, 0);
194
195 /* Init blockTable data */
196 {
197 U32 i;
198 size_t remaining = srcSize;
199 const char* srcPtr = (const char*)srcBuffer;
200 char* cPtr = (char*)compressedBuffer;
201 char* resPtr = (char*)resultBuffer;
Yann Collet70e8c382016-02-10 13:37:52 +0100202 for (i=0; i<nbBlocks; i++) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100203 size_t thisBlockSize = MIN(remaining, blockSize);
204 blockTable[i].srcPtr = srcPtr;
205 blockTable[i].cPtr = cPtr;
206 blockTable[i].resPtr = resPtr;
207 blockTable[i].srcSize = thisBlockSize;
208 blockTable[i].cRoom = ZSTD_compressBound(thisBlockSize);
209 srcPtr += thisBlockSize;
210 cPtr += blockTable[i].cRoom;
211 resPtr += thisBlockSize;
212 remaining -= thisBlockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100213 } }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100214
215 /* warmimg up memory */
216 RDG_genBuffer(compressedBuffer, maxCompressedSize, 0.10, 0.10, 1);
217
218 /* Bench */
Yann Collet158e7702016-07-13 16:45:24 +0200219 { U32 loopNb;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100220 size_t cSize = 0;
221 double fastestC = 100000000., fastestD = 100000000.;
222 double ratio = 0.;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200223 clock_t const benchStart = clock();
Yann Colletfd9d6b82015-10-26 00:06:36 +0100224
225 DISPLAY("\r%79s\r", "");
Yann Collet3ae543c2016-07-11 03:12:17 +0200226 memset(&params, 0, sizeof(params));
Yann Collet51d50042016-03-30 20:42:19 +0200227 params.cParams = cParams;
Yann Collet70e8c382016-02-10 13:37:52 +0100228 for (loopNb = 1; loopNb <= g_nbIterations; loopNb++) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100229 int nbLoops;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100230 U32 blockNb;
Yann Collet158e7702016-07-13 16:45:24 +0200231 clock_t roundStart, roundClock;
Yann Collet786f5b52015-10-26 15:45:58 +0100232
Yann Collet158e7702016-07-13 16:45:24 +0200233 { clock_t const benchTime = BMK_clockSpan(benchStart);
234 if (benchTime > g_maxParamTime) break; }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100235
236 /* Compression */
Yann Collet59d70632015-11-04 12:05:27 +0100237 DISPLAY("\r%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100238 memset(compressedBuffer, 0xE5, maxCompressedSize);
239
240 nbLoops = 0;
Yann Collet158e7702016-07-13 16:45:24 +0200241 roundStart = clock();
242 while (clock() == roundStart);
243 roundStart = clock();
244 while (BMK_clockSpan(roundStart) < TIMELOOP) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100245 for (blockNb=0; blockNb<nbBlocks; blockNb++)
Yann Collet5be2dd22015-11-11 13:43:58 +0100246 blockTable[blockNb].cSize = ZSTD_compress_advanced(ctx,
Yann Collet786f5b52015-10-26 15:45:58 +0100247 blockTable[blockNb].cPtr, blockTable[blockNb].cRoom,
248 blockTable[blockNb].srcPtr, blockTable[blockNb].srcSize,
Yann Collet31683c02015-12-18 01:26:48 +0100249 NULL, 0,
Yann Collet786f5b52015-10-26 15:45:58 +0100250 params);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100251 nbLoops++;
252 }
Yann Collet158e7702016-07-13 16:45:24 +0200253 roundClock = BMK_clockSpan(roundStart);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100254
255 cSize = 0;
256 for (blockNb=0; blockNb<nbBlocks; blockNb++)
257 cSize += blockTable[blockNb].cSize;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100258 ratio = (double)srcSize / (double)cSize;
Yann Collet2724f252017-04-04 16:31:17 -0700259 if ((double)roundClock < fastestC * CLOCKS_PER_SEC * nbLoops) fastestC = ((double)roundClock / CLOCKS_PER_SEC) / nbLoops;
Yann Collet59d70632015-11-04 12:05:27 +0100260 DISPLAY("\r");
Yann Colletbe2010e2015-10-31 12:57:14 +0100261 DISPLAY("%1u-%s : %9u ->", loopNb, name, (U32)srcSize);
Yann Collet158e7702016-07-13 16:45:24 +0200262 DISPLAY(" %9u (%4.3f),%7.1f MB/s", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100263 resultPtr->cSize = cSize;
Yann Collet158e7702016-07-13 16:45:24 +0200264 resultPtr->cSpeed = (double)srcSize / fastestC;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100265
266#if 1
267 /* Decompression */
268 memset(resultBuffer, 0xD6, srcSize);
269
270 nbLoops = 0;
Yann Collet158e7702016-07-13 16:45:24 +0200271 roundStart = clock();
272 while (clock() == roundStart);
273 roundStart = clock();
274 for ( ; BMK_clockSpan(roundStart) < TIMELOOP; nbLoops++) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100275 for (blockNb=0; blockNb<nbBlocks; blockNb++)
276 blockTable[blockNb].resSize = ZSTD_decompress(blockTable[blockNb].resPtr, blockTable[blockNb].srcSize,
277 blockTable[blockNb].cPtr, blockTable[blockNb].cSize);
278 }
Yann Collet158e7702016-07-13 16:45:24 +0200279 roundClock = BMK_clockSpan(roundStart);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100280
Yann Collet158e7702016-07-13 16:45:24 +0200281 if ((double)roundClock < fastestD * CLOCKS_PER_SEC * nbLoops) fastestD = ((double)roundClock / CLOCKS_PER_SEC) / nbLoops;
Yann Collet59d70632015-11-04 12:05:27 +0100282 DISPLAY("\r");
Yann Colletbe2010e2015-10-31 12:57:14 +0100283 DISPLAY("%1u-%s : %9u -> ", loopNb, name, (U32)srcSize);
Yann Collet158e7702016-07-13 16:45:24 +0200284 DISPLAY("%9u (%4.3f),%7.1f MB/s, ", (U32)cSize, ratio, (double)srcSize / fastestC / 1000000.);
285 DISPLAY("%7.1f MB/s", (double)srcSize / fastestD / 1000000.);
286 resultPtr->dSpeed = (double)srcSize / fastestD;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100287
288 /* CRC Checking */
Yann Collet2724f252017-04-04 16:31:17 -0700289 { U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
290 if (crcOrig!=crcCheck) {
291 unsigned u;
292 unsigned eBlockSize = (unsigned)(MIN(65536*2, blockSize));
293 DISPLAY("\n!!! WARNING !!! Invalid Checksum : %x != %x\n", (unsigned)crcOrig, (unsigned)crcCheck);
294 for (u=0; u<srcSize; u++) {
295 if (((const BYTE*)srcBuffer)[u] != ((BYTE*)resultBuffer)[u]) {
296 printf("Decoding error at pos %u (block %u, pos %u) \n", u, u / eBlockSize, u % eBlockSize);
297 break;
298 } }
299 break;
300 } }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100301#endif
Yann Collet70e8c382016-02-10 13:37:52 +0100302 } }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100303
304 /* End cleaning */
Yann Collet59d70632015-11-04 12:05:27 +0100305 DISPLAY("\r");
Yann Colletfd9d6b82015-10-26 00:06:36 +0100306 free(compressedBuffer);
307 free(resultBuffer);
308 return 0;
309}
310
Yann Collet59d70632015-11-04 12:05:27 +0100311
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800312const char* g_stratName[] = { "ZSTD_fast ",
313 "ZSTD_dfast ",
314 "ZSTD_greedy ",
315 "ZSTD_lazy ",
316 "ZSTD_lazy2 ",
317 "ZSTD_btlazy2 ",
318 "ZSTD_btopt ",
319 "ZSTD_btultra "};
Yann Colletfd9d6b82015-10-26 00:06:36 +0100320
Yann Collet51d50042016-03-30 20:42:19 +0200321static void BMK_printWinner(FILE* f, U32 cLevel, BMK_result_t result, ZSTD_compressionParameters params, size_t srcSize)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100322{
323 DISPLAY("\r%79s\r", "");
Yann Collet51d50042016-03-30 20:42:19 +0200324 fprintf(f," {%3u,%3u,%3u,%3u,%3u,%3u, %s }, ",
Yann Collet8a57b922016-04-04 13:49:18 +0200325 params.windowLog, params.chainLog, params.hashLog, params.searchLog, params.searchLength,
Yann Colletbd828d92016-02-11 04:38:55 +0100326 params.targetLength, g_stratName[(U32)(params.strategy)]);
Yann Collet786f5b52015-10-26 15:45:58 +0100327 fprintf(f,
Yann Collet35644872015-11-02 16:14:46 +0100328 "/* level %2u */ /* R:%5.3f at %5.1f MB/s - %5.1f MB/s */\n",
Yann Collet158e7702016-07-13 16:45:24 +0200329 cLevel, (double)srcSize / result.cSize, result.cSpeed / 1000000., result.dSpeed / 1000000.);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100330}
331
332
Yann Collet158e7702016-07-13 16:45:24 +0200333static double g_cSpeedTarget[NB_LEVELS_TRACKED] = { 0. }; /* NB_LEVELS_TRACKED : checked at main() */
Yann Colletb2ad30c2015-10-26 02:45:19 +0100334
Yann Colletfd9d6b82015-10-26 00:06:36 +0100335typedef struct {
336 BMK_result_t result;
Yann Collet51d50042016-03-30 20:42:19 +0200337 ZSTD_compressionParameters params;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100338} winnerInfo_t;
339
Yann Collet8b91abe2015-10-27 02:59:12 +0100340static void BMK_printWinners2(FILE* f, const winnerInfo_t* winners, size_t srcSize)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100341{
Yann Collet41105342016-07-27 15:09:11 +0200342 int cLevel;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100343
Yann Collet09116c22015-11-27 17:46:14 +0100344 fprintf(f, "\n /* Proposed configurations : */ \n");
Yann Collet51d50042016-03-30 20:42:19 +0200345 fprintf(f, " /* W, C, H, S, L, T, strat */ \n");
Yann Colletfd9d6b82015-10-26 00:06:36 +0100346
Yann Collet70e8c382016-02-10 13:37:52 +0100347 for (cLevel=0; cLevel <= ZSTD_maxCLevel(); cLevel++)
Yann Collet786f5b52015-10-26 15:45:58 +0100348 BMK_printWinner(f, cLevel, winners[cLevel].result, winners[cLevel].params, srcSize);
349}
350
Yann Collet8b91abe2015-10-27 02:59:12 +0100351
352static void BMK_printWinners(FILE* f, const winnerInfo_t* winners, size_t srcSize)
353{
354 fseek(f, 0, SEEK_SET);
355 BMK_printWinners2(f, winners, srcSize);
Yann Collet10ba1832015-10-28 14:05:37 +0100356 fflush(f);
Yann Collet8b91abe2015-10-27 02:59:12 +0100357 BMK_printWinners2(stdout, winners, srcSize);
358}
359
Yann Collet51d50042016-03-30 20:42:19 +0200360static int BMK_seed(winnerInfo_t* winners, const ZSTD_compressionParameters params,
Yann Collet786f5b52015-10-26 15:45:58 +0100361 const void* srcBuffer, size_t srcSize,
Yann Collet5be2dd22015-11-11 13:43:58 +0100362 ZSTD_CCtx* ctx)
Yann Collet786f5b52015-10-26 15:45:58 +0100363{
364 BMK_result_t testResult;
365 int better = 0;
Yann Collet41105342016-07-27 15:09:11 +0200366 int cLevel;
Yann Collet786f5b52015-10-26 15:45:58 +0100367
368 BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params);
369
Yann Collet70e8c382016-02-10 13:37:52 +0100370 for (cLevel = 1; cLevel <= ZSTD_maxCLevel(); cLevel++) {
Yann Collet81e49e62015-10-28 15:56:48 +0100371 if (testResult.cSpeed < g_cSpeedTarget[cLevel])
372 continue; /* not fast enough for this level */
Yann Collet70e8c382016-02-10 13:37:52 +0100373 if (winners[cLevel].result.cSize==0) {
Yann Collet81e49e62015-10-28 15:56:48 +0100374 /* first solution for this cLevel */
375 winners[cLevel].result = testResult;
376 winners[cLevel].params = params;
377 BMK_printWinner(stdout, cLevel, testResult, params, srcSize);
378 better = 1;
379 continue;
380 }
Yann Collet1077bb82015-10-28 12:32:25 +0100381
Yann Collet70e8c382016-02-10 13:37:52 +0100382 if ((double)testResult.cSize <= ((double)winners[cLevel].result.cSize * (1. + (0.02 / cLevel))) ) {
Yann Collet1077bb82015-10-28 12:32:25 +0100383 /* Validate solution is "good enough" */
Yann Collet81e49e62015-10-28 15:56:48 +0100384 double W_ratio = (double)srcSize / testResult.cSize;
385 double O_ratio = (double)srcSize / winners[cLevel].result.cSize;
386 double W_ratioNote = log (W_ratio);
387 double O_ratioNote = log (O_ratio);
Yann Collet1077bb82015-10-28 12:32:25 +0100388 size_t W_DMemUsed = (1 << params.windowLog) + (16 KB);
389 size_t O_DMemUsed = (1 << winners[cLevel].params.windowLog) + (16 KB);
Yann Collet76c5c2a2015-10-28 19:07:05 +0100390 double W_DMemUsed_note = W_ratioNote * ( 40 + 9*cLevel) - log((double)W_DMemUsed);
391 double O_DMemUsed_note = O_ratioNote * ( 40 + 9*cLevel) - log((double)O_DMemUsed);
Yann Collet1077bb82015-10-28 12:32:25 +0100392
Yann Collete20d5cf2016-07-14 20:46:24 +0200393 size_t W_CMemUsed = (1 << params.windowLog) + ZSTD_estimateCCtxSize(params);
394 size_t O_CMemUsed = (1 << winners[cLevel].params.windowLog) + ZSTD_estimateCCtxSize(winners[cLevel].params);
Yann Collet81e49e62015-10-28 15:56:48 +0100395 double W_CMemUsed_note = W_ratioNote * ( 50 + 13*cLevel) - log((double)W_CMemUsed);
396 double O_CMemUsed_note = O_ratioNote * ( 50 + 13*cLevel) - log((double)O_CMemUsed);
Yann Collet1077bb82015-10-28 12:32:25 +0100397
Yann Collet158e7702016-07-13 16:45:24 +0200398 double W_CSpeed_note = W_ratioNote * ( 30 + 10*cLevel) + log(testResult.cSpeed);
399 double O_CSpeed_note = O_ratioNote * ( 30 + 10*cLevel) + log(winners[cLevel].result.cSpeed);
Yann Collet10ba1832015-10-28 14:05:37 +0100400
Yann Collet158e7702016-07-13 16:45:24 +0200401 double W_DSpeed_note = W_ratioNote * ( 20 + 2*cLevel) + log(testResult.dSpeed);
402 double O_DSpeed_note = O_ratioNote * ( 20 + 2*cLevel) + log(winners[cLevel].result.dSpeed);
Yann Collet10ba1832015-10-28 14:05:37 +0100403
Yann Collet70e8c382016-02-10 13:37:52 +0100404 if (W_DMemUsed_note < O_DMemUsed_note) {
Yann Collet81e49e62015-10-28 15:56:48 +0100405 /* uses too much Decompression memory for too little benefit */
406 if (W_ratio > O_ratio)
407 DISPLAY ("Decompression Memory : %5.3f @ %4.1f MB vs %5.3f @ %4.1f MB : not enough for level %i\n",
408 W_ratio, (double)(W_DMemUsed) / 1024 / 1024,
409 O_ratio, (double)(O_DMemUsed) / 1024 / 1024, cLevel);
410 continue;
411 }
Yann Collet70e8c382016-02-10 13:37:52 +0100412 if (W_CMemUsed_note < O_CMemUsed_note) {
Yann Collet81e49e62015-10-28 15:56:48 +0100413 /* uses too much memory for compression for too little benefit */
414 if (W_ratio > O_ratio)
415 DISPLAY ("Compression Memory : %5.3f @ %4.1f MB vs %5.3f @ %4.1f MB : not enough for level %i\n",
416 W_ratio, (double)(W_CMemUsed) / 1024 / 1024,
417 O_ratio, (double)(O_CMemUsed) / 1024 / 1024, cLevel);
418 continue;
419 }
Yann Collet70e8c382016-02-10 13:37:52 +0100420 if (W_CSpeed_note < O_CSpeed_note ) {
Yann Collet81e49e62015-10-28 15:56:48 +0100421 /* too large compression speed difference for the compression benefit */
422 if (W_ratio > O_ratio)
423 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 +0200424 W_ratio, testResult.cSpeed / 1000000,
425 O_ratio, winners[cLevel].result.cSpeed / 1000000., cLevel);
Yann Collet81e49e62015-10-28 15:56:48 +0100426 continue;
427 }
Yann Collet70e8c382016-02-10 13:37:52 +0100428 if (W_DSpeed_note < O_DSpeed_note ) {
Yann Collet81e49e62015-10-28 15:56:48 +0100429 /* too large decompression speed difference for the compression benefit */
430 if (W_ratio > O_ratio)
431 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 +0200432 W_ratio, testResult.dSpeed / 1000000.,
433 O_ratio, winners[cLevel].result.dSpeed / 1000000., cLevel);
Yann Collet81e49e62015-10-28 15:56:48 +0100434 continue;
435 }
436
437 if (W_ratio < O_ratio)
438 DISPLAY("Solution %4.3f selected over %4.3f at level %i, due to better secondary statistics \n", W_ratio, O_ratio, cLevel);
439
440 winners[cLevel].result = testResult;
441 winners[cLevel].params = params;
442 BMK_printWinner(stdout, cLevel, testResult, params, srcSize);
Yann Collet1077bb82015-10-28 12:32:25 +0100443
Yann Collet786f5b52015-10-26 15:45:58 +0100444 better = 1;
Yann Collet70e8c382016-02-10 13:37:52 +0100445 } }
Yann Collet786f5b52015-10-26 15:45:58 +0100446
447 return better;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100448}
449
Yann Colletfd9d6b82015-10-26 00:06:36 +0100450
Yann Collet7ccff592015-11-09 12:07:44 +0100451/* nullified useless params, to ensure count stats */
Yann Collet51d50042016-03-30 20:42:19 +0200452static ZSTD_compressionParameters* sanitizeParams(ZSTD_compressionParameters params)
Yann Collet7ccff592015-11-09 12:07:44 +0100453{
454 g_params = params;
Yann Collet5be2dd22015-11-11 13:43:58 +0100455 if (params.strategy == ZSTD_fast)
Yann Collet8a57b922016-04-04 13:49:18 +0200456 g_params.chainLog = 0, g_params.searchLog = 0;
Yann Collet650a8772016-07-13 11:49:05 +0200457 if (params.strategy == ZSTD_dfast)
458 g_params.searchLog = 0;
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800459 if (params.strategy != ZSTD_btopt && params.strategy != ZSTD_btultra)
Yann Colletbd828d92016-02-11 04:38:55 +0100460 g_params.targetLength = 0;
Yann Collet7ccff592015-11-09 12:07:44 +0100461 return &g_params;
462}
463
Yann Collet09116c22015-11-27 17:46:14 +0100464
Yann Collet51d50042016-03-30 20:42:19 +0200465static void paramVariation(ZSTD_compressionParameters* ptr)
Yann Collet09116c22015-11-27 17:46:14 +0100466{
Yann Collet51d50042016-03-30 20:42:19 +0200467 ZSTD_compressionParameters p;
468 U32 validated = 0;
469 while (!validated) {
470 U32 nbChanges = (FUZ_rand(&g_rand) & 3) + 1;
471 p = *ptr;
472 for ( ; nbChanges ; nbChanges--) {
473 const U32 changeID = FUZ_rand(&g_rand) % 14;
474 switch(changeID)
475 {
476 case 0:
Yann Collet8a57b922016-04-04 13:49:18 +0200477 p.chainLog++; break;
Yann Collet51d50042016-03-30 20:42:19 +0200478 case 1:
Yann Collet8a57b922016-04-04 13:49:18 +0200479 p.chainLog--; break;
Yann Collet51d50042016-03-30 20:42:19 +0200480 case 2:
481 p.hashLog++; break;
482 case 3:
483 p.hashLog--; break;
484 case 4:
485 p.searchLog++; break;
486 case 5:
487 p.searchLog--; break;
488 case 6:
489 p.windowLog++; break;
490 case 7:
491 p.windowLog--; break;
492 case 8:
493 p.searchLength++; break;
494 case 9:
495 p.searchLength--; break;
496 case 10:
497 p.strategy = (ZSTD_strategy)(((U32)p.strategy)+1); break;
498 case 11:
499 p.strategy = (ZSTD_strategy)(((U32)p.strategy)-1); break;
500 case 12:
501 p.targetLength *= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break;
502 case 13:
503 p.targetLength /= 1 + ((double)(FUZ_rand(&g_rand)&255)) / 256.; break;
504 }
Yann Collet09116c22015-11-27 17:46:14 +0100505 }
Yann Collet51d50042016-03-30 20:42:19 +0200506 validated = !ZSTD_isError(ZSTD_checkCParams(p));
Yann Collet09116c22015-11-27 17:46:14 +0100507 }
Yann Collet51d50042016-03-30 20:42:19 +0200508 *ptr = p;
Yann Collet09116c22015-11-27 17:46:14 +0100509}
510
511
Yann Collet6d2c9e62015-11-09 11:39:48 +0100512#define PARAMTABLELOG 25
513#define PARAMTABLESIZE (1<<PARAMTABLELOG)
514#define PARAMTABLEMASK (PARAMTABLESIZE-1)
515static BYTE g_alreadyTested[PARAMTABLESIZE] = {0}; /* init to zero */
Yann Collet786f5b52015-10-26 15:45:58 +0100516
517#define NB_TESTS_PLAYED(p) \
Yann Collet7ccff592015-11-09 12:07:44 +0100518 g_alreadyTested[(XXH64(sanitizeParams(p), sizeof(p), 0) >> 3) & PARAMTABLEMASK]
Yann Collet786f5b52015-10-26 15:45:58 +0100519
520
521static void playAround(FILE* f, winnerInfo_t* winners,
Yann Collet51d50042016-03-30 20:42:19 +0200522 ZSTD_compressionParameters params,
Yann Colletfd9d6b82015-10-26 00:06:36 +0100523 const void* srcBuffer, size_t srcSize,
Yann Collet5be2dd22015-11-11 13:43:58 +0100524 ZSTD_CCtx* ctx)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100525{
Yann Collet786f5b52015-10-26 15:45:58 +0100526 int nbVariations = 0;
Yann Collet158e7702016-07-13 16:45:24 +0200527 clock_t const clockStart = clock();
Yann Colletb315bc82015-10-27 13:12:25 +0100528
Yann Collet158e7702016-07-13 16:45:24 +0200529 while (BMK_clockSpan(clockStart) < g_maxVariationTime) {
Yann Collet51d50042016-03-30 20:42:19 +0200530 ZSTD_compressionParameters p = params;
Yann Collet09116c22015-11-27 17:46:14 +0100531
Yann Collet786f5b52015-10-26 15:45:58 +0100532 if (nbVariations++ > g_maxNbVariations) break;
Yann Collet09116c22015-11-27 17:46:14 +0100533 paramVariation(&p);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100534
Yann Collet786f5b52015-10-26 15:45:58 +0100535 /* exclude faster if already played params */
Yann Collet21f96932015-11-01 14:32:59 +0100536 if (FUZ_rand(&g_rand) & ((1 << NB_TESTS_PLAYED(p))-1))
537 continue;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100538
Yann Collet786f5b52015-10-26 15:45:58 +0100539 /* test */
540 NB_TESTS_PLAYED(p)++;
541 if (!BMK_seed(winners, p, srcBuffer, srcSize, ctx)) continue;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100542
Yann Collet786f5b52015-10-26 15:45:58 +0100543 /* improvement found => search more */
544 BMK_printWinners(f, winners, srcSize);
545 playAround(f, winners, p, srcBuffer, srcSize, ctx);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100546 }
547
548}
549
Yann Collet786f5b52015-10-26 15:45:58 +0100550
Yann Colleteb700432016-06-01 18:59:55 +0200551static ZSTD_compressionParameters randomParams(void)
Yann Collet09116c22015-11-27 17:46:14 +0100552{
Yann Colleteb700432016-06-01 18:59:55 +0200553 ZSTD_compressionParameters p;
Yann Collet51d50042016-03-30 20:42:19 +0200554 U32 validated = 0;
Yann Collet51d50042016-03-30 20:42:19 +0200555 while (!validated) {
Yann Collet09116c22015-11-27 17:46:14 +0100556 /* totally random entry */
Yann Colleteb700432016-06-01 18:59:55 +0200557 p.chainLog = FUZ_rand(&g_rand) % (ZSTD_CHAINLOG_MAX+1 - ZSTD_CHAINLOG_MIN) + ZSTD_CHAINLOG_MIN;
558 p.hashLog = FUZ_rand(&g_rand) % (ZSTD_HASHLOG_MAX+1 - ZSTD_HASHLOG_MIN) + ZSTD_HASHLOG_MIN;
559 p.searchLog = FUZ_rand(&g_rand) % (ZSTD_SEARCHLOG_MAX+1 - ZSTD_SEARCHLOG_MIN) + ZSTD_SEARCHLOG_MIN;
560 p.windowLog = FUZ_rand(&g_rand) % (ZSTD_WINDOWLOG_MAX+1 - ZSTD_WINDOWLOG_MIN) + ZSTD_WINDOWLOG_MIN;
561 p.searchLength=FUZ_rand(&g_rand) % (ZSTD_SEARCHLENGTH_MAX+1 - ZSTD_SEARCHLENGTH_MIN) + ZSTD_SEARCHLENGTH_MIN;
562 p.targetLength=FUZ_rand(&g_rand) % (ZSTD_TARGETLENGTH_MAX+1 - ZSTD_TARGETLENGTH_MIN) + ZSTD_TARGETLENGTH_MIN;
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800563 p.strategy = (ZSTD_strategy) (FUZ_rand(&g_rand) % (ZSTD_btultra +1));
Yann Colleteb700432016-06-01 18:59:55 +0200564 validated = !ZSTD_isError(ZSTD_checkCParams(p));
Yann Collet09116c22015-11-27 17:46:14 +0100565 }
Yann Colleteb700432016-06-01 18:59:55 +0200566 return p;
Yann Collet09116c22015-11-27 17:46:14 +0100567}
568
Yann Collet786f5b52015-10-26 15:45:58 +0100569static void BMK_selectRandomStart(
570 FILE* f, winnerInfo_t* winners,
571 const void* srcBuffer, size_t srcSize,
Yann Collet5be2dd22015-11-11 13:43:58 +0100572 ZSTD_CCtx* ctx)
Yann Collet786f5b52015-10-26 15:45:58 +0100573{
Yann Colleteb700432016-06-01 18:59:55 +0200574 U32 const id = (FUZ_rand(&g_rand) % (ZSTD_maxCLevel()+1));
Yann Collet70e8c382016-02-10 13:37:52 +0100575 if ((id==0) || (winners[id].params.windowLog==0)) {
Yann Collet786f5b52015-10-26 15:45:58 +0100576 /* totally random entry */
Yann Colleteb700432016-06-01 18:59:55 +0200577 ZSTD_compressionParameters const p = ZSTD_adjustCParams(randomParams(), srcSize, 0);
Yann Collet786f5b52015-10-26 15:45:58 +0100578 playAround(f, winners, p, srcBuffer, srcSize, ctx);
579 }
580 else
581 playAround(f, winners, winners[id].params, srcBuffer, srcSize, ctx);
582}
583
584
Yann Colletfd9d6b82015-10-26 00:06:36 +0100585static void BMK_benchMem(void* srcBuffer, size_t srcSize)
586{
Yann Colleta43a8542016-07-12 13:42:10 +0200587 ZSTD_CCtx* const ctx = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200588 ZSTD_compressionParameters params;
Yann Collet70e8c382016-02-10 13:37:52 +0100589 winnerInfo_t winners[NB_LEVELS_TRACKED];
Yann Collet158e7702016-07-13 16:45:24 +0200590 const char* const rfName = "grillResults.txt";
Yann Colleta43a8542016-07-12 13:42:10 +0200591 FILE* const f = fopen(rfName, "w");
Yann Collet43e0cd52015-11-09 16:38:17 +0100592 const size_t blockSize = g_blockSize ? g_blockSize : srcSize;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100593
Yann Collet158e7702016-07-13 16:45:24 +0200594 /* init */
595 if (ctx==NULL) { DISPLAY("ZSTD_createCCtx() failed \n"); exit(1); }
596 memset(winners, 0, sizeof(winners));
597 if (f==NULL) { DISPLAY("error opening %s \n", rfName); exit(1); }
598
Yann Collet70e8c382016-02-10 13:37:52 +0100599 if (g_singleRun) {
Yann Collet1077bb82015-10-28 12:32:25 +0100600 BMK_result_t testResult;
Yann Colleteb700432016-06-01 18:59:55 +0200601 g_params = ZSTD_adjustCParams(g_params, srcSize, 0);
Yann Collet8b91abe2015-10-27 02:59:12 +0100602 BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, g_params);
603 DISPLAY("\n");
604 return;
605 }
606
Yann Collet2c6992e2015-10-27 12:18:00 +0100607 if (g_target)
Yann Collet158e7702016-07-13 16:45:24 +0200608 g_cSpeedTarget[1] = g_target * 1000000;
Yann Collet70e8c382016-02-10 13:37:52 +0100609 else {
Yann Colletf12c1302015-11-05 18:16:59 +0100610 /* baseline config for level 1 */
Yann Collet1077bb82015-10-28 12:32:25 +0100611 BMK_result_t testResult;
Yann Collet51d50042016-03-30 20:42:19 +0200612 params = ZSTD_getCParams(1, blockSize, 0);
Yann Collet2c6992e2015-10-27 12:18:00 +0100613 BMK_benchParam(&testResult, srcBuffer, srcSize, ctx, params);
Yann Collet158e7702016-07-13 16:45:24 +0200614 g_cSpeedTarget[1] = (testResult.cSpeed * 31) / 32;
Yann Collet2c6992e2015-10-27 12:18:00 +0100615 }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100616
Yann Colletf12c1302015-11-05 18:16:59 +0100617 /* establish speed objectives (relative to level 1) */
Yann Collet41105342016-07-27 15:09:11 +0200618 { int i;
619 for (i=2; i<=ZSTD_maxCLevel(); i++)
620 g_cSpeedTarget[i] = (g_cSpeedTarget[i-1] * 25) / 32;
Yann Collet158e7702016-07-13 16:45:24 +0200621 }
Yann Collet786f5b52015-10-26 15:45:58 +0100622
623 /* populate initial solution */
Yann Colleta43a8542016-07-12 13:42:10 +0200624 { const int maxSeeds = g_noSeed ? 1 : ZSTD_maxCLevel();
625 int i;
626 for (i=0; i<=maxSeeds; i++) {
Yann Collet51d50042016-03-30 20:42:19 +0200627 params = ZSTD_getCParams(i, blockSize, 0);
Yann Colletb315bc82015-10-27 13:12:25 +0100628 BMK_seed(winners, params, srcBuffer, srcSize, ctx);
Yann Colleta43a8542016-07-12 13:42:10 +0200629 } }
Yann Collet786f5b52015-10-26 15:45:58 +0100630 BMK_printWinners(f, winners, srcSize);
631
632 /* start tests */
Yann Collet158e7702016-07-13 16:45:24 +0200633 { const time_t grillStart = time(NULL);
Yann Collet70e8c382016-02-10 13:37:52 +0100634 do {
Yann Collet786f5b52015-10-26 15:45:58 +0100635 BMK_selectRandomStart(f, winners, srcBuffer, srcSize, ctx);
Yann Collet158e7702016-07-13 16:45:24 +0200636 } while (BMK_timeSpan(grillStart) < g_grillDuration_s);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100637 }
638
Yann Colletfd9d6b82015-10-26 00:06:36 +0100639 /* end summary */
Yann Collet786f5b52015-10-26 15:45:58 +0100640 BMK_printWinners(f, winners, srcSize);
Yann Collet2c6992e2015-10-27 12:18:00 +0100641 DISPLAY("grillParams operations completed \n");
Yann Colletfd9d6b82015-10-26 00:06:36 +0100642
643 /* clean up*/
Yann Collet786f5b52015-10-26 15:45:58 +0100644 fclose(f);
Yann Collet5be2dd22015-11-11 13:43:58 +0100645 ZSTD_freeCCtx(ctx);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100646}
647
648
649static int benchSample(void)
650{
Yann Collet70e8c382016-02-10 13:37:52 +0100651 void* origBuff;
Yann Colleta43a8542016-07-12 13:42:10 +0200652 size_t const benchedSize = sampleSize;
653 const char* const name = "Sample 10MiB";
Yann Colletfd9d6b82015-10-26 00:06:36 +0100654
655 /* Allocation */
Yann Collet70e8c382016-02-10 13:37:52 +0100656 origBuff = malloc(benchedSize);
657 if (!origBuff) { DISPLAY("\nError: not enough memory!\n"); return 12; }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100658
659 /* Fill buffer */
660 RDG_genBuffer(origBuff, benchedSize, g_compressibility, 0.0, 0);
661
662 /* bench */
663 DISPLAY("\r%79s\r", "");
664 DISPLAY("using %s %i%%: \n", name, (int)(g_compressibility*100));
665 BMK_benchMem(origBuff, benchedSize);
666
667 free(origBuff);
668 return 0;
669}
670
671
Yann Colleta43a8542016-07-12 13:42:10 +0200672int benchFiles(const char** fileNamesTable, int nbFiles)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100673{
674 int fileIdx=0;
675
676 /* Loop for each file */
Yann Collet70e8c382016-02-10 13:37:52 +0100677 while (fileIdx<nbFiles) {
Yann Colleta43a8542016-07-12 13:42:10 +0200678 const char* const inFileName = fileNamesTable[fileIdx++];
679 FILE* const inFile = fopen( inFileName, "rb" );
680 U64 const inFileSize = UTIL_getFileSize(inFileName);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100681 size_t benchedSize;
Yann Colleta43a8542016-07-12 13:42:10 +0200682 void* origBuff;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100683
684 /* Check file existence */
Yann Collet70e8c382016-02-10 13:37:52 +0100685 if (inFile==NULL) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100686 DISPLAY( "Pb opening %s\n", inFileName);
687 return 11;
688 }
689
Yann Colleta43a8542016-07-12 13:42:10 +0200690 /* Memory allocation */
Yann Collet70e8c382016-02-10 13:37:52 +0100691 benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100692 if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
693 if (benchedSize < inFileSize)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100694 DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
Yann Colleta43a8542016-07-12 13:42:10 +0200695 origBuff = malloc(benchedSize);
696 if (origBuff==NULL) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100697 DISPLAY("\nError: not enough memory!\n");
698 fclose(inFile);
699 return 12;
700 }
701
702 /* Fill input buffer */
703 DISPLAY("Loading %s... \r", inFileName);
Yann Colleta43a8542016-07-12 13:42:10 +0200704 { size_t const readSize = fread(origBuff, 1, benchedSize, inFile);
705 fclose(inFile);
706 if(readSize != benchedSize) {
707 DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
708 free(origBuff);
709 return 13;
710 } }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100711
712 /* bench */
713 DISPLAY("\r%79s\r", "");
714 DISPLAY("using %s : \n", inFileName);
715 BMK_benchMem(origBuff, benchedSize);
Yann Colleta43a8542016-07-12 13:42:10 +0200716
717 /* clean */
718 free(origBuff);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100719 }
720
721 return 0;
722}
723
724
Yann Collet9631e602017-04-04 16:54:33 -0700725static void BMK_translateAdvancedParams(ZSTD_compressionParameters params)
726{
727 DISPLAY("--zstd=windowLog=%u,chainLog=%u,hashLog=%u,searchLog=%u,searchLength=%u,targetLength=%u,strategy=%u \n",
728 params.windowLog, params.chainLog, params.hashLog, params.searchLog, params.searchLength, params.targetLength, (U32)(params.strategy));
729}
730
Yann Collet2724f252017-04-04 16:31:17 -0700731/* optimizeForSize():
732 * targetSpeed : expressed in MB/s */
Yann Collet696c4d72016-07-13 13:11:08 +0200733int optimizeForSize(const char* inFileName, U32 targetSpeed)
Yann Collet09116c22015-11-27 17:46:14 +0100734{
Yann Collet696c4d72016-07-13 13:11:08 +0200735 FILE* const inFile = fopen( inFileName, "rb" );
736 U64 const inFileSize = UTIL_getFileSize(inFileName);
737 size_t benchedSize = BMK_findMaxMem(inFileSize*3) / 3;
738 void* origBuff;
Yann Collet09116c22015-11-27 17:46:14 +0100739
Yann Collet696c4d72016-07-13 13:11:08 +0200740 /* Init */
741 if (inFile==NULL) { DISPLAY( "Pb opening %s\n", inFileName); return 11; }
Yann Collet09116c22015-11-27 17:46:14 +0100742
743 /* Memory allocation & restrictions */
Yann Collet09116c22015-11-27 17:46:14 +0100744 if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
Yann Collet2724f252017-04-04 16:31:17 -0700745 if (benchedSize < inFileSize) {
746 DISPLAY("Not enough memory for '%s' \n", inFileName);
747 fclose(inFile);
748 return 11;
749 }
Yann Collet09116c22015-11-27 17:46:14 +0100750
751 /* Alloc */
Yann Collet696c4d72016-07-13 13:11:08 +0200752 origBuff = malloc(benchedSize);
Yann Collet70e8c382016-02-10 13:37:52 +0100753 if(!origBuff) {
Yann Collet09116c22015-11-27 17:46:14 +0100754 DISPLAY("\nError: not enough memory!\n");
755 fclose(inFile);
756 return 12;
757 }
758
759 /* Fill input buffer */
760 DISPLAY("Loading %s... \r", inFileName);
Yann Collet696c4d72016-07-13 13:11:08 +0200761 { size_t const readSize = fread(origBuff, 1, benchedSize, inFile);
762 fclose(inFile);
763 if(readSize != benchedSize) {
764 DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
765 free(origBuff);
766 return 13;
767 } }
Yann Collet09116c22015-11-27 17:46:14 +0100768
769 /* bench */
770 DISPLAY("\r%79s\r", "");
Yann Collet696c4d72016-07-13 13:11:08 +0200771 DISPLAY("optimizing for %s - limit speed %u MB/s \n", inFileName, targetSpeed);
Yann Collet2724f252017-04-04 16:31:17 -0700772 targetSpeed *= 1000000;
Yann Collet09116c22015-11-27 17:46:14 +0100773
Yann Collet696c4d72016-07-13 13:11:08 +0200774 { ZSTD_CCtx* const ctx = ZSTD_createCCtx();
Yann Collet09116c22015-11-27 17:46:14 +0100775 winnerInfo_t winner;
776 BMK_result_t candidate;
Yann Collet7fe531e2015-11-29 02:38:09 +0100777 const size_t blockSize = g_blockSize ? g_blockSize : benchedSize;
Yann Collet09116c22015-11-27 17:46:14 +0100778
779 /* init */
Yann Collet696c4d72016-07-13 13:11:08 +0200780 if (ctx==NULL) { DISPLAY("\n ZSTD_createCCtx error \n"); free(origBuff); return 14;}
Yann Collet09116c22015-11-27 17:46:14 +0100781 memset(&winner, 0, sizeof(winner));
782 winner.result.cSize = (size_t)(-1);
783
784 /* find best solution from default params */
Yann Colleta43a8542016-07-12 13:42:10 +0200785 { const int maxSeeds = g_noSeed ? 1 : ZSTD_maxCLevel();
Yann Collet696c4d72016-07-13 13:11:08 +0200786 int i;
Yann Collet70e8c382016-02-10 13:37:52 +0100787 for (i=1; i<=maxSeeds; i++) {
Yann Collet2724f252017-04-04 16:31:17 -0700788 ZSTD_compressionParameters const CParams = ZSTD_getCParams(i, blockSize, 0);
789 BMK_benchParam(&candidate, origBuff, benchedSize, ctx, CParams);
Yann Collet696c4d72016-07-13 13:11:08 +0200790 if (candidate.cSpeed < targetSpeed)
791 break;
Yann Collet09116c22015-11-27 17:46:14 +0100792 if ( (candidate.cSize < winner.result.cSize)
Yann Collet696c4d72016-07-13 13:11:08 +0200793 | ((candidate.cSize == winner.result.cSize) & (candidate.cSpeed > winner.result.cSpeed)) )
Yann Collet09116c22015-11-27 17:46:14 +0100794 {
Yann Collet2724f252017-04-04 16:31:17 -0700795 winner.params = CParams;
Yann Collet09116c22015-11-27 17:46:14 +0100796 winner.result = candidate;
Yann Collet7fe531e2015-11-29 02:38:09 +0100797 BMK_printWinner(stdout, i, winner.result, winner.params, benchedSize);
Yann Collet70e8c382016-02-10 13:37:52 +0100798 } }
Yann Collet09116c22015-11-27 17:46:14 +0100799 }
Yann Collet7fe531e2015-11-29 02:38:09 +0100800 BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
Yann Collet9631e602017-04-04 16:54:33 -0700801 BMK_translateAdvancedParams(winner.params);
Yann Collet09116c22015-11-27 17:46:14 +0100802
803 /* start tests */
Yann Collet158e7702016-07-13 16:45:24 +0200804 { time_t const grillStart = time(NULL);
Yann Collet70e8c382016-02-10 13:37:52 +0100805 do {
Yann Collet2724f252017-04-04 16:31:17 -0700806 ZSTD_compressionParameters params = winner.params;
Yann Collet09116c22015-11-27 17:46:14 +0100807 paramVariation(&params);
Yann Collet2724f252017-04-04 16:31:17 -0700808 if ((FUZ_rand(&g_rand) & 31) == 3) params = randomParams(); /* totally random config to improve search space */
Yann Collet89b32f32017-04-04 16:41:11 -0700809 params = ZSTD_adjustCParams(params, blockSize, 0);
Yann Collet09116c22015-11-27 17:46:14 +0100810
811 /* exclude faster if already played set of params */
812 if (FUZ_rand(&g_rand) & ((1 << NB_TESTS_PLAYED(params))-1)) continue;
813
814 /* test */
815 NB_TESTS_PLAYED(params)++;
Yann Collet7fe531e2015-11-29 02:38:09 +0100816 BMK_benchParam(&candidate, origBuff, benchedSize, ctx, params);
Yann Collet09116c22015-11-27 17:46:14 +0100817
818 /* improvement found => new winner */
Yann Collet696c4d72016-07-13 13:11:08 +0200819 if ( (candidate.cSpeed > targetSpeed)
820 & ( (candidate.cSize < winner.result.cSize)
821 | ((candidate.cSize == winner.result.cSize) & (candidate.cSpeed > winner.result.cSpeed)) ) )
822 {
Yann Collet09116c22015-11-27 17:46:14 +0100823 winner.params = params;
824 winner.result = candidate;
Yann Collet7fe531e2015-11-29 02:38:09 +0100825 BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
Yann Collet9631e602017-04-04 16:54:33 -0700826 BMK_translateAdvancedParams(winner.params);
Yann Collet09116c22015-11-27 17:46:14 +0100827 }
Yann Collet158e7702016-07-13 16:45:24 +0200828 } while (BMK_timeSpan(grillStart) < g_grillDuration_s);
Yann Collet09116c22015-11-27 17:46:14 +0100829 }
830
831 /* end summary */
Yann Collet7fe531e2015-11-29 02:38:09 +0100832 BMK_printWinner(stdout, 99, winner.result, winner.params, benchedSize);
Yann Collet09116c22015-11-27 17:46:14 +0100833 DISPLAY("grillParams size - optimizer completed \n");
834
835 /* clean up*/
836 ZSTD_freeCCtx(ctx);
837 }
838
Yann Collet696c4d72016-07-13 13:11:08 +0200839 free(origBuff);
Yann Collet09116c22015-11-27 17:46:14 +0100840 return 0;
841}
842
843
Yann Colleta43a8542016-07-12 13:42:10 +0200844static int usage(const char* exename)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100845{
846 DISPLAY( "Usage :\n");
847 DISPLAY( " %s [arg] file\n", exename);
848 DISPLAY( "Arguments :\n");
Yann Colletb5d2a0c2015-11-23 17:10:19 +0100849 DISPLAY( " file : path to the file used as reference (if none, generates a compressible sample)\n");
Yann Colletfd9d6b82015-10-26 00:06:36 +0100850 DISPLAY( " -H/-h : Help (this text + advanced options)\n");
851 return 0;
852}
853
Yann Collet04b12d82016-02-11 06:23:24 +0100854static int usage_advanced(void)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100855{
856 DISPLAY( "\nAdvanced options :\n");
Yann Colleta43a8542016-07-12 13:42:10 +0200857 DISPLAY( " -T# : set level 1 speed objective \n");
858 DISPLAY( " -B# : cut input into blocks of size # (default : single block) \n");
859 DISPLAY( " -i# : iteration loops [1-9](default : %i) \n", NBLOOPS);
Yann Collet2724f252017-04-04 16:31:17 -0700860 DISPLAY( " -O# : find Optimized parameters for # MB/s compression speed (default : 0) \n");
Yann Colleta43a8542016-07-12 13:42:10 +0200861 DISPLAY( " -S : Single run \n");
862 DISPLAY( " -P# : generated sample compressibility (default : %.1f%%) \n", COMPRESSIBILITY_DEFAULT * 100);
Yann Colletfd9d6b82015-10-26 00:06:36 +0100863 return 0;
864}
865
Yann Colleta43a8542016-07-12 13:42:10 +0200866static int badusage(const char* exename)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100867{
868 DISPLAY("Wrong parameters\n");
869 usage(exename);
Yann Collet8b91abe2015-10-27 02:59:12 +0100870 return 1;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100871}
872
Yann Colleta43a8542016-07-12 13:42:10 +0200873int main(int argc, const char** argv)
Yann Colletfd9d6b82015-10-26 00:06:36 +0100874{
875 int i,
876 filenamesStart=0,
877 result;
Yann Colleta43a8542016-07-12 13:42:10 +0200878 const char* exename=argv[0];
879 const char* input_filename=0;
Yann Collet09116c22015-11-27 17:46:14 +0100880 U32 optimizer = 0;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100881 U32 main_pause = 0;
Yann Collet696c4d72016-07-13 13:11:08 +0200882 U32 targetSpeed = 0;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100883
Yann Collet70e8c382016-02-10 13:37:52 +0100884 /* checks */
885 if (NB_LEVELS_TRACKED <= ZSTD_maxCLevel()) {
886 DISPLAY("Error : NB_LEVELS_TRACKED <= ZSTD_maxCLevel() \n");
887 exit(1);
888 }
889
Yann Colletfd9d6b82015-10-26 00:06:36 +0100890 /* Welcome message */
891 DISPLAY(WELCOME_MESSAGE);
892
893 if (argc<1) { badusage(exename); return 1; }
894
Yann Collet0dbf2872016-04-08 02:02:12 +0200895 for(i=1; i<argc; i++) {
Yann Colleta43a8542016-07-12 13:42:10 +0200896 const char* argument = argv[i];
Yann Colletfd9d6b82015-10-26 00:06:36 +0100897
Yann Colletb315bc82015-10-27 13:12:25 +0100898 if(!argument) continue; /* Protection if argument empty */
899
900 if(!strcmp(argument,"--no-seed")) { g_noSeed = 1; continue; }
Yann Colletfd9d6b82015-10-26 00:06:36 +0100901
Yann Collet786f5b52015-10-26 15:45:58 +0100902 /* Decode command (note : aggregated commands are allowed) */
Yann Collet70e8c382016-02-10 13:37:52 +0100903 if (argument[0]=='-') {
Yann Collet8b91abe2015-10-27 02:59:12 +0100904 argument++;
905
Yann Collet70e8c382016-02-10 13:37:52 +0100906 while (argument[0]!=0) {
Yann Colletfd9d6b82015-10-26 00:06:36 +0100907
908 switch(argument[0])
909 {
910 /* Display help on usage */
911 case 'h' :
912 case 'H': usage(exename); usage_advanced(); return 0;
913
914 /* Pause at the end (hidden option) */
Yann Collet8b91abe2015-10-27 02:59:12 +0100915 case 'p': main_pause = 1; argument++; break;
Yann Colletfd9d6b82015-10-26 00:06:36 +0100916
917 /* Modify Nb Iterations */
918 case 'i':
Yann Collet8b91abe2015-10-27 02:59:12 +0100919 argument++;
Yann Collet696c4d72016-07-13 13:11:08 +0200920 if ((argument[0] >='0') & (argument[0] <='9'))
Yann Collet4b100f42015-10-30 15:49:48 +0100921 g_nbIterations = *argument++ - '0';
Yann Colletfd9d6b82015-10-26 00:06:36 +0100922 break;
923
924 /* Sample compressibility (when no file provided) */
925 case 'P':
Yann Collet8b91abe2015-10-27 02:59:12 +0100926 argument++;
Yann Collet0dbf2872016-04-08 02:02:12 +0200927 { U32 proba32 = 0;
Yann Collet696c4d72016-07-13 13:11:08 +0200928 while ((argument[0]>= '0') & (argument[0]<= '9'))
Yann Collet0dbf2872016-04-08 02:02:12 +0200929 proba32 = (proba32*10) + (*argument++ - '0');
Yann Colletfd9d6b82015-10-26 00:06:36 +0100930 g_compressibility = (double)proba32 / 100.;
931 }
932 break;
933
Yann Collet09116c22015-11-27 17:46:14 +0100934 case 'O':
935 argument++;
936 optimizer=1;
Yann Collet696c4d72016-07-13 13:11:08 +0200937 targetSpeed = 0;
938 while ((*argument >= '0') & (*argument <= '9'))
939 targetSpeed = (targetSpeed*10) + (*argument++ - '0');
Yann Collet09116c22015-11-27 17:46:14 +0100940 break;
941
Yann Collet8b91abe2015-10-27 02:59:12 +0100942 /* Run Single conf */
943 case 'S':
Yann Collet4b100f42015-10-30 15:49:48 +0100944 g_singleRun = 1;
945 argument++;
Yann Collet51d50042016-03-30 20:42:19 +0200946 g_params = ZSTD_getCParams(2, g_blockSize, 0);
Yann Collet70e8c382016-02-10 13:37:52 +0100947 for ( ; ; ) {
Yann Collet4b100f42015-10-30 15:49:48 +0100948 switch(*argument)
949 {
950 case 'w':
951 g_params.windowLog = 0;
952 argument++;
953 while ((*argument>= '0') && (*argument<='9'))
954 g_params.windowLog *= 10, g_params.windowLog += *argument++ - '0';
955 continue;
956 case 'c':
Yann Collet8a57b922016-04-04 13:49:18 +0200957 g_params.chainLog = 0;
Yann Collet4b100f42015-10-30 15:49:48 +0100958 argument++;
959 while ((*argument>= '0') && (*argument<='9'))
Yann Collet8a57b922016-04-04 13:49:18 +0200960 g_params.chainLog *= 10, g_params.chainLog += *argument++ - '0';
Yann Collet4b100f42015-10-30 15:49:48 +0100961 continue;
962 case 'h':
963 g_params.hashLog = 0;
964 argument++;
965 while ((*argument>= '0') && (*argument<='9'))
966 g_params.hashLog *= 10, g_params.hashLog += *argument++ - '0';
967 continue;
968 case 's':
969 g_params.searchLog = 0;
970 argument++;
971 while ((*argument>= '0') && (*argument<='9'))
972 g_params.searchLog *= 10, g_params.searchLog += *argument++ - '0';
973 continue;
Yann Collet9b11b462015-11-01 12:40:22 +0100974 case 'l': /* search length */
Yann Collet4b100f42015-10-30 15:49:48 +0100975 g_params.searchLength = 0;
976 argument++;
977 while ((*argument>= '0') && (*argument<='9'))
978 g_params.searchLength *= 10, g_params.searchLength += *argument++ - '0';
979 continue;
Yann Collet04b12d82016-02-11 06:23:24 +0100980 case 't': /* target length */
981 g_params.targetLength = 0;
Yann Collet9b11b462015-11-01 12:40:22 +0100982 argument++;
Yann Collet04b12d82016-02-11 06:23:24 +0100983 while ((*argument>= '0') && (*argument<='9'))
984 g_params.targetLength *= 10, g_params.targetLength += *argument++ - '0';
985 continue;
986 case 'S': /* strategy */
987 argument++;
988 while ((*argument>= '0') && (*argument<='9'))
989 g_params.strategy = (ZSTD_strategy)(*argument++ - '0');
Yann Collet9b11b462015-11-01 12:40:22 +0100990 continue;
Yann Collet4b100f42015-10-30 15:49:48 +0100991 case 'L':
Yann Collet0dbf2872016-04-08 02:02:12 +0200992 { int cLevel = 0;
Yann Collet4b100f42015-10-30 15:49:48 +0100993 argument++;
994 while ((*argument>= '0') && (*argument<='9'))
995 cLevel *= 10, cLevel += *argument++ - '0';
Yann Collet51d50042016-03-30 20:42:19 +0200996 g_params = ZSTD_getCParams(cLevel, g_blockSize, 0);
Yann Collet4b100f42015-10-30 15:49:48 +0100997 continue;
998 }
999 default : ;
1000 }
Yann Collet8b91abe2015-10-27 02:59:12 +01001001 break;
1002 }
Yann Collet4b100f42015-10-30 15:49:48 +01001003 break;
Yann Collet8b91abe2015-10-27 02:59:12 +01001004
Yann Colletf12c1302015-11-05 18:16:59 +01001005 /* target level1 speed objective, in MB/s */
Yann Collet2c6992e2015-10-27 12:18:00 +01001006 case 'T':
1007 argument++;
1008 g_target = 0;
Yann Collet0dbf2872016-04-08 02:02:12 +02001009 while ((*argument >= '0') && (*argument <= '9'))
1010 g_target = (g_target*10) + (*argument++ - '0');
Yann Collet2c6992e2015-10-27 12:18:00 +01001011 break;
1012
1013 /* cut input into blocks */
1014 case 'B':
Yann Collet0dbf2872016-04-08 02:02:12 +02001015 g_blockSize = 0;
1016 argument++;
Yann Collet696c4d72016-07-13 13:11:08 +02001017 while ((*argument >='0') & (*argument <='9'))
Yann Collet0dbf2872016-04-08 02:02:12 +02001018 g_blockSize = (g_blockSize*10) + (*argument++ - '0');
1019 if (*argument=='K') g_blockSize<<=10, argument++; /* allows using KB notation */
1020 if (*argument=='M') g_blockSize<<=20, argument++;
1021 if (*argument=='B') argument++;
1022 DISPLAY("using %u KB block size \n", g_blockSize>>10);
Yann Collet2c6992e2015-10-27 12:18:00 +01001023 break;
1024
Yann Colletfd9d6b82015-10-26 00:06:36 +01001025 /* Unknown command */
Yann Collet8b91abe2015-10-27 02:59:12 +01001026 default : return badusage(exename);
Yann Colletfd9d6b82015-10-26 00:06:36 +01001027 }
1028 }
1029 continue;
Yann Collet0dbf2872016-04-08 02:02:12 +02001030 } /* if (argument[0]=='-') */
Yann Colletfd9d6b82015-10-26 00:06:36 +01001031
1032 /* first provided filename is input */
1033 if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
1034 }
1035
Yann Colletfd9d6b82015-10-26 00:06:36 +01001036 if (filenamesStart==0)
1037 result = benchSample();
Yann Collet70e8c382016-02-10 13:37:52 +01001038 else {
Yann Collet00fd7a22015-11-28 16:03:22 +01001039 if (optimizer)
Yann Collet696c4d72016-07-13 13:11:08 +02001040 result = optimizeForSize(input_filename, targetSpeed);
Yann Collet00fd7a22015-11-28 16:03:22 +01001041 else
1042 result = benchFiles(argv+filenamesStart, argc-filenamesStart);
1043 }
Yann Colletfd9d6b82015-10-26 00:06:36 +01001044
1045 if (main_pause) { int unused; printf("press enter...\n"); unused = getchar(); (void)unused; }
1046
1047 return result;
1048}