benchmark silo added
[c11concurrency-benchmarks.git] / silo / third-party / lz4 / bench.c
1 /*\r
2     bench.c - Demo program to benchmark open-source compression algorithm\r
3     Copyright (C) Yann Collet 2012-2013\r
4     GPL v2 License\r
5 \r
6     This program is free software; you can redistribute it and/or modify\r
7     it under the terms of the GNU General Public License as published by\r
8     the Free Software Foundation; either version 2 of the License, or\r
9     (at your option) any later version.\r
10 \r
11     This program is distributed in the hope that it will be useful,\r
12     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
14     GNU General Public License for more details.\r
15 \r
16     You should have received a copy of the GNU General Public License along\r
17     with this program; if not, write to the Free Software Foundation, Inc.,\r
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
19 \r
20     You can contact the author at :\r
21     - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html\r
22     - LZ4 source repository : http://code.google.com/p/lz4/\r
23 */\r
24 \r
25 //**************************************\r
26 // Compiler Options\r
27 //**************************************\r
28 // Disable some Visual warning messages\r
29 #define _CRT_SECURE_NO_WARNINGS\r
30 #define _CRT_SECURE_NO_DEPRECATE     // VS2005\r
31 \r
32 // Unix Large Files support (>4GB)\r
33 #if (defined(__sun__) && (!defined(__LP64__)))   // Sun Solaris 32-bits requires specific definitions\r
34 #  define _LARGEFILE_SOURCE \r
35 #  define _FILE_OFFSET_BITS 64\r
36 #elif ! defined(__LP64__)                        // No point defining Large file for 64 bit\r
37 #  define _LARGEFILE64_SOURCE\r
38 #endif\r
39 \r
40 // S_ISREG & gettimeofday() are not supported by MSVC\r
41 #if defined(_MSC_VER)\r
42 #  define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)\r
43 #  define BMK_LEGACY_TIMER 1\r
44 #endif\r
45 \r
46 // GCC does not support _rotl outside of Windows\r
47 #if !defined(_WIN32)\r
48 #  define _rotl(x,r) ((x << r) | (x >> (32 - r)))\r
49 #endif\r
50 \r
51 \r
52 //**************************************\r
53 // Includes\r
54 //**************************************\r
55 #include <stdlib.h>      // malloc\r
56 #include <stdio.h>       // fprintf, fopen, ftello64\r
57 #include <sys/types.h>   // stat64\r
58 #include <sys/stat.h>    // stat64\r
59 \r
60 // Use ftime() if gettimeofday() is not available on your target\r
61 #if defined(BMK_LEGACY_TIMER)\r
62 #  include <sys/timeb.h>   // timeb, ftime\r
63 #else\r
64 #  include <sys/time.h>    // gettimeofday\r
65 #endif\r
66 \r
67 #include "lz4.h"\r
68 #define COMPRESSOR0 LZ4_compress\r
69 #include "lz4hc.h"\r
70 #define COMPRESSOR1 LZ4_compressHC\r
71 #define DEFAULTCOMPRESSOR COMPRESSOR0\r
72 \r
73 #include "xxhash.h"\r
74 \r
75 \r
76 //**************************************\r
77 // Basic Types\r
78 //**************************************\r
79 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   // C99\r
80 # include <stdint.h>\r
81   typedef uint8_t  BYTE;\r
82   typedef uint16_t U16;\r
83   typedef uint32_t U32;\r
84   typedef  int32_t S32;\r
85   typedef uint64_t U64;\r
86 #else\r
87   typedef unsigned char       BYTE;\r
88   typedef unsigned short      U16;\r
89   typedef unsigned int        U32;\r
90   typedef   signed int        S32;\r
91   typedef unsigned long long  U64;\r
92 #endif\r
93 \r
94 \r
95 //**************************************\r
96 // Constants\r
97 //**************************************\r
98 #define NBLOOPS    3\r
99 #define TIMELOOP   2000\r
100 \r
101 #define KNUTH      2654435761U\r
102 #define MAX_MEM    (1984<<20)\r
103 #define DEFAULT_CHUNKSIZE   (4<<20)\r
104 \r
105 \r
106 //**************************************\r
107 // Local structures\r
108 //**************************************\r
109 struct chunkParameters\r
110 {\r
111     U32   id;\r
112     char* origBuffer;\r
113     char* compressedBuffer;\r
114     int   origSize;\r
115     int   compressedSize;\r
116 };\r
117 \r
118 struct compressionParameters\r
119 {\r
120     int (*compressionFunction)(const char*, char*, int);\r
121     int (*decompressionFunction)(const char*, char*, int);\r
122 };\r
123 \r
124 \r
125 //**************************************\r
126 // MACRO\r
127 //**************************************\r
128 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)\r
129 \r
130 \r
131 \r
132 //**************************************\r
133 // Benchmark Parameters\r
134 //**************************************\r
135 static int chunkSize = DEFAULT_CHUNKSIZE;\r
136 static int nbIterations = NBLOOPS;\r
137 static int BMK_pause = 0;\r
138 \r
139 void BMK_SetBlocksize(int bsize)\r
140 {\r
141     chunkSize = bsize;\r
142     DISPLAY("-Using Block Size of %i KB-\n", chunkSize>>10);\r
143 }\r
144 \r
145 void BMK_SetNbIterations(int nbLoops)\r
146 {\r
147     nbIterations = nbLoops;\r
148     DISPLAY("- %i iterations -\n", nbIterations);\r
149 }\r
150 \r
151 void BMK_SetPause()\r
152 {\r
153     BMK_pause = 1;\r
154 }\r
155 \r
156 //*********************************************************\r
157 //  Private functions\r
158 //*********************************************************\r
159 \r
160 #if defined(BMK_LEGACY_TIMER)\r
161 \r
162 static int BMK_GetMilliStart()\r
163 {\r
164   // Based on Legacy ftime()\r
165   // Rolls over every ~ 12.1 days (0x100000/24/60/60)\r
166   // Use GetMilliSpan to correct for rollover\r
167   struct timeb tb;\r
168   int nCount;\r
169   ftime( &tb );\r
170   nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);\r
171   return nCount;\r
172 }\r
173 \r
174 #else\r
175 \r
176 static int BMK_GetMilliStart()\r
177 {\r
178   // Based on newer gettimeofday()\r
179   // Use GetMilliSpan to correct for rollover\r
180   struct timeval tv;\r
181   int nCount;\r
182   gettimeofday(&tv, NULL);\r
183   nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);\r
184   return nCount;\r
185 }\r
186 \r
187 #endif\r
188 \r
189 \r
190 static int BMK_GetMilliSpan( int nTimeStart )\r
191 {\r
192   int nSpan = BMK_GetMilliStart() - nTimeStart;\r
193   if ( nSpan < 0 )\r
194     nSpan += 0x100000 * 1000;\r
195   return nSpan;\r
196 }\r
197 \r
198 \r
199 static size_t BMK_findMaxMem(U64 requiredMem)\r
200 {\r
201     size_t step = (64U<<20);   // 64 MB\r
202     BYTE* testmem=NULL;\r
203 \r
204     requiredMem = (((requiredMem >> 25) + 1) << 26);\r
205     if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;\r
206 \r
207     requiredMem += 2*step;\r
208     while (!testmem)\r
209     {\r
210         requiredMem -= step;\r
211         testmem = (BYTE*) malloc ((size_t)requiredMem);\r
212     }\r
213 \r
214     free (testmem);\r
215     return (size_t) (requiredMem - step);\r
216 }\r
217 \r
218 \r
219 static U64 BMK_GetFileSize(char* infilename)\r
220 {\r
221     int r;\r
222 #if defined(_MSC_VER)\r
223     struct _stat64 statbuf;\r
224     r = _stat64(infilename, &statbuf);\r
225 #else\r
226     struct stat statbuf;\r
227     r = stat(infilename, &statbuf);\r
228 #endif\r
229     if (r || !S_ISREG(statbuf.st_mode)) return 0;   // No good...\r
230     return (U64)statbuf.st_size;\r
231 }\r
232 \r
233 \r
234 //*********************************************************\r
235 //  Public function\r
236 //*********************************************************\r
237 \r
238 int BMK_benchFile(char** fileNamesTable, int nbFiles, int cLevel)\r
239 {\r
240   int fileIdx=0;\r
241   FILE* fileIn;\r
242   char* infilename;\r
243   U64 largefilesize;\r
244   size_t benchedSize;\r
245   int nbChunks;\r
246   int maxCChunkSize;\r
247   size_t readSize;\r
248   char* orig_buff;\r
249   char* compressed_buff; int compressed_buff_size;\r
250   struct chunkParameters* chunkP;\r
251   U32 crcc, crcd=0;\r
252   struct compressionParameters compP;\r
253 \r
254   U64 totals = 0;\r
255   U64 totalz = 0;\r
256   double totalc = 0.;\r
257   double totald = 0.;\r
258 \r
259 \r
260   // Init\r
261   switch (cLevel)\r
262   {\r
263 #ifdef COMPRESSOR0\r
264   case 0 : compP.compressionFunction = COMPRESSOR0; break;\r
265 #endif\r
266 #ifdef COMPRESSOR1\r
267   case 1 : compP.compressionFunction = COMPRESSOR1; break;\r
268 #endif\r
269   default : compP.compressionFunction = DEFAULTCOMPRESSOR;\r
270   }\r
271   compP.decompressionFunction = LZ4_decompress_fast;\r
272 \r
273   // Loop for each file\r
274   while (fileIdx<nbFiles)\r
275   {\r
276       // Check file existence\r
277       infilename = fileNamesTable[fileIdx++];\r
278       fileIn = fopen( infilename, "rb" );\r
279       if (fileIn==NULL)\r
280       {\r
281         DISPLAY( "Pb opening %s\n", infilename);\r
282         return 11;\r
283       }\r
284 \r
285       // Memory allocation & restrictions\r
286       largefilesize = BMK_GetFileSize(infilename);\r
287       benchedSize = (size_t) BMK_findMaxMem(largefilesize) / 2;\r
288       if ((U64)benchedSize > largefilesize) benchedSize = (size_t)largefilesize;\r
289       if (benchedSize < largefilesize)\r
290       {\r
291           DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", infilename, (int)(benchedSize>>20));\r
292       }\r
293 \r
294       // Alloc\r
295       chunkP = (struct chunkParameters*) malloc(((benchedSize / chunkSize)+1) * sizeof(struct chunkParameters));\r
296       orig_buff = (char*)malloc((size_t )benchedSize);\r
297       nbChunks = (int) (benchedSize / chunkSize) + 1;\r
298       maxCChunkSize = LZ4_compressBound(chunkSize);\r
299       compressed_buff_size = nbChunks * maxCChunkSize;\r
300       compressed_buff = (char*)malloc((size_t )compressed_buff_size);\r
301 \r
302 \r
303       if(!orig_buff || !compressed_buff)\r
304       {\r
305         DISPLAY("\nError: not enough memory!\n");\r
306         free(orig_buff);\r
307         free(compressed_buff);\r
308         fclose(fileIn);\r
309         return 12;\r
310       }\r
311 \r
312       // Init chunks data\r
313       {\r
314           int i;\r
315           size_t remaining = benchedSize;\r
316           char* in = orig_buff;\r
317           char* out = compressed_buff;\r
318           for (i=0; i<nbChunks; i++)\r
319           {\r
320               chunkP[i].id = i;\r
321               chunkP[i].origBuffer = in; in += chunkSize;\r
322               if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }\r
323               chunkP[i].compressedBuffer = out; out += maxCChunkSize;\r
324               chunkP[i].compressedSize = 0;\r
325           }\r
326       }\r
327 \r
328       // Fill input buffer\r
329       DISPLAY("Loading %s...       \r", infilename);\r
330       readSize = fread(orig_buff, 1, benchedSize, fileIn);\r
331       fclose(fileIn);\r
332 \r
333       if(readSize != benchedSize)\r
334       {\r
335         DISPLAY("\nError: problem reading file '%s' !!    \n", infilename);\r
336         free(orig_buff);\r
337         free(compressed_buff);\r
338         return 13;\r
339       }\r
340 \r
341       // Calculating input Checksum\r
342       crcc = XXH32(orig_buff, (unsigned int)benchedSize,0);\r
343 \r
344 \r
345       // Bench\r
346       {\r
347         int loopNb, nb_loops, chunkNb;\r
348         size_t cSize=0;\r
349         int milliTime;\r
350         double fastestC = 100000000., fastestD = 100000000.;\r
351         double ratio=0.;\r
352 \r
353         DISPLAY("\r%79s\r", "");\r
354         for (loopNb = 1; loopNb <= nbIterations; loopNb++)\r
355         {\r
356           // Compression\r
357           DISPLAY("%1i-%-14.14s : %9i ->\r", loopNb, infilename, (int)benchedSize);\r
358           { size_t i; for (i=0; i<benchedSize; i++) compressed_buff[i]=(char)i; }     // warmimg up memory\r
359 \r
360           nb_loops = 0;\r
361           milliTime = BMK_GetMilliStart();\r
362           while(BMK_GetMilliStart() == milliTime);\r
363           milliTime = BMK_GetMilliStart();\r
364           while(BMK_GetMilliSpan(milliTime) < TIMELOOP)\r
365           {\r
366             for (chunkNb=0; chunkNb<nbChunks; chunkNb++)\r
367                 chunkP[chunkNb].compressedSize = compP.compressionFunction(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize);\r
368             nb_loops++;\r
369           }\r
370           milliTime = BMK_GetMilliSpan(milliTime);\r
371 \r
372           if ((double)milliTime < fastestC*nb_loops) fastestC = (double)milliTime/nb_loops;\r
373           cSize=0; for (chunkNb=0; chunkNb<nbChunks; chunkNb++) cSize += chunkP[chunkNb].compressedSize;\r
374           ratio = (double)cSize/(double)benchedSize*100.;\r
375 \r
376           DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%),%7.1f MB/s\r", loopNb, infilename, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000.);\r
377 \r
378           // Decompression\r
379           { size_t i; for (i=0; i<benchedSize; i++) orig_buff[i]=0; }     // zeroing area, for CRC checking\r
380 \r
381           nb_loops = 0;\r
382           milliTime = BMK_GetMilliStart();\r
383           while(BMK_GetMilliStart() == milliTime);\r
384           milliTime = BMK_GetMilliStart();\r
385           while(BMK_GetMilliSpan(milliTime) < TIMELOOP)\r
386           {\r
387             for (chunkNb=0; chunkNb<nbChunks; chunkNb++)\r
388                 //chunkP[chunkNb].origSize = LZ4_decompress_safe(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkSize);\r
389                 chunkP[chunkNb].compressedSize = LZ4_decompress_fast(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].origSize);\r
390                 //chunkP[chunkNb].compressedSize = LZ4_decompress_fast_withPrefix64k(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].origSize);\r
391                 //chunkP[chunkNb].origSize = LZ4_decompress_safe_withPrefix64k(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkSize);\r
392                 //chunkP[chunkNb].origSize = LZ4_decompress_safe_partial(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkSize-5, chunkSize);\r
393                 //chunkP[chunkNb].compressedSize = LZ4_uncompress(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].origSize);\r
394                 //chunkP[chunkNb].origSize = LZ4_uncompress_unknownOutputSize(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkSize);\r
395             nb_loops++;\r
396           }\r
397           milliTime = BMK_GetMilliSpan(milliTime);\r
398 \r
399           if ((double)milliTime < fastestD*nb_loops) fastestD = (double)milliTime/nb_loops;\r
400           DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%),%7.1f MB/s ,%7.1f MB/s\r", loopNb, infilename, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);\r
401 \r
402           // CRC Checking\r
403           crcd = XXH32(orig_buff, (unsigned int)benchedSize,0);\r
404           if (crcc!=crcd) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", infilename, (unsigned)crcc, (unsigned)crcd); break; }\r
405         }\r
406 \r
407         if (crcc==crcd)\r
408         {\r
409             if (ratio<100.)\r
410                 DISPLAY("%-16.16s : %9i -> %9i (%5.2f%%),%7.1f MB/s ,%7.1f MB/s\n", infilename, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);\r
411             else\r
412                 DISPLAY("%-16.16s : %9i -> %9i (%5.1f%%),%7.1f MB/s ,%7.1f MB/s \n", infilename, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);\r
413         }\r
414         totals += benchedSize;\r
415         totalz += cSize;\r
416         totalc += fastestC;\r
417         totald += fastestD;\r
418       }\r
419 \r
420       free(orig_buff);\r
421       free(compressed_buff);\r
422       free(chunkP);\r
423   }\r
424 \r
425   if (nbFiles > 1)\r
426         DISPLAY("%-16.16s :%10llu ->%10llu (%5.2f%%), %6.1f MB/s , %6.1f MB/s\n", "  TOTAL", (long long unsigned int)totals, (long long unsigned int)totalz, (double)totalz/(double)totals*100., (double)totals/totalc/1000., (double)totals/totald/1000.);\r
427 \r
428   if (BMK_pause) { DISPLAY("press enter...\n"); getchar(); }\r
429 \r
430   return 0;\r
431 }\r
432 \r
433 \r
434 \r