Annotation of elwix/tools/oldlzma/SRC/7zip/Compress/LZMA_Alone/LzmaBench.cpp, revision 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>