--- /dev/null
+/*\r
+ bench.c - Demo program to benchmark open-source compression algorithm\r
+ Copyright (C) Yann Collet 2012-2013\r
+ GPL v2 License\r
+\r
+ This program is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU General Public License as published by\r
+ the Free Software Foundation; either version 2 of the License, or\r
+ (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License along\r
+ with this program; if not, write to the Free Software Foundation, Inc.,\r
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+\r
+ You can contact the author at :\r
+ - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html\r
+ - LZ4 source repository : http://code.google.com/p/lz4/\r
+*/\r
+\r
+//**************************************\r
+// Compiler Options\r
+//**************************************\r
+// Disable some Visual warning messages\r
+#define _CRT_SECURE_NO_WARNINGS\r
+#define _CRT_SECURE_NO_DEPRECATE // VS2005\r
+\r
+// Unix Large Files support (>4GB)\r
+#if (defined(__sun__) && (!defined(__LP64__))) // Sun Solaris 32-bits requires specific definitions\r
+# define _LARGEFILE_SOURCE \r
+# define _FILE_OFFSET_BITS 64\r
+#elif ! defined(__LP64__) // No point defining Large file for 64 bit\r
+# define _LARGEFILE64_SOURCE\r
+#endif\r
+\r
+// S_ISREG & gettimeofday() are not supported by MSVC\r
+#if defined(_MSC_VER)\r
+# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)\r
+# define BMK_LEGACY_TIMER 1\r
+#endif\r
+\r
+// GCC does not support _rotl outside of Windows\r
+#if !defined(_WIN32)\r
+# define _rotl(x,r) ((x << r) | (x >> (32 - r)))\r
+#endif\r
+\r
+\r
+//**************************************\r
+// Includes\r
+//**************************************\r
+#include <stdlib.h> // malloc\r
+#include <stdio.h> // fprintf, fopen, ftello64\r
+#include <sys/types.h> // stat64\r
+#include <sys/stat.h> // stat64\r
+\r
+// Use ftime() if gettimeofday() is not available on your target\r
+#if defined(BMK_LEGACY_TIMER)\r
+# include <sys/timeb.h> // timeb, ftime\r
+#else\r
+# include <sys/time.h> // gettimeofday\r
+#endif\r
+\r
+#include "lz4.h"\r
+#define COMPRESSOR0 LZ4_compress\r
+#include "lz4hc.h"\r
+#define COMPRESSOR1 LZ4_compressHC\r
+#define DEFAULTCOMPRESSOR COMPRESSOR0\r
+\r
+#include "xxhash.h"\r
+\r
+\r
+//**************************************\r
+// Basic Types\r
+//**************************************\r
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99\r
+# include <stdint.h>\r
+ typedef uint8_t BYTE;\r
+ typedef uint16_t U16;\r
+ typedef uint32_t U32;\r
+ typedef int32_t S32;\r
+ typedef uint64_t U64;\r
+#else\r
+ typedef unsigned char BYTE;\r
+ typedef unsigned short U16;\r
+ typedef unsigned int U32;\r
+ typedef signed int S32;\r
+ typedef unsigned long long U64;\r
+#endif\r
+\r
+\r
+//**************************************\r
+// Constants\r
+//**************************************\r
+#define NBLOOPS 3\r
+#define TIMELOOP 2000\r
+\r
+#define KNUTH 2654435761U\r
+#define MAX_MEM (1984<<20)\r
+#define DEFAULT_CHUNKSIZE (4<<20)\r
+\r
+\r
+//**************************************\r
+// Local structures\r
+//**************************************\r
+struct chunkParameters\r
+{\r
+ U32 id;\r
+ char* origBuffer;\r
+ char* compressedBuffer;\r
+ int origSize;\r
+ int compressedSize;\r
+};\r
+\r
+struct compressionParameters\r
+{\r
+ int (*compressionFunction)(const char*, char*, int);\r
+ int (*decompressionFunction)(const char*, char*, int);\r
+};\r
+\r
+\r
+//**************************************\r
+// MACRO\r
+//**************************************\r
+#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)\r
+\r
+\r
+\r
+//**************************************\r
+// Benchmark Parameters\r
+//**************************************\r
+static int chunkSize = DEFAULT_CHUNKSIZE;\r
+static int nbIterations = NBLOOPS;\r
+static int BMK_pause = 0;\r
+\r
+void BMK_SetBlocksize(int bsize)\r
+{\r
+ chunkSize = bsize;\r
+ DISPLAY("-Using Block Size of %i KB-\n", chunkSize>>10);\r
+}\r
+\r
+void BMK_SetNbIterations(int nbLoops)\r
+{\r
+ nbIterations = nbLoops;\r
+ DISPLAY("- %i iterations -\n", nbIterations);\r
+}\r
+\r
+void BMK_SetPause()\r
+{\r
+ BMK_pause = 1;\r
+}\r
+\r
+//*********************************************************\r
+// Private functions\r
+//*********************************************************\r
+\r
+#if defined(BMK_LEGACY_TIMER)\r
+\r
+static int BMK_GetMilliStart()\r
+{\r
+ // Based on Legacy ftime()\r
+ // Rolls over every ~ 12.1 days (0x100000/24/60/60)\r
+ // Use GetMilliSpan to correct for rollover\r
+ struct timeb tb;\r
+ int nCount;\r
+ ftime( &tb );\r
+ nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);\r
+ return nCount;\r
+}\r
+\r
+#else\r
+\r
+static int BMK_GetMilliStart()\r
+{\r
+ // Based on newer gettimeofday()\r
+ // Use GetMilliSpan to correct for rollover\r
+ struct timeval tv;\r
+ int nCount;\r
+ gettimeofday(&tv, NULL);\r
+ nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);\r
+ return nCount;\r
+}\r
+\r
+#endif\r
+\r
+\r
+static int BMK_GetMilliSpan( int nTimeStart )\r
+{\r
+ int nSpan = BMK_GetMilliStart() - nTimeStart;\r
+ if ( nSpan < 0 )\r
+ nSpan += 0x100000 * 1000;\r
+ return nSpan;\r
+}\r
+\r
+\r
+static size_t BMK_findMaxMem(U64 requiredMem)\r
+{\r
+ size_t step = (64U<<20); // 64 MB\r
+ BYTE* testmem=NULL;\r
+\r
+ requiredMem = (((requiredMem >> 25) + 1) << 26);\r
+ if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;\r
+\r
+ requiredMem += 2*step;\r
+ while (!testmem)\r
+ {\r
+ requiredMem -= step;\r
+ testmem = (BYTE*) malloc ((size_t)requiredMem);\r
+ }\r
+\r
+ free (testmem);\r
+ return (size_t) (requiredMem - step);\r
+}\r
+\r
+\r
+static U64 BMK_GetFileSize(char* infilename)\r
+{\r
+ int r;\r
+#if defined(_MSC_VER)\r
+ struct _stat64 statbuf;\r
+ r = _stat64(infilename, &statbuf);\r
+#else\r
+ struct stat statbuf;\r
+ r = stat(infilename, &statbuf);\r
+#endif\r
+ if (r || !S_ISREG(statbuf.st_mode)) return 0; // No good...\r
+ return (U64)statbuf.st_size;\r
+}\r
+\r
+\r
+//*********************************************************\r
+// Public function\r
+//*********************************************************\r
+\r
+int BMK_benchFile(char** fileNamesTable, int nbFiles, int cLevel)\r
+{\r
+ int fileIdx=0;\r
+ FILE* fileIn;\r
+ char* infilename;\r
+ U64 largefilesize;\r
+ size_t benchedSize;\r
+ int nbChunks;\r
+ int maxCChunkSize;\r
+ size_t readSize;\r
+ char* orig_buff;\r
+ char* compressed_buff; int compressed_buff_size;\r
+ struct chunkParameters* chunkP;\r
+ U32 crcc, crcd=0;\r
+ struct compressionParameters compP;\r
+\r
+ U64 totals = 0;\r
+ U64 totalz = 0;\r
+ double totalc = 0.;\r
+ double totald = 0.;\r
+\r
+\r
+ // Init\r
+ switch (cLevel)\r
+ {\r
+#ifdef COMPRESSOR0\r
+ case 0 : compP.compressionFunction = COMPRESSOR0; break;\r
+#endif\r
+#ifdef COMPRESSOR1\r
+ case 1 : compP.compressionFunction = COMPRESSOR1; break;\r
+#endif\r
+ default : compP.compressionFunction = DEFAULTCOMPRESSOR;\r
+ }\r
+ compP.decompressionFunction = LZ4_decompress_fast;\r
+\r
+ // Loop for each file\r
+ while (fileIdx<nbFiles)\r
+ {\r
+ // Check file existence\r
+ infilename = fileNamesTable[fileIdx++];\r
+ fileIn = fopen( infilename, "rb" );\r
+ if (fileIn==NULL)\r
+ {\r
+ DISPLAY( "Pb opening %s\n", infilename);\r
+ return 11;\r
+ }\r
+\r
+ // Memory allocation & restrictions\r
+ largefilesize = BMK_GetFileSize(infilename);\r
+ benchedSize = (size_t) BMK_findMaxMem(largefilesize) / 2;\r
+ if ((U64)benchedSize > largefilesize) benchedSize = (size_t)largefilesize;\r
+ if (benchedSize < largefilesize)\r
+ {\r
+ DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", infilename, (int)(benchedSize>>20));\r
+ }\r
+\r
+ // Alloc\r
+ chunkP = (struct chunkParameters*) malloc(((benchedSize / chunkSize)+1) * sizeof(struct chunkParameters));\r
+ orig_buff = (char*)malloc((size_t )benchedSize);\r
+ nbChunks = (int) (benchedSize / chunkSize) + 1;\r
+ maxCChunkSize = LZ4_compressBound(chunkSize);\r
+ compressed_buff_size = nbChunks * maxCChunkSize;\r
+ compressed_buff = (char*)malloc((size_t )compressed_buff_size);\r
+\r
+\r
+ if(!orig_buff || !compressed_buff)\r
+ {\r
+ DISPLAY("\nError: not enough memory!\n");\r
+ free(orig_buff);\r
+ free(compressed_buff);\r
+ fclose(fileIn);\r
+ return 12;\r
+ }\r
+\r
+ // Init chunks data\r
+ {\r
+ int i;\r
+ size_t remaining = benchedSize;\r
+ char* in = orig_buff;\r
+ char* out = compressed_buff;\r
+ for (i=0; i<nbChunks; i++)\r
+ {\r
+ chunkP[i].id = i;\r
+ chunkP[i].origBuffer = in; in += chunkSize;\r
+ if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }\r
+ chunkP[i].compressedBuffer = out; out += maxCChunkSize;\r
+ chunkP[i].compressedSize = 0;\r
+ }\r
+ }\r
+\r
+ // Fill input buffer\r
+ DISPLAY("Loading %s... \r", infilename);\r
+ readSize = fread(orig_buff, 1, benchedSize, fileIn);\r
+ fclose(fileIn);\r
+\r
+ if(readSize != benchedSize)\r
+ {\r
+ DISPLAY("\nError: problem reading file '%s' !! \n", infilename);\r
+ free(orig_buff);\r
+ free(compressed_buff);\r
+ return 13;\r
+ }\r
+\r
+ // Calculating input Checksum\r
+ crcc = XXH32(orig_buff, (unsigned int)benchedSize,0);\r
+\r
+\r
+ // Bench\r
+ {\r
+ int loopNb, nb_loops, chunkNb;\r
+ size_t cSize=0;\r
+ int milliTime;\r
+ double fastestC = 100000000., fastestD = 100000000.;\r
+ double ratio=0.;\r
+\r
+ DISPLAY("\r%79s\r", "");\r
+ for (loopNb = 1; loopNb <= nbIterations; loopNb++)\r
+ {\r
+ // Compression\r
+ DISPLAY("%1i-%-14.14s : %9i ->\r", loopNb, infilename, (int)benchedSize);\r
+ { size_t i; for (i=0; i<benchedSize; i++) compressed_buff[i]=(char)i; } // warmimg up memory\r
+\r
+ nb_loops = 0;\r
+ milliTime = BMK_GetMilliStart();\r
+ while(BMK_GetMilliStart() == milliTime);\r
+ milliTime = BMK_GetMilliStart();\r
+ while(BMK_GetMilliSpan(milliTime) < TIMELOOP)\r
+ {\r
+ for (chunkNb=0; chunkNb<nbChunks; chunkNb++)\r
+ chunkP[chunkNb].compressedSize = compP.compressionFunction(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize);\r
+ nb_loops++;\r
+ }\r
+ milliTime = BMK_GetMilliSpan(milliTime);\r
+\r
+ if ((double)milliTime < fastestC*nb_loops) fastestC = (double)milliTime/nb_loops;\r
+ cSize=0; for (chunkNb=0; chunkNb<nbChunks; chunkNb++) cSize += chunkP[chunkNb].compressedSize;\r
+ ratio = (double)cSize/(double)benchedSize*100.;\r
+\r
+ 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
+\r
+ // Decompression\r
+ { size_t i; for (i=0; i<benchedSize; i++) orig_buff[i]=0; } // zeroing area, for CRC checking\r
+\r
+ nb_loops = 0;\r
+ milliTime = BMK_GetMilliStart();\r
+ while(BMK_GetMilliStart() == milliTime);\r
+ milliTime = BMK_GetMilliStart();\r
+ while(BMK_GetMilliSpan(milliTime) < TIMELOOP)\r
+ {\r
+ for (chunkNb=0; chunkNb<nbChunks; chunkNb++)\r
+ //chunkP[chunkNb].origSize = LZ4_decompress_safe(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkSize);\r
+ chunkP[chunkNb].compressedSize = LZ4_decompress_fast(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].origSize);\r
+ //chunkP[chunkNb].compressedSize = LZ4_decompress_fast_withPrefix64k(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].origSize);\r
+ //chunkP[chunkNb].origSize = LZ4_decompress_safe_withPrefix64k(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkSize);\r
+ //chunkP[chunkNb].origSize = LZ4_decompress_safe_partial(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkSize-5, chunkSize);\r
+ //chunkP[chunkNb].compressedSize = LZ4_uncompress(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].origSize);\r
+ //chunkP[chunkNb].origSize = LZ4_uncompress_unknownOutputSize(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkSize);\r
+ nb_loops++;\r
+ }\r
+ milliTime = BMK_GetMilliSpan(milliTime);\r
+\r
+ if ((double)milliTime < fastestD*nb_loops) fastestD = (double)milliTime/nb_loops;\r
+ 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
+\r
+ // CRC Checking\r
+ crcd = XXH32(orig_buff, (unsigned int)benchedSize,0);\r
+ if (crcc!=crcd) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", infilename, (unsigned)crcc, (unsigned)crcd); break; }\r
+ }\r
+\r
+ if (crcc==crcd)\r
+ {\r
+ if (ratio<100.)\r
+ 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
+ else\r
+ 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
+ }\r
+ totals += benchedSize;\r
+ totalz += cSize;\r
+ totalc += fastestC;\r
+ totald += fastestD;\r
+ }\r
+\r
+ free(orig_buff);\r
+ free(compressed_buff);\r
+ free(chunkP);\r
+ }\r
+\r
+ if (nbFiles > 1)\r
+ 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
+\r
+ if (BMK_pause) { DISPLAY("press enter...\n"); getchar(); }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+\r