blob: 3d19ef4e07de1222c914825049bbe4963eca4b22 [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"
Yann Collet1ffc02e2014-09-05 16:32:04 +010048#include "xxhash.h" // XXH64
Yann Colletdb4c0122014-08-30 18:14:44 +010049
50
51/**************************************
52 Basic Types
53**************************************/
54#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
55# include <stdint.h>
Yann Colletdc5fb732014-09-22 18:42:00 +010056typedef uint8_t BYTE;
57typedef uint16_t U16;
58typedef uint32_t U32;
59typedef int32_t S32;
60typedef uint64_t U64;
Yann Colletdb4c0122014-08-30 18:14:44 +010061#else
Yann Colletdc5fb732014-09-22 18:42:00 +010062typedef unsigned char BYTE;
63typedef unsigned short U16;
64typedef unsigned int U32;
65typedef signed int S32;
66typedef unsigned long long U64;
Yann Colletdb4c0122014-08-30 18:14:44 +010067#endif
68
69
70/**************************************
71 Constants
72**************************************/
73#ifndef LZ4_VERSION
74# define LZ4_VERSION ""
75#endif
76
Yann Colletfc8e3f52014-09-01 22:44:02 +010077#define KB *(1U<<10)
78#define MB *(1U<<20)
79#define GB *(1U<<30)
80
Yann Collet837551f2014-09-07 09:13:02 +010081static const U32 nbTestsDefault = 128 KB;
Yann Colletfc8e3f52014-09-01 22:44:02 +010082#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
Yann Colletdb4c0122014-08-30 18:14:44 +010083#define FUZ_COMPRESSIBILITY_DEFAULT 50
Yann Collet837551f2014-09-07 09:13:02 +010084static const U32 prime1 = 2654435761U;
85static const U32 prime2 = 2246822519U;
Yann Colletdb4c0122014-08-30 18:14:44 +010086
Yann Colletdb4c0122014-08-30 18:14:44 +010087
88
89/**************************************
90 Macros
91**************************************/
Yann Collet1ffc02e2014-09-05 16:32:04 +010092#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
93#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
Yann Colletda1b0c12014-09-06 13:06:28 +010094#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
95 if ((FUZ_GetMilliSpan(g_time) > refreshRate) || (displayLevel>=4)) \
96 { g_time = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \
97 if (displayLevel>=4) fflush(stdout); } }
98static const U32 refreshRate = 150;
99static U32 g_time = 0;
Yann Colletdb4c0122014-08-30 18:14:44 +0100100
101
102/*****************************************
103 Local Parameters
104*****************************************/
Yann Colletda1b0c12014-09-06 13:06:28 +0100105static U32 no_prompt = 0;
Yann Colletdb4c0122014-08-30 18:14:44 +0100106static char* programName;
Yann Colletda1b0c12014-09-06 13:06:28 +0100107static U32 displayLevel = 2;
Yann Collet6330f772014-09-21 09:56:21 +0100108static U32 pause = 0;
Yann Colletdb4c0122014-08-30 18:14:44 +0100109
110
111/*********************************************************
112 Fuzzer functions
113*********************************************************/
Yann Colletda1b0c12014-09-06 13:06:28 +0100114static U32 FUZ_GetMilliStart(void)
Yann Colletdb4c0122014-08-30 18:14:44 +0100115{
Yann Colletdc5fb732014-09-22 18:42:00 +0100116 struct timeb tb;
117 U32 nCount;
118 ftime( &tb );
119 nCount = (U32) (((tb.time & 0xFFFFF) * 1000) + tb.millitm);
120 return nCount;
Yann Colletdb4c0122014-08-30 18:14:44 +0100121}
122
Yann Colletda1b0c12014-09-06 13:06:28 +0100123
124static U32 FUZ_GetMilliSpan(U32 nTimeStart)
Yann Colletdb4c0122014-08-30 18:14:44 +0100125{
Yann Colletdc5fb732014-09-22 18:42:00 +0100126 U32 nCurrent = FUZ_GetMilliStart();
127 U32 nSpan = nCurrent - nTimeStart;
128 if (nTimeStart > nCurrent)
129 nSpan += 0x100000 * 1000;
130 return nSpan;
Yann Colletdb4c0122014-08-30 18:14:44 +0100131}
Yann Colletda1b0c12014-09-06 13:06:28 +0100132
Yann Colletdb4c0122014-08-30 18:14:44 +0100133
134
135# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
136unsigned int FUZ_rand(unsigned int* src)
137{
138 U32 rand32 = *src;
Yann Collet837551f2014-09-07 09:13:02 +0100139 rand32 *= prime1;
140 rand32 += prime2;
Yann Colletdb4c0122014-08-30 18:14:44 +0100141 rand32 = FUZ_rotl32(rand32, 13);
142 *src = rand32;
Yann Collet1ffc02e2014-09-05 16:32:04 +0100143 return rand32 >> 5;
Yann Colletdb4c0122014-08-30 18:14:44 +0100144}
145
146
Yann Collet1ffc02e2014-09-05 16:32:04 +0100147#define FUZ_RAND15BITS (FUZ_rand(seed) & 0x7FFF)
148#define FUZ_RANDLENGTH ( (FUZ_rand(seed) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
Yann Collet23effdb2014-08-31 23:14:20 +0100149static void FUZ_fillCompressibleNoiseBuffer(void* buffer, unsigned bufferSize, double proba, U32* seed)
Yann Colletdb4c0122014-08-30 18:14:44 +0100150{
151 BYTE* BBuffer = (BYTE*)buffer;
Yann Collet23effdb2014-08-31 23:14:20 +0100152 unsigned pos = 0;
Yann Colletdb4c0122014-08-30 18:14:44 +0100153 U32 P32 = (U32)(32768 * proba);
154
155 // First Byte
156 BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
157
158 while (pos < bufferSize)
159 {
160 // Select : Literal (noise) or copy (within 64K)
161 if (FUZ_RAND15BITS < P32)
162 {
163 // Copy (within 64K)
Yann Collet23effdb2014-08-31 23:14:20 +0100164 unsigned match, end;
165 unsigned length = FUZ_RANDLENGTH + 4;
166 unsigned offset = FUZ_RAND15BITS + 1;
Yann Colletdb4c0122014-08-30 18:14:44 +0100167 if (offset > pos) offset = pos;
168 if (pos + length > bufferSize) length = bufferSize - pos;
Yann Collet23effdb2014-08-31 23:14:20 +0100169 match = pos - offset;
170 end = pos + length;
171 while (pos < end) BBuffer[pos++] = BBuffer[match++];
Yann Colletdb4c0122014-08-30 18:14:44 +0100172 }
173 else
174 {
175 // Literal (noise)
Yann Collet23effdb2014-08-31 23:14:20 +0100176 unsigned end;
177 unsigned length = FUZ_RANDLENGTH;
Yann Colletdb4c0122014-08-30 18:14:44 +0100178 if (pos + length > bufferSize) length = bufferSize - pos;
Yann Collet23effdb2014-08-31 23:14:20 +0100179 end = pos + length;
180 while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
Yann Colletdb4c0122014-08-30 18:14:44 +0100181 }
182 }
183}
184
185
Yann Collet1ffc02e2014-09-05 16:32:04 +0100186static unsigned FUZ_highbit(U32 v32)
187{
188 unsigned nbBits = 0;
189 if (v32==0) return 0;
Yann Colletdc5fb732014-09-22 18:42:00 +0100190 while (v32)
191 {
192 v32 >>= 1;
193 nbBits ++;
194 }
Yann Collet1ffc02e2014-09-05 16:32:04 +0100195 return nbBits;
196}
Yann Colletdb4c0122014-08-30 18:14:44 +0100197
Yann Collet1ffc02e2014-09-05 16:32:04 +0100198
Yann Colletf881ccb2014-09-11 22:27:14 +0100199int basicTests(U32 seed, double compressibility)
Yann Colletdb4c0122014-08-30 18:14:44 +0100200{
Yann Colletdc5fb732014-09-22 18:42:00 +0100201 int testResult = 0;
202 void* CNBuffer;
203 void* compressedBuffer;
204 void* decodedBuffer;
205 U32 randState = seed;
206 size_t cSize, testSize;
207 LZ4F_preferences_t prefs = { 0 };
208 LZ4F_decompressionContext_t dCtx;
209 U64 crcOrig;
Yann Colletdb4c0122014-08-30 18:14:44 +0100210
Yann Colletdc5fb732014-09-22 18:42:00 +0100211 // Create compressible test buffer
212 CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
213 compressedBuffer = malloc(LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL));
214 decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
215 FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
216 crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
Yann Colletdb4c0122014-08-30 18:14:44 +0100217
Yann Colletdc5fb732014-09-22 18:42:00 +0100218 // Trivial tests : one-step frame
219 testSize = COMPRESSIBLE_NOISE_LENGTH;
220 DISPLAYLEVEL(3, "Using NULL preferences : \n");
221 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
222 if (LZ4F_isError(cSize)) goto _output_error;
223 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Collet23effdb2014-08-31 23:14:20 +0100224
Yann Colletdc5fb732014-09-22 18:42:00 +0100225 DISPLAYLEVEL(3, "Decompression test : \n");
226 {
Yann Collet0ac00ee2014-09-03 19:49:59 +0100227 size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
228 size_t compressedBufferSize = cSize;
Yann Collet8fbacf42014-09-04 22:56:51 +0100229 BYTE* op = (BYTE*)decodedBuffer;
230 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
231 BYTE* ip = (BYTE*)compressedBuffer;
232 BYTE* const iend = (BYTE*)compressedBuffer + cSize;
Yann Collet1ffc02e2014-09-05 16:32:04 +0100233 U64 crcDest;
234
235 LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
Yann Collet0ac00ee2014-09-03 19:49:59 +0100236 if (LZ4F_isError(errorCode)) goto _output_error;
Yann Collet8fbacf42014-09-04 22:56:51 +0100237
Yann Collet1ffc02e2014-09-05 16:32:04 +0100238 DISPLAYLEVEL(3, "Single Block : \n");
Yann Collet0ac00ee2014-09-03 19:49:59 +0100239 errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL);
Yann Collet1ffc02e2014-09-05 16:32:04 +0100240 crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
241 if (crcDest != crcOrig) goto _output_error;
242 DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
Yann Collet8fbacf42014-09-04 22:56:51 +0100243
Yann Collet1ffc02e2014-09-05 16:32:04 +0100244 DISPLAYLEVEL(3, "Byte after byte : \n");
Yann Collet8fbacf42014-09-04 22:56:51 +0100245 while (ip < iend)
246 {
247 size_t oSize = oend-op;
248 size_t iSize = 1;
249 //DISPLAY("%7i \n", (int)(ip-(BYTE*)compressedBuffer));
250 errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
251 if (LZ4F_isError(errorCode)) goto _output_error;
252 op += oSize;
253 ip += iSize;
254 }
Yann Collet1ffc02e2014-09-05 16:32:04 +0100255 crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
256 if (crcDest != crcOrig) goto _output_error;
257 DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
Yann Collet8fbacf42014-09-04 22:56:51 +0100258
Yann Collet0ac00ee2014-09-03 19:49:59 +0100259 errorCode = LZ4F_freeDecompressionContext(dCtx);
260 if (LZ4F_isError(errorCode)) goto _output_error;
Yann Colletdc5fb732014-09-22 18:42:00 +0100261 }
Yann Collet0ac00ee2014-09-03 19:49:59 +0100262
Yann Colletdc5fb732014-09-22 18:42:00 +0100263 DISPLAYLEVEL(3, "Using 64 KB block : \n");
264 prefs.frameInfo.blockSizeID = max64KB;
265 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
266 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
267 if (LZ4F_isError(cSize)) goto _output_error;
268 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Collet23effdb2014-08-31 23:14:20 +0100269
Yann Colletdc5fb732014-09-22 18:42:00 +0100270 DISPLAYLEVEL(3, "without checksum : \n");
271 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
272 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
273 if (LZ4F_isError(cSize)) goto _output_error;
274 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Collet23effdb2014-08-31 23:14:20 +0100275
Yann Colletdc5fb732014-09-22 18:42:00 +0100276 DISPLAYLEVEL(3, "Using 256 KB block : \n");
277 prefs.frameInfo.blockSizeID = max256KB;
278 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
279 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
280 if (LZ4F_isError(cSize)) goto _output_error;
281 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Collet23effdb2014-08-31 23:14:20 +0100282
Yann Colletdc5fb732014-09-22 18:42:00 +0100283 DISPLAYLEVEL(3, "Decompression test : \n");
284 {
Yann Collet1ffc02e2014-09-05 16:32:04 +0100285 size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
Yann Collete39b22c2014-09-22 17:38:17 +0100286 unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
Yann Collet1ffc02e2014-09-05 16:32:04 +0100287 BYTE* op = (BYTE*)decodedBuffer;
288 BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
289 BYTE* ip = (BYTE*)compressedBuffer;
290 BYTE* const iend = (BYTE*)compressedBuffer + cSize;
291 U64 crcDest;
292
293 LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
294 if (LZ4F_isError(errorCode)) goto _output_error;
295
296 DISPLAYLEVEL(3, "random segment sizes : \n");
297 while (ip < iend)
298 {
299 unsigned nbBits = FUZ_rand(&randState) % maxBits;
300 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
301 size_t oSize = oend-op;
302 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
303 //DISPLAY("%7i : + %6i\n", (int)(ip-(BYTE*)compressedBuffer), (int)iSize);
304 errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
305 if (LZ4F_isError(errorCode)) goto _output_error;
306 op += oSize;
307 ip += iSize;
308 }
309 crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
310 if (crcDest != crcOrig) goto _output_error;
311 DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
312
313 errorCode = LZ4F_freeDecompressionContext(dCtx);
314 if (LZ4F_isError(errorCode)) goto _output_error;
Yann Colletdc5fb732014-09-22 18:42:00 +0100315 }
Yann Collet1ffc02e2014-09-05 16:32:04 +0100316
Yann Colletdc5fb732014-09-22 18:42:00 +0100317 DISPLAYLEVEL(3, "without checksum : \n");
318 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
319 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
320 if (LZ4F_isError(cSize)) goto _output_error;
321 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Collet23effdb2014-08-31 23:14:20 +0100322
Yann Colletdc5fb732014-09-22 18:42:00 +0100323 DISPLAYLEVEL(3, "Using 1 MB block : \n");
324 prefs.frameInfo.blockSizeID = max1MB;
325 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
326 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
327 if (LZ4F_isError(cSize)) goto _output_error;
328 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Collet23effdb2014-08-31 23:14:20 +0100329
Yann Colletdc5fb732014-09-22 18:42:00 +0100330 DISPLAYLEVEL(3, "without checksum : \n");
331 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
332 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
333 if (LZ4F_isError(cSize)) goto _output_error;
334 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Collet23effdb2014-08-31 23:14:20 +0100335
Yann Colletdc5fb732014-09-22 18:42:00 +0100336 DISPLAYLEVEL(3, "Using 4 MB block : \n");
337 prefs.frameInfo.blockSizeID = max4MB;
338 prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
339 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
340 if (LZ4F_isError(cSize)) goto _output_error;
341 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Collet23effdb2014-08-31 23:14:20 +0100342
Yann Colletdc5fb732014-09-22 18:42:00 +0100343 DISPLAYLEVEL(3, "without checksum : \n");
344 prefs.frameInfo.contentChecksumFlag = noContentChecksum;
345 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
346 if (LZ4F_isError(cSize)) goto _output_error;
347 DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
Yann Colletdb4c0122014-08-30 18:14:44 +0100348
Yann Colletdc5fb732014-09-22 18:42:00 +0100349 DISPLAY("Basic tests completed \n");
Yann Colletdb4c0122014-08-30 18:14:44 +0100350_end:
Yann Colletdc5fb732014-09-22 18:42:00 +0100351 free(CNBuffer);
352 free(compressedBuffer);
353 free(decodedBuffer);
354 return testResult;
Yann Colletdb4c0122014-08-30 18:14:44 +0100355
356_output_error:
Yann Colletdc5fb732014-09-22 18:42:00 +0100357 testResult = 1;
358 DISPLAY("Error detected ! \n");
359 goto _end;
Yann Colletdb4c0122014-08-30 18:14:44 +0100360}
361
362
Yann Collet6330f772014-09-21 09:56:21 +0100363static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous)
Yann Colletf881ccb2014-09-11 22:27:14 +0100364{
365 int p=0;
366 BYTE* b1=(BYTE*)buff1;
367 BYTE* b2=(BYTE*)buff2;
Yann Colletdc5fb732014-09-22 18:42:00 +0100368 if (nonContiguous)
369 {
370 DISPLAY("Non-contiguous output test (%i bytes)\n", (int)size);
371 return;
372 }
Yann Colletf881ccb2014-09-11 22:27:14 +0100373 while (b1[p]==b2[p]) p++;
Yann Collet6330f772014-09-21 09:56:21 +0100374 DISPLAY("Error at pos %i/%i : %02X != %02X \n", p, (int)size, b1[p], b2[p]);
Yann Colletdc5fb732014-09-22 18:42:00 +0100375}
Yann Colletf881ccb2014-09-11 22:27:14 +0100376
377
Yann Colletb96f8c12014-09-10 13:53:42 +0100378static const U32 srcDataLength = 9 MB; /* needs to be > 2x4MB to test large blocks */
Yann Collet1ffc02e2014-09-05 16:32:04 +0100379
Yann Collet3d9d1782014-09-07 12:12:46 +0100380int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility)
Yann Collet1ffc02e2014-09-05 16:32:04 +0100381{
Yann Colletdc5fb732014-09-22 18:42:00 +0100382 unsigned testResult = 0;
383 unsigned testNb = 0;
384 void* srcBuffer = NULL;
385 void* compressedBuffer = NULL;
386 void* decodedBuffer = NULL;
387 U32 coreRand = seed;
388 LZ4F_decompressionContext_t dCtx = NULL;
389 LZ4F_compressionContext_t cCtx = NULL;
Yann Collet5929de42014-09-07 12:57:09 +0100390 size_t result;
Yann Collet6330f772014-09-21 09:56:21 +0100391 XXH64_stateSpace_t xxh64;
Yann Colletda1b0c12014-09-06 13:06:28 +0100392# define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
Yann Colletdc5fb732014-09-22 18:42:00 +0100393 DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
Yann Collet1ffc02e2014-09-05 16:32:04 +0100394
Yann Colletdc5fb732014-09-22 18:42:00 +0100395 // Create buffers
396 result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
Yann Collet5929de42014-09-07 12:57:09 +0100397 CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
Yann Colletdc5fb732014-09-22 18:42:00 +0100398 result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
Yann Collet5929de42014-09-07 12:57:09 +0100399 CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
Yann Colletdc5fb732014-09-22 18:42:00 +0100400 srcBuffer = malloc(srcDataLength);
Yann Collet5929de42014-09-07 12:57:09 +0100401 CHECK(srcBuffer==NULL, "srcBuffer Allocation failed");
Yann Colletdc5fb732014-09-22 18:42:00 +0100402 compressedBuffer = malloc(LZ4F_compressFrameBound(srcDataLength, NULL));
Yann Collet5929de42014-09-07 12:57:09 +0100403 CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
Yann Colletdc5fb732014-09-22 18:42:00 +0100404 decodedBuffer = malloc(srcDataLength);
Yann Collet5929de42014-09-07 12:57:09 +0100405 CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
Yann Colletdc5fb732014-09-22 18:42:00 +0100406 FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand);
Yann Collet1ffc02e2014-09-05 16:32:04 +0100407
Yann Collet3d9d1782014-09-07 12:12:46 +0100408 // jump to requested testNb
Yann Colletdc5fb732014-09-22 18:42:00 +0100409 for (testNb =0; testNb < startTest; testNb++) (void)FUZ_rand(&coreRand); // sync randomizer
Yann Collet3d9d1782014-09-07 12:12:46 +0100410
411 // main fuzzer loop
412 for ( ; testNb < nbTests; testNb++)
Yann Collet1ffc02e2014-09-05 16:32:04 +0100413 {
Yann Collet3d9d1782014-09-07 12:12:46 +0100414 U32 randState = coreRand ^ prime1;
Yann Collet20ae8b92014-09-06 09:47:28 +0100415 unsigned BSId = 4 + (FUZ_rand(&randState) & 3);
Yann Collet2b4cdd02014-09-09 23:54:22 +0100416 unsigned BMId = FUZ_rand(&randState) & 1;
Yann Collet414cfb92014-09-10 13:00:39 +0100417 unsigned CCflag = FUZ_rand(&randState) & 1;
Yann Collet9464bfd2014-09-13 23:44:07 +0100418 unsigned autoflush = (FUZ_rand(&randState) & 7) == 2;
Yann Collet18cdb732014-09-13 10:08:55 +0100419 LZ4F_preferences_t prefs = { 0 };
Yann Colletf587a862014-09-15 00:59:30 +0100420 LZ4F_compressOptions_t cOptions = { 0 };
421 LZ4F_decompressOptions_t dOptions = { 0 };
Yann Collet1ffc02e2014-09-05 16:32:04 +0100422 unsigned nbBits = (FUZ_rand(&randState) % (FUZ_highbit(srcDataLength-1) - 1)) + 1;
423 size_t srcSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
424 size_t srcStart = FUZ_rand(&randState) % (srcDataLength - srcSize);
Yann Collet837551f2014-09-07 09:13:02 +0100425 size_t cSize;
Yann Colletb73b2af2014-09-06 12:19:26 +0100426 U64 crcOrig, crcDecoded;
427
Yann Collet6330f772014-09-21 09:56:21 +0100428 (void)FUZ_rand(&coreRand); // update rand seed
Yann Collet18cdb732014-09-13 10:08:55 +0100429 prefs.frameInfo.blockMode = BMId;
430 prefs.frameInfo.blockSizeID = BSId;
431 prefs.frameInfo.contentChecksumFlag = CCflag;
432 prefs.autoFlush = autoflush;
433
Yann Colletdc5fb732014-09-22 18:42:00 +0100434 DISPLAYUPDATE(2, "\r%5u ", testNb);
Yann Collete39b22c2014-09-22 17:38:17 +0100435 crcOrig = XXH64((BYTE*)srcBuffer+srcStart, (U32)srcSize, 1);
Yann Collet837551f2014-09-07 09:13:02 +0100436
Yann Collet73025f22014-09-22 02:59:42 +0100437 if ((FUZ_rand(&randState)&0xF) == 2)
438 {
439 LZ4F_preferences_t* framePrefs = &prefs;
440 if ((FUZ_rand(&randState)&7) == 1) framePrefs = NULL;
Yann Collete39b22c2014-09-22 17:38:17 +0100441 cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, framePrefs), (char*)srcBuffer + srcStart, srcSize, framePrefs);
Yann Collet73025f22014-09-22 02:59:42 +0100442 CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
443 }
444 else
Yann Collet837551f2014-09-07 09:13:02 +0100445 {
Yann Colletf881ccb2014-09-11 22:27:14 +0100446 const BYTE* ip = (const BYTE*)srcBuffer + srcStart;
Yann Collet837551f2014-09-07 09:13:02 +0100447 const BYTE* const iend = ip + srcSize;
448 BYTE* op = compressedBuffer;
449 BYTE* const oend = op + LZ4F_compressFrameBound(srcDataLength, NULL);
Yann Collete39b22c2014-09-22 17:38:17 +0100450 unsigned maxBits = FUZ_highbit((U32)srcSize);
Yann Collet5929de42014-09-07 12:57:09 +0100451 result = LZ4F_compressBegin(cCtx, op, oend-op, &prefs);
Yann Collet837551f2014-09-07 09:13:02 +0100452 CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result);
453 op += result;
454 while (ip < iend)
455 {
Yann Collet3d9d1782014-09-07 12:12:46 +0100456 unsigned nbBitsSeg = FUZ_rand(&randState) % maxBits;
457 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
Yann Collet837551f2014-09-07 09:13:02 +0100458 size_t oSize = oend-op;
Yann Colletb96f8c12014-09-10 13:53:42 +0100459 unsigned forceFlush = ((FUZ_rand(&randState) & 3) == 1);
Yann Collet837551f2014-09-07 09:13:02 +0100460 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
Yann Colletdc5fb732014-09-22 18:42:00 +0100461 cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
Yann Collet18cdb732014-09-13 10:08:55 +0100462
Yann Colletf587a862014-09-15 00:59:30 +0100463 result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
Yann Collet837551f2014-09-07 09:13:02 +0100464 CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
465 op += result;
466 ip += iSize;
Yann Collet18cdb732014-09-13 10:08:55 +0100467
Yann Colletb96f8c12014-09-10 13:53:42 +0100468 if (forceFlush)
469 {
Yann Colletf587a862014-09-15 00:59:30 +0100470 result = LZ4F_flush(cCtx, op, oend-op, &cOptions);
Yann Colletb96f8c12014-09-10 13:53:42 +0100471 CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
472 op += result;
473 }
Yann Collet837551f2014-09-07 09:13:02 +0100474 }
Yann Colletf587a862014-09-15 00:59:30 +0100475 result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions);
Yann Collet837551f2014-09-07 09:13:02 +0100476 CHECK(LZ4F_isError(result), "Compression completion failed (error %i)", (int)result);
477 op += result;
Yann Colleta6af48e2014-09-07 11:04:29 +0100478 cSize = op-(BYTE*)compressedBuffer;
Yann Collet837551f2014-09-07 09:13:02 +0100479 }
Yann Colletb18d4092014-09-06 22:48:03 +0100480
481 {
482 const BYTE* ip = compressedBuffer;
483 const BYTE* const iend = ip + cSize;
484 BYTE* op = decodedBuffer;
485 BYTE* const oend = op + srcDataLength;
Yann Collete39b22c2014-09-22 17:38:17 +0100486 unsigned maxBits = FUZ_highbit((U32)cSize);
Yann Collet6330f772014-09-21 09:56:21 +0100487 unsigned nonContiguousDst = (FUZ_rand(&randState) & 3) == 1;
488 nonContiguousDst += FUZ_rand(&randState) & nonContiguousDst; /* 0=>0; 1=>1,2 */
489 XXH64_resetState(&xxh64, 1);
Yann Colletb18d4092014-09-06 22:48:03 +0100490 while (ip < iend)
491 {
Yann Collet3d9d1782014-09-07 12:12:46 +0100492 unsigned nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1;
Yann Colletb5638572014-09-13 21:21:41 +0100493 unsigned nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1;
Yann Collet3d9d1782014-09-07 12:12:46 +0100494 size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsI)-1)) + 1;
Yann Colletb5638572014-09-13 21:21:41 +0100495 size_t oSize = (FUZ_rand(&randState) & ((1<<nbBitsO)-1)) + 2;
Yann Colletb18d4092014-09-06 22:48:03 +0100496 if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
Yann Colleta6af48e2014-09-07 11:04:29 +0100497 if (oSize > (size_t)(oend-op)) oSize = oend-op;
Yann Colletf587a862014-09-15 00:59:30 +0100498 dOptions.stableDst = FUZ_rand(&randState) & 1;
Yann Collet6330f772014-09-21 09:56:21 +0100499 if (nonContiguousDst==2) dOptions.stableDst = 0;
500 //if (ip == compressedBuffer+62073) DISPLAY("oSize : %i : pos %i \n", (int)oSize, (int)(op-(BYTE*)decodedBuffer));
Yann Colletf587a862014-09-15 00:59:30 +0100501 result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions);
Yann Collet6330f772014-09-21 09:56:21 +0100502 //if (op+oSize >= (BYTE*)decodedBuffer+94727) DISPLAY("iSize : %i : pos %i \n", (int)iSize, (int)(ip-(BYTE*)compressedBuffer));
503 //if ((int)result<0) DISPLAY("iSize : %i : pos %i \n", (int)iSize, (int)(ip-(BYTE*)compressedBuffer));
504 if (result == (size_t)-ERROR_checksum_invalid) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
505 CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s)", (int)result, LZ4F_getErrorName((LZ4F_errorCode_t)result));
506 XXH64_update(&xxh64, op, (U32)oSize);
Yann Colletb18d4092014-09-06 22:48:03 +0100507 op += oSize;
508 ip += iSize;
Yann Collet6330f772014-09-21 09:56:21 +0100509 op += nonContiguousDst;
510 if (nonContiguousDst==2) op = decodedBuffer; // overwritten destination
Yann Colletb18d4092014-09-06 22:48:03 +0100511 }
Yann Collet9258ee52014-09-13 12:15:54 +0100512 CHECK(result != 0, "Frame decompression failed (error %i)", (int)result);
Yann Collet6330f772014-09-21 09:56:21 +0100513 crcDecoded = XXH64_intermediateDigest(&xxh64);
514 if (crcDecoded != crcOrig) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
Yann Colletb18d4092014-09-06 22:48:03 +0100515 CHECK(crcDecoded != crcOrig, "Decompression corruption");
516 }
Yann Collet1ffc02e2014-09-05 16:32:04 +0100517 }
518
Yann Colletdc5fb732014-09-22 18:42:00 +0100519 DISPLAYLEVEL(2, "\rAll tests completed \n");
Yann Collet1ffc02e2014-09-05 16:32:04 +0100520
521_end:
Yann Colletda1b0c12014-09-06 13:06:28 +0100522 LZ4F_freeDecompressionContext(dCtx);
Yann Collet5929de42014-09-07 12:57:09 +0100523 LZ4F_freeCompressionContext(cCtx);
Yann Colletdc5fb732014-09-22 18:42:00 +0100524 free(srcBuffer);
525 free(compressedBuffer);
526 free(decodedBuffer);
Yann Collet6330f772014-09-21 09:56:21 +0100527
Yann Colletdc5fb732014-09-22 18:42:00 +0100528 if (pause)
Yann Collet6330f772014-09-21 09:56:21 +0100529 {
530 DISPLAY("press enter to finish \n");
531 getchar();
532 }
Yann Colletdc5fb732014-09-22 18:42:00 +0100533 return testResult;
Yann Collet1ffc02e2014-09-05 16:32:04 +0100534
535_output_error:
Yann Colletdc5fb732014-09-22 18:42:00 +0100536 testResult = 1;
537 goto _end;
Yann Collet1ffc02e2014-09-05 16:32:04 +0100538}
539
540
Yann Colletdb4c0122014-08-30 18:14:44 +0100541int FUZ_usage(void)
542{
543 DISPLAY( "Usage :\n");
544 DISPLAY( " %s [args]\n", programName);
545 DISPLAY( "\n");
546 DISPLAY( "Arguments :\n");
Yann Colletdc5fb732014-09-22 18:42:00 +0100547 DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
Yann Colletdb4c0122014-08-30 18:14:44 +0100548 DISPLAY( " -s# : Select seed (default:prompt user)\n");
549 DISPLAY( " -t# : Select starting test number (default:0)\n");
550 DISPLAY( " -p# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
551 DISPLAY( " -v : verbose\n");
552 DISPLAY( " -h : display help and exit\n");
553 return 0;
554}
555
556
Yann Colletfc8e3f52014-09-01 22:44:02 +0100557int main(int argc, char** argv)
558{
Yann Colletdb4c0122014-08-30 18:14:44 +0100559 U32 seed=0;
560 int seedset=0;
561 int argNb;
Yann Collet837551f2014-09-07 09:13:02 +0100562 int nbTests = nbTestsDefault;
Yann Colletdb4c0122014-08-30 18:14:44 +0100563 int testNb = 0;
564 int proba = FUZ_COMPRESSIBILITY_DEFAULT;
Yann Colletf881ccb2014-09-11 22:27:14 +0100565 int result=0;
Yann Colletdb4c0122014-08-30 18:14:44 +0100566
567 // Check command line
568 programName = argv[0];
569 for(argNb=1; argNb<argc; argNb++)
570 {
571 char* argument = argv[argNb];
572
573 if(!argument) continue; // Protection if argument empty
574
575 // Decode command (note : aggregated commands are allowed)
576 if (argument[0]=='-')
577 {
Yann Colletdc5fb732014-09-22 18:42:00 +0100578 if (!strcmp(argument, "--no-prompt"))
579 {
580 no_prompt=1;
581 seedset=1;
582 displayLevel=1;
583 continue;
584 }
Yann Collet6330f772014-09-21 09:56:21 +0100585 argument++;
Yann Colletdb4c0122014-08-30 18:14:44 +0100586
Yann Collet6330f772014-09-21 09:56:21 +0100587 while (*argument!=0)
Yann Colletdb4c0122014-08-30 18:14:44 +0100588 {
Yann Colletdb4c0122014-08-30 18:14:44 +0100589 switch(*argument)
590 {
591 case 'h':
592 return FUZ_usage();
593 case 'v':
594 argument++;
595 displayLevel=4;
596 break;
Yann Collet1ffc02e2014-09-05 16:32:04 +0100597 case 'q':
598 argument++;
599 displayLevel--;
600 break;
Yann Colletdb4c0122014-08-30 18:14:44 +0100601 case 'i':
602 argument++;
603 nbTests=0;
604 while ((*argument>='0') && (*argument<='9'))
605 {
606 nbTests *= 10;
607 nbTests += *argument - '0';
608 argument++;
609 }
610 break;
611 case 's':
612 argument++;
Yann Colletdc5fb732014-09-22 18:42:00 +0100613 seed=0;
614 seedset=1;
Yann Colletdb4c0122014-08-30 18:14:44 +0100615 while ((*argument>='0') && (*argument<='9'))
616 {
617 seed *= 10;
618 seed += *argument - '0';
619 argument++;
620 }
621 break;
622 case 't':
623 argument++;
624 testNb=0;
625 while ((*argument>='0') && (*argument<='9'))
626 {
627 testNb *= 10;
628 testNb += *argument - '0';
629 argument++;
630 }
631 break;
Yann Collet6330f772014-09-21 09:56:21 +0100632 case 'p': /* compressibility % */
Yann Colletdb4c0122014-08-30 18:14:44 +0100633 argument++;
634 proba=0;
635 while ((*argument>='0') && (*argument<='9'))
636 {
637 proba *= 10;
638 proba += *argument - '0';
639 argument++;
640 }
641 if (proba<0) proba=0;
642 if (proba>100) proba=100;
643 break;
Yann Collet6330f772014-09-21 09:56:21 +0100644 case 'P': /* pause at the end */
645 argument++;
646 pause = 1;
647 break;
Yann Colletdc5fb732014-09-22 18:42:00 +0100648 default:
649 ;
Yann Collet6330f772014-09-21 09:56:21 +0100650 return FUZ_usage();
Yann Colletdb4c0122014-08-30 18:14:44 +0100651 }
652 }
653 }
654 }
655
656 // Get Seed
657 printf("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION);
658
Yann Colletfc8e3f52014-09-01 22:44:02 +0100659 if (!seedset) seed = FUZ_GetMilliStart() % 10000;
Yann Colletdb4c0122014-08-30 18:14:44 +0100660 printf("Seed = %u\n", seed);
661 if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
662
663 if (nbTests<=0) nbTests=1;
664
Yann Collet1f540332014-09-13 19:49:01 +0100665 //if (testNb==0) result = basicTests(seed, ((double)proba) / 100);
Yann Collet2b4cdd02014-09-09 23:54:22 +0100666 if (result) return 1;
Yann Collet1ffc02e2014-09-05 16:32:04 +0100667 return fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100);
Yann Colletdb4c0122014-08-30 18:14:44 +0100668}