1 // Bench.cpp
2
3 #include "StdAfx.h"
4
5 #include <stdio.h>
6
7 #ifndef _WIN32
8 #define USE_POSIX_TIME
9 #define USE_POSIX_TIME2
10 #endif
11
12 #ifdef USE_POSIX_TIME
13 #include <time.h>
14 #ifdef USE_POSIX_TIME2
15 #include <sys/time.h>
16 #endif
17 #endif
18
19 #ifdef _WIN32
20 #define USE_ALLOCA
21 #endif
22
23 #ifdef USE_ALLOCA
24 #ifdef _WIN32
25 #include <malloc.h>
26 #else
27 #include <stdlib.h>
28 #endif
29 #endif
30
31 #include "../../../../C/7zCrc.h"
32 #include "../../../../C/Alloc.h"
33 #include "../../../../C/CpuArch.h"
34
35 #ifndef _7ZIP_ST
36 #include "../../../Windows/Synchronization.h"
37 #include "../../../Windows/Thread.h"
38 #endif
39
40 #if defined(_WIN32) || defined(UNIX_USE_WIN_FILE)
41 #define USE_WIN_FILE
42 #endif
43
44 #ifdef USE_WIN_FILE
45 #include "../../../Windows/FileIO.h"
46 #endif
47
48
49 #include "../../../Common/IntToString.h"
50 #include "../../../Common/StringConvert.h"
51 #include "../../../Common/StringToInt.h"
52
53 #include "../../Common/MethodProps.h"
54 #include "../../Common/StreamUtils.h"
55
56 #include "Bench.h"
57
58 using namespace NWindows;
59
60 static const UInt32 k_LZMA = 0x030101;
61
62 static const UInt64 kComplexInCommands = (UInt64)1 <<
63 #ifdef UNDER_CE
64 31;
65 #else
66 34;
67 #endif
68
69 static const UInt32 kComplexInSeconds = 4;
70
SetComplexCommands(UInt32 complexInSeconds,bool isSpecifiedFreq,UInt64 cpuFreq,UInt64 & complexInCommands)71 static void SetComplexCommands(UInt32 complexInSeconds,
72 bool isSpecifiedFreq, UInt64 cpuFreq, UInt64 &complexInCommands)
73 {
74 complexInCommands = kComplexInCommands;
75 const UInt64 kMinFreq = (UInt64)1000000 * 4;
76 const UInt64 kMaxFreq = (UInt64)1000000 * 20000;
77 if (cpuFreq < kMinFreq && !isSpecifiedFreq)
78 cpuFreq = kMinFreq;
79 if (cpuFreq < kMaxFreq || isSpecifiedFreq)
80 {
81 if (complexInSeconds != 0)
82 complexInCommands = complexInSeconds * cpuFreq;
83 else
84 complexInCommands = cpuFreq >> 2;
85 }
86 }
87
88 static const unsigned kNumHashDictBits = 17;
89 static const UInt32 kFilterUnpackSize = (48 << 10);
90
91 static const unsigned kOldLzmaDictBits = 30;
92
93 static const UInt32 kAdditionalSize = (1 << 16);
94 static const UInt32 kCompressedAdditionalSize = (1 << 10);
95 static const UInt32 kMaxLzmaPropSize = 5;
96
97 class CBaseRandomGenerator
98 {
99 UInt32 A1;
100 UInt32 A2;
101 public:
CBaseRandomGenerator()102 CBaseRandomGenerator() { Init(); }
Init()103 void Init() { A1 = 362436069; A2 = 521288629;}
GetRnd()104 UInt32 GetRnd()
105 {
106 return
107 ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
108 ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) );
109 }
110 };
111
112
113 static const unsigned kBufferAlignment = 1 << 4;
114
115 struct CBenchBuffer
116 {
117 size_t BufferSize;
118
119 #ifdef _WIN32
120
121 Byte *Buffer;
122
CBenchBufferCBenchBuffer123 CBenchBuffer(): BufferSize(0), Buffer(NULL) {}
~CBenchBufferCBenchBuffer124 ~CBenchBuffer() { ::MidFree(Buffer); }
125
AllocAlignedMaskCBenchBuffer126 void AllocAlignedMask(size_t size, size_t)
127 {
128 ::MidFree(Buffer);
129 BufferSize = 0;
130 Buffer = (Byte *)::MidAlloc(size);
131 if (Buffer)
132 BufferSize = size;
133 }
134
135 #else
136
137 Byte *Buffer;
138 Byte *_bufBase;
139
CBenchBufferCBenchBuffer140 CBenchBuffer(): BufferSize(0), Buffer(NULL), _bufBase(NULL){}
~CBenchBufferCBenchBuffer141 ~CBenchBuffer() { ::MidFree(_bufBase); }
142
AllocAlignedMaskCBenchBuffer143 void AllocAlignedMask(size_t size, size_t alignMask)
144 {
145 ::MidFree(_bufBase);
146 Buffer = NULL;
147 BufferSize = 0;
148 _bufBase = (Byte *)::MidAlloc(size + alignMask);
149
150 if (_bufBase)
151 {
152 // Buffer = (Byte *)(((uintptr_t)_bufBase + alignMask) & ~(uintptr_t)alignMask);
153 Buffer = (Byte *)(((ptrdiff_t)_bufBase + alignMask) & ~(ptrdiff_t)alignMask);
154 BufferSize = size;
155 }
156 }
157
158 #endif
159
AllocCBenchBuffer160 bool Alloc(size_t size)
161 {
162 if (Buffer && BufferSize == size)
163 return true;
164 AllocAlignedMask(size, kBufferAlignment - 1);
165 return (Buffer != NULL || size == 0);
166 }
167 };
168
169
170 class CBenchRandomGenerator: public CBenchBuffer
171 {
GetVal(UInt32 & res,unsigned numBits)172 static UInt32 GetVal(UInt32 &res, unsigned numBits)
173 {
174 UInt32 val = res & (((UInt32)1 << numBits) - 1);
175 res >>= numBits;
176 return val;
177 }
178
GetLen(UInt32 & r)179 static UInt32 GetLen(UInt32 &r)
180 {
181 UInt32 len = GetVal(r, 2);
182 return GetVal(r, 1 + len);
183 }
184
185 public:
186
GenerateSimpleRandom(CBaseRandomGenerator * _RG_)187 void GenerateSimpleRandom(CBaseRandomGenerator *_RG_)
188 {
189 CBaseRandomGenerator rg = *_RG_;
190 const size_t bufSize = BufferSize;
191 Byte *buf = Buffer;
192 for (size_t i = 0; i < bufSize; i++)
193 buf[i] = (Byte)rg.GetRnd();
194 *_RG_ = rg;
195 }
196
GenerateLz(unsigned dictBits,CBaseRandomGenerator * _RG_)197 void GenerateLz(unsigned dictBits, CBaseRandomGenerator *_RG_)
198 {
199 CBaseRandomGenerator rg = *_RG_;
200 UInt32 pos = 0;
201 UInt32 rep0 = 1;
202 const size_t bufSize = BufferSize;
203 Byte *buf = Buffer;
204 unsigned posBits = 1;
205
206 while (pos < bufSize)
207 {
208 UInt32 r = rg.GetRnd();
209 if (GetVal(r, 1) == 0 || pos < 1024)
210 buf[pos++] = (Byte)(r & 0xFF);
211 else
212 {
213 UInt32 len;
214 len = 1 + GetLen(r);
215
216 if (GetVal(r, 3) != 0)
217 {
218 len += GetLen(r);
219
220 while (((UInt32)1 << posBits) < pos)
221 posBits++;
222
223 unsigned numBitsMax = dictBits;
224 if (numBitsMax > posBits)
225 numBitsMax = posBits;
226
227 const unsigned kAddBits = 6;
228 unsigned numLogBits = 5;
229 if (numBitsMax <= (1 << 4) - 1 + kAddBits)
230 numLogBits = 4;
231
232 for (;;)
233 {
234 UInt32 ppp = GetVal(r, numLogBits) + kAddBits;
235 r = rg.GetRnd();
236 if (ppp > numBitsMax)
237 continue;
238 rep0 = GetVal(r, ppp);
239 if (rep0 < pos)
240 break;
241 r = rg.GetRnd();
242 }
243 rep0++;
244 }
245
246 {
247 UInt32 rem = (UInt32)bufSize - pos;
248 if (len > rem)
249 len = rem;
250 }
251 Byte *dest = buf + pos;
252 const Byte *src = dest - rep0;
253 pos += len;
254 for (UInt32 i = 0; i < len; i++)
255 *dest++ = *src++;
256 }
257 }
258
259 *_RG_ = rg;
260 }
261 };
262
263
264 class CBenchmarkInStream:
265 public ISequentialInStream,
266 public CMyUnknownImp
267 {
268 const Byte *Data;
269 size_t Pos;
270 size_t Size;
271 public:
272 MY_UNKNOWN_IMP
Init(const Byte * data,size_t size)273 void Init(const Byte *data, size_t size)
274 {
275 Data = data;
276 Size = size;
277 Pos = 0;
278 }
279 STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
280 };
281
Read(void * data,UInt32 size,UInt32 * processedSize)282 STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
283 {
284 size_t remain = Size - Pos;
285 UInt32 kMaxBlockSize = (1 << 20);
286 if (size > kMaxBlockSize)
287 size = kMaxBlockSize;
288 if (size > remain)
289 size = (UInt32)remain;
290 for (UInt32 i = 0; i < size; i++)
291 ((Byte *)data)[i] = Data[Pos + i];
292 Pos += size;
293 if (processedSize)
294 *processedSize = size;
295 return S_OK;
296 }
297
298 class CBenchmarkOutStream:
299 public ISequentialOutStream,
300 public CBenchBuffer,
301 public CMyUnknownImp
302 {
303 // bool _overflow;
304 public:
305 size_t Pos;
306 bool RealCopy;
307 bool CalcCrc;
308 UInt32 Crc;
309
310 // CBenchmarkOutStream(): _overflow(false) {}
Init(bool realCopy,bool calcCrc)311 void Init(bool realCopy, bool calcCrc)
312 {
313 Crc = CRC_INIT_VAL;
314 RealCopy = realCopy;
315 CalcCrc = calcCrc;
316 // _overflow = false;
317 Pos = 0;
318 }
319
320 // void Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); }
321
322 MY_UNKNOWN_IMP
323 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
324 };
325
Write(const void * data,UInt32 size,UInt32 * processedSize)326 STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
327 {
328 size_t curSize = BufferSize - Pos;
329 if (curSize > size)
330 curSize = size;
331 if (curSize != 0)
332 {
333 if (RealCopy)
334 memcpy(Buffer + Pos, data, curSize);
335 if (CalcCrc)
336 Crc = CrcUpdate(Crc, data, curSize);
337 Pos += curSize;
338 }
339 if (processedSize)
340 *processedSize = (UInt32)curSize;
341 if (curSize != size)
342 {
343 // _overflow = true;
344 return E_FAIL;
345 }
346 return S_OK;
347 }
348
349 class CCrcOutStream:
350 public ISequentialOutStream,
351 public CMyUnknownImp
352 {
353 public:
354 bool CalcCrc;
355 UInt32 Crc;
356 MY_UNKNOWN_IMP
357
CCrcOutStream()358 CCrcOutStream(): CalcCrc(true) {};
Init()359 void Init() { Crc = CRC_INIT_VAL; }
360 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
361 };
362
Write(const void * data,UInt32 size,UInt32 * processedSize)363 STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
364 {
365 if (CalcCrc)
366 Crc = CrcUpdate(Crc, data, size);
367 if (processedSize)
368 *processedSize = size;
369 return S_OK;
370 }
371
GetTimeCount()372 static UInt64 GetTimeCount()
373 {
374 #ifdef USE_POSIX_TIME
375 #ifdef USE_POSIX_TIME2
376 timeval v;
377 if (gettimeofday(&v, 0) == 0)
378 return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec;
379 return (UInt64)time(NULL) * 1000000;
380 #else
381 return time(NULL);
382 #endif
383 #else
384 /*
385 LARGE_INTEGER value;
386 if (::QueryPerformanceCounter(&value))
387 return value.QuadPart;
388 */
389 return GetTickCount();
390 #endif
391 }
392
GetFreq()393 static UInt64 GetFreq()
394 {
395 #ifdef USE_POSIX_TIME
396 #ifdef USE_POSIX_TIME2
397 return 1000000;
398 #else
399 return 1;
400 #endif
401 #else
402 /*
403 LARGE_INTEGER value;
404 if (::QueryPerformanceFrequency(&value))
405 return value.QuadPart;
406 */
407 return 1000;
408 #endif
409 }
410
411 #ifdef USE_POSIX_TIME
412
413 struct CUserTime
414 {
415 UInt64 Sum;
416 clock_t Prev;
417
InitCUserTime418 void Init()
419 {
420 Prev = clock();
421 Sum = 0;
422 }
423
GetUserTimeCUserTime424 UInt64 GetUserTime()
425 {
426 clock_t v = clock();
427 Sum += v - Prev;
428 Prev = v;
429 return Sum;
430 }
431 };
432
433 #else
434
GetTime64(const FILETIME & t)435 static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
GetWinUserTime()436 UInt64 GetWinUserTime()
437 {
438 FILETIME creationTime, exitTime, kernelTime, userTime;
439 if (
440 #ifdef UNDER_CE
441 ::GetThreadTimes(::GetCurrentThread()
442 #else
443 ::GetProcessTimes(::GetCurrentProcess()
444 #endif
445 , &creationTime, &exitTime, &kernelTime, &userTime) != 0)
446 return GetTime64(userTime) + GetTime64(kernelTime);
447 return (UInt64)GetTickCount() * 10000;
448 }
449
450 struct CUserTime
451 {
452 UInt64 StartTime;
453
InitCUserTime454 void Init() { StartTime = GetWinUserTime(); }
GetUserTimeCUserTime455 UInt64 GetUserTime() { return GetWinUserTime() - StartTime; }
456 };
457
458 #endif
459
GetUserFreq()460 static UInt64 GetUserFreq()
461 {
462 #ifdef USE_POSIX_TIME
463 return CLOCKS_PER_SEC;
464 #else
465 return 10000000;
466 #endif
467 }
468
469 class CBenchProgressStatus
470 {
471 #ifndef _7ZIP_ST
472 NSynchronization::CCriticalSection CS;
473 #endif
474 public:
475 HRESULT Res;
476 bool EncodeMode;
SetResult(HRESULT res)477 void SetResult(HRESULT res)
478 {
479 #ifndef _7ZIP_ST
480 NSynchronization::CCriticalSectionLock lock(CS);
481 #endif
482 Res = res;
483 }
GetResult()484 HRESULT GetResult()
485 {
486 #ifndef _7ZIP_ST
487 NSynchronization::CCriticalSectionLock lock(CS);
488 #endif
489 return Res;
490 }
491 };
492
493 struct CBenchInfoCalc
494 {
495 CBenchInfo BenchInfo;
496 CUserTime UserTime;
497
498 void SetStartTime();
499 void SetFinishTime(CBenchInfo &dest);
500 };
501
SetStartTime()502 void CBenchInfoCalc::SetStartTime()
503 {
504 BenchInfo.GlobalFreq = GetFreq();
505 BenchInfo.UserFreq = GetUserFreq();
506 BenchInfo.GlobalTime = ::GetTimeCount();
507 BenchInfo.UserTime = 0;
508 UserTime.Init();
509 }
510
SetFinishTime(CBenchInfo & dest)511 void CBenchInfoCalc::SetFinishTime(CBenchInfo &dest)
512 {
513 dest = BenchInfo;
514 dest.GlobalTime = ::GetTimeCount() - BenchInfo.GlobalTime;
515 dest.UserTime = UserTime.GetUserTime();
516 }
517
518 class CBenchProgressInfo:
519 public ICompressProgressInfo,
520 public CMyUnknownImp,
521 public CBenchInfoCalc
522 {
523 public:
524 CBenchProgressStatus *Status;
525 HRESULT Res;
526 IBenchCallback *Callback;
527
CBenchProgressInfo()528 CBenchProgressInfo(): Callback(0) {}
529 MY_UNKNOWN_IMP
530 STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
531 };
532
SetRatioInfo(const UInt64 * inSize,const UInt64 * outSize)533 STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
534 {
535 HRESULT res = Status->GetResult();
536 if (res != S_OK)
537 return res;
538 if (!Callback)
539 return res;
540 CBenchInfo info;
541 SetFinishTime(info);
542 if (Status->EncodeMode)
543 {
544 info.UnpackSize = BenchInfo.UnpackSize + *inSize;
545 info.PackSize = BenchInfo.PackSize + *outSize;
546 res = Callback->SetEncodeResult(info, false);
547 }
548 else
549 {
550 info.PackSize = BenchInfo.PackSize + *inSize;
551 info.UnpackSize = BenchInfo.UnpackSize + *outSize;
552 res = Callback->SetDecodeResult(info, false);
553 }
554 if (res != S_OK)
555 Status->SetResult(res);
556 return res;
557 }
558
559 static const unsigned kSubBits = 8;
560
GetLogSize(UInt32 size)561 static UInt32 GetLogSize(UInt32 size)
562 {
563 for (unsigned i = kSubBits; i < 32; i++)
564 for (UInt32 j = 0; j < (1 << kSubBits); j++)
565 if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
566 return (i << kSubBits) + j;
567 return (32 << kSubBits);
568 }
569
NormalizeVals(UInt64 & v1,UInt64 & v2)570 static void NormalizeVals(UInt64 &v1, UInt64 &v2)
571 {
572 while (v1 > 1000000)
573 {
574 v1 >>= 1;
575 v2 >>= 1;
576 }
577 }
578
GetUsage() const579 UInt64 CBenchInfo::GetUsage() const
580 {
581 UInt64 userTime = UserTime;
582 UInt64 userFreq = UserFreq;
583 UInt64 globalTime = GlobalTime;
584 UInt64 globalFreq = GlobalFreq;
585 NormalizeVals(userTime, userFreq);
586 NormalizeVals(globalFreq, globalTime);
587 if (userFreq == 0)
588 userFreq = 1;
589 if (globalTime == 0)
590 globalTime = 1;
591 return userTime * globalFreq * 1000000 / userFreq / globalTime;
592 }
593
GetRatingPerUsage(UInt64 rating) const594 UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const
595 {
596 UInt64 userTime = UserTime;
597 UInt64 userFreq = UserFreq;
598 UInt64 globalTime = GlobalTime;
599 UInt64 globalFreq = GlobalFreq;
600 NormalizeVals(userFreq, userTime);
601 NormalizeVals(globalTime, globalFreq);
602 if (globalFreq == 0)
603 globalFreq = 1;
604 if (userTime == 0)
605 userTime = 1;
606 return userFreq * globalTime / globalFreq * rating / userTime;
607 }
608
MyMultDiv64(UInt64 value,UInt64 elapsedTime,UInt64 freq)609 static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
610 {
611 UInt64 elTime = elapsedTime;
612 NormalizeVals(freq, elTime);
613 if (elTime == 0)
614 elTime = 1;
615 return value * freq / elTime;
616 }
617
GetSpeed(UInt64 numCommands) const618 UInt64 CBenchInfo::GetSpeed(UInt64 numCommands) const
619 {
620 return MyMultDiv64(numCommands, GlobalTime, GlobalFreq);
621 }
622
623 struct CBenchProps
624 {
625 bool LzmaRatingMode;
626
627 UInt32 EncComplex;
628 UInt32 DecComplexCompr;
629 UInt32 DecComplexUnc;
630
CBenchPropsCBenchProps631 CBenchProps(): LzmaRatingMode(false) {}
632 void SetLzmaCompexity();
633
GeComprCommandsCBenchProps634 UInt64 GeComprCommands(UInt64 unpackSize)
635 {
636 return unpackSize * EncComplex;
637 }
638
GeDecomprCommandsCBenchProps639 UInt64 GeDecomprCommands(UInt64 packSize, UInt64 unpackSize)
640 {
641 return (packSize * DecComplexCompr + unpackSize * DecComplexUnc);
642 }
643
644 UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
645 UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations);
646 };
647
SetLzmaCompexity()648 void CBenchProps::SetLzmaCompexity()
649 {
650 EncComplex = 1200;
651 DecComplexUnc = 4;
652 DecComplexCompr = 190;
653 LzmaRatingMode = true;
654 }
655
GetCompressRating(UInt32 dictSize,UInt64 elapsedTime,UInt64 freq,UInt64 size)656 UInt64 CBenchProps::GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
657 {
658 if (dictSize < (1 << kBenchMinDicLogSize))
659 dictSize = (1 << kBenchMinDicLogSize);
660 UInt64 encComplex = EncComplex;
661 if (LzmaRatingMode)
662 {
663 UInt64 t = GetLogSize(dictSize) - (kBenchMinDicLogSize << kSubBits);
664 encComplex = 870 + ((t * t * 5) >> (2 * kSubBits));
665 }
666 UInt64 numCommands = (UInt64)size * encComplex;
667 return MyMultDiv64(numCommands, elapsedTime, freq);
668 }
669
GetDecompressRating(UInt64 elapsedTime,UInt64 freq,UInt64 outSize,UInt64 inSize,UInt64 numIterations)670 UInt64 CBenchProps::GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations)
671 {
672 UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * numIterations;
673 return MyMultDiv64(numCommands, elapsedTime, freq);
674 }
675
GetCompressRating(UInt32 dictSize,UInt64 elapsedTime,UInt64 freq,UInt64 size)676 UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
677 {
678 CBenchProps props;
679 props.SetLzmaCompexity();
680 return props.GetCompressRating(dictSize, elapsedTime, freq, size);
681 }
682
GetDecompressRating(UInt64 elapsedTime,UInt64 freq,UInt64 outSize,UInt64 inSize,UInt64 numIterations)683 UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations)
684 {
685 CBenchProps props;
686 props.SetLzmaCompexity();
687 return props.GetDecompressRating(elapsedTime, freq, outSize, inSize, numIterations);
688 }
689
690 struct CEncoderInfo;
691
692 struct CEncoderInfo
693 {
694 #ifndef _7ZIP_ST
695 NWindows::CThread thread[2];
696 UInt32 NumDecoderSubThreads;
697 #endif
698 CMyComPtr<ICompressCoder> _encoder;
699 CMyComPtr<ICompressFilter> _encoderFilter;
700 CBenchProgressInfo *progressInfoSpec[2];
701 CMyComPtr<ICompressProgressInfo> progressInfo[2];
702 UInt64 NumIterations;
703
704 #ifdef USE_ALLOCA
705 size_t AllocaSize;
706 #endif
707
708 Byte _key[32];
709 Byte _iv[16];
710 Byte _psw[16];
711 bool CheckCrc_Enc;
712 bool CheckCrc_Dec;
713
714 struct CDecoderInfo
715 {
716 CEncoderInfo *Encoder;
717 UInt32 DecoderIndex;
718 bool CallbackMode;
719
720 #ifdef USE_ALLOCA
721 size_t AllocaSize;
722 #endif
723 };
724 CDecoderInfo decodersInfo[2];
725
726 CMyComPtr<ICompressCoder> _decoders[2];
727 CMyComPtr<ICompressFilter> _decoderFilter;
728
729 HRESULT Results[2];
730 CBenchmarkOutStream *outStreamSpec;
731 CMyComPtr<ISequentialOutStream> outStream;
732 IBenchCallback *callback;
733 IBenchPrintCallback *printCallback;
734 UInt32 crc;
735 size_t kBufferSize;
736 size_t compressedSize;
737 const Byte *uncompressedDataPtr;
738
739 const Byte *fileData;
740 CBenchRandomGenerator rg;
741
742 CBenchBuffer rgCopy; // it must be 16-byte aligned !!!
743 CBenchmarkOutStream *propStreamSpec;
744 CMyComPtr<ISequentialOutStream> propStream;
745
746 // for decode
747 COneMethodInfo _method;
748 size_t _uncompressedDataSize;
749
750 HRESULT Init(
751 const COneMethodInfo &method,
752 unsigned generateDictBits,
753 CBaseRandomGenerator *rg);
754 HRESULT Encode();
755 HRESULT Decode(UInt32 decoderIndex);
756
CEncoderInfoCEncoderInfo757 CEncoderInfo():
758 fileData(NULL),
759 CheckCrc_Enc(true),
760 CheckCrc_Dec(true),
761 outStreamSpec(0), callback(0), printCallback(0), propStreamSpec(0) {}
762
763 #ifndef _7ZIP_ST
764
EncodeThreadFunctionCEncoderInfo765 static THREAD_FUNC_DECL EncodeThreadFunction(void *param)
766 {
767 HRESULT res;
768 CEncoderInfo *encoder = (CEncoderInfo *)param;
769 try
770 {
771 #ifdef USE_ALLOCA
772 alloca(encoder->AllocaSize);
773 #endif
774
775 res = encoder->Encode();
776 encoder->Results[0] = res;
777 }
778 catch(...)
779 {
780 res = E_FAIL;
781 }
782 if (res != S_OK)
783 encoder->progressInfoSpec[0]->Status->SetResult(res);
784 return 0;
785 }
786
DecodeThreadFunctionCEncoderInfo787 static THREAD_FUNC_DECL DecodeThreadFunction(void *param)
788 {
789 CDecoderInfo *decoder = (CDecoderInfo *)param;
790
791 #ifdef USE_ALLOCA
792 alloca(decoder->AllocaSize);
793 #endif
794
795 CEncoderInfo *encoder = decoder->Encoder;
796 encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);
797 return 0;
798 }
799
CreateEncoderThreadCEncoderInfo800 HRESULT CreateEncoderThread()
801 {
802 return thread[0].Create(EncodeThreadFunction, this);
803 }
804
CreateDecoderThreadCEncoderInfo805 HRESULT CreateDecoderThread(unsigned index, bool callbackMode
806 #ifdef USE_ALLOCA
807 , size_t allocaSize
808 #endif
809 )
810 {
811 CDecoderInfo &decoder = decodersInfo[index];
812 decoder.DecoderIndex = index;
813 decoder.Encoder = this;
814
815 #ifdef USE_ALLOCA
816 decoder.AllocaSize = allocaSize;
817 #endif
818
819 decoder.CallbackMode = callbackMode;
820 return thread[index].Create(DecodeThreadFunction, &decoder);
821 }
822
823 #endif
824 };
825
826
Init(const COneMethodInfo & method,unsigned generateDictBits,CBaseRandomGenerator * rgLoc)827 HRESULT CEncoderInfo::Init(
828 const COneMethodInfo &method,
829 unsigned generateDictBits,
830 CBaseRandomGenerator *rgLoc)
831 {
832 // we need extra space, if input data is already compressed
833 const size_t kCompressedBufferSize =
834 kCompressedAdditionalSize +
835 kBufferSize + kBufferSize / 16;
836 // kBufferSize / 2;
837
838 if (kCompressedBufferSize < kBufferSize)
839 return E_FAIL;
840
841 uncompressedDataPtr = fileData;
842
843 if (!fileData)
844 {
845 if (!rg.Alloc(kBufferSize))
846 return E_OUTOFMEMORY;
847
848 // DWORD ttt = GetTickCount();
849 if (generateDictBits == 0)
850 rg.GenerateSimpleRandom(rgLoc);
851 else
852 rg.GenerateLz(generateDictBits, rgLoc);
853 // printf("\n%d\n ", GetTickCount() - ttt);
854
855 crc = CrcCalc(rg.Buffer, rg.BufferSize);
856 uncompressedDataPtr = rg.Buffer;
857 }
858
859 if (_encoderFilter)
860 {
861 if (!rgCopy.Alloc(kBufferSize))
862 return E_OUTOFMEMORY;
863 }
864
865
866 outStreamSpec = new CBenchmarkOutStream;
867 outStream = outStreamSpec;
868 if (!outStreamSpec->Alloc(kCompressedBufferSize))
869 return E_OUTOFMEMORY;
870
871 propStreamSpec = 0;
872 if (!propStream)
873 {
874 propStreamSpec = new CBenchmarkOutStream;
875 propStream = propStreamSpec;
876 }
877 if (!propStreamSpec->Alloc(kMaxLzmaPropSize))
878 return E_OUTOFMEMORY;
879 propStreamSpec->Init(true, false);
880
881
882 CMyComPtr<IUnknown> coder;
883 if (_encoderFilter)
884 coder = _encoderFilter;
885 else
886 coder = _encoder;
887 {
888 CMyComPtr<ICompressSetCoderProperties> scp;
889 coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
890 if (scp)
891 {
892 UInt64 reduceSize = kBufferSize;
893 RINOK(method.SetCoderProps(scp, &reduceSize));
894 }
895 else
896 {
897 if (method.AreThereNonOptionalProps())
898 return E_INVALIDARG;
899 }
900
901 CMyComPtr<ICompressWriteCoderProperties> writeCoderProps;
902 coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps);
903 if (writeCoderProps)
904 {
905 RINOK(writeCoderProps->WriteCoderProperties(propStream));
906 }
907
908 {
909 CMyComPtr<ICryptoSetPassword> sp;
910 coder.QueryInterface(IID_ICryptoSetPassword, &sp);
911 if (sp)
912 {
913 RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)));
914
915 // we must call encoding one time to calculate password key for key cache.
916 // it must be after WriteCoderProperties!
917 Byte temp[16];
918 memset(temp, 0, sizeof(temp));
919
920 if (_encoderFilter)
921 {
922 _encoderFilter->Init();
923 _encoderFilter->Filter(temp, sizeof(temp));
924 }
925 else
926 {
927 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
928 CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
929 inStreamSpec->Init(temp, sizeof(temp));
930
931 CCrcOutStream *crcStreamSpec = new CCrcOutStream;
932 CMyComPtr<ISequentialOutStream> crcStream = crcStreamSpec;
933 crcStreamSpec->Init();
934
935 RINOK(_encoder->Code(inStream, crcStream, 0, 0, NULL));
936 }
937 }
938 }
939 }
940
941 return S_OK;
942 }
943
944
My_FilterBench(ICompressFilter * filter,Byte * data,size_t size)945 static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size)
946 {
947 while (size != 0)
948 {
949 UInt32 cur = (UInt32)1 << 31;
950 if (cur > size)
951 cur = (UInt32)size;
952 UInt32 processed = filter->Filter(data, cur);
953 data += processed;
954 // if (processed > size) (in AES filter), we must fill last block with zeros.
955 // but it is not important for benchmark. So we just copy that data without filtering.
956 if (processed > size || processed == 0)
957 break;
958 size -= processed;
959 }
960 }
961
962
Encode()963 HRESULT CEncoderInfo::Encode()
964 {
965 CBenchInfo &bi = progressInfoSpec[0]->BenchInfo;
966 bi.UnpackSize = 0;
967 bi.PackSize = 0;
968 CMyComPtr<ICryptoProperties> cp;
969 CMyComPtr<IUnknown> coder;
970 if (_encoderFilter)
971 coder = _encoderFilter;
972 else
973 coder = _encoder;
974 coder.QueryInterface(IID_ICryptoProperties, &cp);
975 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
976 CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
977 UInt64 prev = 0;
978
979 UInt32 crcPrev = 0;
980
981 if (cp)
982 {
983 RINOK(cp->SetKey(_key, sizeof(_key)));
984 RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
985 }
986
987 for (UInt64 i = 0; i < NumIterations; i++)
988 {
989 if (printCallback && bi.UnpackSize - prev > (1 << 20))
990 {
991 RINOK(printCallback->CheckBreak());
992 prev = bi.UnpackSize;
993 }
994
995 bool isLast = (i == NumIterations - 1);
996 bool calcCrc = ((isLast || (i & 0x7F) == 0 || CheckCrc_Enc) && NumIterations != 1);
997 outStreamSpec->Init(isLast, calcCrc);
998
999 if (_encoderFilter)
1000 {
1001 memcpy(rgCopy.Buffer, uncompressedDataPtr, kBufferSize);
1002 _encoderFilter->Init();
1003 My_FilterBench(_encoderFilter, rgCopy.Buffer, kBufferSize);
1004 RINOK(WriteStream(outStream, rgCopy.Buffer, kBufferSize));
1005 }
1006 else
1007 {
1008 inStreamSpec->Init(uncompressedDataPtr, kBufferSize);
1009 RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0]));
1010 }
1011
1012 // outStreamSpec->Print();
1013
1014 UInt32 crcNew = CRC_GET_DIGEST(outStreamSpec->Crc);
1015 if (i == 0)
1016 crcPrev = crcNew;
1017 else if (calcCrc && crcPrev != crcNew)
1018 return E_FAIL;
1019
1020 compressedSize = outStreamSpec->Pos;
1021 bi.UnpackSize += kBufferSize;
1022 bi.PackSize += compressedSize;
1023 }
1024
1025 _encoder.Release();
1026 _encoderFilter.Release();
1027 return S_OK;
1028 }
1029
1030
Decode(UInt32 decoderIndex)1031 HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)
1032 {
1033 CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
1034 CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
1035 CMyComPtr<ICompressCoder> &decoder = _decoders[decoderIndex];
1036 CMyComPtr<IUnknown> coder;
1037 if (_decoderFilter)
1038 {
1039 if (decoderIndex != 0)
1040 return E_FAIL;
1041 coder = _decoderFilter;
1042 }
1043 else
1044 coder = decoder;
1045
1046 CMyComPtr<ICompressSetDecoderProperties2> setDecProps;
1047 coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps);
1048 if (!setDecProps && propStreamSpec->Pos != 0)
1049 return E_FAIL;
1050
1051 CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
1052 CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
1053
1054 CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
1055 pi->BenchInfo.UnpackSize = 0;
1056 pi->BenchInfo.PackSize = 0;
1057
1058 #ifndef _7ZIP_ST
1059 {
1060 CMyComPtr<ICompressSetCoderMt> setCoderMt;
1061 coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
1062 if (setCoderMt)
1063 {
1064 RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads));
1065 }
1066 }
1067 #endif
1068
1069 CMyComPtr<ICompressSetCoderProperties> scp;
1070 coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
1071 if (scp)
1072 {
1073 UInt64 reduceSize = _uncompressedDataSize;
1074 RINOK(_method.SetCoderProps(scp, &reduceSize));
1075 }
1076
1077 CMyComPtr<ICryptoProperties> cp;
1078 coder.QueryInterface(IID_ICryptoProperties, &cp);
1079
1080 if (setDecProps)
1081 {
1082 RINOK(setDecProps->SetDecoderProperties2(propStreamSpec->Buffer, (UInt32)propStreamSpec->Pos));
1083 }
1084
1085 {
1086 CMyComPtr<ICryptoSetPassword> sp;
1087 coder.QueryInterface(IID_ICryptoSetPassword, &sp);
1088 if (sp)
1089 {
1090 RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)));
1091 }
1092 }
1093
1094 UInt64 prev = 0;
1095
1096 if (cp)
1097 {
1098 RINOK(cp->SetKey(_key, sizeof(_key)));
1099 RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
1100 }
1101
1102 for (UInt64 i = 0; i < NumIterations; i++)
1103 {
1104 if (printCallback && pi->BenchInfo.UnpackSize - prev > (1 << 20))
1105 {
1106 RINOK(printCallback->CheckBreak());
1107 prev = pi->BenchInfo.UnpackSize;
1108 }
1109
1110 inStreamSpec->Init(outStreamSpec->Buffer, compressedSize);
1111 crcOutStreamSpec->Init();
1112
1113 UInt64 outSize = kBufferSize;
1114 crcOutStreamSpec->CalcCrc = ((i & 0x7F) == 0 || CheckCrc_Dec);
1115
1116 if (_decoderFilter)
1117 {
1118 if (compressedSize > rgCopy.BufferSize)
1119 return E_FAIL;
1120 memcpy(rgCopy.Buffer, outStreamSpec->Buffer, compressedSize);
1121 _decoderFilter->Init();
1122 My_FilterBench(_decoderFilter, rgCopy.Buffer, compressedSize);
1123 RINOK(WriteStream(crcOutStream, rgCopy.Buffer, compressedSize));
1124 }
1125 else
1126 {
1127 RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex]));
1128 }
1129
1130 if (crcOutStreamSpec->CalcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc)
1131 return S_FALSE;
1132 pi->BenchInfo.UnpackSize += kBufferSize;
1133 pi->BenchInfo.PackSize += compressedSize;
1134 }
1135
1136 decoder.Release();
1137 _decoderFilter.Release();
1138 return S_OK;
1139 }
1140
1141
1142 static const UInt32 kNumThreadsMax = (1 << 12);
1143
1144 struct CBenchEncoders
1145 {
1146 CEncoderInfo *encoders;
CBenchEncodersCBenchEncoders1147 CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; }
~CBenchEncodersCBenchEncoders1148 ~CBenchEncoders() { delete []encoders; }
1149 };
1150
1151
GetNumIterations(UInt64 numCommands,UInt64 complexInCommands)1152 static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands)
1153 {
1154 if (numCommands < (1 << 4))
1155 numCommands = (1 << 4);
1156 UInt64 res = complexInCommands / numCommands;
1157 return (res == 0 ? 1 : res);
1158 }
1159
1160
MethodBench(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,bool oldLzmaBenchMode,UInt32 numThreads,const COneMethodInfo & method2,size_t uncompressedDataSize,const Byte * fileData,unsigned generateDictBits,IBenchPrintCallback * printCallback,IBenchCallback * callback,CBenchProps * benchProps)1161 static HRESULT MethodBench(
1162 DECL_EXTERNAL_CODECS_LOC_VARS
1163 UInt64 complexInCommands,
1164 bool
1165 #ifndef _7ZIP_ST
1166 oldLzmaBenchMode
1167 #endif
1168 ,
1169 UInt32
1170 #ifndef _7ZIP_ST
1171 numThreads
1172 #endif
1173 ,
1174 const COneMethodInfo &method2,
1175 size_t uncompressedDataSize,
1176 const Byte *fileData,
1177 unsigned generateDictBits,
1178
1179 IBenchPrintCallback *printCallback,
1180 IBenchCallback *callback,
1181 CBenchProps *benchProps)
1182 {
1183 COneMethodInfo method = method2;
1184 UInt64 methodId;
1185 UInt32 numStreams;
1186 if (!FindMethod(
1187 EXTERNAL_CODECS_LOC_VARS
1188 method.MethodName, methodId, numStreams))
1189 return E_NOTIMPL;
1190 if (numStreams != 1)
1191 return E_INVALIDARG;
1192
1193 UInt32 numEncoderThreads = 1;
1194 UInt32 numSubDecoderThreads = 1;
1195
1196 #ifndef _7ZIP_ST
1197 numEncoderThreads = numThreads;
1198
1199 if (oldLzmaBenchMode && methodId == k_LZMA)
1200 {
1201 if (numThreads == 1 && method.Get_NumThreads() < 0)
1202 method.AddProp_NumThreads(1);
1203 const UInt32 numLzmaThreads = method.Get_Lzma_NumThreads();
1204 if (numThreads > 1 && numLzmaThreads > 1)
1205 {
1206 numEncoderThreads = numThreads / 2;
1207 numSubDecoderThreads = 2;
1208 }
1209 }
1210 #endif
1211
1212 CBenchEncoders encodersSpec(numEncoderThreads);
1213 CEncoderInfo *encoders = encodersSpec.encoders;
1214
1215 UInt32 i;
1216
1217 for (i = 0; i < numEncoderThreads; i++)
1218 {
1219 CEncoderInfo &encoder = encoders[i];
1220 encoder.callback = (i == 0) ? callback : 0;
1221 encoder.printCallback = printCallback;
1222
1223 {
1224 CCreatedCoder cod;
1225 RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodId, true, encoder._encoderFilter, cod));
1226 encoder._encoder = cod.Coder;
1227 if (!encoder._encoder && !encoder._encoderFilter)
1228 return E_NOTIMPL;
1229 }
1230
1231 encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30 ;
1232 encoder.CheckCrc_Dec = (benchProps->DecComplexCompr + benchProps->DecComplexUnc) > 30 ;
1233
1234 memset(encoder._iv, 0, sizeof(encoder._iv));
1235 memset(encoder._key, 0, sizeof(encoder._key));
1236 memset(encoder._psw, 0, sizeof(encoder._psw));
1237
1238 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1239 {
1240 CCreatedCoder cod;
1241 CMyComPtr<ICompressCoder> &decoder = encoder._decoders[j];
1242 RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod));
1243 decoder = cod.Coder;
1244 if (!encoder._decoderFilter && !decoder)
1245 return E_NOTIMPL;
1246 }
1247 }
1248
1249 CBaseRandomGenerator rg;
1250 rg.Init();
1251
1252 UInt32 crc = 0;
1253 if (fileData)
1254 crc = CrcCalc(fileData, uncompressedDataSize);
1255
1256 for (i = 0; i < numEncoderThreads; i++)
1257 {
1258 CEncoderInfo &encoder = encoders[i];
1259 encoder._method = method;
1260 encoder._uncompressedDataSize = uncompressedDataSize;
1261 encoder.kBufferSize = uncompressedDataSize;
1262 encoder.fileData = fileData;
1263 encoder.crc = crc;
1264
1265 RINOK(encoders[i].Init(method, generateDictBits, &rg));
1266 }
1267
1268 CBenchProgressStatus status;
1269 status.Res = S_OK;
1270 status.EncodeMode = true;
1271
1272 for (i = 0; i < numEncoderThreads; i++)
1273 {
1274 CEncoderInfo &encoder = encoders[i];
1275 encoder.NumIterations = GetNumIterations(benchProps->GeComprCommands(uncompressedDataSize), complexInCommands);
1276
1277 for (int j = 0; j < 2; j++)
1278 {
1279 CBenchProgressInfo *spec = new CBenchProgressInfo;
1280 encoder.progressInfoSpec[j] = spec;
1281 encoder.progressInfo[j] = spec;
1282 spec->Status = &status;
1283 }
1284
1285 if (i == 0)
1286 {
1287 CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
1288 bpi->Callback = callback;
1289 bpi->BenchInfo.NumIterations = numEncoderThreads;
1290 bpi->SetStartTime();
1291 }
1292
1293 #ifndef _7ZIP_ST
1294 if (numEncoderThreads > 1)
1295 {
1296 #ifdef USE_ALLOCA
1297 encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
1298 #endif
1299
1300 RINOK(encoder.CreateEncoderThread())
1301 }
1302 else
1303 #endif
1304 {
1305 RINOK(encoder.Encode());
1306 }
1307 }
1308
1309 #ifndef _7ZIP_ST
1310 if (numEncoderThreads > 1)
1311 for (i = 0; i < numEncoderThreads; i++)
1312 encoders[i].thread[0].Wait();
1313 #endif
1314
1315 RINOK(status.Res);
1316
1317 CBenchInfo info;
1318
1319 encoders[0].progressInfoSpec[0]->SetFinishTime(info);
1320 info.UnpackSize = 0;
1321 info.PackSize = 0;
1322 info.NumIterations = encoders[0].NumIterations;
1323
1324 for (i = 0; i < numEncoderThreads; i++)
1325 {
1326 CEncoderInfo &encoder = encoders[i];
1327 info.UnpackSize += encoder.kBufferSize;
1328 info.PackSize += encoder.compressedSize;
1329 }
1330
1331 RINOK(callback->SetEncodeResult(info, true));
1332
1333
1334 status.Res = S_OK;
1335 status.EncodeMode = false;
1336
1337 UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
1338
1339 for (i = 0; i < numEncoderThreads; i++)
1340 {
1341 CEncoderInfo &encoder = encoders[i];
1342
1343 if (i == 0)
1344 {
1345 encoder.NumIterations = GetNumIterations(benchProps->GeDecomprCommands(encoder.compressedSize, encoder.kBufferSize), complexInCommands);
1346 CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
1347 bpi->Callback = callback;
1348 bpi->BenchInfo.NumIterations = numDecoderThreads;
1349 bpi->SetStartTime();
1350 }
1351 else
1352 encoder.NumIterations = encoders[0].NumIterations;
1353
1354 #ifndef _7ZIP_ST
1355 {
1356 int numSubThreads = method.Get_NumThreads();
1357 encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : numSubThreads;
1358 }
1359 if (numDecoderThreads > 1)
1360 {
1361 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1362 {
1363 HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
1364 #ifdef USE_ALLOCA
1365 , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
1366 #endif
1367 );
1368 RINOK(res);
1369 }
1370 }
1371 else
1372 #endif
1373 {
1374 RINOK(encoder.Decode(0));
1375 }
1376 }
1377
1378 #ifndef _7ZIP_ST
1379 HRESULT res = S_OK;
1380 if (numDecoderThreads > 1)
1381 for (i = 0; i < numEncoderThreads; i++)
1382 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1383 {
1384 CEncoderInfo &encoder = encoders[i];
1385 encoder.thread[j].Wait();
1386 if (encoder.Results[j] != S_OK)
1387 res = encoder.Results[j];
1388 }
1389 RINOK(res);
1390 #endif
1391
1392 RINOK(status.Res);
1393 encoders[0].progressInfoSpec[0]->SetFinishTime(info);
1394
1395 #ifndef _7ZIP_ST
1396 #ifdef UNDER_CE
1397 if (numDecoderThreads > 1)
1398 for (i = 0; i < numEncoderThreads; i++)
1399 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1400 {
1401 FILETIME creationTime, exitTime, kernelTime, userTime;
1402 if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0)
1403 info.UserTime += GetTime64(userTime) + GetTime64(kernelTime);
1404 }
1405 #endif
1406 #endif
1407
1408 info.UnpackSize = 0;
1409 info.PackSize = 0;
1410 info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
1411
1412 for (i = 0; i < numEncoderThreads; i++)
1413 {
1414 CEncoderInfo &encoder = encoders[i];
1415 info.UnpackSize += encoder.kBufferSize;
1416 info.PackSize += encoder.compressedSize;
1417 }
1418
1419 RINOK(callback->SetDecodeResult(info, false));
1420 RINOK(callback->SetDecodeResult(info, true));
1421
1422 return S_OK;
1423 }
1424
1425
GetLZMAUsage(bool multiThread,UInt32 dictionary)1426 static inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)
1427 {
1428 UInt32 hs = dictionary - 1;
1429 hs |= (hs >> 1);
1430 hs |= (hs >> 2);
1431 hs |= (hs >> 4);
1432 hs |= (hs >> 8);
1433 hs >>= 1;
1434 hs |= 0xFFFF;
1435 if (hs > (1 << 24))
1436 hs >>= 1;
1437 hs++;
1438 return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 +
1439 (1 << 20) + (multiThread ? (6 << 20) : 0);
1440 }
1441
GetBenchMemoryUsage(UInt32 numThreads,UInt32 dictionary,bool totalBench)1442 UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench)
1443 {
1444 const UInt32 kBufferSize = dictionary;
1445 const UInt32 kCompressedBufferSize = kBufferSize; // / 2;
1446 bool lzmaMt = (totalBench || numThreads > 1);
1447 UInt32 numBigThreads = numThreads;
1448 if (!totalBench && lzmaMt)
1449 numBigThreads /= 2;
1450 return ((UInt64)kBufferSize + kCompressedBufferSize +
1451 GetLZMAUsage(lzmaMt, dictionary) + (2 << 20)) * numBigThreads;
1452 }
1453
CrcBig(const void * data,UInt32 size,UInt64 numIterations,const UInt32 * checkSum,IHasher * hf,IBenchPrintCallback * callback)1454 static HRESULT CrcBig(const void *data, UInt32 size, UInt64 numIterations,
1455 const UInt32 *checkSum, IHasher *hf,
1456 IBenchPrintCallback *callback)
1457 {
1458 Byte hash[64];
1459 UInt64 i;
1460 for (i = 0; i < sizeof(hash); i++)
1461 hash[i] = 0;
1462 for (i = 0; i < numIterations; i++)
1463 {
1464 if (callback && (i & 0xFF) == 0)
1465 {
1466 RINOK(callback->CheckBreak());
1467 }
1468 hf->Init();
1469 hf->Update(data, size);
1470 hf->Final(hash);
1471 UInt32 hashSize = hf->GetDigestSize();
1472 if (hashSize > sizeof(hash))
1473 return S_FALSE;
1474 UInt32 sum = 0;
1475 for (UInt32 j = 0; j < hashSize; j += 4)
1476 sum ^= GetUi32(hash + j);
1477 if (checkSum && sum != *checkSum)
1478 {
1479 return S_FALSE;
1480 }
1481 }
1482 return S_OK;
1483 }
1484
1485 UInt32 g_BenchCpuFreqTemp = 1;
1486
1487 #define YY1 sum += val; sum ^= val;
1488 #define YY3 YY1 YY1 YY1 YY1
1489 #define YY5 YY3 YY3 YY3 YY3
1490 #define YY7 YY5 YY5 YY5 YY5
1491 static const UInt32 kNumFreqCommands = 128;
1492
1493 EXTERN_C_BEGIN
1494
CountCpuFreq(UInt32 sum,UInt32 num,UInt32 val)1495 static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val)
1496 {
1497 for (UInt32 i = 0; i < num; i++)
1498 {
1499 YY7
1500 }
1501 return sum;
1502 }
1503
1504 EXTERN_C_END
1505
1506
1507 #ifndef _7ZIP_ST
1508
1509 struct CFreqInfo
1510 {
1511 NWindows::CThread Thread;
1512 IBenchPrintCallback *Callback;
1513 HRESULT CallbackRes;
1514 UInt32 ValRes;
1515 UInt32 Size;
1516 UInt64 NumIterations;
1517
WaitCFreqInfo1518 void Wait()
1519 {
1520 Thread.Wait();
1521 Thread.Close();
1522 }
1523 };
1524
FreqThreadFunction(void * param)1525 static THREAD_FUNC_DECL FreqThreadFunction(void *param)
1526 {
1527 CFreqInfo *p = (CFreqInfo *)param;
1528
1529 UInt32 sum = g_BenchCpuFreqTemp;
1530 for (UInt64 k = p->NumIterations; k > 0; k--)
1531 {
1532 p->CallbackRes = p->Callback->CheckBreak();
1533 if (p->CallbackRes != S_OK)
1534 return 0;
1535 sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp);
1536 }
1537 p->ValRes = sum;
1538 return 0;
1539 }
1540
1541 struct CFreqThreads
1542 {
1543 CFreqInfo *Items;
1544 UInt32 NumThreads;
1545
CFreqThreadsCFreqThreads1546 CFreqThreads(): Items(0), NumThreads(0) {}
WaitAllCFreqThreads1547 void WaitAll()
1548 {
1549 for (UInt32 i = 0; i < NumThreads; i++)
1550 Items[i].Wait();
1551 NumThreads = 0;
1552 }
~CFreqThreadsCFreqThreads1553 ~CFreqThreads()
1554 {
1555 WaitAll();
1556 delete []Items;
1557 }
1558 };
1559
1560 struct CCrcInfo
1561 {
1562 NWindows::CThread Thread;
1563 IBenchPrintCallback *Callback;
1564 HRESULT CallbackRes;
1565
1566 const Byte *Data;
1567 UInt32 Size;
1568 UInt64 NumIterations;
1569 bool CheckSumDefined;
1570 UInt32 CheckSum;
1571 CMyComPtr<IHasher> Hasher;
1572 HRESULT Res;
1573
1574 #ifdef USE_ALLOCA
1575 size_t AllocaSize;
1576 #endif
1577
WaitCCrcInfo1578 void Wait()
1579 {
1580 Thread.Wait();
1581 Thread.Close();
1582 }
1583 };
1584
CrcThreadFunction(void * param)1585 static THREAD_FUNC_DECL CrcThreadFunction(void *param)
1586 {
1587 CCrcInfo *p = (CCrcInfo *)param;
1588
1589 #ifdef USE_ALLOCA
1590 alloca(p->AllocaSize);
1591 #endif
1592
1593 p->Res = CrcBig(p->Data, p->Size, p->NumIterations,
1594 p->CheckSumDefined ? &p->CheckSum : NULL, p->Hasher,
1595 p->Callback);
1596 return 0;
1597 }
1598
1599 struct CCrcThreads
1600 {
1601 CCrcInfo *Items;
1602 UInt32 NumThreads;
1603
CCrcThreadsCCrcThreads1604 CCrcThreads(): Items(0), NumThreads(0) {}
WaitAllCCrcThreads1605 void WaitAll()
1606 {
1607 for (UInt32 i = 0; i < NumThreads; i++)
1608 Items[i].Wait();
1609 NumThreads = 0;
1610 }
~CCrcThreadsCCrcThreads1611 ~CCrcThreads()
1612 {
1613 WaitAll();
1614 delete []Items;
1615 }
1616 };
1617
1618 #endif
1619
CrcCalc1(const Byte * buf,UInt32 size)1620 static UInt32 CrcCalc1(const Byte *buf, UInt32 size)
1621 {
1622 UInt32 crc = CRC_INIT_VAL;;
1623 for (UInt32 i = 0; i < size; i++)
1624 crc = CRC_UPDATE_BYTE(crc, buf[i]);
1625 return CRC_GET_DIGEST(crc);
1626 }
1627
RandGen(Byte * buf,UInt32 size,CBaseRandomGenerator & RG)1628 static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
1629 {
1630 for (UInt32 i = 0; i < size; i++)
1631 buf[i] = (Byte)RG.GetRnd();
1632 }
1633
RandGenCrc(Byte * buf,UInt32 size,CBaseRandomGenerator & RG)1634 static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
1635 {
1636 RandGen(buf, size, RG);
1637 return CrcCalc1(buf, size);
1638 }
1639
CrcInternalTest()1640 bool CrcInternalTest()
1641 {
1642 CBenchBuffer buffer;
1643 const UInt32 kBufferSize0 = (1 << 8);
1644 const UInt32 kBufferSize1 = (1 << 10);
1645 const UInt32 kCheckSize = (1 << 5);
1646 if (!buffer.Alloc(kBufferSize0 + kBufferSize1))
1647 return false;
1648 Byte *buf = buffer.Buffer;
1649 UInt32 i;
1650 for (i = 0; i < kBufferSize0; i++)
1651 buf[i] = (Byte)i;
1652 UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
1653 if (crc1 != 0x29058C73)
1654 return false;
1655 CBaseRandomGenerator RG;
1656 RandGen(buf + kBufferSize0, kBufferSize1, RG);
1657 for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
1658 for (UInt32 j = 0; j < kCheckSize; j++)
1659 if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
1660 return false;
1661 return true;
1662 }
1663
1664 struct CBenchMethod
1665 {
1666 unsigned Weight;
1667 unsigned DictBits;
1668 UInt32 EncComplex;
1669 UInt32 DecComplexCompr;
1670 UInt32 DecComplexUnc;
1671 const char *Name;
1672 };
1673
1674 static const CBenchMethod g_Bench[] =
1675 {
1676 { 40, 17, 357, 145, 20, "LZMA:x1" },
1677 { 80, 24, 1220, 145, 20, "LZMA:x5:mt1" },
1678 { 80, 24, 1220, 145, 20, "LZMA:x5:mt2" },
1679
1680 { 10, 16, 124, 40, 14, "Deflate:x1" },
1681 { 20, 16, 376, 40, 14, "Deflate:x5" },
1682 { 10, 16, 1082, 40, 14, "Deflate:x7" },
1683 { 10, 17, 422, 40, 14, "Deflate64:x5" },
1684
1685 { 10, 15, 590, 69, 69, "BZip2:x1" },
1686 { 20, 19, 815, 122, 122, "BZip2:x5" },
1687 { 10, 19, 815, 122, 122, "BZip2:x5:mt2" },
1688 { 10, 19, 2530, 122, 122, "BZip2:x7" },
1689
1690 { 10, 18, 1010, 0, 1150, "PPMD:x1" },
1691 { 10, 22, 1655, 0, 1830, "PPMD:x5" },
1692
1693 { 2, 0, 6, 0, 6, "Delta:4" },
1694 { 2, 0, 4, 0, 4, "BCJ" },
1695
1696 { 10, 0, 24, 0, 24, "AES256CBC:1" },
1697 { 2, 0, 8, 0, 2, "AES256CBC:2" }
1698 };
1699
1700 struct CBenchHash
1701 {
1702 unsigned Weight;
1703 UInt32 Complex;
1704 UInt32 CheckSum;
1705 const char *Name;
1706 };
1707
1708 static const CBenchHash g_Hash[] =
1709 {
1710 { 1, 1820, 0x8F8FEDAB, "CRC32:1" },
1711 { 10, 558, 0x8F8FEDAB, "CRC32:4" },
1712 { 10, 339, 0x8F8FEDAB, "CRC32:8" },
1713 { 10, 512, 0xDF1C17CC, "CRC64" },
1714 { 10, 5100, 0x2D79FF2E, "SHA256" },
1715 { 10, 2340, 0x4C25132B, "SHA1" },
1716 { 2, 5500, 0xE084E913, "BLAKE2sp" }
1717 };
1718
1719 struct CTotalBenchRes
1720 {
1721 // UInt64 NumIterations1; // for Usage
1722 UInt64 NumIterations2; // for Rating / RPU
1723
1724 UInt64 Rating;
1725 UInt64 Usage;
1726 UInt64 RPU;
1727
InitCTotalBenchRes1728 void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; }
1729
SetSumCTotalBenchRes1730 void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
1731 {
1732 Rating = (r1.Rating + r2.Rating);
1733 Usage = (r1.Usage + r2.Usage);
1734 RPU = (r1.RPU + r2.RPU);
1735 // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1);
1736 NumIterations2 = (r1.NumIterations2 + r2.NumIterations2);
1737 }
1738 };
1739
PrintNumber(IBenchPrintCallback & f,UInt64 value,unsigned size)1740 static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size)
1741 {
1742 char s[128];
1743 unsigned startPos = (unsigned)sizeof(s) - 32;
1744 memset(s, ' ', startPos);
1745 ConvertUInt64ToString(value, s + startPos);
1746 // if (withSpace)
1747 {
1748 startPos--;
1749 size++;
1750 }
1751 unsigned len = (unsigned)strlen(s + startPos);
1752 if (size > len)
1753 {
1754 startPos -= (size - len);
1755 if (startPos < 0)
1756 startPos = 0;
1757 }
1758 f.Print(s + startPos);
1759 }
1760
1761 static const unsigned kFieldSize_Name = 12;
1762 static const unsigned kFieldSize_SmallName = 4;
1763 static const unsigned kFieldSize_Speed = 9;
1764 static const unsigned kFieldSize_Usage = 5;
1765 static const unsigned kFieldSize_RU = 6;
1766 static const unsigned kFieldSize_Rating = 6;
1767 static const unsigned kFieldSize_EU = 5;
1768 static const unsigned kFieldSize_Effec = 5;
1769
1770 static const unsigned kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating;
1771 static const unsigned kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec;
1772
1773
PrintRating(IBenchPrintCallback & f,UInt64 rating,unsigned size)1774 static void PrintRating(IBenchPrintCallback &f, UInt64 rating, unsigned size)
1775 {
1776 PrintNumber(f, (rating + 500000) / 1000000, size);
1777 }
1778
1779
PrintPercents(IBenchPrintCallback & f,UInt64 val,UInt64 divider,unsigned size)1780 static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, unsigned size)
1781 {
1782 PrintNumber(f, (val * 100 + divider / 2) / divider, size);
1783 }
1784
PrintChars(IBenchPrintCallback & f,char c,unsigned size)1785 static void PrintChars(IBenchPrintCallback &f, char c, unsigned size)
1786 {
1787 char s[256];
1788 memset(s, (Byte)c, size);
1789 s[size] = 0;
1790 f.Print(s);
1791 }
1792
PrintSpaces(IBenchPrintCallback & f,unsigned size)1793 static void PrintSpaces(IBenchPrintCallback &f, unsigned size)
1794 {
1795 PrintChars(f, ' ', size);
1796 }
1797
PrintResults(IBenchPrintCallback & f,UInt64 usage,UInt64 rpu,UInt64 rating,bool showFreq,UInt64 cpuFreq)1798 static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq)
1799 {
1800 PrintNumber(f, (usage + 5000) / 10000, kFieldSize_Usage);
1801 PrintRating(f, rpu, kFieldSize_RU);
1802 PrintRating(f, rating, kFieldSize_Rating);
1803 if (showFreq)
1804 {
1805 if (cpuFreq == 0)
1806 PrintSpaces(f, kFieldSize_EUAndEffec);
1807 else
1808 {
1809 UInt64 ddd = cpuFreq * usage / 100;
1810 if (ddd == 0)
1811 ddd = 1;
1812 PrintPercents(f, (rating * 10000), ddd, kFieldSize_EU);
1813 PrintPercents(f, rating, cpuFreq, kFieldSize_Effec);
1814 }
1815 }
1816 }
1817
PrintResults(IBenchPrintCallback * f,const CBenchInfo & info,unsigned weight,UInt64 rating,bool showFreq,UInt64 cpuFreq,CTotalBenchRes * res)1818 static void PrintResults(IBenchPrintCallback *f,
1819 const CBenchInfo &info,
1820 unsigned weight,
1821 UInt64 rating,
1822 bool showFreq, UInt64 cpuFreq,
1823 CTotalBenchRes *res)
1824 {
1825 UInt64 speed = info.GetSpeed(info.UnpackSize * info.NumIterations);
1826 if (f)
1827 {
1828 if (speed != 0)
1829 PrintNumber(*f, speed / 1024, kFieldSize_Speed);
1830 else
1831 PrintSpaces(*f, 1 + kFieldSize_Speed);
1832 }
1833 UInt64 usage = info.GetUsage();
1834 UInt64 rpu = info.GetRatingPerUsage(rating);
1835 if (f)
1836 {
1837 PrintResults(*f, usage, rpu, rating, showFreq, cpuFreq);
1838 }
1839
1840 if (res)
1841 {
1842 // res->NumIterations1++;
1843 res->NumIterations2 += weight;
1844 res->RPU += (rpu * weight);
1845 res->Rating += (rating * weight);
1846 res->Usage += (usage * weight);
1847 }
1848 }
1849
PrintTotals(IBenchPrintCallback & f,bool showFreq,UInt64 cpuFreq,const CTotalBenchRes & res)1850 static void PrintTotals(IBenchPrintCallback &f, bool showFreq, UInt64 cpuFreq, const CTotalBenchRes &res)
1851 {
1852 PrintSpaces(f, 1 + kFieldSize_Speed);
1853 // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1;
1854 UInt64 numIterations2 = res.NumIterations2; if (numIterations2 == 0) numIterations2 = 1;
1855 PrintResults(f, res.Usage / numIterations2, res.RPU / numIterations2, res.Rating / numIterations2, showFreq, cpuFreq);
1856 }
1857
1858
PrintHex(AString & s,UInt64 v)1859 static void PrintHex(AString &s, UInt64 v)
1860 {
1861 char temp[32];
1862 ConvertUInt64ToHex(v, temp);
1863 s += temp;
1864 }
1865
GetProcessThreadsInfo(const NSystem::CProcessAffinity & ti)1866 AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
1867 {
1868 AString s;
1869 // s.Add_UInt32(ti.numProcessThreads);
1870 if (ti.processAffinityMask != ti.systemAffinityMask)
1871 {
1872 // if (ti.numProcessThreads != ti.numSysThreads)
1873 {
1874 s += " / ";
1875 s.Add_UInt32(ti.GetNumSystemThreads());
1876 }
1877 s += " : ";
1878 PrintHex(s, ti.processAffinityMask);
1879 s += " / ";
1880 PrintHex(s, ti.systemAffinityMask);
1881 }
1882 return s;
1883 }
1884
1885
1886 extern bool g_LargePagesMode;
1887
1888
PrintRequirements(IBenchPrintCallback & f,const char * sizeString,bool size_Defined,UInt64 size,const char * threadsString,UInt32 numThreads)1889 static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString,
1890 bool size_Defined, UInt64 size, const char *threadsString, UInt32 numThreads)
1891 {
1892 f.Print("RAM ");
1893 f.Print(sizeString);
1894 if (size_Defined)
1895 PrintNumber(f, (size >> 20), 6);
1896 else
1897 f.Print(" ?");
1898 f.Print(" MB");
1899 if (g_LargePagesMode)
1900 f.Print(" LP");
1901 f.Print(", # ");
1902 f.Print(threadsString);
1903 PrintNumber(f, numThreads, 3);
1904 }
1905
1906
1907
1908 struct CBenchCallbackToPrint: public IBenchCallback
1909 {
1910 CBenchProps BenchProps;
1911 CTotalBenchRes EncodeRes;
1912 CTotalBenchRes DecodeRes;
1913 IBenchPrintCallback *_file;
1914 UInt32 DictSize;
1915
1916 bool Use2Columns;
1917 unsigned NameFieldSize;
1918
1919 bool ShowFreq;
1920 UInt64 CpuFreq;
1921
1922 unsigned EncodeWeight;
1923 unsigned DecodeWeight;
1924
CBenchCallbackToPrintCBenchCallbackToPrint1925 CBenchCallbackToPrint():
1926 Use2Columns(false),
1927 NameFieldSize(0),
1928 ShowFreq(false),
1929 CpuFreq(0),
1930 EncodeWeight(1),
1931 DecodeWeight(1)
1932 {}
1933
InitCBenchCallbackToPrint1934 void Init() { EncodeRes.Init(); DecodeRes.Init(); }
1935 void Print(const char *s);
1936 void NewLine();
1937
1938 HRESULT SetFreq(bool showFreq, UInt64 cpuFreq);
1939 HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
1940 HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
1941 };
1942
SetFreq(bool showFreq,UInt64 cpuFreq)1943 HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq)
1944 {
1945 ShowFreq = showFreq;
1946 CpuFreq = cpuFreq;
1947 return S_OK;
1948 }
1949
SetEncodeResult(const CBenchInfo & info,bool final)1950 HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final)
1951 {
1952 RINOK(_file->CheckBreak());
1953 if (final)
1954 {
1955 UInt64 rating = BenchProps.GetCompressRating(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations);
1956 PrintResults(_file, info,
1957 EncodeWeight, rating,
1958 ShowFreq, CpuFreq, &EncodeRes);
1959 if (!Use2Columns)
1960 _file->NewLine();
1961 }
1962 return S_OK;
1963 }
1964
1965 static const char * const kSep = " | ";
1966
SetDecodeResult(const CBenchInfo & info,bool final)1967 HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final)
1968 {
1969 RINOK(_file->CheckBreak());
1970 if (final)
1971 {
1972 UInt64 rating = BenchProps.GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
1973 if (Use2Columns)
1974 _file->Print(kSep);
1975 else
1976 PrintSpaces(*_file, NameFieldSize);
1977 CBenchInfo info2 = info;
1978 info2.UnpackSize *= info2.NumIterations;
1979 info2.PackSize *= info2.NumIterations;
1980 info2.NumIterations = 1;
1981 PrintResults(_file, info2,
1982 DecodeWeight, rating,
1983 ShowFreq, CpuFreq, &DecodeRes);
1984 }
1985 return S_OK;
1986 }
1987
Print(const char * s)1988 void CBenchCallbackToPrint::Print(const char *s)
1989 {
1990 _file->Print(s);
1991 }
1992
NewLine()1993 void CBenchCallbackToPrint::NewLine()
1994 {
1995 _file->NewLine();
1996 }
1997
PrintLeft(IBenchPrintCallback & f,const char * s,unsigned size)1998 void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size)
1999 {
2000 f.Print(s);
2001 int numSpaces = size - MyStringLen(s);
2002 if (numSpaces > 0)
2003 PrintSpaces(f, numSpaces);
2004 }
2005
PrintRight(IBenchPrintCallback & f,const char * s,unsigned size)2006 void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size)
2007 {
2008 int numSpaces = size - MyStringLen(s);
2009 if (numSpaces > 0)
2010 PrintSpaces(f, numSpaces);
2011 f.Print(s);
2012 }
2013
TotalBench(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,UInt32 numThreads,bool forceUnpackSize,size_t unpackSize,const Byte * fileData,IBenchPrintCallback * printCallback,CBenchCallbackToPrint * callback)2014 static HRESULT TotalBench(
2015 DECL_EXTERNAL_CODECS_LOC_VARS
2016 UInt64 complexInCommands,
2017 UInt32 numThreads,
2018 bool forceUnpackSize,
2019 size_t unpackSize,
2020 const Byte *fileData,
2021 IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback)
2022 {
2023 for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++)
2024 {
2025 const CBenchMethod &bench = g_Bench[i];
2026 PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
2027 callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
2028 callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
2029 callback->BenchProps.EncComplex = bench.EncComplex;
2030
2031 COneMethodInfo method;
2032 NCOM::CPropVariant propVariant;
2033 propVariant = bench.Name;
2034 RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant));
2035
2036 size_t unpackSize2 = unpackSize;
2037 if (!forceUnpackSize && bench.DictBits == 0)
2038 unpackSize2 = kFilterUnpackSize;
2039
2040 callback->EncodeWeight = bench.Weight;
2041 callback->DecodeWeight = bench.Weight;
2042
2043 HRESULT res = MethodBench(
2044 EXTERNAL_CODECS_LOC_VARS
2045 complexInCommands,
2046 false, numThreads, method,
2047 unpackSize2, fileData,
2048 bench.DictBits,
2049 printCallback, callback, &callback->BenchProps);
2050
2051 if (res == E_NOTIMPL)
2052 {
2053 // callback->Print(" ---");
2054 // we need additional empty line as line for decompression results
2055 if (!callback->Use2Columns)
2056 callback->NewLine();
2057 }
2058 else
2059 {
2060 RINOK(res);
2061 }
2062
2063 callback->NewLine();
2064 }
2065 return S_OK;
2066 }
2067
2068
FreqBench(UInt64 complexInCommands,UInt32 numThreads,IBenchPrintCallback * _file,bool showFreq,UInt64 specifiedFreq,UInt64 & cpuFreq,UInt32 & res)2069 static HRESULT FreqBench(
2070 UInt64 complexInCommands,
2071 UInt32 numThreads,
2072 IBenchPrintCallback *_file,
2073 bool showFreq,
2074 UInt64 specifiedFreq,
2075 UInt64 &cpuFreq,
2076 UInt32 &res)
2077 {
2078 res = 0;
2079 cpuFreq = 0;
2080
2081 UInt32 bufferSize = 1 << 20;
2082 UInt32 complexity = kNumFreqCommands;
2083 if (numThreads == 0)
2084 numThreads = 1;
2085
2086 #ifdef _7ZIP_ST
2087 numThreads = 1;
2088 #endif
2089
2090 UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);
2091 UInt64 numIterations = complexInCommands / complexity / bsize;
2092 if (numIterations == 0)
2093 numIterations = 1;
2094
2095 CBenchInfoCalc progressInfoSpec;
2096
2097 #ifndef _7ZIP_ST
2098 CFreqThreads threads;
2099 if (numThreads > 1)
2100 {
2101 threads.Items = new CFreqInfo[numThreads];
2102 UInt32 i;
2103 for (i = 0; i < numThreads; i++)
2104 {
2105 CFreqInfo &info = threads.Items[i];
2106 info.Callback = _file;
2107 info.CallbackRes = S_OK;
2108 info.NumIterations = numIterations;
2109 info.Size = bufferSize;
2110 }
2111 progressInfoSpec.SetStartTime();
2112 for (i = 0; i < numThreads; i++)
2113 {
2114 CFreqInfo &info = threads.Items[i];
2115 RINOK(info.Thread.Create(FreqThreadFunction, &info));
2116 threads.NumThreads++;
2117 }
2118 threads.WaitAll();
2119 for (i = 0; i < numThreads; i++)
2120 {
2121 RINOK(threads.Items[i].CallbackRes);
2122 }
2123 }
2124 else
2125 #endif
2126 {
2127 progressInfoSpec.SetStartTime();
2128 UInt32 sum = g_BenchCpuFreqTemp;
2129 for (UInt64 k = numIterations; k > 0; k--)
2130 {
2131 RINOK(_file->CheckBreak());
2132 sum = CountCpuFreq(sum, bufferSize, g_BenchCpuFreqTemp);
2133 }
2134 res += sum;
2135 }
2136
2137 CBenchInfo info;
2138 progressInfoSpec.SetFinishTime(info);
2139
2140 info.UnpackSize = 0;
2141 info.PackSize = 0;
2142 info.NumIterations = 1;
2143
2144 if (_file)
2145 {
2146 {
2147 UInt64 numCommands = (UInt64)numIterations * bufferSize * numThreads * complexity;
2148 UInt64 rating = info.GetSpeed(numCommands);
2149 cpuFreq = rating / numThreads;
2150 PrintResults(_file, info,
2151 0, // weight
2152 rating,
2153 showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : cpuFreq) : 0, NULL);
2154 }
2155 RINOK(_file->CheckBreak());
2156 }
2157
2158 return S_OK;
2159 }
2160
2161
2162
CrcBench(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,UInt32 numThreads,UInt32 bufferSize,UInt64 & speed,UInt32 complexity,unsigned benchWeight,const UInt32 * checkSum,const COneMethodInfo & method,IBenchPrintCallback * _file,CTotalBenchRes * encodeRes,bool showFreq,UInt64 cpuFreq)2163 static HRESULT CrcBench(
2164 DECL_EXTERNAL_CODECS_LOC_VARS
2165 UInt64 complexInCommands,
2166 UInt32 numThreads, UInt32 bufferSize,
2167 UInt64 &speed,
2168 UInt32 complexity, unsigned benchWeight,
2169 const UInt32 *checkSum,
2170 const COneMethodInfo &method,
2171 IBenchPrintCallback *_file,
2172 CTotalBenchRes *encodeRes,
2173 bool showFreq, UInt64 cpuFreq)
2174 {
2175 if (numThreads == 0)
2176 numThreads = 1;
2177
2178 #ifdef _7ZIP_ST
2179 numThreads = 1;
2180 #endif
2181
2182 const AString &methodName = method.MethodName;
2183 // methodName.RemoveChar(L'-');
2184 CMethodId hashID;
2185 if (!FindHashMethod(
2186 EXTERNAL_CODECS_LOC_VARS
2187 methodName, hashID))
2188 return E_NOTIMPL;
2189
2190 CBenchBuffer buffer;
2191 size_t totalSize = (size_t)bufferSize * numThreads;
2192 if (totalSize / numThreads != bufferSize)
2193 return E_OUTOFMEMORY;
2194 if (!buffer.Alloc(totalSize))
2195 return E_OUTOFMEMORY;
2196
2197 Byte *buf = buffer.Buffer;
2198 CBaseRandomGenerator RG;
2199 UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);
2200 UInt64 numIterations = complexInCommands * 256 / complexity / bsize;
2201 if (numIterations == 0)
2202 numIterations = 1;
2203
2204 CBenchInfoCalc progressInfoSpec;
2205
2206 #ifndef _7ZIP_ST
2207 CCrcThreads threads;
2208 if (numThreads > 1)
2209 {
2210 threads.Items = new CCrcInfo[numThreads];
2211
2212 UInt32 i;
2213 for (i = 0; i < numThreads; i++)
2214 {
2215 CCrcInfo &info = threads.Items[i];
2216 AString name;
2217 RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, info.Hasher));
2218 if (!info.Hasher)
2219 return E_NOTIMPL;
2220 CMyComPtr<ICompressSetCoderProperties> scp;
2221 info.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
2222 if (scp)
2223 {
2224 UInt64 reduceSize = 1;
2225 RINOK(method.SetCoderProps(scp, &reduceSize));
2226 }
2227
2228 Byte *data = buf + (size_t)bufferSize * i;
2229 info.Callback = _file;
2230 info.Data = data;
2231 info.NumIterations = numIterations;
2232 info.Size = bufferSize;
2233 /* info.Crc = */ RandGenCrc(data, bufferSize, RG);
2234 info.CheckSumDefined = false;
2235 if (checkSum)
2236 {
2237 info.CheckSum = *checkSum;
2238 info.CheckSumDefined = (checkSum && (i == 0));
2239 }
2240
2241 #ifdef USE_ALLOCA
2242 info.AllocaSize = (i * 16 * 21) & 0x7FF;
2243 #endif
2244 }
2245
2246 progressInfoSpec.SetStartTime();
2247
2248 for (i = 0; i < numThreads; i++)
2249 {
2250 CCrcInfo &info = threads.Items[i];
2251 RINOK(info.Thread.Create(CrcThreadFunction, &info));
2252 threads.NumThreads++;
2253 }
2254 threads.WaitAll();
2255 for (i = 0; i < numThreads; i++)
2256 {
2257 RINOK(threads.Items[i].Res);
2258 }
2259 }
2260 else
2261 #endif
2262 {
2263 /* UInt32 crc = */ RandGenCrc(buf, bufferSize, RG);
2264 progressInfoSpec.SetStartTime();
2265 CMyComPtr<IHasher> hasher;
2266 AString name;
2267 RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher));
2268 if (!hasher)
2269 return E_NOTIMPL;
2270 CMyComPtr<ICompressSetCoderProperties> scp;
2271 hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
2272 if (scp)
2273 {
2274 UInt64 reduceSize = 1;
2275 RINOK(method.SetCoderProps(scp, &reduceSize));
2276 }
2277 RINOK(CrcBig(buf, bufferSize, numIterations, checkSum, hasher, _file));
2278 }
2279
2280 CBenchInfo info;
2281 progressInfoSpec.SetFinishTime(info);
2282
2283 UInt64 unpSize = numIterations * bufferSize;
2284 UInt64 unpSizeThreads = unpSize * numThreads;
2285 info.UnpackSize = unpSizeThreads;
2286 info.PackSize = unpSizeThreads;
2287 info.NumIterations = 1;
2288
2289 if (_file)
2290 {
2291 {
2292 UInt64 numCommands = unpSizeThreads * complexity / 256;
2293 UInt64 rating = info.GetSpeed(numCommands);
2294 PrintResults(_file, info,
2295 benchWeight, rating,
2296 showFreq, cpuFreq, encodeRes);
2297 }
2298 RINOK(_file->CheckBreak());
2299 }
2300
2301 speed = info.GetSpeed(unpSizeThreads);
2302
2303 return S_OK;
2304 }
2305
TotalBench_Hash(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,UInt32 numThreads,UInt32 bufSize,IBenchPrintCallback * printCallback,CBenchCallbackToPrint * callback,CTotalBenchRes * encodeRes,bool showFreq,UInt64 cpuFreq)2306 static HRESULT TotalBench_Hash(
2307 DECL_EXTERNAL_CODECS_LOC_VARS
2308 UInt64 complexInCommands,
2309 UInt32 numThreads, UInt32 bufSize,
2310 IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback,
2311 CTotalBenchRes *encodeRes,
2312 bool showFreq, UInt64 cpuFreq)
2313 {
2314 for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++)
2315 {
2316 const CBenchHash &bench = g_Hash[i];
2317 PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
2318 // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
2319 // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
2320 // callback->BenchProps.EncComplex = bench.EncComplex;
2321
2322 COneMethodInfo method;
2323 NCOM::CPropVariant propVariant;
2324 propVariant = bench.Name;
2325 RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant));
2326
2327 UInt64 speed;
2328 HRESULT res = CrcBench(
2329 EXTERNAL_CODECS_LOC_VARS
2330 complexInCommands,
2331 numThreads, bufSize,
2332 speed,
2333 bench.Complex, bench.Weight,
2334 &bench.CheckSum, method,
2335 printCallback, encodeRes, showFreq, cpuFreq);
2336 if (res == E_NOTIMPL)
2337 {
2338 // callback->Print(" ---");
2339 }
2340 else
2341 {
2342 RINOK(res);
2343 }
2344 callback->NewLine();
2345 }
2346 return S_OK;
2347 }
2348
2349 struct CTempValues
2350 {
2351 UInt64 *Values;
CTempValuesCTempValues2352 CTempValues(UInt32 num) { Values = new UInt64[num]; }
~CTempValuesCTempValues2353 ~CTempValues() { delete []Values; }
2354 };
2355
ParseNumberString(const UString & s,NCOM::CPropVariant & prop)2356 static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
2357 {
2358 const wchar_t *end;
2359 UInt64 result = ConvertStringToUInt64(s, &end);
2360 if (*end != 0 || s.IsEmpty())
2361 prop = s;
2362 else if (result <= (UInt32)0xFFFFFFFF)
2363 prop = (UInt32)result;
2364 else
2365 prop = result;
2366 }
2367
GetNumThreadsNext(unsigned i,UInt32 numThreads)2368 static UInt32 GetNumThreadsNext(unsigned i, UInt32 numThreads)
2369 {
2370 if (i < 2)
2371 return i + 1;
2372 i -= 1;
2373 UInt32 num = (UInt32)(2 + (i & 1)) << (i >> 1);
2374 return (num <= numThreads) ? num : numThreads;
2375 }
2376
AreSameMethodNames(const char * fullName,const char * shortName)2377 static bool AreSameMethodNames(const char *fullName, const char *shortName)
2378 {
2379 return StringsAreEqualNoCase_Ascii(fullName, shortName);
2380 }
2381
2382
2383 #ifdef MY_CPU_X86_OR_AMD64
2384
PrintCpuChars(AString & s,UInt32 v)2385 static void PrintCpuChars(AString &s, UInt32 v)
2386 {
2387 for (int j = 0; j < 4; j++)
2388 {
2389 Byte b = (Byte)(v & 0xFF);
2390 v >>= 8;
2391 if (b == 0)
2392 break;
2393 s += (char)b;
2394 }
2395 }
2396
x86cpuid_to_String(const Cx86cpuid & c,AString & s)2397 static void x86cpuid_to_String(const Cx86cpuid &c, AString &s)
2398 {
2399 s.Empty();
2400
2401 UInt32 maxFunc2 = 0;
2402 UInt32 t[3];
2403
2404 MyCPUID(0x80000000, &maxFunc2, &t[0], &t[1], &t[2]);
2405
2406 bool fullNameIsAvail = (maxFunc2 >= 0x80000004);
2407
2408 if (!fullNameIsAvail)
2409 {
2410 for (int i = 0; i < 3; i++)
2411 PrintCpuChars(s, c.vendor[i]);
2412 }
2413 else
2414 {
2415 for (int i = 0; i < 3; i++)
2416 {
2417 UInt32 d[4] = { 0 };
2418 MyCPUID(0x80000002 + i, &d[0], &d[1], &d[2], &d[3]);
2419 for (int j = 0; j < 4; j++)
2420 PrintCpuChars(s, d[j]);
2421 }
2422 }
2423
2424 s.Add_Space_if_NotEmpty();
2425 {
2426 char temp[32];
2427 ConvertUInt32ToHex(c.ver, temp);
2428 s += '(';
2429 s += temp;
2430 s += ')';
2431 }
2432 }
2433
2434 #endif
2435
2436
2437
2438 static const char * const k_PROCESSOR_ARCHITECTURE[] =
2439 {
2440 "x86" // "INTEL"
2441 , "MIPS"
2442 , "ALPHA"
2443 , "PPC"
2444 , "SHX"
2445 , "ARM"
2446 , "IA64"
2447 , "ALPHA64"
2448 , "MSIL"
2449 , "x64" // "AMD64"
2450 , "IA32_ON_WIN64"
2451 , "NEUTRAL"
2452 , "ARM64"
2453 , "ARM32_ON_WIN64"
2454 };
2455
2456 #define MY__PROCESSOR_ARCHITECTURE_INTEL 0
2457 #define MY__PROCESSOR_ARCHITECTURE_AMD64 9
2458
2459
2460 #define MY__PROCESSOR_INTEL_PENTIUM 586
2461 #define MY__PROCESSOR_AMD_X8664 8664
2462
2463 /*
2464 static const CUInt32PCharPair k_PROCESSOR[] =
2465 {
2466 { 2200, "IA64" },
2467 { 8664, "x64" }
2468 };
2469
2470 #define PROCESSOR_INTEL_386 386
2471 #define PROCESSOR_INTEL_486 486
2472 #define PROCESSOR_INTEL_PENTIUM 586
2473 #define PROCESSOR_INTEL_860 860
2474 #define PROCESSOR_INTEL_IA64 2200
2475 #define PROCESSOR_AMD_X8664 8664
2476 #define PROCESSOR_MIPS_R2000 2000
2477 #define PROCESSOR_MIPS_R3000 3000
2478 #define PROCESSOR_MIPS_R4000 4000
2479 #define PROCESSOR_ALPHA_21064 21064
2480 #define PROCESSOR_PPC_601 601
2481 #define PROCESSOR_PPC_603 603
2482 #define PROCESSOR_PPC_604 604
2483 #define PROCESSOR_PPC_620 620
2484 #define PROCESSOR_HITACHI_SH3 10003
2485 #define PROCESSOR_HITACHI_SH3E 10004
2486 #define PROCESSOR_HITACHI_SH4 10005
2487 #define PROCESSOR_MOTOROLA_821 821
2488 #define PROCESSOR_SHx_SH3 103
2489 #define PROCESSOR_SHx_SH4 104
2490 #define PROCESSOR_STRONGARM 2577 // 0xA11
2491 #define PROCESSOR_ARM720 1824 // 0x720
2492 #define PROCESSOR_ARM820 2080 // 0x820
2493 #define PROCESSOR_ARM920 2336 // 0x920
2494 #define PROCESSOR_ARM_7TDMI 70001
2495 #define PROCESSOR_OPTIL 18767 // 0x494f
2496 */
2497
2498 #ifdef _WIN32
2499
2500 static const char * const k_PF[] =
2501 {
2502 "FP_ERRATA"
2503 , "FP_EMU"
2504 , "CMPXCHG"
2505 , "MMX"
2506 , "PPC_MOVEMEM_64BIT"
2507 , "ALPHA_BYTE"
2508 , "SSE"
2509 , "3DNOW"
2510 , "RDTSC"
2511 , "PAE"
2512 , "SSE2"
2513 , "SSE_DAZ"
2514 , "NX"
2515 , "SSE3"
2516 , "CMPXCHG16B"
2517 , "CMP8XCHG16"
2518 , "CHANNELS"
2519 , "XSAVE"
2520 , "ARM_VFP_32"
2521 , "ARM_NEON"
2522 , "L2AT"
2523 , "VIRT_FIRMWARE"
2524 , "RDWRFSGSBASE"
2525 , "FASTFAIL"
2526 , "ARM_DIVIDE"
2527 , "ARM_64BIT_LOADSTORE_ATOMIC"
2528 , "ARM_EXTERNAL_CACHE"
2529 , "ARM_FMAC"
2530 , "RDRAND"
2531 , "ARM_V8"
2532 , "ARM_V8_CRYPTO"
2533 , "ARM_V8_CRC32"
2534 , "RDTSCP"
2535 };
2536
2537 #endif
2538
2539
PrintSize(AString & s,UInt64 v)2540 static void PrintSize(AString &s, UInt64 v)
2541 {
2542 char c = 0;
2543 if ((v & 0x3FF) == 0) { v >>= 10; c = 'K';
2544 if ((v & 0x3FF) == 0) { v >>= 10; c = 'M';
2545 if ((v & 0x3FF) == 0) { v >>= 10; c = 'G';
2546 if ((v & 0x3FF) == 0) { v >>= 10; c = 'T';
2547 }}}}
2548 else
2549 {
2550 PrintHex(s, v);
2551 return;
2552 }
2553 char temp[32];
2554 ConvertUInt64ToString(v, temp);
2555 s += temp;
2556 if (c)
2557 s += c;
2558 }
2559
2560
PrintPage(AString & s,UInt32 v)2561 static void PrintPage(AString &s, UInt32 v)
2562 {
2563 if ((v & 0x3FF) == 0)
2564 {
2565 s.Add_UInt32(v >> 10);
2566 s += "K";
2567 }
2568 else
2569 s.Add_UInt32(v >> 10);
2570 }
2571
TypeToString2(const char * const table[],unsigned num,UInt32 value)2572 static AString TypeToString2(const char * const table[], unsigned num, UInt32 value)
2573 {
2574 char sz[16];
2575 const char *p = NULL;
2576 if (value < num)
2577 p = table[value];
2578 if (!p)
2579 {
2580 ConvertUInt32ToString(value, sz);
2581 p = sz;
2582 }
2583 return (AString)p;
2584 }
2585
2586 #ifdef _WIN32
2587
SysInfo_To_String(AString & s,const SYSTEM_INFO & si)2588 static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si)
2589 {
2590 s += TypeToString2(k_PROCESSOR_ARCHITECTURE, ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture);
2591
2592 if (!( si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == MY__PROCESSOR_INTEL_PENTIUM
2593 || si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == MY__PROCESSOR_AMD_X8664))
2594 {
2595 s += " ";
2596 // s += TypePairToString(k_PROCESSOR, ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType);
2597 s.Add_UInt32(si.dwProcessorType);
2598 }
2599 s += " ";
2600 PrintHex(s, si.wProcessorLevel);
2601 s += ".";
2602 PrintHex(s, si.wProcessorRevision);
2603 if (si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors))
2604 {
2605 s += " act:";
2606 PrintHex(s, si.dwActiveProcessorMask);
2607 }
2608 s += " cpus:";
2609 s.Add_UInt32(si.dwNumberOfProcessors);
2610 if (si.dwPageSize != 1 << 12)
2611 {
2612 s += " page:";
2613 PrintPage(s, si.dwPageSize);
2614 }
2615 if (si.dwAllocationGranularity != 1 << 16)
2616 {
2617 s += " gran:";
2618 PrintPage(s, si.dwAllocationGranularity);
2619 }
2620 s += " ";
2621
2622 DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress;
2623 UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1;
2624 const UInt32 kReserveSize = ((UInt32)1 << 16);
2625 if (minAdd != kReserveSize)
2626 {
2627 PrintSize(s, minAdd);
2628 s += "-";
2629 }
2630 else
2631 {
2632 if ((maxSize & (kReserveSize - 1)) == 0)
2633 maxSize += kReserveSize;
2634 }
2635 PrintSize(s, maxSize);
2636 }
2637
2638 #ifndef _WIN64
2639 typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo);
2640 #endif
2641
2642 #endif
2643
GetSysInfo(AString & s1,AString & s2)2644 void GetSysInfo(AString &s1, AString &s2)
2645 {
2646 s1.Empty();
2647 s2.Empty();
2648
2649 #ifdef _WIN32
2650 SYSTEM_INFO si;
2651 GetSystemInfo(&si);
2652 {
2653 SysInfo_To_String(s1, si);
2654 // s += " : ";
2655 }
2656
2657 #if !defined(_WIN64) && !defined(UNDER_CE)
2658 Func_GetNativeSystemInfo fn_GetNativeSystemInfo = (Func_GetNativeSystemInfo)GetProcAddress(
2659 GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
2660 if (fn_GetNativeSystemInfo)
2661 {
2662 SYSTEM_INFO si2;
2663 fn_GetNativeSystemInfo(&si2);
2664 // if (memcmp(&si, &si2, sizeof(si)) != 0)
2665 {
2666 // s += " - ";
2667 SysInfo_To_String(s2, si2);
2668 }
2669 }
2670 #endif
2671 #endif
2672 }
2673
2674
GetCpuName(AString & s)2675 void GetCpuName(AString &s)
2676 {
2677 s.Empty();
2678
2679 #ifdef MY_CPU_X86_OR_AMD64
2680 {
2681 Cx86cpuid cpuid;
2682 if (x86cpuid_CheckAndRead(&cpuid))
2683 {
2684 AString s2;
2685 x86cpuid_to_String(cpuid, s2);
2686 s += s2;
2687 return;
2688 }
2689 #ifdef MY_CPU_AMD64
2690 s += "x64";
2691 #else
2692 s += "x86";
2693 #endif
2694 }
2695 #else
2696
2697 #ifdef MY_CPU_LE
2698 s += "LE";
2699 #elif defined(MY_CPU_BE)
2700 s += "BE";
2701 #endif
2702
2703 #endif
2704 }
2705
2706
GetCpuFeatures(AString & s)2707 void GetCpuFeatures(AString &s)
2708 {
2709 s.Empty();
2710
2711 #ifdef _WIN32
2712 const unsigned kNumFeatures_Extra = 32; // we check also for unknown features
2713 const unsigned kNumFeatures = ARRAY_SIZE(k_PF) + kNumFeatures_Extra;
2714 for (unsigned i = 0; i < kNumFeatures; i++)
2715 {
2716 if (IsProcessorFeaturePresent(i))
2717 {
2718 s.Add_Space_if_NotEmpty();
2719 s += TypeToString2(k_PF, ARRAY_SIZE(k_PF), i);
2720 }
2721 }
2722 #endif
2723 }
2724
2725
Bench(DECL_EXTERNAL_CODECS_LOC_VARS IBenchPrintCallback * printCallback,IBenchCallback * benchCallback,const CObjectVector<CProperty> & props,UInt32 numIterations,bool multiDict)2726 HRESULT Bench(
2727 DECL_EXTERNAL_CODECS_LOC_VARS
2728 IBenchPrintCallback *printCallback,
2729 IBenchCallback *benchCallback,
2730 // IBenchFreqCallback *freqCallback,
2731 const CObjectVector<CProperty> &props,
2732 UInt32 numIterations,
2733 bool multiDict)
2734 {
2735 if (!CrcInternalTest())
2736 return S_FALSE;
2737
2738 UInt32 numCPUs = 1;
2739 UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29;
2740
2741 NSystem::CProcessAffinity threadsInfo;
2742 threadsInfo.InitST();
2743
2744 #ifndef _7ZIP_ST
2745
2746 if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0)
2747 numCPUs = threadsInfo.GetNumProcessThreads();
2748 else
2749 numCPUs = NSystem::GetNumberOfProcessors();
2750
2751 #endif
2752
2753 bool ramSize_Defined = NSystem::GetRamSize(ramSize);
2754
2755 UInt32 numThreadsSpecified = numCPUs;
2756
2757 UInt32 testTime = kComplexInSeconds;
2758
2759 UInt64 specifiedFreq = 0;
2760
2761 bool multiThreadTests = false;
2762
2763 COneMethodInfo method;
2764
2765 CBenchBuffer fileDataBuffer;
2766
2767 {
2768 unsigned i;
2769 for (i = 0; i < props.Size(); i++)
2770 {
2771 const CProperty &property = props[i];
2772 UString name (property.Name);
2773 name.MakeLower_Ascii();
2774
2775 if (name.IsEqualTo("file"))
2776 {
2777 if (property.Value.IsEmpty())
2778 return E_INVALIDARG;
2779
2780 #ifdef USE_WIN_FILE
2781
2782 NFile::NIO::CInFile file;
2783 if (!file.Open(us2fs(property.Value)))
2784 return E_INVALIDARG;
2785 UInt64 len;
2786 if (!file.GetLength(len))
2787 return E_FAIL;
2788 if (len >= ((UInt32)1 << 31) || len == 0)
2789 return E_INVALIDARG;
2790 if (!fileDataBuffer.Alloc((size_t)len))
2791 return E_OUTOFMEMORY;
2792 UInt32 processedSize;
2793 file.Read(fileDataBuffer.Buffer, (UInt32)len, processedSize);
2794 if (processedSize != len)
2795 return E_FAIL;
2796 if (printCallback)
2797 {
2798 printCallback->Print("file size =");
2799 PrintNumber(*printCallback, len, 0);
2800 printCallback->NewLine();
2801 }
2802 continue;
2803
2804 #else
2805
2806 return E_NOTIMPL;
2807
2808 #endif
2809 }
2810
2811 NCOM::CPropVariant propVariant;
2812 if (!property.Value.IsEmpty())
2813 ParseNumberString(property.Value, propVariant);
2814
2815 if (name.IsEqualTo("time"))
2816 {
2817 RINOK(ParsePropToUInt32(UString(), propVariant, testTime));
2818 continue;
2819 }
2820
2821 if (name.IsEqualTo("freq"))
2822 {
2823 UInt32 freq32 = 0;
2824 RINOK(ParsePropToUInt32(UString(), propVariant, freq32));
2825 if (freq32 == 0)
2826 return E_INVALIDARG;
2827 specifiedFreq = (UInt64)freq32 * 1000000;
2828
2829 if (printCallback)
2830 {
2831 printCallback->Print("freq=");
2832 PrintNumber(*printCallback, freq32, 0);
2833 printCallback->NewLine();
2834 }
2835
2836 continue;
2837 }
2838
2839 if (name.IsPrefixedBy_Ascii_NoCase("mt"))
2840 {
2841 UString s = name.Ptr(2);
2842 if (s.IsEqualTo("*")
2843 || s.IsEmpty() && propVariant.vt == VT_BSTR && StringsAreEqual_Ascii(propVariant.bstrVal, "*"))
2844 {
2845 multiThreadTests = true;
2846 continue;
2847 }
2848 #ifndef _7ZIP_ST
2849 RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified));
2850 #endif
2851 continue;
2852 }
2853
2854 RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));
2855 }
2856 }
2857
2858 if (printCallback)
2859 {
2860 {
2861 AString s1, s2;
2862 GetSysInfo(s1, s2);
2863 if (!s1.IsEmpty() || !s2.IsEmpty())
2864 {
2865 printCallback->Print(s1);
2866 if (s1 != s2 && !s2.IsEmpty())
2867 {
2868 printCallback->Print(" - ");
2869 printCallback->Print(s2);
2870 }
2871 printCallback->NewLine();
2872 }
2873 }
2874 {
2875 AString s;
2876 GetCpuFeatures(s);
2877 if (!s.IsEmpty())
2878 {
2879 printCallback->Print(s);
2880 printCallback->NewLine();
2881 }
2882 }
2883 {
2884 AString s;
2885 GetCpuName(s);
2886 if (!s.IsEmpty())
2887 {
2888 printCallback->Print(s);
2889 printCallback->NewLine();
2890 }
2891 }
2892 }
2893
2894 if (printCallback)
2895 {
2896 printCallback->Print("CPU Freq:");
2897 }
2898
2899 UInt64 complexInCommands = kComplexInCommands;
2900
2901 if (printCallback /* || freqCallback */)
2902 {
2903 UInt64 numMilCommands = 1 << 6;
2904 if (specifiedFreq != 0)
2905 {
2906 while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000))
2907 numMilCommands >>= 1;
2908 }
2909
2910 for (int jj = 0;; jj++)
2911 {
2912 if (printCallback)
2913 RINOK(printCallback->CheckBreak());
2914
2915 UInt64 start = ::GetTimeCount();
2916 UInt32 sum = (UInt32)start;
2917 sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp);
2918 const UInt64 realDelta = ::GetTimeCount() - start;
2919 start = realDelta;
2920 if (start == 0)
2921 start = 1;
2922 UInt64 freq = GetFreq();
2923 // mips is constant in some compilers
2924 const UInt64 mipsVal = numMilCommands * freq / start;
2925 if (printCallback)
2926 {
2927 if (realDelta == 0)
2928 {
2929 printCallback->Print(" -");
2930 }
2931 else
2932 {
2933 // PrintNumber(*printCallback, start, 0);
2934 PrintNumber(*printCallback, mipsVal, 5 + ((sum == 0xF1541213) ? 1 : 0));
2935 }
2936 }
2937 /*
2938 if (freqCallback)
2939 freqCallback->AddCpuFreq(mipsVal);
2940 */
2941
2942 if (jj >= 3)
2943 {
2944 SetComplexCommands(testTime, false, mipsVal * 1000000, complexInCommands);
2945 if (jj >= 8 || start >= freq)
2946 break;
2947 // break; // change it
2948 numMilCommands <<= 1;
2949 }
2950 }
2951 }
2952
2953 if (printCallback)
2954 {
2955 printCallback->NewLine();
2956 printCallback->NewLine();
2957 PrintRequirements(*printCallback, "size: ", ramSize_Defined, ramSize, "CPU hardware threads:", numCPUs);
2958 printCallback->Print(GetProcessThreadsInfo(threadsInfo));
2959 printCallback->NewLine();
2960 }
2961
2962 if (numThreadsSpecified < 1 || numThreadsSpecified > kNumThreadsMax)
2963 return E_INVALIDARG;
2964
2965 UInt32 dict;
2966 bool dictIsDefined = method.Get_DicSize(dict);
2967
2968 if (method.MethodName.IsEmpty())
2969 method.MethodName = "LZMA";
2970
2971 if (benchCallback)
2972 {
2973 CBenchProps benchProps;
2974 benchProps.SetLzmaCompexity();
2975 UInt32 dictSize = method.Get_Lzma_DicSize();
2976 UInt32 uncompressedDataSize = kAdditionalSize + dictSize;
2977 return MethodBench(
2978 EXTERNAL_CODECS_LOC_VARS
2979 complexInCommands,
2980 true, numThreadsSpecified,
2981 method,
2982 uncompressedDataSize, fileDataBuffer.Buffer,
2983 kOldLzmaDictBits, printCallback, benchCallback, &benchProps);
2984 }
2985
2986 AString methodName (method.MethodName);
2987 if (methodName.IsEqualTo_Ascii_NoCase("CRC"))
2988 methodName = "crc32";
2989 method.MethodName = methodName;
2990 CMethodId hashID;
2991
2992 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID))
2993 {
2994 if (!printCallback)
2995 return S_FALSE;
2996 IBenchPrintCallback &f = *printCallback;
2997 if (!dictIsDefined)
2998 dict = (1 << 24);
2999
3000
3001 // methhodName.RemoveChar(L'-');
3002 UInt32 complexity = 10000;
3003 const UInt32 *checkSum = NULL;
3004 {
3005 unsigned i;
3006 for (i = 0; i < ARRAY_SIZE(g_Hash); i++)
3007 {
3008 const CBenchHash &h = g_Hash[i];
3009 AString benchMethod (h.Name);
3010 AString benchProps;
3011 int propPos = benchMethod.Find(':');
3012 if (propPos >= 0)
3013 {
3014 benchProps = benchMethod.Ptr(propPos + 1);
3015 benchMethod.DeleteFrom(propPos);
3016 }
3017
3018 if (AreSameMethodNames(benchMethod, methodName))
3019 {
3020 if (benchProps.IsEmpty()
3021 || benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps == "8" && method.PropsString.IsEmpty()
3022 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
3023 {
3024 complexity = h.Complex;
3025 checkSum = &h.CheckSum;
3026 if (method.PropsString.IsEqualTo_Ascii_NoCase(benchProps))
3027 break;
3028 }
3029 }
3030 }
3031 if (i == ARRAY_SIZE(g_Hash))
3032 return E_NOTIMPL;
3033 }
3034
3035 f.NewLine();
3036 f.Print("Size");
3037 const unsigned kFieldSize_CrcSpeed = 6;
3038 unsigned numThreadsTests = 0;
3039 for (;;)
3040 {
3041 UInt32 t = GetNumThreadsNext(numThreadsTests, numThreadsSpecified);
3042 PrintNumber(f, t, kFieldSize_CrcSpeed);
3043 numThreadsTests++;
3044 if (t >= numThreadsSpecified)
3045 break;
3046 }
3047 f.NewLine();
3048 f.NewLine();
3049 CTempValues speedTotals(numThreadsTests);
3050 {
3051 for (unsigned ti = 0; ti < numThreadsTests; ti++)
3052 speedTotals.Values[ti] = 0;
3053 }
3054
3055 UInt64 numSteps = 0;
3056 for (UInt32 i = 0; i < numIterations; i++)
3057 {
3058 for (unsigned pow = 10; pow < 32; pow++)
3059 {
3060 UInt32 bufSize = (UInt32)1 << pow;
3061 if (bufSize > dict)
3062 break;
3063 char s[16];
3064 ConvertUInt32ToString(pow, s);
3065 unsigned pos = MyStringLen(s);
3066 s[pos++] = ':';
3067 s[pos++] = ' ';
3068 s[pos] = 0;
3069 f.Print(s);
3070
3071 for (unsigned ti = 0; ti < numThreadsTests; ti++)
3072 {
3073 RINOK(f.CheckBreak());
3074 UInt32 t = GetNumThreadsNext(ti, numThreadsSpecified);
3075 UInt64 speed = 0;
3076 RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands,
3077 t, bufSize, speed,
3078 complexity,
3079 1, // benchWeight,
3080 (pow == kNumHashDictBits) ? checkSum : NULL, method, NULL, NULL, false, 0));
3081 PrintNumber(f, (speed >> 20), kFieldSize_CrcSpeed);
3082 speedTotals.Values[ti] += speed;
3083 }
3084 f.NewLine();
3085 numSteps++;
3086 }
3087 }
3088 if (numSteps != 0)
3089 {
3090 f.NewLine();
3091 f.Print("Avg:");
3092 for (unsigned ti = 0; ti < numThreadsTests; ti++)
3093 {
3094 PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), kFieldSize_CrcSpeed);
3095 }
3096 f.NewLine();
3097 }
3098 return S_OK;
3099 }
3100
3101 bool use2Columns = false;
3102
3103 bool totalBenchMode = (method.MethodName.IsEqualTo_Ascii_NoCase("*"));
3104 bool onlyHashBench = false;
3105 if (method.MethodName.IsEqualTo_Ascii_NoCase("hash"))
3106 {
3107 onlyHashBench = true;
3108 totalBenchMode = true;
3109 }
3110
3111 // ---------- Threads loop ----------
3112 for (unsigned threadsPassIndex = 0; threadsPassIndex < 3; threadsPassIndex++)
3113 {
3114
3115 UInt32 numThreads = numThreadsSpecified;
3116
3117 if (!multiThreadTests)
3118 {
3119 if (threadsPassIndex != 0)
3120 break;
3121 }
3122 else
3123 {
3124 numThreads = 1;
3125 if (threadsPassIndex != 0)
3126 {
3127 if (numCPUs < 2)
3128 break;
3129 numThreads = numCPUs;
3130 if (threadsPassIndex == 1)
3131 {
3132 if (numCPUs >= 4)
3133 numThreads = numCPUs / 2;
3134 }
3135 else if (numCPUs < 4)
3136 break;
3137 }
3138 }
3139
3140 CBenchCallbackToPrint callback;
3141 callback.Init();
3142 callback._file = printCallback;
3143
3144 IBenchPrintCallback &f = *printCallback;
3145
3146 if (threadsPassIndex > 0)
3147 {
3148 f.NewLine();
3149 f.NewLine();
3150 }
3151
3152 if (!dictIsDefined)
3153 {
3154 const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25);
3155 unsigned dicSizeLog = dicSizeLog_Main;
3156
3157 #ifdef UNDER_CE
3158 dicSizeLog = (UInt64)1 << 20;
3159 #endif
3160
3161 if (ramSize_Defined)
3162 for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
3163 if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize)
3164 break;
3165
3166 dict = (UInt32)1 << dicSizeLog;
3167
3168 if (totalBenchMode && dicSizeLog != dicSizeLog_Main)
3169 {
3170 f.Print("Dictionary reduced to: ");
3171 PrintNumber(f, dicSizeLog, 1);
3172 f.NewLine();
3173 }
3174 }
3175
3176 PrintRequirements(f, "usage:", true, GetBenchMemoryUsage(numThreads, dict, totalBenchMode), "Benchmark threads: ", numThreads);
3177 f.NewLine();
3178
3179 f.NewLine();
3180
3181 if (totalBenchMode)
3182 {
3183 callback.NameFieldSize = kFieldSize_Name;
3184 use2Columns = false;
3185 }
3186 else
3187 {
3188 callback.NameFieldSize = kFieldSize_SmallName;
3189 use2Columns = true;
3190 }
3191 callback.Use2Columns = use2Columns;
3192
3193 bool showFreq = false;
3194 UInt64 cpuFreq = 0;
3195
3196 if (totalBenchMode)
3197 {
3198 showFreq = true;
3199 }
3200
3201 unsigned fileldSize = kFieldSize_TotalSize;
3202 if (showFreq)
3203 fileldSize += kFieldSize_EUAndEffec;
3204
3205 if (use2Columns)
3206 {
3207 PrintSpaces(f, callback.NameFieldSize);
3208 PrintRight(f, "Compressing", fileldSize);
3209 f.Print(kSep);
3210 PrintRight(f, "Decompressing", fileldSize);
3211 }
3212 f.NewLine();
3213 PrintLeft(f, totalBenchMode ? "Method" : "Dict", callback.NameFieldSize);
3214
3215 int j;
3216
3217 for (j = 0; j < 2; j++)
3218 {
3219 PrintRight(f, "Speed", kFieldSize_Speed + 1);
3220 PrintRight(f, "Usage", kFieldSize_Usage + 1);
3221 PrintRight(f, "R/U", kFieldSize_RU + 1);
3222 PrintRight(f, "Rating", kFieldSize_Rating + 1);
3223 if (showFreq)
3224 {
3225 PrintRight(f, "E/U", kFieldSize_EU + 1);
3226 PrintRight(f, "Effec", kFieldSize_Effec + 1);
3227 }
3228 if (!use2Columns)
3229 break;
3230 if (j == 0)
3231 f.Print(kSep);
3232 }
3233
3234 f.NewLine();
3235 PrintSpaces(f, callback.NameFieldSize);
3236
3237 for (j = 0; j < 2; j++)
3238 {
3239 PrintRight(f, "KiB/s", kFieldSize_Speed + 1);
3240 PrintRight(f, "%", kFieldSize_Usage + 1);
3241 PrintRight(f, "MIPS", kFieldSize_RU + 1);
3242 PrintRight(f, "MIPS", kFieldSize_Rating + 1);
3243 if (showFreq)
3244 {
3245 PrintRight(f, "%", kFieldSize_EU + 1);
3246 PrintRight(f, "%", kFieldSize_Effec + 1);
3247 }
3248 if (!use2Columns)
3249 break;
3250 if (j == 0)
3251 f.Print(kSep);
3252 }
3253
3254 f.NewLine();
3255 f.NewLine();
3256
3257 if (specifiedFreq != 0)
3258 cpuFreq = specifiedFreq;
3259
3260
3261 if (totalBenchMode)
3262 {
3263 for (UInt32 i = 0; i < numIterations; i++)
3264 {
3265 if (i != 0)
3266 printCallback->NewLine();
3267 HRESULT res;
3268
3269 const unsigned kNumCpuTests = 3;
3270 for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++)
3271 {
3272 PrintLeft(f, "CPU", kFieldSize_Name);
3273 UInt32 resVal;
3274 RINOK(FreqBench(complexInCommands, numThreads, printCallback,
3275 (freqTest == kNumCpuTests - 1 || specifiedFreq != 0), // showFreq
3276 specifiedFreq,
3277 cpuFreq, resVal));
3278 callback.NewLine();
3279
3280 if (specifiedFreq != 0)
3281 cpuFreq = specifiedFreq;
3282
3283 if (freqTest == kNumCpuTests - 1)
3284 SetComplexCommands(testTime, specifiedFreq != 0, cpuFreq, complexInCommands);
3285 }
3286 callback.NewLine();
3287
3288 callback.SetFreq(true, cpuFreq);
3289
3290 if (!onlyHashBench)
3291 {
3292 res = TotalBench(EXTERNAL_CODECS_LOC_VARS
3293 complexInCommands, numThreads,
3294 dictIsDefined || fileDataBuffer.Buffer, // forceUnpackSize
3295 fileDataBuffer.Buffer ? fileDataBuffer.BufferSize : dict,
3296 fileDataBuffer.Buffer,
3297 printCallback, &callback);
3298 RINOK(res);
3299 }
3300
3301 res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads,
3302 1 << kNumHashDictBits, printCallback, &callback, &callback.EncodeRes, true, cpuFreq);
3303 RINOK(res);
3304
3305 callback.NewLine();
3306 {
3307 PrintLeft(f, "CPU", kFieldSize_Name);
3308 UInt32 resVal;
3309 UInt64 cpuFreqLastTemp = cpuFreq;
3310 RINOK(FreqBench(complexInCommands, numThreads, printCallback,
3311 specifiedFreq != 0, // showFreq
3312 specifiedFreq,
3313 cpuFreqLastTemp, resVal));
3314 callback.NewLine();
3315 }
3316 }
3317 }
3318 else
3319 {
3320 bool needSetComplexity = true;
3321 if (!methodName.IsEqualTo_Ascii_NoCase("LZMA"))
3322 {
3323 unsigned i;
3324 for (i = 0; i < ARRAY_SIZE(g_Bench); i++)
3325 {
3326 const CBenchMethod &h = g_Bench[i];
3327 AString benchMethod (h.Name);
3328 AString benchProps;
3329 int propPos = benchMethod.Find(':');
3330 if (propPos >= 0)
3331 {
3332 benchProps = benchMethod.Ptr(propPos + 1);
3333 benchMethod.DeleteFrom(propPos);
3334 }
3335
3336 if (AreSameMethodNames(benchMethod, methodName))
3337 {
3338 if (benchProps.IsEmpty()
3339 || benchProps == "x5" && method.PropsString.IsEmpty()
3340 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
3341 {
3342 callback.BenchProps.EncComplex = h.EncComplex;
3343 callback.BenchProps.DecComplexCompr = h.DecComplexCompr;
3344 callback.BenchProps.DecComplexUnc = h.DecComplexUnc;;
3345 needSetComplexity = false;
3346 break;
3347 }
3348 }
3349 }
3350 if (i == ARRAY_SIZE(g_Bench))
3351 return E_NOTIMPL;
3352 }
3353 if (needSetComplexity)
3354 callback.BenchProps.SetLzmaCompexity();
3355
3356 for (unsigned i = 0; i < numIterations; i++)
3357 {
3358 const unsigned kStartDicLog = 22;
3359 unsigned pow = (dict < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
3360 if (!multiDict)
3361 pow = 31;
3362 while (((UInt32)1 << pow) > dict && pow > 0)
3363 pow--;
3364 for (; ((UInt32)1 << pow) <= dict; pow++)
3365 {
3366 char s[16];
3367 ConvertUInt32ToString(pow, s);
3368 unsigned pos = MyStringLen(s);
3369 s[pos++] = ':';
3370 s[pos] = 0;
3371 PrintLeft(f, s, kFieldSize_SmallName);
3372 callback.DictSize = (UInt32)1 << pow;
3373
3374 COneMethodInfo method2 = method;
3375
3376 if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA"))
3377 {
3378 // We add dictionary size property.
3379 // method2 can have two different dictionary size properties.
3380 // And last property is main.
3381 NCOM::CPropVariant propVariant = (UInt32)pow;
3382 RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant));
3383 }
3384
3385 size_t uncompressedDataSize;
3386 if (fileDataBuffer.Buffer)
3387 {
3388 uncompressedDataSize = fileDataBuffer.BufferSize;
3389 }
3390 else
3391 {
3392 uncompressedDataSize = callback.DictSize;
3393 if (uncompressedDataSize >= (1 << 18))
3394 uncompressedDataSize += kAdditionalSize;
3395 }
3396
3397 HRESULT res = MethodBench(
3398 EXTERNAL_CODECS_LOC_VARS
3399 complexInCommands,
3400 true, numThreads,
3401 method2,
3402 uncompressedDataSize, fileDataBuffer.Buffer,
3403 kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps);
3404 f.NewLine();
3405 RINOK(res);
3406 if (!multiDict)
3407 break;
3408 }
3409 }
3410 }
3411
3412 PrintChars(f, '-', callback.NameFieldSize + fileldSize);
3413
3414 if (use2Columns)
3415 {
3416 f.Print(kSep);
3417 PrintChars(f, '-', fileldSize);
3418 }
3419
3420 f.NewLine();
3421
3422 if (use2Columns)
3423 {
3424 PrintLeft(f, "Avr:", callback.NameFieldSize);
3425 PrintTotals(f, showFreq, cpuFreq, callback.EncodeRes);
3426 f.Print(kSep);
3427 PrintTotals(f, showFreq, cpuFreq, callback.DecodeRes);
3428 f.NewLine();
3429 }
3430
3431 PrintLeft(f, "Tot:", callback.NameFieldSize);
3432 CTotalBenchRes midRes;
3433 midRes.SetSum(callback.EncodeRes, callback.DecodeRes);
3434 PrintTotals(f, showFreq, cpuFreq, midRes);
3435 f.NewLine();
3436
3437 }
3438 return S_OK;
3439 }
3440