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