Annotation of elwix/tools/oldlzma/SRC/7zip/Compress/LZMA_Alone/LzmaBench.cpp, revision 1.1.1.1

1.1       misho       1: // LzmaBench.cpp
                      2: 
                      3: #include "StdAfx.h"
                      4: 
                      5: #include "LzmaBench.h"
                      6: 
                      7: #ifndef _WIN32
                      8: #include <time.h>
                      9: #endif
                     10: 
                     11: #include "../../../Common/CRC.h"
                     12: #include "../LZMA/LZMADecoder.h"
                     13: #include "../LZMA/LZMAEncoder.h"
                     14: 
                     15: static const UInt32 kAdditionalSize = 
                     16: #ifdef _WIN32_WCE
                     17: (1 << 20);
                     18: #else
                     19: (6 << 20);
                     20: #endif
                     21: 
                     22: static const UInt32 kCompressedAdditionalSize = (1 << 10);
                     23: static const UInt32 kMaxLzmaPropSize = 10;
                     24: 
                     25: class CRandomGenerator
                     26: {
                     27:   UInt32 A1;
                     28:   UInt32 A2;
                     29: public:
                     30:   CRandomGenerator() { Init(); }
                     31:   void Init() { A1 = 362436069; A2 = 521288629;}
                     32:   UInt32 GetRnd() 
                     33:   {
                     34:     return 
                     35:       ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^
                     36:       ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
                     37:   }
                     38: };
                     39: 
                     40: class CBitRandomGenerator
                     41: {
                     42:   CRandomGenerator RG;
                     43:   UInt32 Value;
                     44:   int NumBits;
                     45: public:
                     46:   void Init()
                     47:   {
                     48:     Value = 0;
                     49:     NumBits = 0;
                     50:   }
                     51:   UInt32 GetRnd(int numBits) 
                     52:   {
                     53:     if (NumBits > numBits)
                     54:     {
                     55:       UInt32 result = Value & ((1 << numBits) - 1);
                     56:       Value >>= numBits;
                     57:       NumBits -= numBits;
                     58:       return result;
                     59:     }
                     60:     numBits -= NumBits;
                     61:     UInt32 result = (Value << numBits);
                     62:     Value = RG.GetRnd();
                     63:     result |= Value & ((1 << numBits) - 1);
                     64:     Value >>= numBits;
                     65:     NumBits = 32 - numBits;
                     66:     return result;
                     67:   }
                     68: };
                     69: 
                     70: class CBenchRandomGenerator
                     71: {
                     72:   CBitRandomGenerator RG;
                     73:   UInt32 Pos;
                     74: public:
                     75:   UInt32 BufferSize;
                     76:   Byte *Buffer;
                     77:   CBenchRandomGenerator(): Buffer(0) {} 
                     78:   ~CBenchRandomGenerator() { delete []Buffer; }
                     79:   void Init() { RG.Init(); }
                     80:   void Set(UInt32 bufferSize) 
                     81:   {
                     82:     delete []Buffer;
                     83:     Buffer = 0;
                     84:     Buffer = new Byte[bufferSize];
                     85:     Pos = 0;
                     86:     BufferSize = bufferSize;
                     87:   }
                     88:   UInt32 GetRndBit() { return RG.GetRnd(1); }
                     89:   /*
                     90:   UInt32 GetLogRand(int maxLen)
                     91:   {
                     92:     UInt32 len = GetRnd() % (maxLen + 1);
                     93:     return GetRnd() & ((1 << len) - 1);
                     94:   }
                     95:   */
                     96:   UInt32 GetLogRandBits(int numBits)
                     97:   {
                     98:     UInt32 len = RG.GetRnd(numBits);
                     99:     return RG.GetRnd(len);
                    100:   }
                    101:   UInt32 GetOffset()
                    102:   {
                    103:     if (GetRndBit() == 0)
                    104:       return GetLogRandBits(4);
                    105:     return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
                    106:   }
                    107:   UInt32 GetLen()
                    108:   {
                    109:     if (GetRndBit() == 0)
                    110:       return RG.GetRnd(2);
                    111:     if (GetRndBit() == 0)
                    112:       return 4 + RG.GetRnd(3);
                    113:     return 12 + RG.GetRnd(4);
                    114:   }
                    115:   void Generate()
                    116:   {
                    117:     while(Pos < BufferSize)
                    118:     {
                    119:       if (GetRndBit() == 0 || Pos < 1)
                    120:         Buffer[Pos++] = Byte(RG.GetRnd(8));
                    121:       else
                    122:       {
                    123:         UInt32 offset = GetOffset();
                    124:         while (offset >= Pos)
                    125:           offset >>= 1;
                    126:         offset += 1;
                    127:         UInt32 len = 2 + GetLen();
                    128:         for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++)
                    129:           Buffer[Pos] = Buffer[Pos - offset];
                    130:       }
                    131:     }
                    132:   }
                    133: };
                    134: 
                    135: class CBenchmarkInStream: 
                    136:   public ISequentialInStream,
                    137:   public CMyUnknownImp
                    138: {
                    139:   const Byte *Data;
                    140:   UInt32 Pos;
                    141:   UInt32 Size;
                    142: public:
                    143:   MY_UNKNOWN_IMP
                    144:   void Init(const Byte *data, UInt32 size)
                    145:   {
                    146:     Data = data;
                    147:     Size = size;
                    148:     Pos = 0;
                    149:   }
                    150:   STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
                    151:   STDMETHOD(ReadPart)(void *data, UInt32 size, UInt32 *processedSize);
                    152: };
                    153: 
                    154: STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
                    155: {
                    156:   UInt32 remain = Size - Pos;
                    157:   if (size > remain)
                    158:     size = remain;
                    159:   for (UInt32 i = 0; i < size; i++)
                    160:   {
                    161:     ((Byte *)data)[i] = Data[Pos + i];
                    162:   }
                    163:   Pos += size;
                    164:   if(processedSize != NULL)
                    165:     *processedSize = size;
                    166:   return S_OK;
                    167: }
                    168:   
                    169: STDMETHODIMP CBenchmarkInStream::ReadPart(void *data, UInt32 size, UInt32 *processedSize)
                    170: {
                    171:   return Read(data, size, processedSize);
                    172: }
                    173: 
                    174: class CBenchmarkOutStream: 
                    175:   public ISequentialOutStream,
                    176:   public CMyUnknownImp
                    177: {
                    178:   UInt32 BufferSize;
                    179:   FILE *_f;
                    180: public:
                    181:   UInt32 Pos;
                    182:   Byte *Buffer;
                    183:   CBenchmarkOutStream(): _f(0), Buffer(0) {} 
                    184:   virtual ~CBenchmarkOutStream() { delete []Buffer; }
                    185:   void Init(FILE *f, UInt32 bufferSize) 
                    186:   {
                    187:     delete []Buffer;
                    188:     Buffer = 0;
                    189:     Buffer = new Byte[bufferSize];
                    190:     Pos = 0;
                    191:     BufferSize = bufferSize;
                    192:     _f = f;
                    193:   }
                    194:   MY_UNKNOWN_IMP
                    195:   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
                    196:   STDMETHOD(WritePart)(const void *data, UInt32 size, UInt32 *processedSize);
                    197: };
                    198: 
                    199: STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
                    200: {
                    201:   UInt32 i;
                    202:   for (i = 0; i < size && Pos < BufferSize; i++)
                    203:     Buffer[Pos++] = ((const Byte *)data)[i];
                    204:   if(processedSize != NULL)
                    205:     *processedSize = i;
                    206:   if (i != size)
                    207:   {
                    208:     fprintf(_f, "\nERROR: Buffer is full\n");
                    209:     return E_FAIL;
                    210:   }
                    211:   return S_OK;
                    212: }
                    213:   
                    214: STDMETHODIMP CBenchmarkOutStream::WritePart(const void *data, UInt32 size, UInt32 *processedSize)
                    215: {
                    216:   return Write(data, size, processedSize);
                    217: }
                    218: 
                    219: class CCrcOutStream: 
                    220:   public ISequentialOutStream,
                    221:   public CMyUnknownImp
                    222: {
                    223: public:
                    224:   CCRC CRC;
                    225:   MY_UNKNOWN_IMP
                    226:   void Init() { CRC.Init(); }
                    227:   STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
                    228:   STDMETHOD(WritePart)(const void *data, UInt32 size, UInt32 *processedSize);
                    229: };
                    230: 
                    231: STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
                    232: {
                    233:   CRC.Update(data, size);
                    234:   if(processedSize != NULL)
                    235:     *processedSize = size;
                    236:   return S_OK;
                    237: }
                    238:   
                    239: STDMETHODIMP CCrcOutStream::WritePart(const void *data, UInt32 size, UInt32 *processedSize)
                    240: {
                    241:   return Write(data, size, processedSize);
                    242: }
                    243: 
                    244: static UInt64 GetTimeCount()
                    245: {
                    246:   #ifdef _WIN32
                    247:   LARGE_INTEGER value;
                    248:   if (::QueryPerformanceCounter(&value))
                    249:     return value.QuadPart;
                    250:   return GetTickCount();
                    251:   #else
                    252:   return clock();
                    253:   #endif 
                    254: }
                    255: 
                    256: static UInt64 GetFreq()
                    257: {
                    258:   #ifdef _WIN32
                    259:   LARGE_INTEGER value;
                    260:   if (::QueryPerformanceFrequency(&value))
                    261:     return value.QuadPart;
                    262:   return 1000;
                    263:   #else
                    264:   return CLOCKS_PER_SEC;
                    265:   #endif 
                    266: }
                    267: 
                    268: struct CProgressInfo:
                    269:   public ICompressProgressInfo,
                    270:   public CMyUnknownImp
                    271: {
                    272:   UInt64 ApprovedStart;
                    273:   UInt64 InSize;
                    274:   UInt64 Time;
                    275:   void Init()
                    276:   {
                    277:     InSize = 0;
                    278:     Time = 0;
                    279:   }
                    280:   MY_UNKNOWN_IMP
                    281:   STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
                    282: };
                    283: 
                    284: STDMETHODIMP CProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
                    285: {
                    286:   if (*inSize >= ApprovedStart && InSize == 0)
                    287:   {
                    288:     Time = ::GetTimeCount();
                    289:     InSize = *inSize;
                    290:   }
                    291:   return S_OK;
                    292: }
                    293: 
                    294: static const int kSubBits = 8;
                    295: 
                    296: static UInt32 GetLogSize(UInt32 size)
                    297: {
                    298:   for (int i = kSubBits; i < 32; i++)
                    299:     for (UInt32 j = 0; j < (1 << kSubBits); j++)
                    300:       if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
                    301:         return (i << kSubBits) + j;
                    302:   return (32 << kSubBits);
                    303: }
                    304: 
                    305: static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime)
                    306: {
                    307:   UInt64 freq = GetFreq();
                    308:   UInt64 elTime = elapsedTime;
                    309:   while(freq > 1000000)
                    310:   {
                    311:     freq >>= 1;
                    312:     elTime >>= 1;
                    313:   }
                    314:   if (elTime == 0)
                    315:     elTime = 1;
                    316:   return value * freq / elTime;
                    317: }
                    318: 
                    319: static UInt64 GetCompressRating(UInt32 dictionarySize, bool isBT4,
                    320:     UInt64 elapsedTime, UInt64 size)
                    321: {
                    322:   UInt64 numCommandsForOne;
                    323:   if (isBT4)
                    324:   {
                    325:     UInt64 t = GetLogSize(dictionarySize) - (19 << kSubBits);
                    326:     numCommandsForOne = 2000 + ((t * t * 68) >> (2 * kSubBits));
                    327:   }
                    328:   else
                    329:   {
                    330:     UInt64 t = GetLogSize(dictionarySize) - (15 << kSubBits);
                    331:     numCommandsForOne = 1500 + ((t * t * 41) >> (2 * kSubBits));
                    332:   }
                    333:   UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
                    334:   return MyMultDiv64(numCommands, elapsedTime);
                    335: }
                    336: 
                    337: static UInt64 GetDecompressRating(UInt64 elapsedTime, 
                    338:     UInt64 outSize, UInt64 inSize)
                    339: {
                    340:   UInt64 numCommands = inSize * 250 + outSize * 21;
                    341:   return MyMultDiv64(numCommands, elapsedTime);
                    342: }
                    343: 
                    344: /*
                    345: static UInt64 GetTotalRating(
                    346:     UInt32 dictionarySize, 
                    347:     bool isBT4,
                    348:     UInt64 elapsedTimeEn, UInt64 sizeEn,
                    349:     UInt64 elapsedTimeDe, 
                    350:     UInt64 inSizeDe, UInt64 outSizeDe)
                    351: {
                    352:   return (GetCompressRating(dictionarySize, isBT4, elapsedTimeEn, sizeEn) + 
                    353:     GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
                    354: }
                    355: */
                    356: 
                    357: static void PrintRating(FILE *f, UInt64 rating)
                    358: {
                    359:   fprintf(f, "%5d MIPS", (unsigned int)(rating / 1000000));
                    360: }
                    361: 
                    362: static void PrintResults(
                    363:     FILE *f, 
                    364:     UInt32 dictionarySize,
                    365:     bool isBT4,
                    366:     UInt64 elapsedTime, 
                    367:     UInt64 size, 
                    368:     bool decompressMode, UInt64 secondSize)
                    369: {
                    370:   UInt64 speed = MyMultDiv64(size, elapsedTime);
                    371:   fprintf(f, "%6d KB/s  ", (unsigned int)(speed / 1024));
                    372:   UInt64 rating;
                    373:   if (decompressMode)
                    374:     rating = GetDecompressRating(elapsedTime, size, secondSize);
                    375:   else
                    376:     rating = GetCompressRating(dictionarySize, isBT4, elapsedTime, size);
                    377:   PrintRating(f, rating);
                    378: }
                    379: 
                    380: static void ThrowError(FILE *f, HRESULT result, const char *s)
                    381: {
                    382:   fprintf(f, "\nError: ");
                    383:   if (result == E_ABORT)
                    384:     fprintf(f, "User break");
                    385:   if (result == E_OUTOFMEMORY)
                    386:     fprintf(f, "Can not allocate memory");
                    387:   else
                    388:     fprintf(f, s);
                    389:   fprintf(f, "\n");
                    390: }
                    391: 
                    392: const wchar_t *bt2 = L"BT2";
                    393: const wchar_t *bt4 = L"BT4";
                    394: 
                    395: int LzmaBenchmark(FILE *f, UInt32 numIterations, UInt32 dictionarySize, bool isBT4)
                    396: {
                    397:   if (numIterations == 0)
                    398:     return 0;
                    399:   if (dictionarySize < (1 << 19) && isBT4 || dictionarySize < (1 << 15))
                    400:   {
                    401:     fprintf(f, "\nError: dictionary size for benchmark must be >= 19 (512 KB)\n");
                    402:     return 1;
                    403:   }
                    404:   fprintf(f, "\n       Compressing                Decompressing\n\n");
                    405:   NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
                    406:   CMyComPtr<ICompressCoder> encoder = encoderSpec;
                    407: 
                    408:   NCompress::NLZMA::CDecoder *decoderSpec = new NCompress::NLZMA::CDecoder;
                    409:   CMyComPtr<ICompressCoder> decoder = decoderSpec;
                    410: 
                    411:   CBenchmarkOutStream *propStreamSpec = new CBenchmarkOutStream;
                    412:   CMyComPtr<ISequentialOutStream> propStream = propStreamSpec;
                    413:   propStreamSpec->Init(f, kMaxLzmaPropSize);
                    414:   
                    415:   PROPID propIDs[] = 
                    416:   { 
                    417:     NCoderPropID::kDictionarySize,  
                    418:     NCoderPropID::kMatchFinder  
                    419:   };
                    420:   const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
                    421:   PROPVARIANT properties[kNumProps];
                    422:   properties[0].vt = VT_UI4;
                    423:   properties[0].ulVal = UInt32(dictionarySize);
                    424: 
                    425:   properties[1].vt = VT_BSTR;
                    426:   properties[1].bstrVal = isBT4 ? (BSTR)bt4: (BSTR)bt2;
                    427: 
                    428:   const UInt32 kBufferSize = dictionarySize + kAdditionalSize;
                    429:   const UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
                    430: 
                    431:   if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
                    432:   {
                    433:     fprintf(f, "\nError: Incorrect command\n");
                    434:     return 1;
                    435:   }
                    436:   encoderSpec->WriteCoderProperties(propStream);
                    437: 
                    438:   CBenchRandomGenerator rg;
                    439:   rg.Init();
                    440:   rg.Set(kBufferSize);
                    441:   rg.Generate();
                    442:   CCRC crc;
                    443:   crc.Update(rg.Buffer, rg.BufferSize);
                    444: 
                    445:   CProgressInfo *progressInfoSpec = new CProgressInfo;
                    446:   CMyComPtr<ICompressProgressInfo> progressInfo = progressInfoSpec;
                    447: 
                    448:   progressInfoSpec->ApprovedStart = dictionarySize;
                    449: 
                    450:   UInt64 totalBenchSize = 0;
                    451:   UInt64 totalEncodeTime = 0;
                    452:   UInt64 totalDecodeTime = 0;
                    453:   UInt64 totalCompressedSize = 0;
                    454: 
                    455:   for (UInt32 i = 0; i < numIterations; i++)
                    456:   {
                    457:     progressInfoSpec->Init();
                    458:     CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
                    459:     inStreamSpec->Init(rg.Buffer, rg.BufferSize);
                    460:     CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
                    461:     CBenchmarkOutStream *outStreamSpec = new CBenchmarkOutStream;
                    462:     outStreamSpec->Init(f, kCompressedBufferSize);
                    463:     CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
                    464:     HRESULT result = encoder->Code(inStream, outStream, 0, 0, progressInfo);
                    465:     UInt64 encodeTime = ::GetTimeCount() - progressInfoSpec->Time;
                    466:     UInt32 compressedSize = outStreamSpec->Pos;
                    467:     if(result != S_OK)
                    468:     {
                    469:       ThrowError(f, result, "Encoder Error");
                    470:       return 1;
                    471:     }
                    472:     if (progressInfoSpec->InSize == 0)
                    473:     {
                    474:       fprintf(f, "\nError: Internal ERROR 1282\n");
                    475:       return 1;
                    476:     }
                    477:   
                    478:     ///////////////////////
                    479:     // Decompressing
                    480:   
                    481:     CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
                    482:     CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
                    483:     
                    484:     UInt64 decodeTime;
                    485:     for (int j = 0; j < 2; j++)
                    486:     {
                    487:       inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
                    488:       crcOutStreamSpec->Init();
                    489:       
                    490:       if (decoderSpec->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos) != S_OK)
                    491:       {
                    492:         fprintf(f, "\nError: Set Decoder Properties Error\n");
                    493:         return 1;
                    494:       }
                    495:       UInt64 outSize = kBufferSize;
                    496:       UInt64 startTime = ::GetTimeCount();
                    497:       result = decoder->Code(inStream, crcOutStream, 0, &outSize, 0);
                    498:       decodeTime = ::GetTimeCount() - startTime;
                    499:       if(result != S_OK)
                    500:       {
                    501:         ThrowError(f, result, "Decode Error");
                    502:         return 1;
                    503:       }
                    504:       if (crcOutStreamSpec->CRC.GetDigest() != crc.GetDigest())
                    505:       {
                    506:         fprintf(f, "\nError: CRC Error\n");
                    507:         return 1;
                    508:       }
                    509:     }
                    510:     UInt64 benchSize = kBufferSize - progressInfoSpec->InSize;
                    511:     PrintResults(f, dictionarySize, isBT4, encodeTime, benchSize, false, 0);
                    512:     fprintf(f, "     ");
                    513:     PrintResults(f, dictionarySize, isBT4, decodeTime, kBufferSize, true, compressedSize);
                    514:     fprintf(f, "\n");
                    515: 
                    516:     totalBenchSize += benchSize;
                    517:     totalEncodeTime += encodeTime;
                    518:     totalDecodeTime += decodeTime;
                    519:     totalCompressedSize += compressedSize;
                    520:   }
                    521:   fprintf(f, "---------------------------------------------------\n");
                    522:   PrintResults(f, dictionarySize, isBT4, totalEncodeTime, totalBenchSize, false, 0);
                    523:   fprintf(f, "     ");
                    524:   PrintResults(f, dictionarySize, isBT4, totalDecodeTime, 
                    525:       kBufferSize * numIterations, true, totalCompressedSize);
                    526:   fprintf(f, "    Average\n");
                    527:   return 0;
                    528: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>