CMSIS2000  0.0.7
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bench.c
Go to the documentation of this file.
1 /*
2  bench.c - Demo program to benchmark open-source compression algorithm
3  Copyright (C) Yann Collet 2012
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 homepage : http://fastcompression.blogspot.com/p/lz4.html
22  - LZ4 source repository : http://code.google.com/p/lz4/
23 */
24 
25 //**************************************
26 // Compiler Options
27 //**************************************
28 // Disable some Visual warning messages
29 #define _CRT_SECURE_NO_WARNINGS
30 #define _CRT_SECURE_NO_DEPRECATE // VS2005
31 
32 // Unix Large Files support (>4GB)
33 #if (defined(__sun__) && (!defined(__LP64__))) // Sun Solaris 32-bits requires specific definitions
34 # define _LARGEFILE_SOURCE
35 # define FILE_OFFSET_BITS=64
36 #elif ! defined(__LP64__) // No point defining Large file for 64 bit
37 # define _LARGEFILE64_SOURCE
38 #endif
39 
40 // S_ISREG & gettimeofday() are not supported by MSVC
41 #if defined(_MSC_VER)
42 # define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
43 # define BMK_LEGACY_TIMER 1
44 #endif
45 
46 // GCC does not support _rotl outside of Windows
47 #if !defined(_WIN32)
48 # define _rotl(x,r) ((x << r) | (x >> (32 - r)))
49 #endif
50 
51 
52 //**************************************
53 // Includes
54 //**************************************
55 #include <stdlib.h> // malloc
56 #include <stdio.h> // fprintf, fopen, ftello64
57 #include <sys/types.h> // stat64
58 #include <sys/stat.h> // stat64
59 
60 // Use ftime() if gettimeofday() is not available on your target
61 #if defined(BMK_LEGACY_TIMER)
62 # include <sys/timeb.h> // timeb, ftime
63 #else
64 # include <sys/time.h> // gettimeofday
65 #endif
66 
67 #include "lz4.h"
68 #define COMPRESSOR0 LZ4_compress
69 #include "lz4hc.h"
70 #define COMPRESSOR1 LZ4_compressHC
71 #define DEFAULTCOMPRESSOR LZ4_compress
72 
73 
74 
75 //**************************************
76 // Basic Types
77 //**************************************
78 #if defined(_MSC_VER) // Visual Studio does not support 'stdint' natively
79 #define BYTE unsigned __int8
80 #define U16 unsigned __int16
81 #define U32 unsigned __int32
82 #define S32 __int32
83 #define U64 unsigned __int64
84 #else
85 #include <stdint.h>
86 #define BYTE uint8_t
87 #define U16 uint16_t
88 #define U32 uint32_t
89 #define S32 int32_t
90 #define U64 uint64_t
91 #endif
92 
93 
94 //**************************************
95 // Constants
96 //**************************************
97 #define NBLOOPS 3
98 #define TIMELOOP 2000
99 
100 #define KNUTH 2654435761U
101 #define MAX_MEM (1984<<20)
102 #define DEFAULT_CHUNKSIZE (8<<20)
103 
104 
105 //**************************************
106 // Local structures
107 //**************************************
109 {
111  char* inputBuffer;
115 };
116 
118 {
119  int (*compressionFunction)(const char*, char*, int);
120  int (*decompressionFunction)(const char*, char*, int);
121 };
122 
123 
124 //**************************************
125 // MACRO
126 //**************************************
127 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
128 
129 
130 
131 //**************************************
132 // Benchmark Parameters
133 //**************************************
135 static int nbIterations = NBLOOPS;
136 static int BMK_pause = 0;
137 
138 void BMK_SetBlocksize(int bsize)
139 {
140  chunkSize = bsize;
141  DISPLAY("-Using Block Size of %i KB-", chunkSize>>10);
142 }
143 
144 void BMK_SetNbIterations(int nbLoops)
145 {
146  nbIterations = nbLoops;
147  DISPLAY("- %i iterations-", nbIterations);
148 }
149 
151 {
152  BMK_pause = 1;
153 }
154 
155 //*********************************************************
156 // Private functions
157 //*********************************************************
158 
159 #if defined(BMK_LEGACY_TIMER)
160 
161 static int BMK_GetMilliStart()
162 {
163  // Based on Legacy ftime()
164  // Rolls over every ~ 12.1 days (0x100000/24/60/60)
165  // Use GetMilliSpan to correct for rollover
166  struct timeb tb;
167  int nCount;
168  ftime( &tb );
169  nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
170  return nCount;
171 }
172 
173 #else
174 
175 static int BMK_GetMilliStart()
176 {
177  // Based on newer gettimeofday()
178  // Use GetMilliSpan to correct for rollover
179  struct timeval tv;
180  int nCount;
181  gettimeofday(&tv, NULL);
182  nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
183  return nCount;
184 }
185 
186 #endif
187 
188 
189 static int BMK_GetMilliSpan( int nTimeStart )
190 {
191  int nSpan = BMK_GetMilliStart() - nTimeStart;
192  if ( nSpan < 0 )
193  nSpan += 0x100000 * 1000;
194  return nSpan;
195 }
196 
197 
198 static U32 BMK_checksum_MMH3A (char* buff, U32 length)
199 {
200  const BYTE* data = (const BYTE*)buff;
201  const int nblocks = length >> 2;
202 
203  U32 h1 = KNUTH;
204  U32 c1 = 0xcc9e2d51;
205  U32 c2 = 0x1b873593;
206 
207  const U32* blocks = (const U32*)(data + nblocks*4);
208  int i;
209 
210  for(i = -nblocks; i; i++)
211  {
212  U32 k1 = blocks[i];
213 
214  k1 *= c1;
215  k1 = _rotl(k1,15);
216  k1 *= c2;
217 
218  h1 ^= k1;
219  h1 = _rotl(h1,13);
220  h1 = h1*5+0xe6546b64;
221  }
222 
223  {
224  const BYTE* tail = (const BYTE*)(data + nblocks*4);
225  U32 k1 = 0;
226 
227  switch(length & 3)
228  {
229  case 3: k1 ^= tail[2] << 16;
230  case 2: k1 ^= tail[1] << 8;
231  case 1: k1 ^= tail[0];
232  k1 *= c1; k1 = _rotl(k1,15); k1 *= c2; h1 ^= k1;
233  };
234  }
235 
236  h1 ^= length;
237  h1 ^= h1 >> 16;
238  h1 *= 0x85ebca6b;
239  h1 ^= h1 >> 13;
240  h1 *= 0xc2b2ae35;
241  h1 ^= h1 >> 16;
242 
243  return h1;
244 }
245 
246 
247 static size_t BMK_findMaxMem(U64 requiredMem)
248 {
249  size_t step = (64U<<20); // 64 MB
250  BYTE* testmem=NULL;
251 
252  requiredMem = (((requiredMem >> 25) + 1) << 26);
253  if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
254 
255  requiredMem += 2*step;
256  while (!testmem)
257  {
258  requiredMem -= step;
259  testmem = malloc ((size_t)requiredMem);
260  }
261 
262  free (testmem);
263  return (size_t) (requiredMem - step);
264 }
265 
266 
267 static U64 BMK_GetFileSize(char* infilename)
268 {
269  int r;
270 #if defined(_MSC_VER)
271  struct _stat64 statbuf;
272  r = _stat64(infilename, &statbuf);
273 #else
274  struct stat statbuf;
275  r = stat(infilename, &statbuf);
276 #endif
277  if (r || !S_ISREG(statbuf.st_mode)) return 0; // No good...
278  return (U64)statbuf.st_size;
279 }
280 
281 
282 //*********************************************************
283 // Public function
284 //*********************************************************
285 
286 int BMK_benchFile(char** fileNamesTable, int nbFiles, int cLevel)
287 {
288  int fileIdx=0;
289  FILE* fileIn;
290  char* infilename;
291  U64 largefilesize;
292  size_t benchedsize;
293  int nbChunks;
294  int maxCChunkSize;
295  size_t readSize;
296  char* in_buff;
297  char* out_buff; int out_buff_size;
298  struct chunkParameters* chunkP;
299  U32 crcc, crcd=0;
300  struct compressionParameters compP;
301 
302  U64 totals = 0;
303  U64 totalz = 0;
304  double totalc = 0.;
305  double totald = 0.;
306 
307 
308  // Init
309  switch (cLevel)
310  {
311 #ifdef COMPRESSOR0
312  case 0 : compP.compressionFunction = COMPRESSOR0; break;
313 #endif
314 #ifdef COMPRESSOR1
315  case 1 : compP.compressionFunction = COMPRESSOR1; break;
316 #endif
317  default : compP.compressionFunction = DEFAULTCOMPRESSOR;
318  }
320 
321  // Loop for each file
322  while (fileIdx<nbFiles)
323  {
324  // Check file existence
325  infilename = fileNamesTable[fileIdx++];
326  fileIn = fopen( infilename, "rb" );
327  if (fileIn==NULL)
328  {
329  DISPLAY( "Pb opening %s\n", infilename);
330  return 11;
331  }
332 
333  // Memory allocation & restrictions
334  largefilesize = BMK_GetFileSize(infilename);
335  benchedsize = (size_t) BMK_findMaxMem(largefilesize) / 2;
336  if ((U64)benchedsize > largefilesize) benchedsize = (size_t)largefilesize;
337  if (benchedsize < largefilesize)
338  {
339  DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", infilename, (int)(benchedsize>>20));
340  }
341 
342  // Alloc
343  chunkP = (struct chunkParameters*) malloc(((benchedsize / chunkSize)+1) * sizeof(struct chunkParameters));
344  in_buff = malloc((size_t )benchedsize);
345  nbChunks = (int) (benchedsize / chunkSize) + 1;
346  maxCChunkSize = LZ4_compressBound(chunkSize);
347  out_buff_size = nbChunks * maxCChunkSize;
348  out_buff = malloc((size_t )out_buff_size);
349 
350 
351  if(!in_buff || !out_buff)
352  {
353  DISPLAY("\nError: not enough memory!\n");
354  free(in_buff);
355  free(out_buff);
356  fclose(fileIn);
357  return 12;
358  }
359 
360  // Init chunks data
361  {
362  int i;
363  size_t remaining = benchedsize;
364  char* in = in_buff;
365  char* out = out_buff;
366  for (i=0; i<nbChunks; i++)
367  {
368  chunkP[i].id = i;
369  chunkP[i].inputBuffer = in; in += chunkSize;
370  if ((int)remaining > chunkSize) { chunkP[i].inputSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].inputSize = (int)remaining; remaining = 0; }
371  chunkP[i].outputBuffer = out; out += maxCChunkSize;
372  chunkP[i].outputSize = 0;
373  }
374  }
375 
376  // Fill input buffer
377  DISPLAY("Loading %s... \r", infilename);
378  readSize = fread(in_buff, 1, benchedsize, fileIn);
379  fclose(fileIn);
380 
381  if(readSize != benchedsize)
382  {
383  DISPLAY("\nError: problem reading file '%s' !! \n", infilename);
384  free(in_buff);
385  free(out_buff);
386  return 13;
387  }
388 
389  // Calculating input Checksum
390  crcc = BMK_checksum_MMH3A(in_buff, (unsigned int)benchedsize);
391 
392 
393  // Bench
394  {
395  int loopNb, nb_loops, chunkNb;
396  size_t cSize=0;
397  int milliTime;
398  double fastestC = 100000000., fastestD = 100000000.;
399  double ratio=0.;
400 
401  DISPLAY("\r%79s\r", "");
402  for (loopNb = 1; loopNb <= nbIterations; loopNb++)
403  {
404  // Compression
405  DISPLAY("%1i-%-14.14s : %9i ->\r", loopNb, infilename, (int)benchedsize);
406  { size_t i; for (i=0; i<benchedsize; i++) out_buff[i]=(char)i; } // warmimg up memory
407 
408  nb_loops = 0;
409  milliTime = BMK_GetMilliStart();
410  while(BMK_GetMilliStart() == milliTime);
411  milliTime = BMK_GetMilliStart();
412  while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
413  {
414  for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
415  chunkP[chunkNb].outputSize = compP.compressionFunction(chunkP[chunkNb].inputBuffer, chunkP[chunkNb].outputBuffer, chunkP[chunkNb].inputSize);
416  nb_loops++;
417  }
418  milliTime = BMK_GetMilliSpan(milliTime);
419 
420  if ((double)milliTime < fastestC*nb_loops) fastestC = (double)milliTime/nb_loops;
421  cSize=0; for (chunkNb=0; chunkNb<nbChunks; chunkNb++) cSize += chunkP[chunkNb].outputSize;
422  ratio = (double)cSize/(double)benchedsize*100.;
423 
424  DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%),%7.1f MB/s\r", loopNb, infilename, (int)benchedsize, (int)cSize, ratio, (double)benchedsize / fastestC / 1000.);
425 
426  // Decompression
427  { size_t i; for (i=0; i<benchedsize; i++) in_buff[i]=0; } // zeroing area, for CRC checking
428 
429  nb_loops = 0;
430  milliTime = BMK_GetMilliStart();
431  while(BMK_GetMilliStart() == milliTime);
432  milliTime = BMK_GetMilliStart();
433  while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
434  {
435  for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
436  chunkP[chunkNb].outputSize = LZ4_uncompress(chunkP[chunkNb].outputBuffer, chunkP[chunkNb].inputBuffer, chunkP[chunkNb].inputSize);
437  //chunkP[chunkNb].inputSize = LZ4_uncompress_unknownOutputSize(chunkP[chunkNb].outputBuffer, chunkP[chunkNb].inputBuffer, chunkP[chunkNb].outputSize, chunkSize);
438  nb_loops++;
439  }
440  milliTime = BMK_GetMilliSpan(milliTime);
441 
442  if ((double)milliTime < fastestD*nb_loops) fastestD = (double)milliTime/nb_loops;
443  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.);
444 
445  // CRC Checking
446  crcd = BMK_checksum_MMH3A(in_buff, (unsigned int)benchedsize);
447  if (crcc!=crcd) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", infilename, (unsigned)crcc, (unsigned)crcd); break; }
448  }
449 
450  if (crcc==crcd)
451  {
452  if (ratio<100.)
453  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.);
454  else
455  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.);
456  }
457  totals += benchedsize;
458  totalz += cSize;
459  totalc += fastestC;
460  totald += fastestD;
461  }
462 
463  free(in_buff);
464  free(out_buff);
465  free(chunkP);
466  }
467 
468  if (nbFiles > 1)
469  printf("%-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.);
470 
471  if (BMK_pause) { printf("press enter...\n"); getchar(); }
472 
473  return 0;
474 }
475 
476 
477