blob: e61205a74dc7a3851261ede1146c2814358e46cd [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 Colletdb4c0122014-08-30 18:14:44 +0100190
191 (void)nbCycles; (void)startCycle;
192 // Create compressible test buffer
193 CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
194 FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
195 compressedBuffer = malloc(LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL));
196 decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
197
Yann Collet23effdb2014-08-31 23:14:20 +0100198 // Trivial tests : one-step frame
199 testSize = COMPRESSIBLE_NOISE_LENGTH;
200 DISPLAY("Using NULL preferences : \n");
201 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
Yann Colletdb4c0122014-08-30 18:14:44 +0100202 if (LZ4F_isError(cSize)) goto _output_error;
Yann Collet23effdb2014-08-31 23:14:20 +0100203 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
204
205 DISPLAY("Using 64 KB block : \n");
206 prefs.frameInfo.blockSizeID = max64KB;
207 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
208 if (LZ4F_isError(cSize)) goto _output_error;
209 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
210
211 DISPLAY("without checksum : \n");
212 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
213 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
214 if (LZ4F_isError(cSize)) goto _output_error;
215 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
216
217 DISPLAY("Using 256 KB block : \n");
218 prefs.frameInfo.blockSizeID = max256KB;
219 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
220 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
221 if (LZ4F_isError(cSize)) goto _output_error;
222 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
223
224 DISPLAY("without checksum : \n");
225 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
226 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
227 if (LZ4F_isError(cSize)) goto _output_error;
228 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
229
230 DISPLAY("Using 1 MB block : \n");
231 prefs.frameInfo.blockSizeID = max1MB;
232 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
233 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
234 if (LZ4F_isError(cSize)) goto _output_error;
235 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
236
237 DISPLAY("without checksum : \n");
238 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
239 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
240 if (LZ4F_isError(cSize)) goto _output_error;
241 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
242
243 DISPLAY("Using 4 MB block : \n");
244 prefs.frameInfo.blockSizeID = max4MB;
245 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
246 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
247 if (LZ4F_isError(cSize)) goto _output_error;
248 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
249
250 DISPLAY("without checksum : \n");
251 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
252 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &(prefs.frameInfo)), CNBuffer, testSize, &prefs);
253 if (LZ4F_isError(cSize)) goto _output_error;
254 DISPLAY("Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
255
Yann Colletdb4c0122014-08-30 18:14:44 +0100256
257_end:
258 free(CNBuffer);
259 free(compressedBuffer);
260 free(decodedBuffer);
261 return testResult;
262
263_output_error:
264 testResult = 1;
265 if(!no_prompt) getchar();
266 goto _end;
267}
268
269
270int FUZ_usage(void)
271{
272 DISPLAY( "Usage :\n");
273 DISPLAY( " %s [args]\n", programName);
274 DISPLAY( "\n");
275 DISPLAY( "Arguments :\n");
276 DISPLAY( " -i# : Nb of tests (default:%i) \n", NB_ATTEMPTS);
277 DISPLAY( " -s# : Select seed (default:prompt user)\n");
278 DISPLAY( " -t# : Select starting test number (default:0)\n");
279 DISPLAY( " -p# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
280 DISPLAY( " -v : verbose\n");
281 DISPLAY( " -h : display help and exit\n");
282 return 0;
283}
284
285
Yann Colletfc8e3f52014-09-01 22:44:02 +0100286int main(int argc, char** argv)
287{
Yann Colletdb4c0122014-08-30 18:14:44 +0100288 U32 seed=0;
289 int seedset=0;
290 int argNb;
291 int nbTests = NB_ATTEMPTS;
292 int testNb = 0;
293 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
294
295 // Check command line
296 programName = argv[0];
297 for(argNb=1; argNb<argc; argNb++)
298 {
299 char* argument = argv[argNb];
300
301 if(!argument) continue; // Protection if argument empty
302
303 // Decode command (note : aggregated commands are allowed)
304 if (argument[0]=='-')
305 {
306 if (!strcmp(argument, "--no-prompt")) { no_prompt=1; seedset=1; displayLevel=1; continue; }
307
308 while (argument[1]!=0)
309 {
310 argument++;
311 switch(*argument)
312 {
313 case 'h':
314 return FUZ_usage();
315 case 'v':
316 argument++;
317 displayLevel=4;
318 break;
319 case 'i':
320 argument++;
321 nbTests=0;
322 while ((*argument>='0') && (*argument<='9'))
323 {
324 nbTests *= 10;
325 nbTests += *argument - '0';
326 argument++;
327 }
328 break;
329 case 's':
330 argument++;
331 seed=0; seedset=1;
332 while ((*argument>='0') && (*argument<='9'))
333 {
334 seed *= 10;
335 seed += *argument - '0';
336 argument++;
337 }
338 break;
339 case 't':
340 argument++;
341 testNb=0;
342 while ((*argument>='0') && (*argument<='9'))
343 {
344 testNb *= 10;
345 testNb += *argument - '0';
346 argument++;
347 }
348 break;
349 case 'p':
350 argument++;
351 proba=0;
352 while ((*argument>='0') && (*argument<='9'))
353 {
354 proba *= 10;
355 proba += *argument - '0';
356 argument++;
357 }
358 if (proba<0) proba=0;
359 if (proba>100) proba=100;
360 break;
361 default: ;
362 }
363 }
364 }
365 }
366
367 // Get Seed
368 printf("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION);
369
Yann Colletfc8e3f52014-09-01 22:44:02 +0100370 if (!seedset) seed = FUZ_GetMilliStart() % 10000;
Yann Colletdb4c0122014-08-30 18:14:44 +0100371 printf("Seed = %u\n", seed);
372 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
373
374 if (nbTests<=0) nbTests=1;
375
376 return frameTest(seed, nbTests, testNb, ((double)proba) / 100);
377}