1 // Bench.cpp
2
3 #include "StdAfx.h"
4
5 #ifndef _WIN32
6 #define USE_POSIX_TIME
7 #define USE_POSIX_TIME2
8 #endif
9
10 #ifdef USE_POSIX_TIME
11 #include <time.h>
12 #ifdef USE_POSIX_TIME2
13 #include <sys/time.h>
14 #endif
15 #endif
16
17 #ifdef _WIN32
18 #define USE_ALLOCA
19 #endif
20
21 #ifdef USE_ALLOCA
22 #ifdef _WIN32
23 #include <malloc.h>
24 #else
25 #include <stdlib.h>
26 #endif
27 #endif
28
29 #include "../../../../C/7zCrc.h"
30 #include "../../../../C/Alloc.h"
31 #include "../../../../C/CpuArch.h"
32
33 #if !defined(_7ZIP_ST) || defined(_WIN32)
34 #include "../../../Windows/System.h"
35 #endif
36
37 #ifndef _7ZIP_ST
38 #include "../../../Windows/Synchronization.h"
39 #include "../../../Windows/Thread.h"
40 #endif
41
42 #include "../../../Common/IntToString.h"
43 #include "../../../Common/StringConvert.h"
44 #include "../../../Common/StringToInt.h"
45
46 #include "../../Common/MethodProps.h"
47 #include "../../Common/StreamUtils.h"
48
49 #include "Bench.h"
50
51 using namespace NWindows;
52
53 static const UInt64 kComplexInCommands = (UInt64)1 <<
54 #ifdef UNDER_CE
55 31;
56 #else
57 34;
58 #endif
59
60 static const UInt64 kComplexInSeconds = 4;
61
SetComplexCommands(UInt32 complexInSeconds,UInt64 cpuFreq,UInt64 & complexInCommands)62 static void SetComplexCommands(UInt32 complexInSeconds, UInt64 cpuFreq, UInt64 &complexInCommands)
63 {
64 complexInCommands = kComplexInCommands;
65 const UInt64 kMinFreq = (UInt64)1000000 * 30;
66 const UInt64 kMaxFreq = (UInt64)1000000 * 20000;
67 if (cpuFreq < kMinFreq) cpuFreq = kMinFreq;
68 if (cpuFreq < kMaxFreq)
69 {
70 if (complexInSeconds != 0)
71 complexInCommands = complexInSeconds * cpuFreq;
72 else
73 complexInCommands = cpuFreq >> 2;
74 }
75 }
76
77 static const unsigned kNumHashDictBits = 17;
78 static const UInt32 kFilterUnpackSize = (48 << 10);
79
80 static const unsigned kOldLzmaDictBits = 30;
81
82 static const UInt32 kAdditionalSize = (1 << 16);
83 static const UInt32 kCompressedAdditionalSize = (1 << 10);
84 static const UInt32 kMaxLzmaPropSize = 5;
85
86 class CBaseRandomGenerator
87 {
88 UInt32 A1;
89 UInt32 A2;
90 public:
CBaseRandomGenerator()91 CBaseRandomGenerator() { Init(); }
Init()92 void Init() { A1 = 362436069; A2 = 521288629;}
GetRnd()93 UInt32 GetRnd()
94 {
95 return
96 ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
97 ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
98 }
99 };
100
101 class CBenchBuffer
102 {
103 public:
104 size_t BufferSize;
105 Byte *Buffer;
106
CBenchBuffer()107 CBenchBuffer(): Buffer(0) {}
~CBenchBuffer()108 virtual ~CBenchBuffer() { Free(); }
Free()109 void Free()
110 {
111 ::MidFree(Buffer);
112 Buffer = 0;
113 }
Alloc(size_t bufferSize)114 bool Alloc(size_t bufferSize)
115 {
116 if (Buffer != 0 && BufferSize == bufferSize)
117 return true;
118 Free();
119 Buffer = (Byte *)::MidAlloc(bufferSize);
120 BufferSize = bufferSize;
121 return (Buffer != 0 || bufferSize == 0);
122 }
123 };
124
125 class CBenchRandomGenerator: public CBenchBuffer
126 {
127 CBaseRandomGenerator *RG;
128 public:
Set(CBaseRandomGenerator * rg)129 void Set(CBaseRandomGenerator *rg) { RG = rg; }
GetVal(UInt32 & res,unsigned numBits)130 UInt32 GetVal(UInt32 &res, unsigned numBits)
131 {
132 UInt32 val = res & (((UInt32)1 << numBits) - 1);
133 res >>= numBits;
134 return val;
135 }
GetLen(UInt32 & res)136 UInt32 GetLen(UInt32 &res)
137 {
138 UInt32 len = GetVal(res, 2);
139 return GetVal(res, 1 + len);
140 }
141
GenerateSimpleRandom()142 void GenerateSimpleRandom()
143 {
144 for (UInt32 i = 0; i < BufferSize; i++)
145 Buffer[i] = (Byte)RG->GetRnd();
146 }
147
Generate(unsigned dictBits)148 void Generate(unsigned dictBits)
149 {
150 UInt32 pos = 0;
151 UInt32 rep0 = 1;
152 while (pos < BufferSize)
153 {
154 UInt32 res = RG->GetRnd();
155 res >>= 1;
156 if (GetVal(res, 1) == 0 || pos < 1024)
157 Buffer[pos++] = (Byte)(res & 0xFF);
158 else
159 {
160 UInt32 len;
161 len = 1 + GetLen(res);
162 if (GetVal(res, 3) != 0)
163 {
164 len += GetLen(res);
165 do
166 {
167 UInt32 ppp = GetVal(res, 5) + 6;
168 res = RG->GetRnd();
169 if (ppp > dictBits)
170 continue;
171 rep0 = /* (1 << ppp) +*/ GetVal(res, ppp);
172 res = RG->GetRnd();
173 }
174 while (rep0 >= pos);
175 rep0++;
176 }
177
178 for (UInt32 i = 0; i < len && pos < BufferSize; i++, pos++)
179 Buffer[pos] = Buffer[pos - rep0];
180 }
181 }
182 }
183 };
184
185
186 class CBenchmarkInStream:
187 public ISequentialInStream,
188 public CMyUnknownImp
189 {
190 const Byte *Data;
191 size_t Pos;
192 size_t Size;
193 public:
194 MY_UNKNOWN_IMP
Init(const Byte * data,size_t size)195 void Init(const Byte *data, size_t size)
196 {
197 Data = data;
198 Size = size;
199 Pos = 0;
200 }
201 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
202 };
203
Read(void * data,UInt32 size,UInt32 * processedSize)204 STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
205 {
206 size_t remain = Size - Pos;
207 UInt32 kMaxBlockSize = (1 << 20);
208 if (size > kMaxBlockSize)
209 size = kMaxBlockSize;
210 if (size > remain)
211 size = (UInt32)remain;
212 for (UInt32 i = 0; i < size; i++)
213 ((Byte *)data)[i] = Data[Pos + i];
214 Pos += size;
215 if(processedSize != NULL)
216 *processedSize = size;
217 return S_OK;
218 }
219
220 class CBenchmarkOutStream:
221 public ISequentialOutStream,
222 public CBenchBuffer,
223 public CMyUnknownImp
224 {
225 // bool _overflow;
226 public:
227 UInt32 Pos;
228 bool RealCopy;
229 bool CalcCrc;
230 UInt32 Crc;
231
232 // CBenchmarkOutStream(): _overflow(false) {}
Init(bool realCopy,bool calcCrc)233 void Init(bool realCopy, bool calcCrc)
234 {
235 Crc = CRC_INIT_VAL;
236 RealCopy = realCopy;
237 CalcCrc = calcCrc;
238 // _overflow = false;
239 Pos = 0;
240 }
241 MY_UNKNOWN_IMP
242 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
243 };
244
Write(const void * data,UInt32 size,UInt32 * processedSize)245 STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
246 {
247 size_t curSize = BufferSize - Pos;
248 if (curSize > size)
249 curSize = size;
250 if (RealCopy)
251 memcpy(Buffer + Pos, data, curSize);
252 if (CalcCrc)
253 Crc = CrcUpdate(Crc, data, curSize);
254 Pos += (UInt32)curSize;
255 if(processedSize != NULL)
256 *processedSize = (UInt32)curSize;
257 if (curSize != size)
258 {
259 // _overflow = true;
260 return E_FAIL;
261 }
262 return S_OK;
263 }
264
265 class CCrcOutStream:
266 public ISequentialOutStream,
267 public CMyUnknownImp
268 {
269 public:
270 bool CalcCrc;
271 UInt32 Crc;
272 MY_UNKNOWN_IMP
273
CCrcOutStream()274 CCrcOutStream(): CalcCrc(true) {};
Init()275 void Init() { Crc = CRC_INIT_VAL; }
276 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
277 };
278
Write(const void * data,UInt32 size,UInt32 * processedSize)279 STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
280 {
281 if (CalcCrc)
282 Crc = CrcUpdate(Crc, data, size);
283 if (processedSize != NULL)
284 *processedSize = size;
285 return S_OK;
286 }
287
GetTimeCount()288 static UInt64 GetTimeCount()
289 {
290 #ifdef USE_POSIX_TIME
291 #ifdef USE_POSIX_TIME2
292 timeval v;
293 if (gettimeofday(&v, 0) == 0)
294 return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec;
295 return (UInt64)time(NULL) * 1000000;
296 #else
297 return time(NULL);
298 #endif
299 #else
300 /*
301 LARGE_INTEGER value;
302 if (::QueryPerformanceCounter(&value))
303 return value.QuadPart;
304 */
305 return GetTickCount();
306 #endif
307 }
308
GetFreq()309 static UInt64 GetFreq()
310 {
311 #ifdef USE_POSIX_TIME
312 #ifdef USE_POSIX_TIME2
313 return 1000000;
314 #else
315 return 1;
316 #endif
317 #else
318 /*
319 LARGE_INTEGER value;
320 if (::QueryPerformanceFrequency(&value))
321 return value.QuadPart;
322 */
323 return 1000;
324 #endif
325 }
326
327 #ifdef USE_POSIX_TIME
328
329 struct CUserTime
330 {
331 UInt64 Sum;
332 clock_t Prev;
333
InitCUserTime334 void Init()
335 {
336 Prev = clock();
337 Sum = 0;
338 }
339
GetUserTimeCUserTime340 UInt64 GetUserTime()
341 {
342 clock_t v = clock();
343 Sum += v - Prev;
344 Prev = v;
345 return Sum;
346 }
347 };
348
349 #else
350
GetTime64(const FILETIME & t)351 static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
GetWinUserTime()352 UInt64 GetWinUserTime()
353 {
354 FILETIME creationTime, exitTime, kernelTime, userTime;
355 if (
356 #ifdef UNDER_CE
357 ::GetThreadTimes(::GetCurrentThread()
358 #else
359 ::GetProcessTimes(::GetCurrentProcess()
360 #endif
361 , &creationTime, &exitTime, &kernelTime, &userTime) != 0)
362 return GetTime64(userTime) + GetTime64(kernelTime);
363 return (UInt64)GetTickCount() * 10000;
364 }
365
366 struct CUserTime
367 {
368 UInt64 StartTime;
369
InitCUserTime370 void Init() { StartTime = GetWinUserTime(); }
GetUserTimeCUserTime371 UInt64 GetUserTime() { return GetWinUserTime() - StartTime; }
372 };
373
374 #endif
375
GetUserFreq()376 static UInt64 GetUserFreq()
377 {
378 #ifdef USE_POSIX_TIME
379 return CLOCKS_PER_SEC;
380 #else
381 return 10000000;
382 #endif
383 }
384
385 class CBenchProgressStatus
386 {
387 #ifndef _7ZIP_ST
388 NSynchronization::CCriticalSection CS;
389 #endif
390 public:
391 HRESULT Res;
392 bool EncodeMode;
SetResult(HRESULT res)393 void SetResult(HRESULT res)
394 {
395 #ifndef _7ZIP_ST
396 NSynchronization::CCriticalSectionLock lock(CS);
397 #endif
398 Res = res;
399 }
GetResult()400 HRESULT GetResult()
401 {
402 #ifndef _7ZIP_ST
403 NSynchronization::CCriticalSectionLock lock(CS);
404 #endif
405 return Res;
406 }
407 };
408
409 struct CBenchInfoCalc
410 {
411 CBenchInfo BenchInfo;
412 CUserTime UserTime;
413
414 void SetStartTime();
415 void SetFinishTime(CBenchInfo &dest);
416 };
417
SetStartTime()418 void CBenchInfoCalc::SetStartTime()
419 {
420 BenchInfo.GlobalFreq = GetFreq();
421 BenchInfo.UserFreq = GetUserFreq();
422 BenchInfo.GlobalTime = ::GetTimeCount();
423 BenchInfo.UserTime = 0;
424 UserTime.Init();
425 }
426
SetFinishTime(CBenchInfo & dest)427 void CBenchInfoCalc::SetFinishTime(CBenchInfo &dest)
428 {
429 dest = BenchInfo;
430 dest.GlobalTime = ::GetTimeCount() - BenchInfo.GlobalTime;
431 dest.UserTime = UserTime.GetUserTime();
432 }
433
434 class CBenchProgressInfo:
435 public ICompressProgressInfo,
436 public CMyUnknownImp,
437 public CBenchInfoCalc
438 {
439 public:
440 CBenchProgressStatus *Status;
441 HRESULT Res;
442 IBenchCallback *Callback;
443
CBenchProgressInfo()444 CBenchProgressInfo(): Callback(0) {}
445 MY_UNKNOWN_IMP
446 STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
447 };
448
SetRatioInfo(const UInt64 * inSize,const UInt64 * outSize)449 STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
450 {
451 HRESULT res = Status->GetResult();
452 if (res != S_OK)
453 return res;
454 if (!Callback)
455 return res;
456 CBenchInfo info;
457 SetFinishTime(info);
458 if (Status->EncodeMode)
459 {
460 info.UnpackSize = BenchInfo.UnpackSize + *inSize;
461 info.PackSize = BenchInfo.PackSize + *outSize;
462 res = Callback->SetEncodeResult(info, false);
463 }
464 else
465 {
466 info.PackSize = BenchInfo.PackSize + *inSize;
467 info.UnpackSize = BenchInfo.UnpackSize + *outSize;
468 res = Callback->SetDecodeResult(info, false);
469 }
470 if (res != S_OK)
471 Status->SetResult(res);
472 return res;
473 }
474
475 static const int kSubBits = 8;
476
GetLogSize(UInt32 size)477 static UInt32 GetLogSize(UInt32 size)
478 {
479 for (int i = kSubBits; i < 32; i++)
480 for (UInt32 j = 0; j < (1 << kSubBits); j++)
481 if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
482 return (i << kSubBits) + j;
483 return (32 << kSubBits);
484 }
485
NormalizeVals(UInt64 & v1,UInt64 & v2)486 static void NormalizeVals(UInt64 &v1, UInt64 &v2)
487 {
488 while (v1 > 1000000)
489 {
490 v1 >>= 1;
491 v2 >>= 1;
492 }
493 }
494
GetUsage() const495 UInt64 CBenchInfo::GetUsage() const
496 {
497 UInt64 userTime = UserTime;
498 UInt64 userFreq = UserFreq;
499 UInt64 globalTime = GlobalTime;
500 UInt64 globalFreq = GlobalFreq;
501 NormalizeVals(userTime, userFreq);
502 NormalizeVals(globalFreq, globalTime);
503 if (userFreq == 0)
504 userFreq = 1;
505 if (globalTime == 0)
506 globalTime = 1;
507 return userTime * globalFreq * 1000000 / userFreq / globalTime;
508 }
509
GetRatingPerUsage(UInt64 rating) const510 UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const
511 {
512 UInt64 userTime = UserTime;
513 UInt64 userFreq = UserFreq;
514 UInt64 globalTime = GlobalTime;
515 UInt64 globalFreq = GlobalFreq;
516 NormalizeVals(userFreq, userTime);
517 NormalizeVals(globalTime, globalFreq);
518 if (globalFreq == 0)
519 globalFreq = 1;
520 if (userTime == 0)
521 userTime = 1;
522 return userFreq * globalTime / globalFreq * rating / userTime;
523 }
524
MyMultDiv64(UInt64 value,UInt64 elapsedTime,UInt64 freq)525 static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
526 {
527 UInt64 elTime = elapsedTime;
528 NormalizeVals(freq, elTime);
529 if (elTime == 0)
530 elTime = 1;
531 return value * freq / elTime;
532 }
533
GetSpeed(UInt64 numCommands) const534 UInt64 CBenchInfo::GetSpeed(UInt64 numCommands) const
535 {
536 return MyMultDiv64(numCommands, GlobalTime, GlobalFreq);
537 }
538
539 struct CBenchProps
540 {
541 bool LzmaRatingMode;
542
543 UInt32 EncComplex;
544 UInt32 DecComplexCompr;
545 UInt32 DecComplexUnc;
546
CBenchPropsCBenchProps547 CBenchProps(): LzmaRatingMode(false) {}
548 void SetLzmaCompexity();
549
GeComprCommandsCBenchProps550 UInt64 GeComprCommands(UInt64 unpackSize)
551 {
552 return unpackSize * EncComplex;
553 }
554
GeDecomprCommandsCBenchProps555 UInt64 GeDecomprCommands(UInt64 packSize, UInt64 unpackSize)
556 {
557 return (packSize * DecComplexCompr + unpackSize * DecComplexUnc);
558 }
559
560 UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
561 UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations);
562 };
563
SetLzmaCompexity()564 void CBenchProps::SetLzmaCompexity()
565 {
566 EncComplex = 1200;
567 DecComplexUnc = 4;
568 DecComplexCompr = 190;
569 LzmaRatingMode = true;
570 }
571
GetCompressRating(UInt32 dictSize,UInt64 elapsedTime,UInt64 freq,UInt64 size)572 UInt64 CBenchProps::GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
573 {
574 if (dictSize < (1 << kBenchMinDicLogSize))
575 dictSize = (1 << kBenchMinDicLogSize);
576 UInt64 encComplex = EncComplex;
577 if (LzmaRatingMode)
578 {
579 UInt64 t = GetLogSize(dictSize) - (kBenchMinDicLogSize << kSubBits);
580 encComplex = 870 + ((t * t * 5) >> (2 * kSubBits));
581 }
582 UInt64 numCommands = (UInt64)size * encComplex;
583 return MyMultDiv64(numCommands, elapsedTime, freq);
584 }
585
GetDecompressRating(UInt64 elapsedTime,UInt64 freq,UInt64 outSize,UInt64 inSize,UInt64 numIterations)586 UInt64 CBenchProps::GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations)
587 {
588 UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * numIterations;
589 return MyMultDiv64(numCommands, elapsedTime, freq);
590 }
591
GetCompressRating(UInt32 dictSize,UInt64 elapsedTime,UInt64 freq,UInt64 size)592 UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
593 {
594 CBenchProps props;
595 props.SetLzmaCompexity();
596 return props.GetCompressRating(dictSize, elapsedTime, freq, size);
597 }
598
GetDecompressRating(UInt64 elapsedTime,UInt64 freq,UInt64 outSize,UInt64 inSize,UInt64 numIterations)599 UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations)
600 {
601 CBenchProps props;
602 props.SetLzmaCompexity();
603 return props.GetDecompressRating(elapsedTime, freq, outSize, inSize, numIterations);
604 }
605
606 struct CEncoderInfo;
607
608 struct CEncoderInfo
609 {
610 #ifndef _7ZIP_ST
611 NWindows::CThread thread[2];
612 UInt32 NumDecoderSubThreads;
613 #endif
614 CMyComPtr<ICompressCoder> _encoder;
615 CMyComPtr<ICompressFilter> _encoderFilter;
616 CBenchProgressInfo *progressInfoSpec[2];
617 CMyComPtr<ICompressProgressInfo> progressInfo[2];
618 UInt64 NumIterations;
619 #ifdef USE_ALLOCA
620 size_t AllocaSize;
621 #endif
622
623 Byte _key[32];
624 Byte _iv[16];
625 Byte _psw[16];
626 bool CheckCrc_Enc;
627 bool CheckCrc_Dec;
628
629 struct CDecoderInfo
630 {
631 CEncoderInfo *Encoder;
632 UInt32 DecoderIndex;
633 #ifdef USE_ALLOCA
634 size_t AllocaSize;
635 #endif
636 bool CallbackMode;
637 };
638 CDecoderInfo decodersInfo[2];
639
640 CMyComPtr<ICompressCoder> _decoders[2];
641 CMyComPtr<ICompressFilter> _decoderFilter;
642
643 HRESULT Results[2];
644 CBenchmarkOutStream *outStreamSpec;
645 CMyComPtr<ISequentialOutStream> outStream;
646 IBenchCallback *callback;
647 IBenchPrintCallback *printCallback;
648 UInt32 crc;
649 UInt32 kBufferSize;
650 UInt32 compressedSize;
651 CBenchRandomGenerator rg;
652 CBenchBuffer rgCopy; // it must be 16-byte aligned !!!
653 CBenchmarkOutStream *propStreamSpec;
654 CMyComPtr<ISequentialOutStream> propStream;
655
656 // for decode
657 COneMethodInfo _method;
658 UInt32 _uncompressedDataSize;
659
660 HRESULT Init(
661 const COneMethodInfo &method,
662 UInt32 uncompressedDataSize,
663 unsigned generateDictBits,
664 CBaseRandomGenerator *rg);
665 HRESULT Encode();
666 HRESULT Decode(UInt32 decoderIndex);
667
CEncoderInfoCEncoderInfo668 CEncoderInfo():
669 CheckCrc_Enc(true),
670 CheckCrc_Dec(true),
671 outStreamSpec(0), callback(0), printCallback(0), propStreamSpec(0) {}
672
673 #ifndef _7ZIP_ST
EncodeThreadFunctionCEncoderInfo674 static THREAD_FUNC_DECL EncodeThreadFunction(void *param)
675 {
676 HRESULT res;
677 CEncoderInfo *encoder = (CEncoderInfo *)param;
678 try
679 {
680 #ifdef USE_ALLOCA
681 alloca(encoder->AllocaSize);
682 #endif
683 res = encoder->Encode();
684 encoder->Results[0] = res;
685 }
686 catch(...)
687 {
688 res = E_FAIL;
689 }
690 if (res != S_OK)
691 encoder->progressInfoSpec[0]->Status->SetResult(res);
692 return 0;
693 }
DecodeThreadFunctionCEncoderInfo694 static THREAD_FUNC_DECL DecodeThreadFunction(void *param)
695 {
696 CDecoderInfo *decoder = (CDecoderInfo *)param;
697 #ifdef USE_ALLOCA
698 alloca(decoder->AllocaSize);
699 #endif
700 CEncoderInfo *encoder = decoder->Encoder;
701 encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);
702 return 0;
703 }
704
CreateEncoderThreadCEncoderInfo705 HRESULT CreateEncoderThread()
706 {
707 return thread[0].Create(EncodeThreadFunction, this);
708 }
709
CreateDecoderThreadCEncoderInfo710 HRESULT CreateDecoderThread(int index, bool callbackMode
711 #ifdef USE_ALLOCA
712 , size_t allocaSize
713 #endif
714 )
715 {
716 CDecoderInfo &decoder = decodersInfo[index];
717 decoder.DecoderIndex = index;
718 decoder.Encoder = this;
719 #ifdef USE_ALLOCA
720 decoder.AllocaSize = allocaSize;
721 #endif
722 decoder.CallbackMode = callbackMode;
723 return thread[index].Create(DecodeThreadFunction, &decoder);
724 }
725 #endif
726 };
727
728 static const UInt32 k_LZMA = 0x030101;
729
Init(const COneMethodInfo & method,UInt32 uncompressedDataSize,unsigned generateDictBits,CBaseRandomGenerator * rgLoc)730 HRESULT CEncoderInfo::Init(
731 const COneMethodInfo &method,
732 UInt32 uncompressedDataSize,
733 unsigned generateDictBits,
734 CBaseRandomGenerator *rgLoc)
735 {
736 rg.Set(rgLoc);
737 kBufferSize = uncompressedDataSize;
738 UInt32 kCompressedBufferSize =
739 kBufferSize + kCompressedAdditionalSize;
740 // (kBufferSize - kBufferSize / 4) + kCompressedAdditionalSize;
741 if (!rg.Alloc(kBufferSize))
742 return E_OUTOFMEMORY;
743 if (generateDictBits == 0)
744 rg.GenerateSimpleRandom();
745 else
746 rg.Generate(generateDictBits);
747 crc = CrcCalc(rg.Buffer, rg.BufferSize);
748
749 if (_encoderFilter)
750 {
751 if (!rgCopy.Alloc(rg.BufferSize))
752 return E_OUTOFMEMORY;
753 }
754
755
756 outStreamSpec = new CBenchmarkOutStream;
757 if (!outStreamSpec->Alloc(kCompressedBufferSize))
758 return E_OUTOFMEMORY;
759
760 outStream = outStreamSpec;
761
762 propStreamSpec = 0;
763 if (!propStream)
764 {
765 propStreamSpec = new CBenchmarkOutStream;
766 propStream = propStreamSpec;
767 }
768 if (!propStreamSpec->Alloc(kMaxLzmaPropSize))
769 return E_OUTOFMEMORY;
770 propStreamSpec->Init(true, false);
771
772
773 CMyComPtr<IUnknown> coder;
774 if (_encoderFilter)
775 coder = _encoderFilter;
776 else
777 coder = _encoder;
778 {
779 CMyComPtr<ICompressSetCoderProperties> scp;
780 coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
781 if (scp)
782 {
783 UInt64 reduceSize = uncompressedDataSize;
784 RINOK(method.SetCoderProps(scp, &reduceSize));
785 }
786 else
787 {
788 if (method.AreThereNonOptionalProps())
789 return E_INVALIDARG;
790 }
791
792 CMyComPtr<ICompressWriteCoderProperties> writeCoderProps;
793 coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps);
794 if (writeCoderProps)
795 {
796 RINOK(writeCoderProps->WriteCoderProperties(propStream));
797 }
798
799 {
800 CMyComPtr<ICryptoSetPassword> sp;
801 coder.QueryInterface(IID_ICryptoSetPassword, &sp);
802 if (sp)
803 {
804 RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)));
805
806 // we must call encoding one time to calculate password key for key cache.
807 // it must be after WriteCoderProperties!
808 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
809 CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
810 Byte temp[16];
811 memset(temp, 0, sizeof(temp));
812 inStreamSpec->Init(temp, sizeof(temp));
813
814 CCrcOutStream *outStreamSpec = new CCrcOutStream;
815 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
816 outStreamSpec->Init();
817
818 if (_encoderFilter)
819 {
820 _encoderFilter->Init();
821 _encoderFilter->Filter(temp, sizeof(temp));
822 }
823 else
824 {
825 RINOK(_encoder->Code(inStream, outStream, 0, 0, NULL));
826 }
827 }
828 }
829
830 }
831 return S_OK;
832 }
833
Encode()834 HRESULT CEncoderInfo::Encode()
835 {
836 CBenchInfo &bi = progressInfoSpec[0]->BenchInfo;
837 bi.UnpackSize = 0;
838 bi.PackSize = 0;
839 CMyComPtr<ICryptoProperties> cp;
840 CMyComPtr<IUnknown> coder;
841 if (_encoderFilter)
842 coder = _encoderFilter;
843 else
844 coder = _encoder;
845 coder.QueryInterface(IID_ICryptoProperties, &cp);
846 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
847 CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
848 UInt64 prev = 0;
849
850 UInt32 crcPrev = 0;
851
852 if (cp)
853 {
854 RINOK(cp->SetKey(_key, sizeof(_key)));
855 RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
856 }
857
858 for (UInt64 i = 0; i < NumIterations; i++)
859 {
860 if (printCallback && bi.UnpackSize - prev > (1 << 20))
861 {
862 RINOK(printCallback->CheckBreak());
863 prev = bi.UnpackSize;
864 }
865
866 bool isLast = (i == NumIterations - 1);
867 bool calcCrc = ((isLast || (i & 0x7F) == 0 || CheckCrc_Enc) && NumIterations != 1);
868 outStreamSpec->Init(isLast, calcCrc);
869
870 if (_encoderFilter)
871 {
872 memcpy(rgCopy.Buffer, rg.Buffer, rg.BufferSize);
873 _encoderFilter->Init();
874 _encoderFilter->Filter(rgCopy.Buffer, (UInt32)rg.BufferSize);
875 RINOK(WriteStream(outStream, rgCopy.Buffer, rg.BufferSize));
876 }
877 else
878 {
879 inStreamSpec->Init(rg.Buffer, rg.BufferSize);
880 RINOK(_encoder->Code(inStream, outStream, 0, 0, progressInfo[0]));
881 }
882
883 UInt32 crcNew = CRC_GET_DIGEST(outStreamSpec->Crc);
884 if (i == 0)
885 crcPrev = crcNew;
886 else if (calcCrc && crcPrev != crcNew)
887 return E_FAIL;
888 compressedSize = outStreamSpec->Pos;
889 bi.UnpackSize += rg.BufferSize;
890 bi.PackSize += compressedSize;
891 }
892 _encoder.Release();
893 _encoderFilter.Release();
894 return S_OK;
895 }
896
Decode(UInt32 decoderIndex)897 HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)
898 {
899 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
900 CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
901 CMyComPtr<ICompressCoder> &decoder = _decoders[decoderIndex];
902 CMyComPtr<IUnknown> coder;
903 if (_decoderFilter)
904 {
905 if (decoderIndex != 0)
906 return E_FAIL;
907 coder = _decoderFilter;
908 }
909 else
910 coder = decoder;
911
912 CMyComPtr<ICompressSetDecoderProperties2> setDecProps;
913 coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps);
914 if (!setDecProps && propStreamSpec->Pos != 0)
915 return E_FAIL;
916
917 CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
918 CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
919
920 CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
921 pi->BenchInfo.UnpackSize = 0;
922 pi->BenchInfo.PackSize = 0;
923
924 #ifndef _7ZIP_ST
925 {
926 CMyComPtr<ICompressSetCoderMt> setCoderMt;
927 coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
928 if (setCoderMt)
929 {
930 RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads));
931 }
932 }
933 #endif
934
935 CMyComPtr<ICompressSetCoderProperties> scp;
936 coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
937 if (scp)
938 {
939 UInt64 reduceSize = _uncompressedDataSize;
940 RINOK(_method.SetCoderProps(scp, &reduceSize));
941 }
942
943 CMyComPtr<ICryptoProperties> cp;
944 coder.QueryInterface(IID_ICryptoProperties, &cp);
945
946 if (setDecProps)
947 {
948 RINOK(setDecProps->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos));
949 }
950
951 {
952 CMyComPtr<ICryptoSetPassword> sp;
953 coder.QueryInterface(IID_ICryptoSetPassword, &sp);
954 if (sp)
955 {
956 RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)));
957 }
958 }
959
960 UInt64 prev = 0;
961
962 if (cp)
963 {
964 RINOK(cp->SetKey(_key, sizeof(_key)));
965 RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
966 }
967
968 for (UInt64 i = 0; i < NumIterations; i++)
969 {
970 if (printCallback && pi->BenchInfo.UnpackSize - prev > (1 << 20))
971 {
972 RINOK(printCallback->CheckBreak());
973 prev = pi->BenchInfo.UnpackSize;
974 }
975
976 inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
977 crcOutStreamSpec->Init();
978
979 UInt64 outSize = kBufferSize;
980 crcOutStreamSpec->CalcCrc = ((i & 0x7F) == 0 || CheckCrc_Dec);
981 if (_decoderFilter)
982 {
983 if (compressedSize > rgCopy.BufferSize)
984 return E_FAIL;
985 memcpy(rgCopy.Buffer, outStreamSpec->Buffer, compressedSize);
986 _decoderFilter->Init();
987 _decoderFilter->Filter(rgCopy.Buffer, compressedSize);
988 RINOK(WriteStream(crcOutStream, rgCopy.Buffer, rg.BufferSize));
989 }
990 else
991 {
992 RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex]));
993 }
994 if (crcOutStreamSpec->CalcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc)
995 return S_FALSE;
996 pi->BenchInfo.UnpackSize += kBufferSize;
997 pi->BenchInfo.PackSize += compressedSize;
998 }
999 decoder.Release();
1000 _decoderFilter.Release();
1001 return S_OK;
1002 }
1003
1004 static const UInt32 kNumThreadsMax = (1 << 12);
1005
1006 struct CBenchEncoders
1007 {
1008 CEncoderInfo *encoders;
CBenchEncodersCBenchEncoders1009 CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; }
~CBenchEncodersCBenchEncoders1010 ~CBenchEncoders() { delete []encoders; }
1011 };
1012
GetNumIterations(UInt64 numCommands,UInt64 complexInCommands)1013 static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands)
1014 {
1015 if (numCommands < (1 << 4))
1016 numCommands = (1 << 4);
1017 UInt64 res = complexInCommands / numCommands;
1018 return (res == 0 ? 1 : res);
1019 }
1020
MethodBench(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,bool oldLzmaBenchMode,UInt32 numThreads,const COneMethodInfo & method2,UInt32 uncompressedDataSize,unsigned generateDictBits,IBenchPrintCallback * printCallback,IBenchCallback * callback,CBenchProps * benchProps)1021 static HRESULT MethodBench(
1022 DECL_EXTERNAL_CODECS_LOC_VARS
1023 UInt64 complexInCommands,
1024 bool oldLzmaBenchMode,
1025 UInt32 numThreads,
1026 const COneMethodInfo &method2,
1027 UInt32 uncompressedDataSize,
1028 unsigned generateDictBits,
1029 IBenchPrintCallback *printCallback,
1030 IBenchCallback *callback,
1031 CBenchProps *benchProps)
1032 {
1033 COneMethodInfo method = method2;
1034 UInt64 methodId;
1035 UInt32 numInStreams, numOutStreams;
1036 if (!FindMethod(
1037 EXTERNAL_CODECS_LOC_VARS
1038 method.MethodName, methodId, numInStreams, numOutStreams))
1039 return E_NOTIMPL;
1040 if (numInStreams != 1 || numOutStreams != 1)
1041 return E_INVALIDARG;
1042
1043 UInt32 numEncoderThreads = 1;
1044 UInt32 numSubDecoderThreads = 1;
1045
1046 #ifndef _7ZIP_ST
1047 numEncoderThreads = numThreads;
1048
1049 if (oldLzmaBenchMode && methodId == k_LZMA)
1050 {
1051 bool fixedNumber;
1052 UInt32 numLzmaThreads = method.Get_Lzma_NumThreads(fixedNumber);
1053 if (!fixedNumber && numThreads == 1)
1054 method.AddNumThreadsProp(1);
1055 if (numThreads > 1 && numLzmaThreads > 1)
1056 {
1057 numEncoderThreads = numThreads / 2;
1058 numSubDecoderThreads = 2;
1059 }
1060 }
1061 #endif
1062
1063 CBenchEncoders encodersSpec(numEncoderThreads);
1064 CEncoderInfo *encoders = encodersSpec.encoders;
1065
1066 UInt32 i;
1067 for (i = 0; i < numEncoderThreads; i++)
1068 {
1069 CEncoderInfo &encoder = encoders[i];
1070 encoder.callback = (i == 0) ? callback : 0;
1071 encoder.printCallback = printCallback;
1072
1073 CMyComPtr<ICompressCoder2> coder2;
1074 RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodId,
1075 encoder._encoderFilter, encoder._encoder, coder2, true, false));
1076 if (!encoder._encoder && !encoder._encoderFilter)
1077 return E_NOTIMPL;
1078 // encoder._encoderFilter.Release(); // we can disable filter to check the speed of FilterCoder.
1079
1080 encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30 ;
1081 encoder.CheckCrc_Dec = (benchProps->DecComplexCompr + benchProps->DecComplexUnc) > 30 ;
1082
1083 memset(encoder._iv, 0, sizeof(encoder._iv));
1084 memset(encoder._key, 0, sizeof(encoder._key));
1085 memset(encoder._psw, 0, sizeof(encoder._psw));
1086
1087 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1088 {
1089 CMyComPtr<ICompressCoder2> coder2de;
1090 CMyComPtr<ICompressCoder> &decoder = encoder._decoders[j];
1091 RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodId,
1092 encoder._decoderFilter, decoder, coder2de, false, false));
1093 if (!encoder._decoderFilter && !decoder)
1094 return E_NOTIMPL;
1095 }
1096 }
1097
1098 CBaseRandomGenerator rg;
1099 rg.Init();
1100 for (i = 0; i < numEncoderThreads; i++)
1101 {
1102 CEncoderInfo &encoder = encoders[i];
1103 encoder._method = method;
1104 encoder._uncompressedDataSize = uncompressedDataSize;
1105 RINOK(encoders[i].Init(method, uncompressedDataSize, generateDictBits, &rg));
1106 }
1107
1108 CBenchProgressStatus status;
1109 status.Res = S_OK;
1110 status.EncodeMode = true;
1111
1112 for (i = 0; i < numEncoderThreads; i++)
1113 {
1114 CEncoderInfo &encoder = encoders[i];
1115 encoder.NumIterations = GetNumIterations(benchProps->GeComprCommands(uncompressedDataSize), complexInCommands);
1116
1117 for (int j = 0; j < 2; j++)
1118 {
1119 CBenchProgressInfo *spec = new CBenchProgressInfo;
1120 encoder.progressInfoSpec[j] = spec;
1121 encoder.progressInfo[j] = spec;
1122 spec->Status = &status;
1123 }
1124 if (i == 0)
1125 {
1126 CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
1127 bpi->Callback = callback;
1128 bpi->BenchInfo.NumIterations = numEncoderThreads;
1129 bpi->SetStartTime();
1130 }
1131
1132 #ifndef _7ZIP_ST
1133 if (numEncoderThreads > 1)
1134 {
1135 #ifdef USE_ALLOCA
1136 encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
1137 #endif
1138 RINOK(encoder.CreateEncoderThread())
1139 }
1140 else
1141 #endif
1142 {
1143 RINOK(encoder.Encode());
1144 }
1145 }
1146 #ifndef _7ZIP_ST
1147 if (numEncoderThreads > 1)
1148 for (i = 0; i < numEncoderThreads; i++)
1149 encoders[i].thread[0].Wait();
1150 #endif
1151
1152 RINOK(status.Res);
1153
1154 CBenchInfo info;
1155
1156 encoders[0].progressInfoSpec[0]->SetFinishTime(info);
1157 info.UnpackSize = 0;
1158 info.PackSize = 0;
1159 info.NumIterations = encoders[0].NumIterations;
1160 for (i = 0; i < numEncoderThreads; i++)
1161 {
1162 CEncoderInfo &encoder = encoders[i];
1163 info.UnpackSize += encoder.kBufferSize;
1164 info.PackSize += encoder.compressedSize;
1165 }
1166 RINOK(callback->SetEncodeResult(info, true));
1167
1168
1169 status.Res = S_OK;
1170 status.EncodeMode = false;
1171
1172 UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
1173 for (i = 0; i < numEncoderThreads; i++)
1174 {
1175 CEncoderInfo &encoder = encoders[i];
1176
1177 if (i == 0)
1178 {
1179 encoder.NumIterations = GetNumIterations(benchProps->GeDecomprCommands(encoder.compressedSize, encoder.kBufferSize), complexInCommands);
1180 CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
1181 bpi->Callback = callback;
1182 bpi->BenchInfo.NumIterations = numDecoderThreads;
1183 bpi->SetStartTime();
1184 }
1185 else
1186 encoder.NumIterations = encoders[0].NumIterations;
1187
1188 #ifndef _7ZIP_ST
1189 {
1190 int numSubThreads = method.Get_NumThreads();
1191 encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : numSubThreads;
1192 }
1193 if (numDecoderThreads > 1)
1194 {
1195 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1196 {
1197 HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
1198 #ifdef USE_ALLOCA
1199 , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
1200 #endif
1201 );
1202 RINOK(res);
1203 }
1204 }
1205 else
1206 #endif
1207 {
1208 RINOK(encoder.Decode(0));
1209 }
1210 }
1211 #ifndef _7ZIP_ST
1212 HRESULT res = S_OK;
1213 if (numDecoderThreads > 1)
1214 for (i = 0; i < numEncoderThreads; i++)
1215 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1216 {
1217 CEncoderInfo &encoder = encoders[i];
1218 encoder.thread[j].Wait();
1219 if (encoder.Results[j] != S_OK)
1220 res = encoder.Results[j];
1221 }
1222 RINOK(res);
1223 #endif
1224 RINOK(status.Res);
1225 encoders[0].progressInfoSpec[0]->SetFinishTime(info);
1226 #ifndef _7ZIP_ST
1227 #ifdef UNDER_CE
1228 if (numDecoderThreads > 1)
1229 for (i = 0; i < numEncoderThreads; i++)
1230 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1231 {
1232 FILETIME creationTime, exitTime, kernelTime, userTime;
1233 if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0)
1234 info.UserTime += GetTime64(userTime) + GetTime64(kernelTime);
1235 }
1236 #endif
1237 #endif
1238 info.UnpackSize = 0;
1239 info.PackSize = 0;
1240 info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
1241 for (i = 0; i < numEncoderThreads; i++)
1242 {
1243 CEncoderInfo &encoder = encoders[i];
1244 info.UnpackSize += encoder.kBufferSize;
1245 info.PackSize += encoder.compressedSize;
1246 }
1247 RINOK(callback->SetDecodeResult(info, false));
1248 RINOK(callback->SetDecodeResult(info, true));
1249 return S_OK;
1250 }
1251
1252
GetLZMAUsage(bool multiThread,UInt32 dictionary)1253 inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)
1254 {
1255 UInt32 hs = dictionary - 1;
1256 hs |= (hs >> 1);
1257 hs |= (hs >> 2);
1258 hs |= (hs >> 4);
1259 hs |= (hs >> 8);
1260 hs >>= 1;
1261 hs |= 0xFFFF;
1262 if (hs > (1 << 24))
1263 hs >>= 1;
1264 hs++;
1265 return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 +
1266 (1 << 20) + (multiThread ? (6 << 20) : 0);
1267 }
1268
GetBenchMemoryUsage(UInt32 numThreads,UInt32 dictionary)1269 UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary)
1270 {
1271 const UInt32 kBufferSize = dictionary;
1272 const UInt32 kCompressedBufferSize = (kBufferSize / 2);
1273 UInt32 numSubThreads = (numThreads > 1) ? 2 : 1;
1274 UInt32 numBigThreads = numThreads / numSubThreads;
1275 return (kBufferSize + kCompressedBufferSize +
1276 GetLZMAUsage((numThreads > 1), dictionary) + (2 << 20)) * numBigThreads;
1277 }
1278
CrcBig(const void * data,UInt32 size,UInt64 numIterations,const UInt32 * checkSum,IHasher * hf,IBenchPrintCallback * callback)1279 static HRESULT CrcBig(const void *data, UInt32 size, UInt64 numIterations,
1280 const UInt32 *checkSum, IHasher *hf,
1281 IBenchPrintCallback *callback)
1282 {
1283 Byte hash[64];
1284 UInt64 i;
1285 for (i = 0; i < sizeof(hash); i++)
1286 hash[i] = 0;
1287 for (i = 0; i < numIterations; i++)
1288 {
1289 if (callback && (i & 0xFF) == 0)
1290 {
1291 RINOK(callback->CheckBreak());
1292 }
1293 hf->Init();
1294 hf->Update(data, size);
1295 hf->Final(hash);
1296 UInt32 hashSize = hf->GetDigestSize();
1297 if (hashSize > sizeof(hash))
1298 return S_FALSE;
1299 UInt32 sum = 0;
1300 for (UInt32 j = 0; j < hashSize; j += 4)
1301 sum ^= GetUi32(hash + j);
1302 if (checkSum && sum != *checkSum)
1303 {
1304 // printf(" %08X ", sum);
1305 return S_FALSE;
1306 }
1307 }
1308 return S_OK;
1309 }
1310
1311 UInt32 g_BenchCpuFreqTemp = 1;
1312
1313 #define YY1 sum += val; sum ^= val;
1314 #define YY3 YY1 YY1 YY1 YY1
1315 #define YY5 YY3 YY3 YY3 YY3
1316 #define YY7 YY5 YY5 YY5 YY5
1317 static const UInt32 kNumFreqCommands = 128;
1318
CountCpuFreq(UInt32 sum,UInt32 num,UInt32 val)1319 static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val)
1320 {
1321 for (UInt32 i = 0; i < num; i++)
1322 {
1323 YY7
1324 }
1325 return sum;
1326 }
1327
1328 #ifndef _7ZIP_ST
1329
1330 struct CFreqInfo
1331 {
1332 NWindows::CThread Thread;
1333 IBenchPrintCallback *Callback;
1334 HRESULT CallbackRes;
1335 UInt32 ValRes;
1336 UInt32 Size;
1337 UInt64 NumIterations;
1338
WaitCFreqInfo1339 void Wait()
1340 {
1341 Thread.Wait();
1342 Thread.Close();
1343 }
1344 };
1345
FreqThreadFunction(void * param)1346 static THREAD_FUNC_DECL FreqThreadFunction(void *param)
1347 {
1348 CFreqInfo *p = (CFreqInfo *)param;
1349
1350 UInt32 sum = g_BenchCpuFreqTemp;
1351 for (UInt64 k = p->NumIterations; k > 0; k--)
1352 {
1353 p->CallbackRes = p->Callback->CheckBreak();
1354 if (p->CallbackRes != S_OK)
1355 return 0;
1356 sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp);
1357 }
1358 p->ValRes = sum;
1359 return 0;
1360 }
1361
1362 struct CFreqThreads
1363 {
1364 CFreqInfo *Items;
1365 UInt32 NumThreads;
1366
CFreqThreadsCFreqThreads1367 CFreqThreads(): Items(0), NumThreads(0) {}
WaitAllCFreqThreads1368 void WaitAll()
1369 {
1370 for (UInt32 i = 0; i < NumThreads; i++)
1371 Items[i].Wait();
1372 NumThreads = 0;
1373 }
~CFreqThreadsCFreqThreads1374 ~CFreqThreads()
1375 {
1376 WaitAll();
1377 delete []Items;
1378 }
1379 };
1380
1381 struct CCrcInfo
1382 {
1383 NWindows::CThread Thread;
1384 IBenchPrintCallback *Callback;
1385 HRESULT CallbackRes;
1386
1387 const Byte *Data;
1388 UInt32 Size;
1389 UInt64 NumIterations;
1390 bool CheckSumDefined;
1391 UInt32 CheckSum;
1392 CMyComPtr<IHasher> Hasher;
1393 HRESULT Res;
1394
WaitCCrcInfo1395 void Wait()
1396 {
1397 Thread.Wait();
1398 Thread.Close();
1399 }
1400 };
1401
CrcThreadFunction(void * param)1402 static THREAD_FUNC_DECL CrcThreadFunction(void *param)
1403 {
1404 CCrcInfo *p = (CCrcInfo *)param;
1405 p->Res = CrcBig(p->Data, p->Size, p->NumIterations,
1406 p->CheckSumDefined ? &p->CheckSum : NULL, p->Hasher,
1407 p->Callback);
1408 return 0;
1409 }
1410
1411 struct CCrcThreads
1412 {
1413 CCrcInfo *Items;
1414 UInt32 NumThreads;
1415
CCrcThreadsCCrcThreads1416 CCrcThreads(): Items(0), NumThreads(0) {}
WaitAllCCrcThreads1417 void WaitAll()
1418 {
1419 for (UInt32 i = 0; i < NumThreads; i++)
1420 Items[i].Wait();
1421 NumThreads = 0;
1422 }
~CCrcThreadsCCrcThreads1423 ~CCrcThreads()
1424 {
1425 WaitAll();
1426 delete []Items;
1427 }
1428 };
1429
1430 #endif
1431
CrcCalc1(const Byte * buf,UInt32 size)1432 static UInt32 CrcCalc1(const Byte *buf, UInt32 size)
1433 {
1434 UInt32 crc = CRC_INIT_VAL;;
1435 for (UInt32 i = 0; i < size; i++)
1436 crc = CRC_UPDATE_BYTE(crc, buf[i]);
1437 return CRC_GET_DIGEST(crc);
1438 }
1439
RandGen(Byte * buf,UInt32 size,CBaseRandomGenerator & RG)1440 static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
1441 {
1442 for (UInt32 i = 0; i < size; i++)
1443 buf[i] = (Byte)RG.GetRnd();
1444 }
1445
RandGenCrc(Byte * buf,UInt32 size,CBaseRandomGenerator & RG)1446 static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
1447 {
1448 RandGen(buf, size, RG);
1449 return CrcCalc1(buf, size);
1450 }
1451
CrcInternalTest()1452 bool CrcInternalTest()
1453 {
1454 CBenchBuffer buffer;
1455 const UInt32 kBufferSize0 = (1 << 8);
1456 const UInt32 kBufferSize1 = (1 << 10);
1457 const UInt32 kCheckSize = (1 << 5);
1458 if (!buffer.Alloc(kBufferSize0 + kBufferSize1))
1459 return false;
1460 Byte *buf = buffer.Buffer;
1461 UInt32 i;
1462 for (i = 0; i < kBufferSize0; i++)
1463 buf[i] = (Byte)i;
1464 UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
1465 if (crc1 != 0x29058C73)
1466 return false;
1467 CBaseRandomGenerator RG;
1468 RandGen(buf + kBufferSize0, kBufferSize1, RG);
1469 for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
1470 for (UInt32 j = 0; j < kCheckSize; j++)
1471 if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
1472 return false;
1473 return true;
1474 }
1475
1476 struct CBenchMethod
1477 {
1478 unsigned DictBits;
1479 UInt32 EncComplex;
1480 UInt32 DecComplexCompr;
1481 UInt32 DecComplexUnc;
1482 const char *Name;
1483 };
1484
1485 static const CBenchMethod g_Bench[] =
1486 {
1487 { 17, 357, 145, 20, "LZMA:x1" },
1488 { 24, 1220, 145, 20, "LZMA:x5:mt1" },
1489 { 24, 1220, 145, 20, "LZMA:x5:mt2" },
1490 { 16, 124, 40, 14, "Deflate:x1" },
1491 { 16, 376, 40, 14, "Deflate:x5" },
1492 { 16, 1082, 40, 14, "Deflate:x7" },
1493 { 17, 422, 40, 14, "Deflate64:x5" },
1494 { 15, 590, 69, 69, "BZip2:x1" },
1495 { 19, 815, 122, 122, "BZip2:x5" },
1496 { 19, 815, 122, 122, "BZip2:x5:mt2" },
1497 { 19, 2530, 122, 122, "BZip2:x7" },
1498 { 18, 1010, 0, 1150, "PPMD:x1" },
1499 { 22, 1655, 0, 1830, "PPMD:x5" },
1500 { 0, 6, 0, 6, "Delta:4" },
1501 { 0, 4, 0, 4, "BCJ" },
1502 { 0, 24, 0, 24, "AES256CBC:1" },
1503 { 0, 8, 0, 2, "AES256CBC:2" }
1504 };
1505
1506 struct CBenchHash
1507 {
1508 UInt32 Complex;
1509 UInt32 CheckSum;
1510 const char *Name;
1511 };
1512
1513 static const CBenchHash g_Hash[] =
1514 {
1515 { 558, 0x8F8FEDAB, "CRC32:4" },
1516 { 339, 0x8F8FEDAB, "CRC32:8" },
1517 { 512, 0xDF1C17CC, "CRC64" },
1518 { 11900, 0x2D79FF2E, "SHA256" },
1519 { 5230, 0x4C25132B, "SHA1" }
1520 };
1521
1522 struct CTotalBenchRes
1523 {
1524 UInt64 NumIterations;
1525 UInt64 Rating;
1526 UInt64 Usage;
1527 UInt64 RPU;
InitCTotalBenchRes1528 void Init() { NumIterations = 0; Rating = 0; Usage = 0; RPU = 0; }
SetSumCTotalBenchRes1529 void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
1530 {
1531 Rating = (r1.Rating + r2.Rating);
1532 Usage = (r1.Usage + r2.Usage);
1533 RPU = (r1.RPU + r2.RPU);
1534 NumIterations = (r1.NumIterations + r2.NumIterations);
1535 }
1536 };
1537
PrintNumber(IBenchPrintCallback & f,UInt64 value,int size)1538 static void PrintNumber(IBenchPrintCallback &f, UInt64 value, int size)
1539 {
1540 char s[128];
1541 int startPos = (int)sizeof(s) - 32;
1542 memset(s, ' ', startPos);
1543 ConvertUInt64ToString(value, s + startPos);
1544 // if (withSpace)
1545 {
1546 startPos--;
1547 size++;
1548 }
1549 int len = (int)strlen(s + startPos);
1550 if (size > len)
1551 {
1552 startPos -= (size - len);
1553 if (startPos < 0)
1554 startPos = 0;
1555 }
1556 f.Print(s + startPos);
1557 }
1558
1559 static const int kFieldSize_Name = 12;
1560 static const int kFieldSize_SmallName = 4;
1561 static const int kFieldSize_Speed = 9;
1562 static const int kFieldSize_Usage = 5;
1563 static const int kFieldSize_RU = 6;
1564 static const int kFieldSize_Rating = 6;
1565 static const int kFieldSize_EU = 5;
1566 static const int kFieldSize_Effec = 5;
1567
1568 static const int kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating;
1569 static const int kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec;
1570
1571
PrintRating(IBenchPrintCallback & f,UInt64 rating,int size)1572 static void PrintRating(IBenchPrintCallback &f, UInt64 rating, int size)
1573 {
1574 PrintNumber(f, (rating + 500000) / 1000000, size);
1575 }
1576
1577
PrintPercents(IBenchPrintCallback & f,UInt64 val,UInt64 divider,int size)1578 static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, int size)
1579 {
1580 PrintNumber(f, (val * 100 + divider / 2) / divider, size);
1581 }
1582
PrintChars(IBenchPrintCallback & f,char c,int size)1583 static void PrintChars(IBenchPrintCallback &f, char c, int size)
1584 {
1585 char s[256];
1586 memset(s, (Byte)c, size);
1587 s[size] = 0;
1588 f.Print(s);
1589 }
1590
PrintSpaces(IBenchPrintCallback & f,int size)1591 static void PrintSpaces(IBenchPrintCallback &f, int size)
1592 {
1593 PrintChars(f, ' ', size);
1594 }
1595
PrintResults(IBenchPrintCallback & f,UInt64 usage,UInt64 rpu,UInt64 rating,bool showFreq,UInt64 cpuFreq)1596 static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq)
1597 {
1598 PrintNumber(f, (usage + 5000) / 10000, kFieldSize_Usage);
1599 PrintRating(f, rpu, kFieldSize_RU);
1600 PrintRating(f, rating, kFieldSize_Rating);
1601 if (showFreq)
1602 {
1603 if (cpuFreq == 0)
1604 PrintSpaces(f, kFieldSize_EUAndEffec);
1605 else
1606 {
1607 UInt64 ddd = cpuFreq * usage / 100;
1608 if (ddd == 0)
1609 ddd = 1;
1610 PrintPercents(f, (rating * 10000), ddd, kFieldSize_EU);
1611 PrintPercents(f, rating, cpuFreq, kFieldSize_Effec);
1612 }
1613 }
1614 }
1615
PrintResults(IBenchPrintCallback * f,const CBenchInfo & info,UInt64 rating,bool showFreq,UInt64 cpuFreq,CTotalBenchRes * res)1616 static void PrintResults(IBenchPrintCallback *f, const CBenchInfo &info, UInt64 rating, bool showFreq, UInt64 cpuFreq, CTotalBenchRes *res)
1617 {
1618 UInt64 speed = info.GetSpeed(info.UnpackSize * info.NumIterations);
1619 if (f)
1620 {
1621 if (speed != 0)
1622 PrintNumber(*f, speed / 1024, kFieldSize_Speed);
1623 else
1624 PrintSpaces(*f, 1 + kFieldSize_Speed);
1625 }
1626 UInt64 usage = info.GetUsage();
1627 UInt64 rpu = info.GetRatingPerUsage(rating);
1628 if (f)
1629 {
1630 PrintResults(*f, usage, rpu, rating, showFreq, cpuFreq);
1631 }
1632
1633 if (res)
1634 {
1635 res->NumIterations++;
1636 res->RPU += rpu;
1637 res->Rating += rating;
1638 res->Usage += usage;
1639 }
1640 }
1641
PrintTotals(IBenchPrintCallback & f,bool showFreq,UInt64 cpuFreq,const CTotalBenchRes & res)1642 static void PrintTotals(IBenchPrintCallback &f, bool showFreq, UInt64 cpuFreq, const CTotalBenchRes &res)
1643 {
1644 PrintSpaces(f, 1 + kFieldSize_Speed);
1645 UInt64 numIterations = res.NumIterations;
1646 if (numIterations == 0)
1647 numIterations = 1;
1648 PrintResults(f, res.Usage / numIterations, res.RPU / numIterations, res.Rating / numIterations, showFreq, cpuFreq);
1649 }
1650
PrintRequirements(IBenchPrintCallback & f,const char * sizeString,UInt64 size,const char * threadsString,UInt32 numThreads)1651 static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString, UInt64 size, const char *threadsString, UInt32 numThreads)
1652 {
1653 f.Print("RAM ");
1654 f.Print(sizeString);
1655 PrintNumber(f, (size >> 20), 6);
1656 f.Print(" MB, # ");
1657 f.Print(threadsString);
1658 PrintNumber(f, numThreads, 3);
1659 f.NewLine();
1660 }
1661
1662 struct CBenchCallbackToPrint: public IBenchCallback
1663 {
1664 CBenchProps BenchProps;
1665 CTotalBenchRes EncodeRes;
1666 CTotalBenchRes DecodeRes;
1667 IBenchPrintCallback *_file;
1668 UInt32 DictSize;
1669
1670 bool Use2Columns;
1671 int NameFieldSize;
1672
1673 bool ShowFreq;
1674 UInt64 CpuFreq;
1675
CBenchCallbackToPrintCBenchCallbackToPrint1676 CBenchCallbackToPrint(): Use2Columns(false), NameFieldSize(0), ShowFreq(false), CpuFreq(0) {}
1677
InitCBenchCallbackToPrint1678 void Init() { EncodeRes.Init(); DecodeRes.Init(); }
1679 void Print(const char *s);
1680 void NewLine();
1681
1682 HRESULT SetFreq(bool showFreq, UInt64 cpuFreq);
1683 HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
1684 HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
1685 };
1686
SetFreq(bool showFreq,UInt64 cpuFreq)1687 HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq)
1688 {
1689 ShowFreq = showFreq;
1690 CpuFreq = cpuFreq;
1691 return S_OK;
1692 }
1693
SetEncodeResult(const CBenchInfo & info,bool final)1694 HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final)
1695 {
1696 RINOK(_file->CheckBreak());
1697 if (final)
1698 {
1699 UInt64 rating = BenchProps.GetCompressRating(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations);
1700 PrintResults(_file, info, rating, ShowFreq, CpuFreq, &EncodeRes);
1701 }
1702 return S_OK;
1703 }
1704
1705 static const char *kSep = " | ";
1706
SetDecodeResult(const CBenchInfo & info,bool final)1707 HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final)
1708 {
1709 RINOK(_file->CheckBreak());
1710 if (final)
1711 {
1712 UInt64 rating = BenchProps.GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
1713 if (Use2Columns)
1714 _file->Print(kSep);
1715 else
1716 {
1717 _file->NewLine();
1718 PrintSpaces(*_file, NameFieldSize);
1719 }
1720 CBenchInfo info2 = info;
1721 info2.UnpackSize *= info2.NumIterations;
1722 info2.PackSize *= info2.NumIterations;
1723 info2.NumIterations = 1;
1724 PrintResults(_file, info2, rating, ShowFreq, CpuFreq, &DecodeRes);
1725 }
1726 return S_OK;
1727 }
1728
Print(const char * s)1729 void CBenchCallbackToPrint::Print(const char *s)
1730 {
1731 _file->Print(s);
1732 }
1733
NewLine()1734 void CBenchCallbackToPrint::NewLine()
1735 {
1736 _file->NewLine();
1737 }
1738
PrintLeft(IBenchPrintCallback & f,const char * s,unsigned size)1739 void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size)
1740 {
1741 f.Print(s);
1742 int numSpaces = size - MyStringLen(s);
1743 if (numSpaces > 0)
1744 PrintSpaces(f, numSpaces);
1745 }
1746
PrintRight(IBenchPrintCallback & f,const char * s,unsigned size)1747 void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size)
1748 {
1749 int numSpaces = size - MyStringLen(s);
1750 if (numSpaces > 0)
1751 PrintSpaces(f, numSpaces);
1752 f.Print(s);
1753 }
1754
TotalBench(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,UInt32 numThreads,bool forceUnpackSize,UInt32 unpackSize,IBenchPrintCallback * printCallback,CBenchCallbackToPrint * callback)1755 static HRESULT TotalBench(
1756 DECL_EXTERNAL_CODECS_LOC_VARS
1757 UInt64 complexInCommands,
1758 UInt32 numThreads, bool forceUnpackSize, UInt32 unpackSize, IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback)
1759 {
1760 for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++)
1761 {
1762 CBenchMethod bench = g_Bench[i];
1763 PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
1764 callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
1765 callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
1766 callback->BenchProps.EncComplex = bench.EncComplex;
1767 COneMethodInfo method;
1768 NCOM::CPropVariant propVariant;
1769 propVariant = bench.Name;
1770 RINOK(method.ParseMethodFromPROPVARIANT(L"", propVariant));
1771
1772 UInt32 unpackSize2 = unpackSize;
1773 if (!forceUnpackSize && bench.DictBits == 0)
1774 unpackSize2 = kFilterUnpackSize;
1775
1776 HRESULT res = MethodBench(
1777 EXTERNAL_CODECS_LOC_VARS
1778 complexInCommands,
1779 false, numThreads, method, unpackSize2, bench.DictBits,
1780 printCallback, callback, &callback->BenchProps);
1781 if (res == E_NOTIMPL)
1782 {
1783 // callback->Print(" ---");
1784 // we need additional empty line as line for decompression results
1785 if (!callback->Use2Columns)
1786 callback->NewLine();
1787 }
1788 else
1789 {
1790 RINOK(res);
1791 }
1792 callback->NewLine();
1793 }
1794 return S_OK;
1795 }
1796
1797
FreqBench(UInt64 complexInCommands,UInt32 numThreads,IBenchPrintCallback * _file,bool showFreq,UInt64 & cpuFreq,UInt32 & res)1798 static HRESULT FreqBench(
1799 UInt64 complexInCommands,
1800 UInt32 numThreads,
1801 IBenchPrintCallback *_file,
1802 bool showFreq,
1803 UInt64 &cpuFreq,
1804 UInt32 &res)
1805 {
1806 res = 0;
1807 cpuFreq = 0;
1808
1809 UInt32 bufferSize = 1 << 20;
1810 UInt32 complexity = kNumFreqCommands;
1811 if (numThreads == 0)
1812 numThreads = 1;
1813
1814 #ifdef _7ZIP_ST
1815 numThreads = 1;
1816 #endif
1817
1818 UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);
1819 UInt64 numIterations = complexInCommands / complexity / bsize;
1820 if (numIterations == 0)
1821 numIterations = 1;
1822
1823 CBenchInfoCalc progressInfoSpec;
1824
1825 #ifndef _7ZIP_ST
1826 CFreqThreads threads;
1827 if (numThreads > 1)
1828 {
1829 threads.Items = new CFreqInfo[numThreads];
1830 UInt32 i;
1831 for (i = 0; i < numThreads; i++)
1832 {
1833 CFreqInfo &info = threads.Items[i];
1834 info.Callback = _file;
1835 info.CallbackRes = S_OK;
1836 info.NumIterations = numIterations;
1837 info.Size = bufferSize;
1838 }
1839 progressInfoSpec.SetStartTime();
1840 for (i = 0; i < numThreads; i++)
1841 {
1842 CFreqInfo &info = threads.Items[i];
1843 RINOK(info.Thread.Create(FreqThreadFunction, &info));
1844 threads.NumThreads++;
1845 }
1846 threads.WaitAll();
1847 for (i = 0; i < numThreads; i++)
1848 {
1849 RINOK(threads.Items[i].CallbackRes);
1850 }
1851 }
1852 else
1853 #endif
1854 {
1855 progressInfoSpec.SetStartTime();
1856 UInt32 sum = g_BenchCpuFreqTemp;
1857 for (UInt64 k = numIterations; k > 0; k--)
1858 {
1859 RINOK(_file->CheckBreak());
1860 sum = CountCpuFreq(sum, bufferSize, g_BenchCpuFreqTemp);
1861 }
1862 res += sum;
1863 }
1864 CBenchInfo info;
1865 progressInfoSpec.SetFinishTime(info);
1866
1867 info.UnpackSize = 0;
1868 info.PackSize = 0;
1869 info.NumIterations = 1;
1870
1871 if (_file)
1872 {
1873 {
1874 UInt64 numCommands = (UInt64)numIterations * bufferSize * numThreads * complexity;
1875 UInt64 rating = info.GetSpeed(numCommands);
1876 cpuFreq = rating / numThreads;
1877 PrintResults(_file, info, rating, showFreq, showFreq ? cpuFreq : 0, NULL);
1878 }
1879 RINOK(_file->CheckBreak());
1880 }
1881
1882 return S_OK;
1883 }
1884
1885
1886
CrcBench(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,UInt32 numThreads,UInt32 bufferSize,UInt64 & speed,UInt32 complexity,const UInt32 * checkSum,const COneMethodInfo & method,IBenchPrintCallback * _file,CTotalBenchRes * encodeRes,bool showFreq,UInt64 cpuFreq)1887 static HRESULT CrcBench(
1888 DECL_EXTERNAL_CODECS_LOC_VARS
1889 UInt64 complexInCommands,
1890 UInt32 numThreads, UInt32 bufferSize,
1891 UInt64 &speed,
1892 UInt32 complexity,
1893 const UInt32 *checkSum,
1894 const COneMethodInfo &method,
1895 IBenchPrintCallback *_file,
1896 CTotalBenchRes *encodeRes,
1897 bool showFreq, UInt64 cpuFreq)
1898 {
1899 if (numThreads == 0)
1900 numThreads = 1;
1901
1902 #ifdef _7ZIP_ST
1903 numThreads = 1;
1904 #endif
1905
1906 UString methodName = method.MethodName;
1907 // methodName.RemoveChar(L'-');
1908 CMethodId hashID;
1909 if (!FindHashMethod(
1910 EXTERNAL_CODECS_LOC_VARS
1911 methodName, hashID))
1912 return E_NOTIMPL;
1913
1914 CBenchBuffer buffer;
1915 size_t totalSize = (size_t)bufferSize * numThreads;
1916 if (totalSize / numThreads != bufferSize)
1917 return E_OUTOFMEMORY;
1918 if (!buffer.Alloc(totalSize))
1919 return E_OUTOFMEMORY;
1920
1921 Byte *buf = buffer.Buffer;
1922 CBaseRandomGenerator RG;
1923 UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);
1924 UInt64 numIterations = complexInCommands * 256 / complexity / bsize;
1925 if (numIterations == 0)
1926 numIterations = 1;
1927
1928 CBenchInfoCalc progressInfoSpec;
1929
1930 #ifndef _7ZIP_ST
1931 CCrcThreads threads;
1932 if (numThreads > 1)
1933 {
1934 threads.Items = new CCrcInfo[numThreads];
1935 UInt32 i;
1936 for (i = 0; i < numThreads; i++)
1937 {
1938 CCrcInfo &info = threads.Items[i];
1939 UString name;
1940 RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, info.Hasher));
1941 if (!info.Hasher)
1942 return E_NOTIMPL;
1943 CMyComPtr<ICompressSetCoderProperties> scp;
1944 info.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
1945 if (scp)
1946 {
1947 UInt64 reduceSize = 1;
1948 RINOK(method.SetCoderProps(scp, &reduceSize));
1949 }
1950
1951 Byte *data = buf + (size_t)bufferSize * i;
1952 info.Callback = _file;
1953 info.Data = data;
1954 info.NumIterations = numIterations;
1955 info.Size = bufferSize;
1956 /* info.Crc = */ RandGenCrc(data, bufferSize, RG);
1957 info.CheckSumDefined = false;
1958 if (checkSum)
1959 {
1960 info.CheckSum = *checkSum;
1961 info.CheckSumDefined = (checkSum && (i == 0));
1962 }
1963 }
1964 progressInfoSpec.SetStartTime();
1965 for (i = 0; i < numThreads; i++)
1966 {
1967 CCrcInfo &info = threads.Items[i];
1968 RINOK(info.Thread.Create(CrcThreadFunction, &info));
1969 threads.NumThreads++;
1970 }
1971 threads.WaitAll();
1972 for (i = 0; i < numThreads; i++)
1973 {
1974 RINOK(threads.Items[i].Res);
1975 }
1976 }
1977 else
1978 #endif
1979 {
1980 /* UInt32 crc = */ RandGenCrc(buf, bufferSize, RG);
1981 progressInfoSpec.SetStartTime();
1982 CMyComPtr<IHasher> hasher;
1983 UString name;
1984 RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher));
1985 if (!hasher)
1986 return E_NOTIMPL;
1987 CMyComPtr<ICompressSetCoderProperties> scp;
1988 hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
1989 if (scp)
1990 {
1991 UInt64 reduceSize = 1;
1992 RINOK(method.SetCoderProps(scp, &reduceSize));
1993 }
1994 RINOK(CrcBig(buf, bufferSize, numIterations, checkSum, hasher, _file));
1995 }
1996 CBenchInfo info;
1997 progressInfoSpec.SetFinishTime(info);
1998
1999 UInt64 unpSize = numIterations * bufferSize;
2000 UInt64 unpSizeThreads = unpSize * numThreads;
2001 info.UnpackSize = unpSizeThreads;
2002 info.PackSize = unpSizeThreads;
2003 info.NumIterations = 1;
2004
2005 if (_file)
2006 {
2007 {
2008 UInt64 numCommands = unpSizeThreads * complexity / 256;
2009 UInt64 rating = info.GetSpeed(numCommands);
2010 PrintResults(_file, info, rating, showFreq, cpuFreq, encodeRes);
2011 }
2012 RINOK(_file->CheckBreak());
2013 }
2014
2015 speed = info.GetSpeed(unpSizeThreads);
2016
2017 return S_OK;
2018 }
2019
TotalBench_Hash(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,UInt32 numThreads,UInt32 bufSize,IBenchPrintCallback * printCallback,CBenchCallbackToPrint * callback,CTotalBenchRes * encodeRes,bool showFreq,UInt64 cpuFreq)2020 static HRESULT TotalBench_Hash(
2021 DECL_EXTERNAL_CODECS_LOC_VARS
2022 UInt64 complexInCommands,
2023 UInt32 numThreads, UInt32 bufSize,
2024 IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback,
2025 CTotalBenchRes *encodeRes,
2026 bool showFreq, UInt64 cpuFreq)
2027 {
2028 for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++)
2029 {
2030 const CBenchHash &bench = g_Hash[i];
2031 PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
2032 // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
2033 // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
2034 // callback->BenchProps.EncComplex = bench.EncComplex;
2035
2036 COneMethodInfo method;
2037 NCOM::CPropVariant propVariant;
2038 propVariant = bench.Name;
2039 RINOK(method.ParseMethodFromPROPVARIANT(L"", propVariant));
2040
2041 UInt64 speed;
2042 HRESULT res = CrcBench(
2043 EXTERNAL_CODECS_LOC_VARS
2044 complexInCommands,
2045 numThreads, bufSize,
2046 speed,
2047 bench.Complex, &bench.CheckSum, method,
2048 printCallback, encodeRes, showFreq, cpuFreq);
2049 if (res == E_NOTIMPL)
2050 {
2051 // callback->Print(" ---");
2052 }
2053 else
2054 {
2055 RINOK(res);
2056 }
2057 callback->NewLine();
2058 }
2059 return S_OK;
2060 }
2061
2062 struct CTempValues
2063 {
2064 UInt64 *Values;
CTempValuesCTempValues2065 CTempValues(UInt32 num) { Values = new UInt64[num]; }
~CTempValuesCTempValues2066 ~CTempValues() { delete []Values; }
2067 };
2068
ParseNumberString(const UString & s,NCOM::CPropVariant & prop)2069 static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
2070 {
2071 const wchar_t *end;
2072 UInt64 result = ConvertStringToUInt64(s, &end);
2073 if (*end != 0 || s.IsEmpty())
2074 prop = s;
2075 else if (result <= (UInt32)0xFFFFFFFF)
2076 prop = (UInt32)result;
2077 else
2078 prop = result;
2079 }
2080
GetNumThreadsNext(unsigned i,UInt32 numThreads)2081 static UInt32 GetNumThreadsNext(unsigned i, UInt32 numThreads)
2082 {
2083 if (i < 2)
2084 return i + 1;
2085 i -= 1;
2086 UInt32 num = (UInt32)(2 + (i & 1)) << (i >> 1);
2087 return (num <= numThreads) ? num : numThreads;
2088 }
2089
AreSameMethodNames(const char * fullName,const wchar_t * shortName)2090 static bool AreSameMethodNames(const char *fullName, const wchar_t *shortName)
2091 {
2092 for (;;)
2093 {
2094 wchar_t c2 = *shortName++;
2095 if (c2 == 0)
2096 return true;
2097 char c1 = *fullName++;
2098 if ((unsigned char)MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
2099 return false;
2100 }
2101 }
2102
Bench(DECL_EXTERNAL_CODECS_LOC_VARS IBenchPrintCallback * printCallback,IBenchCallback * benchCallback,const CObjectVector<CProperty> & props,UInt32 numIterations,bool multiDict)2103 HRESULT Bench(
2104 DECL_EXTERNAL_CODECS_LOC_VARS
2105 IBenchPrintCallback *printCallback,
2106 IBenchCallback *benchCallback,
2107 const CObjectVector<CProperty> &props,
2108 UInt32 numIterations,
2109 bool multiDict)
2110 {
2111 if (!CrcInternalTest())
2112 return S_FALSE;
2113
2114 UInt32 numCPUs = 1;
2115 UInt64 ramSize = (UInt64)512 << 20;
2116 #ifndef _7ZIP_ST
2117 numCPUs = NSystem::GetNumberOfProcessors();
2118 #endif
2119 #if !defined(_7ZIP_ST) || defined(_WIN32)
2120 ramSize = NSystem::GetRamSize();
2121 #endif
2122 UInt32 numThreads = numCPUs;
2123
2124 UInt32 testTime = kComplexInSeconds;
2125
2126 COneMethodInfo method;
2127 unsigned i;
2128 for (i = 0; i < props.Size(); i++)
2129 {
2130 const CProperty &property = props[i];
2131 NCOM::CPropVariant propVariant;
2132 UString name = property.Name;
2133 name.MakeLower_Ascii();
2134 if (!property.Value.IsEmpty())
2135 ParseNumberString(property.Value, propVariant);
2136 if (name.IsEqualTo("testtime"))
2137 {
2138 RINOK(ParsePropToUInt32(L"", propVariant, testTime));
2139 continue;
2140 }
2141 if (name.IsPrefixedBy(L"mt"))
2142 {
2143 #ifndef _7ZIP_ST
2144 RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads));
2145 #endif
2146 continue;
2147 }
2148 RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));
2149 }
2150
2151 if (printCallback)
2152 {
2153 printCallback->Print("CPU Freq:");
2154 }
2155
2156 UInt64 complexInCommands = kComplexInCommands;
2157
2158 if (printCallback)
2159 {
2160 UInt64 numMilCommands = (1 << 6);
2161
2162 for (int jj = 0;; jj++)
2163 {
2164 UInt64 start = ::GetTimeCount();
2165 UInt32 sum = (UInt32)start;
2166 sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp);
2167 start = ::GetTimeCount() - start;
2168 if (start == 0)
2169 start = 1;
2170 UInt64 freq = GetFreq();
2171 UInt64 mipsVal = numMilCommands * freq / start;
2172 if (printCallback)
2173 PrintNumber(*printCallback, mipsVal, 5 + ((sum >> 31) & 1));
2174 if (jj >= 3)
2175 {
2176 SetComplexCommands(testTime, mipsVal * 1000000, complexInCommands);
2177 if (jj >= 8 || start >= freq)
2178 break;
2179 // break; // change it
2180 numMilCommands <<= 1;
2181 }
2182 }
2183 }
2184 if (printCallback)
2185 {
2186 printCallback->NewLine();
2187 printCallback->NewLine();
2188 PrintRequirements(*printCallback, "size: ", ramSize, "CPU hardware threads:", numCPUs);
2189 }
2190
2191 if (numThreads < 1 || numThreads > kNumThreadsMax)
2192 return E_INVALIDARG;
2193
2194 UInt32 dict;
2195 bool dictIsDefined = method.Get_DicSize(dict);
2196
2197 if (method.MethodName.IsEmpty())
2198 method.MethodName = L"LZMA";
2199
2200 if (benchCallback)
2201 {
2202 CBenchProps benchProps;
2203 benchProps.SetLzmaCompexity();
2204 UInt32 dictSize = method.Get_Lzma_DicSize();
2205 UInt32 uncompressedDataSize = kAdditionalSize + dictSize;
2206 return MethodBench(
2207 EXTERNAL_CODECS_LOC_VARS
2208 complexInCommands,
2209 true, numThreads,
2210 method, uncompressedDataSize,
2211 kOldLzmaDictBits, printCallback, benchCallback, &benchProps);
2212 }
2213
2214 UString methodName = method.MethodName;
2215 if (methodName.IsEqualToNoCase(L"CRC"))
2216 methodName = L"crc32";
2217 method.MethodName = methodName;
2218 CMethodId hashID;
2219 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID))
2220 {
2221 if (!printCallback)
2222 return S_FALSE;
2223 IBenchPrintCallback &f = *printCallback;
2224 if (!dictIsDefined)
2225 dict = (1 << 24);
2226
2227
2228 // methhodName.RemoveChar(L'-');
2229 UInt32 complexity = 10000;
2230 const UInt32 *checkSum = NULL;
2231 {
2232 for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++)
2233 {
2234 const CBenchHash &h = g_Hash[i];
2235 if (AreSameMethodNames(h.Name, methodName))
2236 {
2237 complexity = h.Complex;
2238 checkSum = &h.CheckSum;
2239 if (strcmp(h.Name, "CRC32:4") != 0)
2240 break;
2241 }
2242 }
2243 }
2244
2245 f.NewLine();
2246 f.Print("Size");
2247 const int kFieldSize_CrcSpeed = 6;
2248 unsigned numThreadsTests = 0;
2249 for (;;)
2250 {
2251 UInt32 t = GetNumThreadsNext(numThreadsTests, numThreads);
2252 PrintNumber(f, t, kFieldSize_CrcSpeed);
2253 numThreadsTests++;
2254 if (t >= numThreads)
2255 break;
2256 }
2257 f.NewLine();
2258 f.NewLine();
2259 CTempValues speedTotals(numThreadsTests);
2260 {
2261 for (unsigned ti = 0; ti < numThreadsTests; ti++)
2262 speedTotals.Values[ti] = 0;
2263 }
2264
2265 UInt64 numSteps = 0;
2266 for (UInt32 i = 0; i < numIterations; i++)
2267 {
2268 for (unsigned pow = 10; pow < 32; pow++)
2269 {
2270 UInt32 bufSize = (UInt32)1 << pow;
2271 if (bufSize > dict)
2272 break;
2273 char s[16];
2274 ConvertUInt32ToString(pow, s);
2275 int pos = MyStringLen(s);
2276 s[pos++] = ':';
2277 s[pos++] = ' ';
2278 s[pos] = 0;
2279 f.Print(s);
2280
2281 for (unsigned ti = 0; ti < numThreadsTests; ti++)
2282 {
2283 RINOK(f.CheckBreak());
2284 UInt32 t = GetNumThreadsNext(ti, numThreads);
2285 UInt64 speed = 0;
2286 RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands,
2287 t, bufSize, speed, complexity,
2288 (pow == kNumHashDictBits) ? checkSum : NULL, method, NULL, NULL, false, 0));
2289 PrintNumber(f, (speed >> 20), kFieldSize_CrcSpeed);
2290 speedTotals.Values[ti] += speed;
2291 }
2292 f.NewLine();
2293 numSteps++;
2294 }
2295 }
2296 if (numSteps != 0)
2297 {
2298 f.NewLine();
2299 f.Print("Avg:");
2300 for (unsigned ti = 0; ti < numThreadsTests; ti++)
2301 {
2302 PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), kFieldSize_CrcSpeed);
2303 }
2304 f.NewLine();
2305 }
2306 return S_OK;
2307 }
2308
2309 bool use2Columns = false;
2310
2311 CBenchCallbackToPrint callback;
2312 callback.Init();
2313 callback._file = printCallback;
2314
2315 if (!dictIsDefined)
2316 {
2317 int dicSizeLog;
2318 for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
2319 if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
2320 break;
2321 dict = (1 << dicSizeLog);
2322 }
2323
2324 IBenchPrintCallback &f = *printCallback;
2325 PrintRequirements(f, "usage:", GetBenchMemoryUsage(numThreads, dict), "Benchmark threads: ", numThreads);
2326
2327 bool totalBenchMode = (method.MethodName == L"*");
2328 f.NewLine();
2329
2330 if (totalBenchMode)
2331 {
2332 callback.NameFieldSize = kFieldSize_Name;
2333 use2Columns = false;
2334 }
2335 else
2336 {
2337 callback.NameFieldSize = kFieldSize_SmallName;
2338 use2Columns = true;
2339 }
2340 callback.Use2Columns = use2Columns;
2341
2342 bool showFreq = false;
2343 UInt64 cpuFreq = 0;
2344
2345 if (totalBenchMode)
2346 {
2347 showFreq = true;
2348 }
2349
2350 int fileldSize = kFieldSize_TotalSize;
2351 if (showFreq)
2352 fileldSize += kFieldSize_EUAndEffec;
2353
2354 if (use2Columns)
2355 {
2356 PrintSpaces(f, callback.NameFieldSize);
2357 PrintRight(f, "Compressing", fileldSize);
2358 f.Print(kSep);
2359 PrintRight(f, "Decompressing", fileldSize);
2360 }
2361 f.NewLine();
2362 PrintLeft(f, totalBenchMode ? "Method" : "Dict", callback.NameFieldSize);
2363
2364 int j;
2365
2366 for (j = 0; j < 2; j++)
2367 {
2368 PrintRight(f, "Speed", kFieldSize_Speed + 1);
2369 PrintRight(f, "Usage", kFieldSize_Usage + 1);
2370 PrintRight(f, "R/U", kFieldSize_RU + 1);
2371 PrintRight(f, "Rating", kFieldSize_Rating + 1);
2372 if (showFreq)
2373 {
2374 PrintRight(f, "E/U", kFieldSize_EU + 1);
2375 PrintRight(f, "Effec", kFieldSize_Effec + 1);
2376 }
2377 if (!use2Columns)
2378 break;
2379 if (j == 0)
2380 f.Print(kSep);
2381 }
2382
2383 f.NewLine();
2384 PrintSpaces(f, callback.NameFieldSize);
2385
2386 for (j = 0; j < 2; j++)
2387 {
2388 PrintRight(f, "KB/s", kFieldSize_Speed + 1);
2389 PrintRight(f, "%", kFieldSize_Usage + 1);
2390 PrintRight(f, "MIPS", kFieldSize_RU + 1);
2391 PrintRight(f, "MIPS", kFieldSize_Rating + 1);
2392 if (showFreq)
2393 {
2394 PrintRight(f, "%", kFieldSize_EU + 1);
2395 PrintRight(f, "%", kFieldSize_Effec + 1);
2396 }
2397 if (!use2Columns)
2398 break;
2399 if (j == 0)
2400 f.Print(kSep);
2401 }
2402
2403 f.NewLine();
2404 f.NewLine();
2405
2406 if (totalBenchMode)
2407 {
2408 if (!dictIsDefined)
2409 dict =
2410 #ifdef UNDER_CE
2411 (UInt64)1 << 20;
2412 #else
2413 (UInt64)1 << 24;
2414 #endif
2415 for (UInt32 i = 0; i < numIterations; i++)
2416 {
2417 if (i != 0)
2418 printCallback->NewLine();
2419 HRESULT res;
2420
2421 int freqTest;
2422 const int kNumCpuTests = 3;
2423 for (freqTest = 0; freqTest < kNumCpuTests; freqTest++)
2424 {
2425 PrintLeft(f, "CPU", kFieldSize_Name);
2426 UInt32 resVal;
2427 RINOK(FreqBench(complexInCommands, numThreads, printCallback, freqTest == kNumCpuTests - 1, cpuFreq, resVal));
2428 callback.NewLine();
2429
2430 if (freqTest == kNumCpuTests - 1)
2431 SetComplexCommands(testTime, cpuFreq, complexInCommands);
2432 }
2433 callback.NewLine();
2434
2435 callback.SetFreq(true, cpuFreq);
2436 res = TotalBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads, dictIsDefined, dict, printCallback, &callback);
2437 RINOK(res);
2438
2439 res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads,
2440 1 << kNumHashDictBits, printCallback, &callback, &callback.EncodeRes, true, cpuFreq);
2441 RINOK(res);
2442
2443 callback.NewLine();
2444 {
2445 PrintLeft(f, "CPU", kFieldSize_Name);
2446 UInt32 resVal;
2447 UInt64 cpuFreqLastTemp = cpuFreq;
2448 RINOK(FreqBench(complexInCommands, numThreads, printCallback, false, cpuFreqLastTemp, resVal));
2449 callback.NewLine();
2450 }
2451 }
2452 }
2453 else
2454 {
2455 bool needSetComplexity = true;
2456 if (!methodName.IsEqualToNoCase(L"LZMA"))
2457 {
2458 for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++)
2459 {
2460 const CBenchMethod &h = g_Bench[i];
2461 AString s = h.Name;
2462 if (AreSameMethodNames(h.Name, methodName))
2463 {
2464 callback.BenchProps.EncComplex = h.EncComplex;
2465 callback.BenchProps.DecComplexCompr = h.DecComplexCompr;
2466 callback.BenchProps.DecComplexUnc = h.DecComplexUnc;;
2467 needSetComplexity = false;
2468 break;
2469 }
2470 }
2471 }
2472 if (needSetComplexity)
2473 callback.BenchProps.SetLzmaCompexity();
2474
2475 for (i = 0; i < numIterations; i++)
2476 {
2477 const unsigned kStartDicLog = 22;
2478 unsigned pow = (dict < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
2479 if (!multiDict)
2480 pow = 31;
2481 while (((UInt32)1 << pow) > dict && pow > 0)
2482 pow--;
2483 for (; ((UInt32)1 << pow) <= dict; pow++)
2484 {
2485 char s[16];
2486 ConvertUInt32ToString(pow, s);
2487 unsigned pos = MyStringLen(s);
2488 s[pos++] = ':';
2489 s[pos] = 0;
2490 PrintLeft(f, s, kFieldSize_SmallName);
2491 callback.DictSize = (UInt32)1 << pow;
2492
2493 COneMethodInfo method2 = method;
2494
2495 if (StringsAreEqualNoCase_Ascii(method2.MethodName, L"LZMA"))
2496 {
2497 // We add dictionary size property.
2498 // method2 can have two different dictionary size properties.
2499 // And last property is main.
2500 NCOM::CPropVariant propVariant = (UInt32)pow;
2501 RINOK(method2.ParseMethodFromPROPVARIANT(L"d", propVariant));
2502 }
2503
2504 UInt32 uncompressedDataSize = callback.DictSize;
2505 if (uncompressedDataSize >= (1 << 18))
2506 uncompressedDataSize += kAdditionalSize;
2507
2508 HRESULT res = MethodBench(
2509 EXTERNAL_CODECS_LOC_VARS
2510 complexInCommands,
2511 true, numThreads,
2512 method2, uncompressedDataSize,
2513 kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps);
2514 f.NewLine();
2515 RINOK(res);
2516 if (!multiDict)
2517 break;
2518 }
2519 }
2520 }
2521
2522 PrintChars(f, '-', callback.NameFieldSize + fileldSize);
2523
2524 if (use2Columns)
2525 {
2526 f.Print(kSep);
2527 PrintChars(f, '-', fileldSize);
2528 }
2529 f.NewLine();
2530 if (use2Columns)
2531 {
2532 PrintLeft(f, "Avr:", callback.NameFieldSize);
2533 PrintTotals(f, showFreq, cpuFreq, callback.EncodeRes);
2534 f.Print(kSep);
2535 PrintTotals(f, showFreq, cpuFreq, callback.DecodeRes);
2536 f.NewLine();
2537 }
2538 PrintLeft(f, "Tot:", callback.NameFieldSize);
2539 CTotalBenchRes midRes;
2540 midRes.SetSum(callback.EncodeRes, callback.DecodeRes);
2541 PrintTotals(f, showFreq, cpuFreq, midRes);
2542 f.NewLine();
2543 return S_OK;
2544 }
2545