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>