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