11 #include "../../../Common/CRC.h"
12 #include "../LZMA/LZMADecoder.h"
13 #include "../LZMA/LZMAEncoder.h"
15 static const UInt32 kAdditionalSize
=
22 static const UInt32 kCompressedAdditionalSize
= (1 << 10);
23 static const UInt32 kMaxLzmaPropSize
= 10;
25 class CRandomGenerator
30 CRandomGenerator() { Init(); }
31 void Init() { A1
= 362436069; A2
= 521288629;}
35 ((A1
= 36969 * (A1
& 0xffff) + (A1
>> 16)) << 16) ^
36 ((A2
= 18000 * (A2
& 0xffff) + (A2
>> 16)) );
40 class CBitRandomGenerator
51 UInt32
GetRnd(int numBits
)
53 if (NumBits
> numBits
)
55 UInt32 result
= Value
& ((1 << numBits
) - 1);
61 UInt32 result
= (Value
<< numBits
);
63 result
|= Value
& ((1 << numBits
) - 1);
65 NumBits
= 32 - numBits
;
70 class CBenchRandomGenerator
72 CBitRandomGenerator RG
;
77 CBenchRandomGenerator(): Buffer(0) {}
78 ~CBenchRandomGenerator() { delete []Buffer
; }
79 void Init() { RG
.Init(); }
80 void Set(UInt32 bufferSize
)
84 Buffer
= new Byte
[bufferSize
];
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
);
103 if (GetRndBit() == 0)
104 return GetLogRandBits(4);
105 return (GetLogRandBits(4) << 10) | RG
.GetRnd(10);
109 if (GetRndBit() == 0)
111 if (GetRndBit() == 0)
112 return 4 + RG
.GetRnd(3);
113 return 12 + RG
.GetRnd(4);
117 while(Pos
< BufferSize
)
119 if (GetRndBit() == 0 || Pos
< 1)
120 Buffer
[Pos
++] = Byte(RG
.GetRnd(8));
123 UInt32 offset
= GetOffset();
124 while (offset
>= Pos
)
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
,
144 void Init(const Byte
*data
, UInt32 size
)
150 STDMETHOD(Read
)(void *data
, UInt32 size
, UInt32
*processedSize
);
153 STDMETHODIMP
CBenchmarkInStream::Read(void *data
, UInt32 size
, UInt32
*processedSize
)
155 UInt32 remain
= Size
- Pos
;
158 for (UInt32 i
= 0; i
< size
; i
++)
159 ((Byte
*)data
)[i
] = Data
[Pos
+ i
];
161 if(processedSize
!= NULL
)
162 *processedSize
= size
;
166 class CBenchmarkOutStream
:
167 public ISequentialOutStream
,
175 CBenchmarkOutStream(): _f(0), Buffer(0) {}
176 virtual ~CBenchmarkOutStream() { delete []Buffer
; }
177 void Init(FILE *f
, UInt32 bufferSize
)
181 Buffer
= new Byte
[bufferSize
];
183 BufferSize
= bufferSize
;
187 STDMETHOD(Write
)(const void *data
, UInt32 size
, UInt32
*processedSize
);
190 STDMETHODIMP
CBenchmarkOutStream::Write(const void *data
, UInt32 size
, UInt32
*processedSize
)
193 for (i
= 0; i
< size
&& Pos
< BufferSize
; i
++)
194 Buffer
[Pos
++] = ((const Byte
*)data
)[i
];
195 if(processedSize
!= NULL
)
199 fprintf(_f
, "\nERROR: Buffer is full\n");
206 public ISequentialOutStream
,
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
;
224 static UInt64
GetTimeCount()
228 if (::QueryPerformanceCounter(&value
))
229 return value
.QuadPart
;
230 return GetTickCount();
236 static UInt64
GetFreq()
240 if (::QueryPerformanceFrequency(&value
))
241 return value
.QuadPart
;
244 return CLOCKS_PER_SEC
;
248 struct CProgressInfo
:
249 public ICompressProgressInfo
,
252 UInt64 ApprovedStart
;
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();
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)
296 return value
* freq
/ elTime
;
299 static UInt64
GetCompressRating(UInt32 dictionarySize
, bool isBT4
,
300 UInt64 elapsedTime
, UInt64 size
)
302 UInt64 numCommandsForOne
;
305 UInt64 t
= GetLogSize(dictionarySize
) - (19 << kSubBits
);
306 numCommandsForOne
= 2000 + ((t
* t
* 68) >> (2 * kSubBits
));
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,
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(
344 UInt32 dictionarySize
,
348 bool decompressMode
, UInt64 secondSize
)
350 UInt64 speed
= MyMultDiv64(size
, elapsedTime
);
351 fprintf(f
, "%6d KB/s ", (unsigned int)(speed
/ 1024));
354 rating
= GetDecompressRating(elapsedTime
, size
, secondSize
);
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");
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)
379 if (dictionarySize
< (1 << 19) && isBT4
|| dictionarySize
< (1 << 15))
381 fprintf(f
, "\nError: dictionary size for benchmark must be >= 19 (512 KB)\n");
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
);
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");
416 encoderSpec
->WriteCoderProperties(propStream
);
418 CBenchRandomGenerator rg
;
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
;
449 ThrowError(f
, result
, "Encoder Error");
452 if (progressInfoSpec
->InSize
== 0)
454 fprintf(f
, "\nError: Internal ERROR 1282\n");
458 ///////////////////////
461 CCrcOutStream
*crcOutStreamSpec
= new CCrcOutStream
;
462 CMyComPtr
<ISequentialOutStream
> crcOutStream
= crcOutStreamSpec
;
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");
475 UInt64 outSize
= kBufferSize
;
476 UInt64 startTime
= ::GetTimeCount();
477 result
= decoder
->Code(inStream
, crcOutStream
, 0, &outSize
, 0);
478 decodeTime
= ::GetTimeCount() - startTime
;
481 ThrowError(f
, result
, "Decode Error");
484 if (crcOutStreamSpec
->CRC
.GetDigest() != crc
.GetDigest())
486 fprintf(f
, "\nError: CRC Error\n");
490 UInt64 benchSize
= kBufferSize
- progressInfoSpec
->InSize
;
491 PrintResults(f
, dictionarySize
, isBT4
, encodeTime
, benchSize
, false, 0);
493 PrintResults(f
, dictionarySize
, isBT4
, decodeTime
, kBufferSize
, true, compressedSize
);
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);
504 PrintResults(f
, dictionarySize
, isBT4
, totalDecodeTime
,
505 kBufferSize
* numIterations
, true, totalCompressedSize
);
506 fprintf(f
, " Average\n");