RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / scripts / squashfs / lzma / C / 7zip / Compress / LZMA_Alone / LzmaBench.cpp
blobfd6af9bd5820de9d5d8a978441ff631aba9de169
1 // LzmaBench.cpp
3 #include "StdAfx.h"
5 #include "LzmaBench.h"
7 #ifndef _WIN32
8 #include <time.h>
9 #endif
11 #include "../../../Common/CRC.h"
12 #include "../LZMA/LZMADecoder.h"
13 #include "../LZMA/LZMAEncoder.h"
15 static const UInt32 kAdditionalSize =
16 #ifdef _WIN32_WCE
17 (1 << 20);
18 #else
19 (6 << 20);
20 #endif
22 static const UInt32 kCompressedAdditionalSize = (1 << 10);
23 static const UInt32 kMaxLzmaPropSize = 10;
25 class CRandomGenerator
27 UInt32 A1;
28 UInt32 A2;
29 public:
30 CRandomGenerator() { Init(); }
31 void Init() { A1 = 362436069; A2 = 521288629;}
32 UInt32 GetRnd()
34 return
35 ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^
36 ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
40 class CBitRandomGenerator
42 CRandomGenerator RG;
43 UInt32 Value;
44 int NumBits;
45 public:
46 void Init()
48 Value = 0;
49 NumBits = 0;
51 UInt32 GetRnd(int numBits)
53 if (NumBits > numBits)
55 UInt32 result = Value & ((1 << numBits) - 1);
56 Value >>= numBits;
57 NumBits -= numBits;
58 return result;
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;
70 class CBenchRandomGenerator
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)
82 delete []Buffer;
83 Buffer = 0;
84 Buffer = new Byte[bufferSize];
85 Pos = 0;
86 BufferSize = bufferSize;
88 UInt32 GetRndBit() { return RG.GetRnd(1); }
90 UInt32 GetLogRand(int maxLen)
92 UInt32 len = GetRnd() % (maxLen + 1);
93 return GetRnd() & ((1 << len) - 1);
96 UInt32 GetLogRandBits(int numBits)
98 UInt32 len = RG.GetRnd(numBits);
99 return RG.GetRnd(len);
101 UInt32 GetOffset()
103 if (GetRndBit() == 0)
104 return GetLogRandBits(4);
105 return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
107 UInt32 GetLen()
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);
115 void Generate()
117 while(Pos < BufferSize)
119 if (GetRndBit() == 0 || Pos < 1)
120 Buffer[Pos++] = Byte(RG.GetRnd(8));
121 else
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];
135 class CBenchmarkInStream:
136 public ISequentialInStream,
137 public CMyUnknownImp
139 const Byte *Data;
140 UInt32 Pos;
141 UInt32 Size;
142 public:
143 MY_UNKNOWN_IMP
144 void Init(const Byte *data, UInt32 size)
146 Data = data;
147 Size = size;
148 Pos = 0;
150 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
153 STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
155 UInt32 remain = Size - Pos;
156 if (size > remain)
157 size = remain;
158 for (UInt32 i = 0; i < size; i++)
159 ((Byte *)data)[i] = Data[Pos + i];
160 Pos += size;
161 if(processedSize != NULL)
162 *processedSize = size;
163 return S_OK;
166 class CBenchmarkOutStream:
167 public ISequentialOutStream,
168 public CMyUnknownImp
170 UInt32 BufferSize;
171 FILE *_f;
172 public:
173 UInt32 Pos;
174 Byte *Buffer;
175 CBenchmarkOutStream(): _f(0), Buffer(0) {}
176 virtual ~CBenchmarkOutStream() { delete []Buffer; }
177 void Init(FILE *f, UInt32 bufferSize)
179 delete []Buffer;
180 Buffer = 0;
181 Buffer = new Byte[bufferSize];
182 Pos = 0;
183 BufferSize = bufferSize;
184 _f = f;
186 MY_UNKNOWN_IMP
187 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
190 STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
192 UInt32 i;
193 for (i = 0; i < size && Pos < BufferSize; i++)
194 Buffer[Pos++] = ((const Byte *)data)[i];
195 if(processedSize != NULL)
196 *processedSize = i;
197 if (i != size)
199 fprintf(_f, "\nERROR: Buffer is full\n");
200 return E_FAIL;
202 return S_OK;
205 class CCrcOutStream:
206 public ISequentialOutStream,
207 public CMyUnknownImp
209 public:
210 CCRC CRC;
211 MY_UNKNOWN_IMP
212 void Init() { CRC.Init(); }
213 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
216 STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
218 CRC.Update(data, size);
219 if(processedSize != NULL)
220 *processedSize = size;
221 return S_OK;
224 static UInt64 GetTimeCount()
226 #ifdef _WIN32
227 LARGE_INTEGER value;
228 if (::QueryPerformanceCounter(&value))
229 return value.QuadPart;
230 return GetTickCount();
231 #else
232 return clock();
233 #endif
236 static UInt64 GetFreq()
238 #ifdef _WIN32
239 LARGE_INTEGER value;
240 if (::QueryPerformanceFrequency(&value))
241 return value.QuadPart;
242 return 1000;
243 #else
244 return CLOCKS_PER_SEC;
245 #endif
248 struct CProgressInfo:
249 public ICompressProgressInfo,
250 public CMyUnknownImp
252 UInt64 ApprovedStart;
253 UInt64 InSize;
254 UInt64 Time;
255 void Init()
257 InSize = 0;
258 Time = 0;
260 MY_UNKNOWN_IMP
261 STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
264 STDMETHODIMP CProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
266 if (*inSize >= ApprovedStart && InSize == 0)
268 Time = ::GetTimeCount();
269 InSize = *inSize;
271 return S_OK;
274 static const int kSubBits = 8;
276 static UInt32 GetLogSize(UInt32 size)
278 for (int i = kSubBits; i < 32; i++)
279 for (UInt32 j = 0; j < (1 << kSubBits); j++)
280 if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
281 return (i << kSubBits) + j;
282 return (32 << kSubBits);
285 static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime)
287 UInt64 freq = GetFreq();
288 UInt64 elTime = elapsedTime;
289 while(freq > 1000000)
291 freq >>= 1;
292 elTime >>= 1;
294 if (elTime == 0)
295 elTime = 1;
296 return value * freq / elTime;
299 static UInt64 GetCompressRating(UInt32 dictionarySize, bool isBT4,
300 UInt64 elapsedTime, UInt64 size)
302 UInt64 numCommandsForOne;
303 if (isBT4)
305 UInt64 t = GetLogSize(dictionarySize) - (19 << kSubBits);
306 numCommandsForOne = 2000 + ((t * t * 68) >> (2 * kSubBits));
308 else
310 UInt64 t = GetLogSize(dictionarySize) - (15 << kSubBits);
311 numCommandsForOne = 1500 + ((t * t * 41) >> (2 * kSubBits));
313 UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
314 return MyMultDiv64(numCommands, elapsedTime);
317 static UInt64 GetDecompressRating(UInt64 elapsedTime,
318 UInt64 outSize, UInt64 inSize)
320 UInt64 numCommands = inSize * 250 + outSize * 21;
321 return MyMultDiv64(numCommands, elapsedTime);
325 static UInt64 GetTotalRating(
326 UInt32 dictionarySize,
327 bool isBT4,
328 UInt64 elapsedTimeEn, UInt64 sizeEn,
329 UInt64 elapsedTimeDe,
330 UInt64 inSizeDe, UInt64 outSizeDe)
332 return (GetCompressRating(dictionarySize, isBT4, elapsedTimeEn, sizeEn) +
333 GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
337 static void PrintRating(FILE *f, UInt64 rating)
339 fprintf(f, "%5d MIPS", (unsigned int)(rating / 1000000));
342 static void PrintResults(
343 FILE *f,
344 UInt32 dictionarySize,
345 bool isBT4,
346 UInt64 elapsedTime,
347 UInt64 size,
348 bool decompressMode, UInt64 secondSize)
350 UInt64 speed = MyMultDiv64(size, elapsedTime);
351 fprintf(f, "%6d KB/s ", (unsigned int)(speed / 1024));
352 UInt64 rating;
353 if (decompressMode)
354 rating = GetDecompressRating(elapsedTime, size, secondSize);
355 else
356 rating = GetCompressRating(dictionarySize, isBT4, elapsedTime, size);
357 PrintRating(f, rating);
360 static void ThrowError(FILE *f, HRESULT result, const char *s)
362 fprintf(f, "\nError: ");
363 if (result == E_ABORT)
364 fprintf(f, "User break");
365 if (result == E_OUTOFMEMORY)
366 fprintf(f, "Can not allocate memory");
367 else
368 fprintf(f, s);
369 fprintf(f, "\n");
372 const wchar_t *bt2 = L"BT2";
373 const wchar_t *bt4 = L"BT4";
375 int LzmaBenchmark(FILE *f, UInt32 numIterations, UInt32 dictionarySize, bool isBT4)
377 if (numIterations == 0)
378 return 0;
379 if (dictionarySize < (1 << 19) && isBT4 || dictionarySize < (1 << 15))
381 fprintf(f, "\nError: dictionary size for benchmark must be >= 19 (512 KB)\n");
382 return 1;
384 fprintf(f, "\n Compressing Decompressing\n\n");
385 NCompress::NLZMA::CEncoder *encoderSpec = new NCompress::NLZMA::CEncoder;
386 CMyComPtr<ICompressCoder> encoder = encoderSpec;
388 NCompress::NLZMA::CDecoder *decoderSpec = new NCompress::NLZMA::CDecoder;
389 CMyComPtr<ICompressCoder> decoder = decoderSpec;
391 CBenchmarkOutStream *propStreamSpec = new CBenchmarkOutStream;
392 CMyComPtr<ISequentialOutStream> propStream = propStreamSpec;
393 propStreamSpec->Init(f, kMaxLzmaPropSize);
395 PROPID propIDs[] =
397 NCoderPropID::kDictionarySize,
398 NCoderPropID::kMatchFinder
400 const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]);
401 PROPVARIANT properties[kNumProps];
402 properties[0].vt = VT_UI4;
403 properties[0].ulVal = UInt32(dictionarySize);
405 properties[1].vt = VT_BSTR;
406 properties[1].bstrVal = isBT4 ? (BSTR)bt4: (BSTR)bt2;
408 const UInt32 kBufferSize = dictionarySize + kAdditionalSize;
409 const UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
411 if (encoderSpec->SetCoderProperties(propIDs, properties, kNumProps) != S_OK)
413 fprintf(f, "\nError: Incorrect command\n");
414 return 1;
416 encoderSpec->WriteCoderProperties(propStream);
418 CBenchRandomGenerator rg;
419 rg.Init();
420 rg.Set(kBufferSize);
421 rg.Generate();
422 CCRC crc;
423 crc.Update(rg.Buffer, rg.BufferSize);
425 CProgressInfo *progressInfoSpec = new CProgressInfo;
426 CMyComPtr<ICompressProgressInfo> progressInfo = progressInfoSpec;
428 progressInfoSpec->ApprovedStart = dictionarySize;
430 UInt64 totalBenchSize = 0;
431 UInt64 totalEncodeTime = 0;
432 UInt64 totalDecodeTime = 0;
433 UInt64 totalCompressedSize = 0;
435 for (UInt32 i = 0; i < numIterations; i++)
437 progressInfoSpec->Init();
438 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
439 inStreamSpec->Init(rg.Buffer, rg.BufferSize);
440 CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
441 CBenchmarkOutStream *outStreamSpec = new CBenchmarkOutStream;
442 outStreamSpec->Init(f, kCompressedBufferSize);
443 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
444 HRESULT result = encoder->Code(inStream, outStream, 0, 0, progressInfo);
445 UInt64 encodeTime = ::GetTimeCount() - progressInfoSpec->Time;
446 UInt32 compressedSize = outStreamSpec->Pos;
447 if(result != S_OK)
449 ThrowError(f, result, "Encoder Error");
450 return 1;
452 if (progressInfoSpec->InSize == 0)
454 fprintf(f, "\nError: Internal ERROR 1282\n");
455 return 1;
458 ///////////////////////
459 // Decompressing
461 CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
462 CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
464 UInt64 decodeTime;
465 for (int j = 0; j < 2; j++)
467 inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
468 crcOutStreamSpec->Init();
470 if (decoderSpec->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos) != S_OK)
472 fprintf(f, "\nError: Set Decoder Properties Error\n");
473 return 1;
475 UInt64 outSize = kBufferSize;
476 UInt64 startTime = ::GetTimeCount();
477 result = decoder->Code(inStream, crcOutStream, 0, &outSize, 0);
478 decodeTime = ::GetTimeCount() - startTime;
479 if(result != S_OK)
481 ThrowError(f, result, "Decode Error");
482 return 1;
484 if (crcOutStreamSpec->CRC.GetDigest() != crc.GetDigest())
486 fprintf(f, "\nError: CRC Error\n");
487 return 1;
490 UInt64 benchSize = kBufferSize - progressInfoSpec->InSize;
491 PrintResults(f, dictionarySize, isBT4, encodeTime, benchSize, false, 0);
492 fprintf(f, " ");
493 PrintResults(f, dictionarySize, isBT4, decodeTime, kBufferSize, true, compressedSize);
494 fprintf(f, "\n");
496 totalBenchSize += benchSize;
497 totalEncodeTime += encodeTime;
498 totalDecodeTime += decodeTime;
499 totalCompressedSize += compressedSize;
501 fprintf(f, "---------------------------------------------------\n");
502 PrintResults(f, dictionarySize, isBT4, totalEncodeTime, totalBenchSize, false, 0);
503 fprintf(f, " ");
504 PrintResults(f, dictionarySize, isBT4, totalDecodeTime,
505 kBufferSize * numIterations, true, totalCompressedSize);
506 fprintf(f, " Average\n");
507 return 0;