blob: 2b5219082efb0d31061a716e960290cdd12b4501 [file] [log] [blame]
Yann Colletdb4c0122014-08-30 18:14:44 +01001/*
2 frameTest - test tool for lz4frame
3 Copyright (C) Yann Collet 2014
4 GPL v2 License
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 You can contact the author at :
21 - LZ4 source repository : http://code.google.com/p/lz4/
22 - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
23*/
24
25/**************************************
26 Compiler specific
27**************************************/
28#define _CRT_SECURE_NO_WARNINGS // fgets
29#ifdef _MSC_VER /* Visual Studio */
30# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
31# pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
32#endif
Yann Collet23effdb2014-08-31 23:14:20 +010033#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
34#ifdef __GNUC__
35# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
36# pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
37#endif
Yann Colletdb4c0122014-08-30 18:14:44 +010038
39
40/**************************************
41 Includes
42**************************************/
43#include <stdlib.h>
44#include <stdio.h> // fgets, sscanf
45#include <sys/timeb.h> // timeb
46#include <string.h> // strcmp
47#include "lz4frame.h"
48
49
50/**************************************
51 Basic Types
52**************************************/
53#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
54# include <stdint.h>
55 typedef uint8_t BYTE;
56 typedef uint16_t U16;
57 typedef uint32_t U32;
58 typedef int32_t S32;
59 typedef uint64_t U64;
60#else
61 typedef unsigned char BYTE;
62 typedef unsigned short U16;
63 typedef unsigned int U32;
64 typedef signed int S32;
65 typedef unsigned long long U64;
66#endif
67
68
69/**************************************
70 Constants
71**************************************/
72#ifndef LZ4_VERSION
73# define LZ4_VERSION ""
74#endif
75
Yann Colletfc8e3f52014-09-01 22:44:02 +010076#define KB *(1U<<10)
77#define MB *(1U<<20)
78#define GB *(1U<<30)
79
80#define NB_ATTEMPTS (64 KB)
81#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
82#define FUZ_MAX_BLOCK_SIZE (128 KB)
83#define FUZ_MAX_DICT_SIZE (32 KB)
Yann Colletdb4c0122014-08-30 18:14:44 +010084#define FUZ_COMPRESSIBILITY_DEFAULT 50
85#define PRIME1 2654435761U
86#define PRIME2 2246822519U
87#define PRIME3 3266489917U
88
Yann Colletdb4c0122014-08-30 18:14:44 +010089
90
91/**************************************
92 Macros
93**************************************/
94#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
95#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
96
97
98/*****************************************
99 Local Parameters
100*****************************************/
101static int no_prompt = 0;
102static char* programName;
103static int displayLevel = 2;
104
105
106/*********************************************************
107 Fuzzer functions
108*********************************************************/
109static int FUZ_GetMilliStart(void)
110{
111 struct timeb tb;
112 int nCount;
113 ftime( &tb );
114 nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
115 return nCount;
116}
117
Yann Colletfc8e3f52014-09-01 22:44:02 +0100118/*
Yann Colletdb4c0122014-08-30 18:14:44 +0100119static int FUZ_GetMilliSpan( int nTimeStart )
120{
121 int nSpan = FUZ_GetMilliStart() - nTimeStart;
122 if ( nSpan < 0 )
123 nSpan += 0x100000 * 1000;
124 return nSpan;
125}
Yann Colletfc8e3f52014-09-01 22:44:02 +0100126*/
Yann Colletdb4c0122014-08-30 18:14:44 +0100127
128
129# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
130unsigned int FUZ_rand(unsigned int* src)
131{
132 U32 rand32 = *src;
133 rand32 *= PRIME1;
134 rand32 += PRIME2;
135 rand32 = FUZ_rotl32(rand32, 13);
136 *src = rand32;
137 return rand32 >> 3;
138}
139
140
141#define FUZ_RAND15BITS ((FUZ_rand(seed) >> 3) & 32767)
Yann Collet23effdb2014-08-31 23:14:20 +0100142#define FUZ_RANDLENGTH ( ((FUZ_rand(seed) >> 7) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
143static void FUZ_fillCompressibleNoiseBuffer(void* buffer, unsigned bufferSize, double proba, U32* seed)
Yann Colletdb4c0122014-08-30 18:14:44 +0100144{
145 BYTE* BBuffer = (BYTE*)buffer;
Yann Collet23effdb2014-08-31 23:14:20 +0100146 unsigned pos = 0;
Yann Colletdb4c0122014-08-30 18:14:44 +0100147 U32 P32 = (U32)(32768 * proba);
148
149 // First Byte
150 BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
151
152 while (pos < bufferSize)
153 {
154 // Select : Literal (noise) or copy (within 64K)
155 if (FUZ_RAND15BITS < P32)
156 {
157 // Copy (within 64K)
Yann Collet23effdb2014-08-31 23:14:20 +0100158 unsigned match, end;
159 unsigned length = FUZ_RANDLENGTH + 4;
160 unsigned offset = FUZ_RAND15BITS + 1;
Yann Colletdb4c0122014-08-30 18:14:44 +0100161 if (offset > pos) offset = pos;
162 if (pos + length > bufferSize) length = bufferSize - pos;
Yann Collet23effdb2014-08-31 23:14:20 +0100163 match = pos - offset;
164 end = pos + length;
165 while (pos < end) BBuffer[pos++] = BBuffer[match++];
Yann Colletdb4c0122014-08-30 18:14:44 +0100166 }
167 else
168 {
169 // Literal (noise)
Yann Collet23effdb2014-08-31 23:14:20 +0100170 unsigned end;
171 unsigned length = FUZ_RANDLENGTH;
Yann Colletdb4c0122014-08-30 18:14:44 +0100172 if (pos + length > bufferSize) length = bufferSize - pos;
Yann Collet23effdb2014-08-31 23:14:20 +0100173 end = pos + length;
174 while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
Yann Colletdb4c0122014-08-30 18:14:44 +0100175 }
176 }
177}
178
179
180
Yann Colletdb4c0122014-08-30 18:14:44 +0100181int frameTest(U32 seed, int nbCycles, int startCycle, double compressibility)
182{
183 int testResult = 0;
184 void* CNBuffer;
185 void* compressedBuffer;
186 void* decodedBuffer;
187 U32 randState = seed;
Yann Collet23effdb2014-08-31 23:14:20 +0100188 size_t cSize, testSize;
189 LZ4F_preferences_t prefs = { 0 };
Yann Collet0ac00ee2014-09-03 19:49:59 +0100190 LZ4F_decompressionContext_t dCtx;
Yann Colletdb4c0122014-08-30 18:14:44 +0100191
192 (void)nbCycles; (void)startCycle;
193 // Create compressible test buffer
194 CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
195 FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
196 compressedBuffer = malloc(LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL));
197 decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
198
Yann Collet23effdb2014-08-31 23:14:20 +0100199 // Trivial tests : one-step frame
200 testSize = COMPRESSIBLE_NOISE_LENGTH;
201 DISPLAY("Using NULL preferences : \n");
202 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
Yann Colletdb4c0122014-08-30 18:14:44 +0100203 if (LZ4F_isError(cSize)) goto _output_error;
Yann Collet23effdb2014-08-31 23:14:20 +0100204 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
205
Yann Collet0ac00ee2014-09-03 19:49:59 +0100206 DISPLAY("Decompression test : \n");
207 {
208 LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx);
209 size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
210 size_t compressedBufferSize = cSize;
211 if (LZ4F_isError(errorCode)) goto _output_error;
212 errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL);
213 if (LZ4F_isError(errorCode)) goto _output_error;
214 DISPLAY("Regenerated %i bytes \n", (int)decodedBufferSize);
215 errorCode = LZ4F_freeDecompressionContext(dCtx);
216 if (LZ4F_isError(errorCode)) goto _output_error;
217 }
218
Yann Collet23effdb2014-08-31 23:14:20 +0100219 DISPLAY("Using 64 KB block : \n");
220 prefs.frameInfo.blockSizeID = max64KB;
221 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
222 if (LZ4F_isError(cSize)) goto _output_error;
223 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
224
225 DISPLAY("without checksum : \n");
226 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
227 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
228 if (LZ4F_isError(cSize)) goto _output_error;
229 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
230
231 DISPLAY("Using 256 KB block : \n");
232 prefs.frameInfo.blockSizeID = max256KB;
233 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
234 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
235 if (LZ4F_isError(cSize)) goto _output_error;
236 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
237
238 DISPLAY("without checksum : \n");
239 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
240 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
241 if (LZ4F_isError(cSize)) goto _output_error;
242 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
243
244 DISPLAY("Using 1 MB block : \n");
245 prefs.frameInfo.blockSizeID = max1MB;
246 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
247 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
248 if (LZ4F_isError(cSize)) goto _output_error;
249 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
250
251 DISPLAY("without checksum : \n");
252 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
253 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
254 if (LZ4F_isError(cSize)) goto _output_error;
255 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
256
257 DISPLAY("Using 4 MB block : \n");
258 prefs.frameInfo.blockSizeID = max4MB;
259 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
260 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
261 if (LZ4F_isError(cSize)) goto _output_error;
262 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
263
264 DISPLAY("without checksum : \n");
265 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
266 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
267 if (LZ4F_isError(cSize)) goto _output_error;
268 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
269
Yann Colletdb4c0122014-08-30 18:14:44 +0100270
271_end:
272 free(CNBuffer);
273 free(compressedBuffer);
274 free(decodedBuffer);
275 return testResult;
276
277_output_error:
278 testResult = 1;
Yann Collet0ac00ee2014-09-03 19:49:59 +0100279 DISPLAY("Error detected ! \n");
Yann Colletdb4c0122014-08-30 18:14:44 +0100280 if(!no_prompt) getchar();
281 goto _end;
282}
283
284
285int FUZ_usage(void)
286{
287 DISPLAY( "Usage :\n");
288 DISPLAY( " %s [args]\n", programName);
289 DISPLAY( "\n");
290 DISPLAY( "Arguments :\n");
291 DISPLAY( " -i# : Nb of tests (default:%i) \n", NB_ATTEMPTS);
292 DISPLAY( " -s# : Select seed (default:prompt user)\n");
293 DISPLAY( " -t# : Select starting test number (default:0)\n");
294 DISPLAY( " -p# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
295 DISPLAY( " -v : verbose\n");
296 DISPLAY( " -h : display help and exit\n");
297 return 0;
298}
299
300
Yann Colletfc8e3f52014-09-01 22:44:02 +0100301int main(int argc, char** argv)
302{
Yann Colletdb4c0122014-08-30 18:14:44 +0100303 U32 seed=0;
304 int seedset=0;
305 int argNb;
306 int nbTests = NB_ATTEMPTS;
307 int testNb = 0;
308 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
309
310 // Check command line
311 programName = argv[0];
312 for(argNb=1; argNb<argc; argNb++)
313 {
314 char* argument = argv[argNb];
315
316 if(!argument) continue; // Protection if argument empty
317
318 // Decode command (note : aggregated commands are allowed)
319 if (argument[0]=='-')
320 {
321 if (!strcmp(argument, "--no-prompt")) { no_prompt=1; seedset=1; displayLevel=1; continue; }
322
323 while (argument[1]!=0)
324 {
325 argument++;
326 switch(*argument)
327 {
328 case 'h':
329 return FUZ_usage();
330 case 'v':
331 argument++;
332 displayLevel=4;
333 break;
334 case 'i':
335 argument++;
336 nbTests=0;
337 while ((*argument>='0') && (*argument<='9'))
338 {
339 nbTests *= 10;
340 nbTests += *argument - '0';
341 argument++;
342 }
343 break;
344 case 's':
345 argument++;
346 seed=0; seedset=1;
347 while ((*argument>='0') && (*argument<='9'))
348 {
349 seed *= 10;
350 seed += *argument - '0';
351 argument++;
352 }
353 break;
354 case 't':
355 argument++;
356 testNb=0;
357 while ((*argument>='0') && (*argument<='9'))
358 {
359 testNb *= 10;
360 testNb += *argument - '0';
361 argument++;
362 }
363 break;
364 case 'p':
365 argument++;
366 proba=0;
367 while ((*argument>='0') && (*argument<='9'))
368 {
369 proba *= 10;
370 proba += *argument - '0';
371 argument++;
372 }
373 if (proba<0) proba=0;
374 if (proba>100) proba=100;
375 break;
376 default: ;
377 }
378 }
379 }
380 }
381
382 // Get Seed
383 printf("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION);
384
Yann Colletfc8e3f52014-09-01 22:44:02 +0100385 if (!seedset) seed = FUZ_GetMilliStart() % 10000;
Yann Colletdb4c0122014-08-30 18:14:44 +0100386 printf("Seed = %u\n", seed);
387 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
388
389 if (nbTests<=0) nbTests=1;
390
391 return frameTest(seed, nbTests, testNb, ((double)proba) / 100);
392}