Home | History | Annotate | Download | only in programs
      1 /*
      2     bench.c - Demo program to benchmark open-source compression algorithm
      3     Copyright (C) Yann Collet 2012-2015
      4 
      5     GPL v2 License
      6 
      7     This program is free software; you can redistribute it and/or modify
      8     it under the terms of the GNU General Public License as published by
      9     the Free Software Foundation; either version 2 of the License, or
     10     (at your option) any later version.
     11 
     12     This program is distributed in the hope that it will be useful,
     13     but WITHOUT ANY WARRANTY; without even the implied warranty of
     14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15     GNU General Public License for more details.
     16 
     17     You should have received a copy of the GNU General Public License along
     18     with this program; if not, write to the Free Software Foundation, Inc.,
     19     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     20 
     21     You can contact the author at :
     22     - LZ4 source repository : http://code.google.com/p/lz4
     23     - LZ4 source mirror : https://github.com/Cyan4973/lz4
     24     - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
     25 */
     26 
     27 //**************************************
     28 // Compiler Options
     29 //**************************************
     30 // Disable some Visual warning messages
     31 #define _CRT_SECURE_NO_WARNINGS
     32 #define _CRT_SECURE_NO_DEPRECATE     // VS2005
     33 
     34 // Unix Large Files support (>4GB)
     35 #if (defined(__sun__) && (!defined(__LP64__)))   // Sun Solaris 32-bits requires specific definitions
     36 #  define _LARGEFILE_SOURCE
     37 #  define _FILE_OFFSET_BITS 64
     38 #elif ! defined(__LP64__)                        // No point defining Large file for 64 bit
     39 #  define _LARGEFILE64_SOURCE
     40 #endif
     41 
     42 // S_ISREG & gettimeofday() are not supported by MSVC
     43 #if defined(_MSC_VER) || defined(_WIN32)
     44 #  define BMK_LEGACY_TIMER 1
     45 #endif
     46 
     47 
     48 //**************************************
     49 // Includes
     50 //**************************************
     51 #include <stdlib.h>      // malloc
     52 #include <stdio.h>       // fprintf, fopen, ftello64
     53 #include <sys/types.h>   // stat64
     54 #include <sys/stat.h>    // stat64
     55 #include <string.h>      // strcmp
     56 
     57 // Use ftime() if gettimeofday() is not available on your target
     58 #if defined(BMK_LEGACY_TIMER)
     59 #  include <sys/timeb.h>   // timeb, ftime
     60 #else
     61 #  include <sys/time.h>    // gettimeofday
     62 #endif
     63 
     64 #include "lz4.h"
     65 #include "lz4hc.h"
     66 #include "lz4frame.h"
     67 
     68 #include "xxhash.h"
     69 
     70 
     71 //**************************************
     72 // Compiler Options
     73 //**************************************
     74 // S_ISREG & gettimeofday() are not supported by MSVC
     75 #if !defined(S_ISREG)
     76 #  define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
     77 #endif
     78 
     79 // GCC does not support _rotl outside of Windows
     80 #if !defined(_WIN32)
     81 #  define _rotl(x,r) ((x << r) | (x >> (32 - r)))
     82 #endif
     83 
     84 
     85 //**************************************
     86 // Basic Types
     87 //**************************************
     88 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   // C99
     89 # include <stdint.h>
     90   typedef uint8_t  BYTE;
     91   typedef uint16_t U16;
     92   typedef uint32_t U32;
     93   typedef  int32_t S32;
     94   typedef uint64_t U64;
     95 #else
     96   typedef unsigned char       BYTE;
     97   typedef unsigned short      U16;
     98   typedef unsigned int        U32;
     99   typedef   signed int        S32;
    100   typedef unsigned long long  U64;
    101 #endif
    102 
    103 
    104 //****************************
    105 // Constants
    106 //****************************
    107 #define PROGRAM_DESCRIPTION "LZ4 speed analyzer"
    108 #ifndef LZ4_VERSION
    109 #  define LZ4_VERSION ""
    110 #endif
    111 #define AUTHOR "Yann Collet"
    112 #define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", PROGRAM_DESCRIPTION, LZ4_VERSION, (int)(sizeof(void*)*8), AUTHOR, __DATE__
    113 
    114 #define NBLOOPS    6
    115 #define TIMELOOP   2500
    116 
    117 #define KNUTH      2654435761U
    118 #define MAX_MEM    (1984<<20)
    119 #define DEFAULT_CHUNKSIZE   (4<<20)
    120 
    121 #define ALL_COMPRESSORS 0
    122 #define ALL_DECOMPRESSORS 0
    123 
    124 
    125 //**************************************
    126 // Local structures
    127 //**************************************
    128 struct chunkParameters
    129 {
    130     U32   id;
    131     char* origBuffer;
    132     char* compressedBuffer;
    133     int   origSize;
    134     int   compressedSize;
    135 };
    136 
    137 
    138 //**************************************
    139 // MACRO
    140 //**************************************
    141 #define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
    142 #define PROGRESS(...) no_prompt ? 0 : DISPLAY(__VA_ARGS__)
    143 
    144 
    145 
    146 //**************************************
    147 // Benchmark Parameters
    148 //**************************************
    149 static int chunkSize = DEFAULT_CHUNKSIZE;
    150 static int nbIterations = NBLOOPS;
    151 static int BMK_pause = 0;
    152 static int compressionTest = 1;
    153 static int decompressionTest = 1;
    154 static int compressionAlgo = ALL_COMPRESSORS;
    155 static int decompressionAlgo = ALL_DECOMPRESSORS;
    156 static int no_prompt = 0;
    157 
    158 void BMK_SetBlocksize(int bsize)
    159 {
    160     chunkSize = bsize;
    161     DISPLAY("-Using Block Size of %i KB-\n", chunkSize>>10);
    162 }
    163 
    164 void BMK_SetNbIterations(int nbLoops)
    165 {
    166     nbIterations = nbLoops;
    167     DISPLAY("- %i iterations -\n", nbIterations);
    168 }
    169 
    170 void BMK_SetPause(void)
    171 {
    172     BMK_pause = 1;
    173 }
    174 
    175 //*********************************************************
    176 //  Private functions
    177 //*********************************************************
    178 
    179 #if defined(BMK_LEGACY_TIMER)
    180 
    181 static int BMK_GetMilliStart(void)
    182 {
    183   // Based on Legacy ftime()
    184   // Rolls over every ~ 12.1 days (0x100000/24/60/60)
    185   // Use GetMilliSpan to correct for rollover
    186   struct timeb tb;
    187   int nCount;
    188   ftime( &tb );
    189   nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
    190   return nCount;
    191 }
    192 
    193 #else
    194 
    195 static int BMK_GetMilliStart(void)
    196 {
    197   // Based on newer gettimeofday()
    198   // Use GetMilliSpan to correct for rollover
    199   struct timeval tv;
    200   int nCount;
    201   gettimeofday(&tv, NULL);
    202   nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
    203   return nCount;
    204 }
    205 
    206 #endif
    207 
    208 
    209 static int BMK_GetMilliSpan( int nTimeStart )
    210 {
    211   int nSpan = BMK_GetMilliStart() - nTimeStart;
    212   if ( nSpan < 0 )
    213     nSpan += 0x100000 * 1000;
    214   return nSpan;
    215 }
    216 
    217 
    218 static size_t BMK_findMaxMem(U64 requiredMem)
    219 {
    220     size_t step = (64U<<20);   // 64 MB
    221     BYTE* testmem=NULL;
    222 
    223     requiredMem = (((requiredMem >> 25) + 1) << 26);
    224     if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
    225 
    226     requiredMem += 2*step;
    227     while (!testmem)
    228     {
    229         requiredMem -= step;
    230         testmem = (BYTE*) malloc ((size_t)requiredMem);
    231     }
    232 
    233     free (testmem);
    234     return (size_t) (requiredMem - step);
    235 }
    236 
    237 
    238 static U64 BMK_GetFileSize(char* infilename)
    239 {
    240     int r;
    241 #if defined(_MSC_VER)
    242     struct _stat64 statbuf;
    243     r = _stat64(infilename, &statbuf);
    244 #else
    245     struct stat statbuf;
    246     r = stat(infilename, &statbuf);
    247 #endif
    248     if (r || !S_ISREG(statbuf.st_mode)) return 0;   // No good...
    249     return (U64)statbuf.st_size;
    250 }
    251 
    252 
    253 /*********************************************************
    254   Benchmark function
    255 *********************************************************/
    256 
    257 static int local_LZ4_compress_limitedOutput(const char* in, char* out, int inSize)
    258 {
    259     return LZ4_compress_limitedOutput(in, out, inSize, LZ4_compressBound(inSize));
    260 }
    261 
    262 static void* stateLZ4;
    263 static int local_LZ4_compress_withState(const char* in, char* out, int inSize)
    264 {
    265     return LZ4_compress_withState(stateLZ4, in, out, inSize);
    266 }
    267 
    268 static int local_LZ4_compress_limitedOutput_withState(const char* in, char* out, int inSize)
    269 {
    270     return LZ4_compress_limitedOutput_withState(stateLZ4, in, out, inSize, LZ4_compressBound(inSize));
    271 }
    272 
    273 static LZ4_stream_t* ctx;
    274 static int local_LZ4_compress_continue(const char* in, char* out, int inSize)
    275 {
    276     return LZ4_compress_continue(ctx, in, out, inSize);
    277 }
    278 
    279 static int local_LZ4_compress_limitedOutput_continue(const char* in, char* out, int inSize)
    280 {
    281     return LZ4_compress_limitedOutput_continue(ctx, in, out, inSize, LZ4_compressBound(inSize));
    282 }
    283 
    284 
    285 LZ4_stream_t LZ4_dict;
    286 static void* local_LZ4_resetDictT(const char* fake)
    287 {
    288     (void)fake;
    289     memset(&LZ4_dict, 0, sizeof(LZ4_stream_t));
    290     return NULL;
    291 }
    292 
    293 int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize);
    294 static int local_LZ4_compress_forceDict(const char* in, char* out, int inSize)
    295 {
    296     return LZ4_compress_forceExtDict(&LZ4_dict, in, out, inSize);
    297 }
    298 
    299 
    300 static void* stateLZ4HC;
    301 static int local_LZ4_compressHC_withStateHC(const char* in, char* out, int inSize)
    302 {
    303     return LZ4_compressHC_withStateHC(stateLZ4HC, in, out, inSize);
    304 }
    305 
    306 static int local_LZ4_compressHC_limitedOutput_withStateHC(const char* in, char* out, int inSize)
    307 {
    308     return LZ4_compressHC_limitedOutput_withStateHC(stateLZ4HC, in, out, inSize, LZ4_compressBound(inSize));
    309 }
    310 
    311 static int local_LZ4_compressHC_limitedOutput(const char* in, char* out, int inSize)
    312 {
    313     return LZ4_compressHC_limitedOutput(in, out, inSize, LZ4_compressBound(inSize));
    314 }
    315 
    316 static int local_LZ4_compressHC_continue(const char* in, char* out, int inSize)
    317 {
    318     return LZ4_compressHC_continue((LZ4_streamHC_t*)ctx, in, out, inSize);
    319 }
    320 
    321 static int local_LZ4_compressHC_limitedOutput_continue(const char* in, char* out, int inSize)
    322 {
    323     return LZ4_compressHC_limitedOutput_continue((LZ4_streamHC_t*)ctx, in, out, inSize, LZ4_compressBound(inSize));
    324 }
    325 
    326 static int local_LZ4F_compressFrame(const char* in, char* out, int inSize)
    327 {
    328     return (int)LZ4F_compressFrame(out, 2*inSize + 16, in, inSize, NULL);
    329 }
    330 
    331 static int local_LZ4_saveDict(const char* in, char* out, int inSize)
    332 {
    333     (void)in;
    334     return LZ4_saveDict(&LZ4_dict, out, inSize);
    335 }
    336 
    337 LZ4_streamHC_t LZ4_dictHC;
    338 static int local_LZ4_saveDictHC(const char* in, char* out, int inSize)
    339 {
    340     (void)in;
    341     return LZ4_saveDictHC(&LZ4_dictHC, out, inSize);
    342 }
    343 
    344 
    345 static int local_LZ4_decompress_fast(const char* in, char* out, int inSize, int outSize)
    346 {
    347     (void)inSize;
    348     LZ4_decompress_fast(in, out, outSize);
    349     return outSize;
    350 }
    351 
    352 static int local_LZ4_decompress_fast_withPrefix64k(const char* in, char* out, int inSize, int outSize)
    353 {
    354     (void)inSize;
    355     LZ4_decompress_fast_withPrefix64k(in, out, outSize);
    356     return outSize;
    357 }
    358 
    359 static int local_LZ4_decompress_fast_usingDict(const char* in, char* out, int inSize, int outSize)
    360 {
    361     (void)inSize;
    362     LZ4_decompress_fast_usingDict(in, out, outSize, out - 65536, 65536);
    363     return outSize;
    364 }
    365 
    366 static int local_LZ4_decompress_safe_usingDict(const char* in, char* out, int inSize, int outSize)
    367 {
    368     (void)inSize;
    369     LZ4_decompress_safe_usingDict(in, out, inSize, outSize, out - 65536, 65536);
    370     return outSize;
    371 }
    372 
    373 extern int LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSize, int outSize, const char* dict, int dictSize);
    374 
    375 static int local_LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSize, int outSize)
    376 {
    377     (void)inSize;
    378     LZ4_decompress_safe_forceExtDict(in, out, inSize, outSize, out - 65536, 65536);
    379     return outSize;
    380 }
    381 
    382 static int local_LZ4_decompress_safe_partial(const char* in, char* out, int inSize, int outSize)
    383 {
    384     return LZ4_decompress_safe_partial(in, out, inSize, outSize - 5, outSize);
    385 }
    386 
    387 static LZ4F_decompressionContext_t g_dCtx;
    388 
    389 static int local_LZ4F_decompress(const char* in, char* out, int inSize, int outSize)
    390 {
    391     size_t srcSize = inSize;
    392     size_t dstSize = outSize;
    393     size_t result;
    394     result = LZ4F_decompress(g_dCtx, out, &dstSize, in, &srcSize, NULL);
    395     if (result!=0) { DISPLAY("Error decompressing frame : unfinished frame\n"); exit(8); }
    396     if (srcSize != (size_t)inSize) { DISPLAY("Error decompressing frame : read size incorrect\n"); exit(9); }
    397     return (int)dstSize;
    398 }
    399 
    400 
    401 int fullSpeedBench(char** fileNamesTable, int nbFiles)
    402 {
    403   int fileIdx=0;
    404   char* orig_buff;
    405 # define NB_COMPRESSION_ALGORITHMS 16
    406   double totalCTime[NB_COMPRESSION_ALGORITHMS+1] = {0};
    407   double totalCSize[NB_COMPRESSION_ALGORITHMS+1] = {0};
    408 # define NB_DECOMPRESSION_ALGORITHMS 9
    409   double totalDTime[NB_DECOMPRESSION_ALGORITHMS+1] = {0};
    410   size_t errorCode;
    411 
    412   errorCode = LZ4F_createDecompressionContext(&g_dCtx, LZ4F_VERSION);
    413   if (LZ4F_isError(errorCode))
    414   {
    415      DISPLAY("dctx allocation issue \n");
    416      return 10;
    417   }
    418 
    419   // Loop for each file
    420   while (fileIdx<nbFiles)
    421   {
    422       FILE* inFile;
    423       char* inFileName;
    424       U64   inFileSize;
    425       size_t benchedSize;
    426       int nbChunks;
    427       int maxCompressedChunkSize;
    428       struct chunkParameters* chunkP;
    429       size_t readSize;
    430       char* compressed_buff; int compressedBuffSize;
    431       U32 crcOriginal;
    432 
    433 
    434       // Init
    435       stateLZ4   = LZ4_createStream();
    436       stateLZ4HC = LZ4_createStreamHC();
    437 
    438       // Check file existence
    439       inFileName = fileNamesTable[fileIdx++];
    440       inFile = fopen( inFileName, "rb" );
    441       if (inFile==NULL)
    442       {
    443         DISPLAY( "Pb opening %s\n", inFileName);
    444         return 11;
    445       }
    446 
    447       // Memory allocation & restrictions
    448       inFileSize = BMK_GetFileSize(inFileName);
    449       benchedSize = (size_t) BMK_findMaxMem(inFileSize) / 2;
    450       if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
    451       if (benchedSize < inFileSize)
    452       {
    453           DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
    454       }
    455 
    456       // Alloc
    457       chunkP = (struct chunkParameters*) malloc(((benchedSize / (size_t)chunkSize)+1) * sizeof(struct chunkParameters));
    458       orig_buff = (char*) malloc((size_t)benchedSize);
    459       nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
    460       maxCompressedChunkSize = LZ4_compressBound(chunkSize);
    461       compressedBuffSize = nbChunks * maxCompressedChunkSize;
    462       compressed_buff = (char*)malloc((size_t)compressedBuffSize);
    463 
    464 
    465       if(!orig_buff || !compressed_buff)
    466       {
    467         DISPLAY("\nError: not enough memory!\n");
    468         free(orig_buff);
    469         free(compressed_buff);
    470         free(chunkP);
    471         fclose(inFile);
    472         return 12;
    473       }
    474 
    475       // Fill input buffer
    476       DISPLAY("Loading %s...       \r", inFileName);
    477       readSize = fread(orig_buff, 1, benchedSize, inFile);
    478       fclose(inFile);
    479 
    480       if(readSize != benchedSize)
    481       {
    482         DISPLAY("\nError: problem reading file '%s' !!    \n", inFileName);
    483         free(orig_buff);
    484         free(compressed_buff);
    485         free(chunkP);
    486         return 13;
    487       }
    488 
    489       // Calculating input Checksum
    490       crcOriginal = XXH32(orig_buff, (unsigned int)benchedSize,0);
    491 
    492 
    493       // Bench
    494       {
    495         int loopNb, nb_loops, chunkNb, cAlgNb, dAlgNb;
    496         size_t cSize=0;
    497         double ratio=0.;
    498 
    499         DISPLAY("\r%79s\r", "");
    500         DISPLAY(" %s : \n", inFileName);
    501 
    502         // Compression Algorithms
    503         for (cAlgNb=1; (cAlgNb <= NB_COMPRESSION_ALGORITHMS) && (compressionTest); cAlgNb++)
    504         {
    505             const char* compressorName;
    506             int (*compressionFunction)(const char*, char*, int);
    507             void* (*initFunction)(const char*) = NULL;
    508             double bestTime = 100000000.;
    509 
    510             // Init data chunks
    511             {
    512               int i;
    513               size_t remaining = benchedSize;
    514               char* in = orig_buff;
    515               char* out = compressed_buff;
    516                 nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
    517               for (i=0; i<nbChunks; i++)
    518               {
    519                   chunkP[i].id = i;
    520                   chunkP[i].origBuffer = in; in += chunkSize;
    521                   if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }
    522                   chunkP[i].compressedBuffer = out; out += maxCompressedChunkSize;
    523                   chunkP[i].compressedSize = 0;
    524               }
    525             }
    526 
    527             if ((compressionAlgo != ALL_COMPRESSORS) && (compressionAlgo != cAlgNb)) continue;
    528 
    529             switch(cAlgNb)
    530             {
    531             case 1 : compressionFunction = LZ4_compress; compressorName = "LZ4_compress"; break;
    532             case 2 : compressionFunction = local_LZ4_compress_limitedOutput; compressorName = "LZ4_compress_limitedOutput"; break;
    533             case 3 : compressionFunction = local_LZ4_compress_withState; compressorName = "LZ4_compress_withState"; break;
    534             case 4 : compressionFunction = local_LZ4_compress_limitedOutput_withState; compressorName = "LZ4_compress_limitedOutput_withState"; break;
    535             case 5 : compressionFunction = local_LZ4_compress_continue; initFunction = LZ4_create; compressorName = "LZ4_compress_continue"; break;
    536             case 6 : compressionFunction = local_LZ4_compress_limitedOutput_continue; initFunction = LZ4_create; compressorName = "LZ4_compress_limitedOutput_continue"; break;
    537             case 7 : compressionFunction = LZ4_compressHC; compressorName = "LZ4_compressHC"; break;
    538             case 8 : compressionFunction = local_LZ4_compressHC_limitedOutput; compressorName = "LZ4_compressHC_limitedOutput"; break;
    539             case 9 : compressionFunction = local_LZ4_compressHC_withStateHC; compressorName = "LZ4_compressHC_withStateHC"; break;
    540             case 10: compressionFunction = local_LZ4_compressHC_limitedOutput_withStateHC; compressorName = "LZ4_compressHC_limitedOutput_withStateHC"; break;
    541             case 11: compressionFunction = local_LZ4_compressHC_continue; initFunction = LZ4_createHC; compressorName = "LZ4_compressHC_continue"; break;
    542             case 12: compressionFunction = local_LZ4_compressHC_limitedOutput_continue; initFunction = LZ4_createHC; compressorName = "LZ4_compressHC_limitedOutput_continue"; break;
    543             case 13: compressionFunction = local_LZ4_compress_forceDict; initFunction = local_LZ4_resetDictT; compressorName = "LZ4_compress_forceDict"; break;
    544             case 14: compressionFunction = local_LZ4F_compressFrame; compressorName = "LZ4F_compressFrame";
    545                         chunkP[0].origSize = (int)benchedSize; nbChunks=1;
    546                         break;
    547             case 15: compressionFunction = local_LZ4_saveDict; compressorName = "LZ4_saveDict";
    548                         LZ4_loadDict(&LZ4_dict, chunkP[0].origBuffer, chunkP[0].origSize);
    549                         break;
    550             case 16: compressionFunction = local_LZ4_saveDictHC; compressorName = "LZ4_saveDictHC";
    551                         LZ4_loadDictHC(&LZ4_dictHC, chunkP[0].origBuffer, chunkP[0].origSize);
    552                         break;
    553             default : DISPLAY("ERROR ! Bad algorithm Id !! \n"); free(chunkP); return 1;
    554             }
    555 
    556             for (loopNb = 1; loopNb <= nbIterations; loopNb++)
    557             {
    558                 double averageTime;
    559                 int milliTime;
    560 
    561                 PROGRESS("%1i- %-28.28s :%9i ->\r", loopNb, compressorName, (int)benchedSize);
    562                 { size_t i; for (i=0; i<benchedSize; i++) compressed_buff[i]=(char)i; }     // warming up memory
    563 
    564                 nb_loops = 0;
    565                 milliTime = BMK_GetMilliStart();
    566                 while(BMK_GetMilliStart() == milliTime);
    567                 milliTime = BMK_GetMilliStart();
    568                 while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
    569                 {
    570                     if (initFunction!=NULL) ctx = initFunction(chunkP[0].origBuffer);
    571                     for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
    572                     {
    573                         chunkP[chunkNb].compressedSize = compressionFunction(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize);
    574                         if (chunkP[chunkNb].compressedSize==0) DISPLAY("ERROR ! %s() = 0 !! \n", compressorName), exit(1);
    575                     }
    576                     if (initFunction!=NULL) free(ctx);
    577                     nb_loops++;
    578                 }
    579                 milliTime = BMK_GetMilliSpan(milliTime);
    580 
    581                 averageTime = (double)milliTime / nb_loops;
    582                 if (averageTime < bestTime) bestTime = averageTime;
    583                 cSize=0; for (chunkNb=0; chunkNb<nbChunks; chunkNb++) cSize += chunkP[chunkNb].compressedSize;
    584                 ratio = (double)cSize/(double)benchedSize*100.;
    585                 PROGRESS("%1i- %-28.28s :%9i ->%9i (%5.2f%%),%7.1f MB/s\r", loopNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
    586             }
    587 
    588             if (ratio<100.)
    589                 DISPLAY("%2i-%-28.28s :%9i ->%9i (%5.2f%%),%7.1f MB/s\n", cAlgNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
    590             else
    591                 DISPLAY("%2i-%-28.28s :%9i ->%9i (%5.1f%%),%7.1f MB/s\n", cAlgNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
    592 
    593             totalCTime[cAlgNb] += bestTime;
    594             totalCSize[cAlgNb] += cSize;
    595         }
    596 
    597         // Prepare layout for decompression
    598         // Init data chunks
    599         {
    600           int i;
    601           size_t remaining = benchedSize;
    602           char* in = orig_buff;
    603           char* out = compressed_buff;
    604             nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
    605           for (i=0; i<nbChunks; i++)
    606           {
    607               chunkP[i].id = i;
    608               chunkP[i].origBuffer = in; in += chunkSize;
    609               if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }
    610               chunkP[i].compressedBuffer = out; out += maxCompressedChunkSize;
    611               chunkP[i].compressedSize = 0;
    612           }
    613         }
    614         for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
    615         {
    616             chunkP[chunkNb].compressedSize = LZ4_compress(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize);
    617             if (chunkP[chunkNb].compressedSize==0) DISPLAY("ERROR ! %s() = 0 !! \n", "LZ4_compress"), exit(1);
    618         }
    619 
    620         // Decompression Algorithms
    621         for (dAlgNb=1; (dAlgNb <= NB_DECOMPRESSION_ALGORITHMS) && (decompressionTest); dAlgNb++)
    622         {
    623             //const char* dName = decompressionNames[dAlgNb];
    624             const char* dName;
    625             int (*decompressionFunction)(const char*, char*, int, int);
    626             double bestTime = 100000000.;
    627 
    628             if ((decompressionAlgo != ALL_DECOMPRESSORS) && (decompressionAlgo != dAlgNb)) continue;
    629 
    630             switch(dAlgNb)
    631             {
    632             case 1: decompressionFunction = local_LZ4_decompress_fast; dName = "LZ4_decompress_fast"; break;
    633             case 2: decompressionFunction = local_LZ4_decompress_fast_withPrefix64k; dName = "LZ4_decompress_fast_withPrefix64k"; break;
    634             case 3: decompressionFunction = local_LZ4_decompress_fast_usingDict; dName = "LZ4_decompress_fast_usingDict"; break;
    635             case 4: decompressionFunction = LZ4_decompress_safe; dName = "LZ4_decompress_safe"; break;
    636             case 5: decompressionFunction = LZ4_decompress_safe_withPrefix64k; dName = "LZ4_decompress_safe_withPrefix64k"; break;
    637             case 6: decompressionFunction = local_LZ4_decompress_safe_usingDict; dName = "LZ4_decompress_safe_usingDict"; break;
    638             case 7: decompressionFunction = local_LZ4_decompress_safe_partial; dName = "LZ4_decompress_safe_partial"; break;
    639             case 8: decompressionFunction = local_LZ4_decompress_safe_forceExtDict; dName = "LZ4_decompress_safe_forceExtDict"; break;
    640             case 9: decompressionFunction = local_LZ4F_decompress; dName = "LZ4F_decompress";
    641                     errorCode = LZ4F_compressFrame(compressed_buff, compressedBuffSize, orig_buff, benchedSize, NULL);
    642                     if (LZ4F_isError(errorCode)) { DISPLAY("Preparation error compressing frame\n"); return 1; }
    643                     chunkP[0].origSize = (int)benchedSize;
    644                     chunkP[0].compressedSize = (int)errorCode;
    645                     nbChunks = 1;
    646                     break;
    647             default : DISPLAY("ERROR ! Bad decompression algorithm Id !! \n"); free(chunkP); return 1;
    648             }
    649 
    650             { size_t i; for (i=0; i<benchedSize; i++) orig_buff[i]=0; }     // zeroing source area, for CRC checking
    651 
    652             for (loopNb = 1; loopNb <= nbIterations; loopNb++)
    653             {
    654                 double averageTime;
    655                 int milliTime;
    656                 U32 crcDecoded;
    657 
    658                 PROGRESS("%1i- %-29.29s :%10i ->\r", loopNb, dName, (int)benchedSize);
    659 
    660                 nb_loops = 0;
    661                 milliTime = BMK_GetMilliStart();
    662                 while(BMK_GetMilliStart() == milliTime);
    663                 milliTime = BMK_GetMilliStart();
    664                 while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
    665                 {
    666                     for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
    667                     {
    668                         int decodedSize = decompressionFunction(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkP[chunkNb].origSize);
    669                         if (chunkP[chunkNb].origSize != decodedSize) DISPLAY("ERROR ! %s() == %i != %i !! \n", dName, decodedSize, chunkP[chunkNb].origSize), exit(1);
    670                     }
    671                     nb_loops++;
    672                 }
    673                 milliTime = BMK_GetMilliSpan(milliTime);
    674 
    675                 averageTime = (double)milliTime / nb_loops;
    676                 if (averageTime < bestTime) bestTime = averageTime;
    677 
    678                 PROGRESS("%1i- %-29.29s :%10i -> %7.1f MB/s\r", loopNb, dName, (int)benchedSize, (double)benchedSize / bestTime / 1000.);
    679 
    680                 // CRC Checking
    681                 crcDecoded = XXH32(orig_buff, (int)benchedSize, 0);
    682                 if (crcOriginal!=crcDecoded) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", inFileName, (unsigned)crcOriginal, (unsigned)crcDecoded); exit(1); }
    683             }
    684 
    685             DISPLAY("%2i-%-29.29s :%10i -> %7.1f MB/s\n", dAlgNb, dName, (int)benchedSize, (double)benchedSize / bestTime / 1000.);
    686 
    687             totalDTime[dAlgNb] += bestTime;
    688         }
    689 
    690       }
    691 
    692       free(orig_buff);
    693       free(compressed_buff);
    694       free(chunkP);
    695   }
    696 
    697   if (BMK_pause) { printf("press enter...\n"); getchar(); }
    698 
    699   return 0;
    700 }
    701 
    702 
    703 int usage(char* exename)
    704 {
    705     DISPLAY( "Usage :\n");
    706     DISPLAY( "      %s [arg] file1 file2 ... fileX\n", exename);
    707     DISPLAY( "Arguments :\n");
    708     DISPLAY( " -c     : compression tests only\n");
    709     DISPLAY( " -d     : decompression tests only\n");
    710     DISPLAY( " -H/-h  : Help (this text + advanced options)\n");
    711     return 0;
    712 }
    713 
    714 int usage_advanced(void)
    715 {
    716     DISPLAY( "\nAdvanced options :\n");
    717     DISPLAY( " -c#    : test only compression function # [1-%i]\n", NB_COMPRESSION_ALGORITHMS);
    718     DISPLAY( " -d#    : test only decompression function # [1-%i]\n", NB_DECOMPRESSION_ALGORITHMS);
    719     DISPLAY( " -i#    : iteration loops [1-9](default : %i)\n", NBLOOPS);
    720     DISPLAY( " -B#    : Block size [4-7](default : 7)\n");
    721     return 0;
    722 }
    723 
    724 int badusage(char* exename)
    725 {
    726     DISPLAY("Wrong parameters\n");
    727     usage(exename);
    728     return 0;
    729 }
    730 
    731 int main(int argc, char** argv)
    732 {
    733     int i,
    734         filenamesStart=2;
    735     char* exename=argv[0];
    736     char* input_filename=0;
    737 
    738     // Welcome message
    739     DISPLAY(WELCOME_MESSAGE);
    740 
    741     if (argc<2) { badusage(exename); return 1; }
    742 
    743     for(i=1; i<argc; i++)
    744     {
    745         char* argument = argv[i];
    746 
    747         if(!argument) continue;   // Protection if argument empty
    748         if (!strcmp(argument, "--no-prompt"))
    749         {
    750             no_prompt = 1;
    751             continue;
    752         }
    753 
    754         // Decode command (note : aggregated commands are allowed)
    755         if (argument[0]=='-')
    756         {
    757             while (argument[1]!=0)
    758             {
    759                 argument ++;
    760 
    761                 switch(argument[0])
    762                 {
    763                     // Select compression algorithm only
    764                 case 'c':
    765                     decompressionTest = 0;
    766                     while ((argument[1]>= '0') && (argument[1]<= '9'))
    767                     {
    768                         compressionAlgo *= 10;
    769                         compressionAlgo += argument[1] - '0';
    770                         argument++;
    771                     }
    772                     break;
    773 
    774                     // Select decompression algorithm only
    775                 case 'd':
    776                     compressionTest = 0;
    777                     while ((argument[1]>= '0') && (argument[1]<= '9'))
    778                     {
    779                         decompressionAlgo *= 10;
    780                         decompressionAlgo += argument[1] - '0';
    781                         argument++;
    782                     }
    783                     break;
    784 
    785                     // Display help on usage
    786                 case 'h' :
    787                 case 'H': usage(exename); usage_advanced(); return 0;
    788 
    789                     // Modify Block Properties
    790                 case 'B':
    791                     while (argument[1]!=0)
    792                     switch(argument[1])
    793                     {
    794                     case '4':
    795                     case '5':
    796                     case '6':
    797                     case '7':
    798                     {
    799                         int B = argument[1] - '0';
    800                         int S = 1 << (8 + 2*B);
    801                         BMK_SetBlocksize(S);
    802                         argument++;
    803                         break;
    804                     }
    805                     case 'D': argument++; break;
    806                     default : goto _exit_blockProperties;
    807                     }
    808 _exit_blockProperties:
    809                     break;
    810 
    811                     // Modify Nb Iterations
    812                 case 'i':
    813                     if ((argument[1] >='1') && (argument[1] <='9'))
    814                     {
    815                         int iters = argument[1] - '0';
    816                         BMK_SetNbIterations(iters);
    817                         argument++;
    818                     }
    819                     break;
    820 
    821                     // Pause at the end (hidden option)
    822                 case 'p': BMK_SetPause(); break;
    823 
    824                     // Unknown command
    825                 default : badusage(exename); return 1;
    826                 }
    827             }
    828             continue;
    829         }
    830 
    831         // first provided filename is input
    832         if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
    833 
    834     }
    835 
    836     // No input filename ==> Error
    837     if(!input_filename) { badusage(exename); return 1; }
    838 
    839     return fullSpeedBench(argv+filenamesStart, argc-filenamesStart);
    840 
    841 }
    842 
    843