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 int codecIndex = FindMethod_Index(
1187 EXTERNAL_CODECS_LOC_VARS
1188 method.MethodName, true,
1189 methodId, numStreams);
1190 if (codecIndex < 0)
1191 return E_NOTIMPL;
1192 if (numStreams != 1)
1193 return E_INVALIDARG;
1194
1195 UInt32 numEncoderThreads = 1;
1196 UInt32 numSubDecoderThreads = 1;
1197
1198 #ifndef _7ZIP_ST
1199 numEncoderThreads = numThreads;
1200
1201 if (oldLzmaBenchMode && methodId == k_LZMA)
1202 {
1203 if (numThreads == 1 && method.Get_NumThreads() < 0)
1204 method.AddProp_NumThreads(1);
1205 const UInt32 numLzmaThreads = method.Get_Lzma_NumThreads();
1206 if (numThreads > 1 && numLzmaThreads > 1)
1207 {
1208 numEncoderThreads = numThreads / 2;
1209 numSubDecoderThreads = 2;
1210 }
1211 }
1212 #endif
1213
1214 CBenchEncoders encodersSpec(numEncoderThreads);
1215 CEncoderInfo *encoders = encodersSpec.encoders;
1216
1217 UInt32 i;
1218
1219 for (i = 0; i < numEncoderThreads; i++)
1220 {
1221 CEncoderInfo &encoder = encoders[i];
1222 encoder.callback = (i == 0) ? callback : 0;
1223 encoder.printCallback = printCallback;
1224
1225 {
1226 CCreatedCoder cod;
1227 RINOK(CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS codecIndex, true, encoder._encoderFilter, cod));
1228 encoder._encoder = cod.Coder;
1229 if (!encoder._encoder && !encoder._encoderFilter)
1230 return E_NOTIMPL;
1231 }
1232
1233 encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30 ;
1234 encoder.CheckCrc_Dec = (benchProps->DecComplexCompr + benchProps->DecComplexUnc) > 30 ;
1235
1236 memset(encoder._iv, 0, sizeof(encoder._iv));
1237 memset(encoder._key, 0, sizeof(encoder._key));
1238 memset(encoder._psw, 0, sizeof(encoder._psw));
1239
1240 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1241 {
1242 CCreatedCoder cod;
1243 CMyComPtr<ICompressCoder> &decoder = encoder._decoders[j];
1244 RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod));
1245 decoder = cod.Coder;
1246 if (!encoder._decoderFilter && !decoder)
1247 return E_NOTIMPL;
1248 }
1249 }
1250
1251 CBaseRandomGenerator rg;
1252 rg.Init();
1253
1254 UInt32 crc = 0;
1255 if (fileData)
1256 crc = CrcCalc(fileData, uncompressedDataSize);
1257
1258 for (i = 0; i < numEncoderThreads; i++)
1259 {
1260 CEncoderInfo &encoder = encoders[i];
1261 encoder._method = method;
1262 encoder._uncompressedDataSize = uncompressedDataSize;
1263 encoder.kBufferSize = uncompressedDataSize;
1264 encoder.fileData = fileData;
1265 encoder.crc = crc;
1266
1267 RINOK(encoders[i].Init(method, generateDictBits, &rg));
1268 }
1269
1270 CBenchProgressStatus status;
1271 status.Res = S_OK;
1272 status.EncodeMode = true;
1273
1274 for (i = 0; i < numEncoderThreads; i++)
1275 {
1276 CEncoderInfo &encoder = encoders[i];
1277 encoder.NumIterations = GetNumIterations(benchProps->GeComprCommands(uncompressedDataSize), complexInCommands);
1278
1279 for (int j = 0; j < 2; j++)
1280 {
1281 CBenchProgressInfo *spec = new CBenchProgressInfo;
1282 encoder.progressInfoSpec[j] = spec;
1283 encoder.progressInfo[j] = spec;
1284 spec->Status = &status;
1285 }
1286
1287 if (i == 0)
1288 {
1289 CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
1290 bpi->Callback = callback;
1291 bpi->BenchInfo.NumIterations = numEncoderThreads;
1292 bpi->SetStartTime();
1293 }
1294
1295 #ifndef _7ZIP_ST
1296 if (numEncoderThreads > 1)
1297 {
1298 #ifdef USE_ALLOCA
1299 encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
1300 #endif
1301
1302 RINOK(encoder.CreateEncoderThread())
1303 }
1304 else
1305 #endif
1306 {
1307 RINOK(encoder.Encode());
1308 }
1309 }
1310
1311 #ifndef _7ZIP_ST
1312 if (numEncoderThreads > 1)
1313 for (i = 0; i < numEncoderThreads; i++)
1314 encoders[i].thread[0].Wait();
1315 #endif
1316
1317 RINOK(status.Res);
1318
1319 CBenchInfo info;
1320
1321 encoders[0].progressInfoSpec[0]->SetFinishTime(info);
1322 info.UnpackSize = 0;
1323 info.PackSize = 0;
1324 info.NumIterations = encoders[0].NumIterations;
1325
1326 for (i = 0; i < numEncoderThreads; i++)
1327 {
1328 CEncoderInfo &encoder = encoders[i];
1329 info.UnpackSize += encoder.kBufferSize;
1330 info.PackSize += encoder.compressedSize;
1331 }
1332
1333 RINOK(callback->SetEncodeResult(info, true));
1334
1335
1336 status.Res = S_OK;
1337 status.EncodeMode = false;
1338
1339 UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
1340
1341 for (i = 0; i < numEncoderThreads; i++)
1342 {
1343 CEncoderInfo &encoder = encoders[i];
1344
1345 if (i == 0)
1346 {
1347 encoder.NumIterations = GetNumIterations(benchProps->GeDecomprCommands(encoder.compressedSize, encoder.kBufferSize), complexInCommands);
1348 CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
1349 bpi->Callback = callback;
1350 bpi->BenchInfo.NumIterations = numDecoderThreads;
1351 bpi->SetStartTime();
1352 }
1353 else
1354 encoder.NumIterations = encoders[0].NumIterations;
1355
1356 #ifndef _7ZIP_ST
1357 {
1358 int numSubThreads = method.Get_NumThreads();
1359 encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : numSubThreads;
1360 }
1361 if (numDecoderThreads > 1)
1362 {
1363 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1364 {
1365 HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
1366 #ifdef USE_ALLOCA
1367 , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
1368 #endif
1369 );
1370 RINOK(res);
1371 }
1372 }
1373 else
1374 #endif
1375 {
1376 RINOK(encoder.Decode(0));
1377 }
1378 }
1379
1380 #ifndef _7ZIP_ST
1381 HRESULT res = S_OK;
1382 if (numDecoderThreads > 1)
1383 for (i = 0; i < numEncoderThreads; i++)
1384 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1385 {
1386 CEncoderInfo &encoder = encoders[i];
1387 encoder.thread[j].Wait();
1388 if (encoder.Results[j] != S_OK)
1389 res = encoder.Results[j];
1390 }
1391 RINOK(res);
1392 #endif
1393
1394 RINOK(status.Res);
1395 encoders[0].progressInfoSpec[0]->SetFinishTime(info);
1396
1397 #ifndef _7ZIP_ST
1398 #ifdef UNDER_CE
1399 if (numDecoderThreads > 1)
1400 for (i = 0; i < numEncoderThreads; i++)
1401 for (UInt32 j = 0; j < numSubDecoderThreads; j++)
1402 {
1403 FILETIME creationTime, exitTime, kernelTime, userTime;
1404 if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0)
1405 info.UserTime += GetTime64(userTime) + GetTime64(kernelTime);
1406 }
1407 #endif
1408 #endif
1409
1410 info.UnpackSize = 0;
1411 info.PackSize = 0;
1412 info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
1413
1414 for (i = 0; i < numEncoderThreads; i++)
1415 {
1416 CEncoderInfo &encoder = encoders[i];
1417 info.UnpackSize += encoder.kBufferSize;
1418 info.PackSize += encoder.compressedSize;
1419 }
1420
1421 RINOK(callback->SetDecodeResult(info, false));
1422 RINOK(callback->SetDecodeResult(info, true));
1423
1424 return S_OK;
1425 }
1426
1427
GetLZMAUsage(bool multiThread,UInt32 dictionary)1428 static inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)
1429 {
1430 UInt32 hs = dictionary - 1;
1431 hs |= (hs >> 1);
1432 hs |= (hs >> 2);
1433 hs |= (hs >> 4);
1434 hs |= (hs >> 8);
1435 hs >>= 1;
1436 hs |= 0xFFFF;
1437 if (hs > (1 << 24))
1438 hs >>= 1;
1439 hs++;
1440 return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 +
1441 (1 << 20) + (multiThread ? (6 << 20) : 0);
1442 }
1443
GetBenchMemoryUsage(UInt32 numThreads,UInt32 dictionary,bool totalBench)1444 UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench)
1445 {
1446 const UInt32 kBufferSize = dictionary;
1447 const UInt32 kCompressedBufferSize = kBufferSize; // / 2;
1448 bool lzmaMt = (totalBench || numThreads > 1);
1449 UInt32 numBigThreads = numThreads;
1450 if (!totalBench && lzmaMt)
1451 numBigThreads /= 2;
1452 return ((UInt64)kBufferSize + kCompressedBufferSize +
1453 GetLZMAUsage(lzmaMt, dictionary) + (2 << 20)) * numBigThreads;
1454 }
1455
CrcBig(const void * data,UInt32 size,UInt64 numIterations,const UInt32 * checkSum,IHasher * hf,IBenchPrintCallback * callback)1456 static HRESULT CrcBig(const void *data, UInt32 size, UInt64 numIterations,
1457 const UInt32 *checkSum, IHasher *hf,
1458 IBenchPrintCallback *callback)
1459 {
1460 Byte hash[64];
1461 UInt64 i;
1462 for (i = 0; i < sizeof(hash); i++)
1463 hash[i] = 0;
1464 for (i = 0; i < numIterations; i++)
1465 {
1466 if (callback && (i & 0xFF) == 0)
1467 {
1468 RINOK(callback->CheckBreak());
1469 }
1470 hf->Init();
1471 hf->Update(data, size);
1472 hf->Final(hash);
1473 UInt32 hashSize = hf->GetDigestSize();
1474 if (hashSize > sizeof(hash))
1475 return S_FALSE;
1476 UInt32 sum = 0;
1477 for (UInt32 j = 0; j < hashSize; j += 4)
1478 sum ^= GetUi32(hash + j);
1479 if (checkSum && sum != *checkSum)
1480 {
1481 return S_FALSE;
1482 }
1483 }
1484 return S_OK;
1485 }
1486
1487 UInt32 g_BenchCpuFreqTemp = 1;
1488
1489 #define YY1 sum += val; sum ^= val;
1490 #define YY3 YY1 YY1 YY1 YY1
1491 #define YY5 YY3 YY3 YY3 YY3
1492 #define YY7 YY5 YY5 YY5 YY5
1493 static const UInt32 kNumFreqCommands = 128;
1494
1495 EXTERN_C_BEGIN
1496
CountCpuFreq(UInt32 sum,UInt32 num,UInt32 val)1497 static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val)
1498 {
1499 for (UInt32 i = 0; i < num; i++)
1500 {
1501 YY7
1502 }
1503 return sum;
1504 }
1505
1506 EXTERN_C_END
1507
1508
1509 #ifndef _7ZIP_ST
1510
1511 struct CFreqInfo
1512 {
1513 NWindows::CThread Thread;
1514 IBenchPrintCallback *Callback;
1515 HRESULT CallbackRes;
1516 UInt32 ValRes;
1517 UInt32 Size;
1518 UInt64 NumIterations;
1519
WaitCFreqInfo1520 void Wait()
1521 {
1522 Thread.Wait();
1523 Thread.Close();
1524 }
1525 };
1526
FreqThreadFunction(void * param)1527 static THREAD_FUNC_DECL FreqThreadFunction(void *param)
1528 {
1529 CFreqInfo *p = (CFreqInfo *)param;
1530
1531 UInt32 sum = g_BenchCpuFreqTemp;
1532 for (UInt64 k = p->NumIterations; k > 0; k--)
1533 {
1534 p->CallbackRes = p->Callback->CheckBreak();
1535 if (p->CallbackRes != S_OK)
1536 return 0;
1537 sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp);
1538 }
1539 p->ValRes = sum;
1540 return 0;
1541 }
1542
1543 struct CFreqThreads
1544 {
1545 CFreqInfo *Items;
1546 UInt32 NumThreads;
1547
CFreqThreadsCFreqThreads1548 CFreqThreads(): Items(0), NumThreads(0) {}
WaitAllCFreqThreads1549 void WaitAll()
1550 {
1551 for (UInt32 i = 0; i < NumThreads; i++)
1552 Items[i].Wait();
1553 NumThreads = 0;
1554 }
~CFreqThreadsCFreqThreads1555 ~CFreqThreads()
1556 {
1557 WaitAll();
1558 delete []Items;
1559 }
1560 };
1561
1562 struct CCrcInfo
1563 {
1564 NWindows::CThread Thread;
1565 IBenchPrintCallback *Callback;
1566 HRESULT CallbackRes;
1567
1568 const Byte *Data;
1569 UInt32 Size;
1570 UInt64 NumIterations;
1571 bool CheckSumDefined;
1572 UInt32 CheckSum;
1573 CMyComPtr<IHasher> Hasher;
1574 HRESULT Res;
1575
1576 #ifdef USE_ALLOCA
1577 size_t AllocaSize;
1578 #endif
1579
WaitCCrcInfo1580 void Wait()
1581 {
1582 Thread.Wait();
1583 Thread.Close();
1584 }
1585 };
1586
CrcThreadFunction(void * param)1587 static THREAD_FUNC_DECL CrcThreadFunction(void *param)
1588 {
1589 CCrcInfo *p = (CCrcInfo *)param;
1590
1591 #ifdef USE_ALLOCA
1592 alloca(p->AllocaSize);
1593 #endif
1594
1595 p->Res = CrcBig(p->Data, p->Size, p->NumIterations,
1596 p->CheckSumDefined ? &p->CheckSum : NULL, p->Hasher,
1597 p->Callback);
1598 return 0;
1599 }
1600
1601 struct CCrcThreads
1602 {
1603 CCrcInfo *Items;
1604 UInt32 NumThreads;
1605
CCrcThreadsCCrcThreads1606 CCrcThreads(): Items(0), NumThreads(0) {}
WaitAllCCrcThreads1607 void WaitAll()
1608 {
1609 for (UInt32 i = 0; i < NumThreads; i++)
1610 Items[i].Wait();
1611 NumThreads = 0;
1612 }
~CCrcThreadsCCrcThreads1613 ~CCrcThreads()
1614 {
1615 WaitAll();
1616 delete []Items;
1617 }
1618 };
1619
1620 #endif
1621
CrcCalc1(const Byte * buf,UInt32 size)1622 static UInt32 CrcCalc1(const Byte *buf, UInt32 size)
1623 {
1624 UInt32 crc = CRC_INIT_VAL;;
1625 for (UInt32 i = 0; i < size; i++)
1626 crc = CRC_UPDATE_BYTE(crc, buf[i]);
1627 return CRC_GET_DIGEST(crc);
1628 }
1629
RandGen(Byte * buf,UInt32 size,CBaseRandomGenerator & RG)1630 static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
1631 {
1632 for (UInt32 i = 0; i < size; i++)
1633 buf[i] = (Byte)RG.GetRnd();
1634 }
1635
RandGenCrc(Byte * buf,UInt32 size,CBaseRandomGenerator & RG)1636 static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG)
1637 {
1638 RandGen(buf, size, RG);
1639 return CrcCalc1(buf, size);
1640 }
1641
CrcInternalTest()1642 bool CrcInternalTest()
1643 {
1644 CBenchBuffer buffer;
1645 const UInt32 kBufferSize0 = (1 << 8);
1646 const UInt32 kBufferSize1 = (1 << 10);
1647 const UInt32 kCheckSize = (1 << 5);
1648 if (!buffer.Alloc(kBufferSize0 + kBufferSize1))
1649 return false;
1650 Byte *buf = buffer.Buffer;
1651 UInt32 i;
1652 for (i = 0; i < kBufferSize0; i++)
1653 buf[i] = (Byte)i;
1654 UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
1655 if (crc1 != 0x29058C73)
1656 return false;
1657 CBaseRandomGenerator RG;
1658 RandGen(buf + kBufferSize0, kBufferSize1, RG);
1659 for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
1660 for (UInt32 j = 0; j < kCheckSize; j++)
1661 if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
1662 return false;
1663 return true;
1664 }
1665
1666 struct CBenchMethod
1667 {
1668 unsigned Weight;
1669 unsigned DictBits;
1670 UInt32 EncComplex;
1671 UInt32 DecComplexCompr;
1672 UInt32 DecComplexUnc;
1673 const char *Name;
1674 };
1675
1676 static const CBenchMethod g_Bench[] =
1677 {
1678 { 40, 17, 357, 145, 20, "LZMA:x1" },
1679 { 80, 24, 1220, 145, 20, "LZMA:x5:mt1" },
1680 { 80, 24, 1220, 145, 20, "LZMA:x5:mt2" },
1681
1682 { 10, 16, 124, 40, 14, "Deflate:x1" },
1683 { 20, 16, 376, 40, 14, "Deflate:x5" },
1684 { 10, 16, 1082, 40, 14, "Deflate:x7" },
1685 { 10, 17, 422, 40, 14, "Deflate64:x5" },
1686
1687 { 10, 15, 590, 69, 69, "BZip2:x1" },
1688 { 20, 19, 815, 122, 122, "BZip2:x5" },
1689 { 10, 19, 815, 122, 122, "BZip2:x5:mt2" },
1690 { 10, 19, 2530, 122, 122, "BZip2:x7" },
1691
1692 { 10, 18, 1010, 0, 1150, "PPMD:x1" },
1693 { 10, 22, 1655, 0, 1830, "PPMD:x5" },
1694
1695 { 2, 0, 6, 0, 6, "Delta:4" },
1696 { 2, 0, 4, 0, 4, "BCJ" },
1697
1698 { 10, 0, 24, 0, 24, "AES256CBC:1" },
1699 { 2, 0, 8, 0, 2, "AES256CBC:2" }
1700 };
1701
1702 struct CBenchHash
1703 {
1704 unsigned Weight;
1705 UInt32 Complex;
1706 UInt32 CheckSum;
1707 const char *Name;
1708 };
1709
1710 static const CBenchHash g_Hash[] =
1711 {
1712 { 1, 1820, 0x8F8FEDAB, "CRC32:1" },
1713 { 10, 558, 0x8F8FEDAB, "CRC32:4" },
1714 { 10, 339, 0x8F8FEDAB, "CRC32:8" },
1715 { 10, 512, 0xDF1C17CC, "CRC64" },
1716 { 10, 5100, 0x2D79FF2E, "SHA256" },
1717 { 10, 2340, 0x4C25132B, "SHA1" },
1718 { 2, 5500, 0xE084E913, "BLAKE2sp" }
1719 };
1720
1721 struct CTotalBenchRes
1722 {
1723 // UInt64 NumIterations1; // for Usage
1724 UInt64 NumIterations2; // for Rating / RPU
1725
1726 UInt64 Rating;
1727 UInt64 Usage;
1728 UInt64 RPU;
1729
InitCTotalBenchRes1730 void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; }
1731
SetSumCTotalBenchRes1732 void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
1733 {
1734 Rating = (r1.Rating + r2.Rating);
1735 Usage = (r1.Usage + r2.Usage);
1736 RPU = (r1.RPU + r2.RPU);
1737 // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1);
1738 NumIterations2 = (r1.NumIterations2 + r2.NumIterations2);
1739 }
1740 };
1741
PrintNumber(IBenchPrintCallback & f,UInt64 value,unsigned size)1742 static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size)
1743 {
1744 char s[128];
1745 unsigned startPos = (unsigned)sizeof(s) - 32;
1746 memset(s, ' ', startPos);
1747 ConvertUInt64ToString(value, s + startPos);
1748 // if (withSpace)
1749 {
1750 startPos--;
1751 size++;
1752 }
1753 unsigned len = (unsigned)strlen(s + startPos);
1754 if (size > len)
1755 {
1756 startPos -= (size - len);
1757 if (startPos < 0)
1758 startPos = 0;
1759 }
1760 f.Print(s + startPos);
1761 }
1762
1763 static const unsigned kFieldSize_Name = 12;
1764 static const unsigned kFieldSize_SmallName = 4;
1765 static const unsigned kFieldSize_Speed = 9;
1766 static const unsigned kFieldSize_Usage = 5;
1767 static const unsigned kFieldSize_RU = 6;
1768 static const unsigned kFieldSize_Rating = 6;
1769 static const unsigned kFieldSize_EU = 5;
1770 static const unsigned kFieldSize_Effec = 5;
1771
1772 static const unsigned kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating;
1773 static const unsigned kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec;
1774
1775
PrintRating(IBenchPrintCallback & f,UInt64 rating,unsigned size)1776 static void PrintRating(IBenchPrintCallback &f, UInt64 rating, unsigned size)
1777 {
1778 PrintNumber(f, (rating + 500000) / 1000000, size);
1779 }
1780
1781
PrintPercents(IBenchPrintCallback & f,UInt64 val,UInt64 divider,unsigned size)1782 static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, unsigned size)
1783 {
1784 PrintNumber(f, (val * 100 + divider / 2) / divider, size);
1785 }
1786
PrintChars(IBenchPrintCallback & f,char c,unsigned size)1787 static void PrintChars(IBenchPrintCallback &f, char c, unsigned size)
1788 {
1789 char s[256];
1790 memset(s, (Byte)c, size);
1791 s[size] = 0;
1792 f.Print(s);
1793 }
1794
PrintSpaces(IBenchPrintCallback & f,unsigned size)1795 static void PrintSpaces(IBenchPrintCallback &f, unsigned size)
1796 {
1797 PrintChars(f, ' ', size);
1798 }
1799
PrintResults(IBenchPrintCallback & f,UInt64 usage,UInt64 rpu,UInt64 rating,bool showFreq,UInt64 cpuFreq)1800 static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq)
1801 {
1802 PrintNumber(f, (usage + 5000) / 10000, kFieldSize_Usage);
1803 PrintRating(f, rpu, kFieldSize_RU);
1804 PrintRating(f, rating, kFieldSize_Rating);
1805 if (showFreq)
1806 {
1807 if (cpuFreq == 0)
1808 PrintSpaces(f, kFieldSize_EUAndEffec);
1809 else
1810 {
1811 UInt64 ddd = cpuFreq * usage / 100;
1812 if (ddd == 0)
1813 ddd = 1;
1814 PrintPercents(f, (rating * 10000), ddd, kFieldSize_EU);
1815 PrintPercents(f, rating, cpuFreq, kFieldSize_Effec);
1816 }
1817 }
1818 }
1819
PrintResults(IBenchPrintCallback * f,const CBenchInfo & info,unsigned weight,UInt64 rating,bool showFreq,UInt64 cpuFreq,CTotalBenchRes * res)1820 static void PrintResults(IBenchPrintCallback *f,
1821 const CBenchInfo &info,
1822 unsigned weight,
1823 UInt64 rating,
1824 bool showFreq, UInt64 cpuFreq,
1825 CTotalBenchRes *res)
1826 {
1827 UInt64 speed = info.GetSpeed(info.UnpackSize * info.NumIterations);
1828 if (f)
1829 {
1830 if (speed != 0)
1831 PrintNumber(*f, speed / 1024, kFieldSize_Speed);
1832 else
1833 PrintSpaces(*f, 1 + kFieldSize_Speed);
1834 }
1835 UInt64 usage = info.GetUsage();
1836 UInt64 rpu = info.GetRatingPerUsage(rating);
1837 if (f)
1838 {
1839 PrintResults(*f, usage, rpu, rating, showFreq, cpuFreq);
1840 }
1841
1842 if (res)
1843 {
1844 // res->NumIterations1++;
1845 res->NumIterations2 += weight;
1846 res->RPU += (rpu * weight);
1847 res->Rating += (rating * weight);
1848 res->Usage += (usage * weight);
1849 }
1850 }
1851
PrintTotals(IBenchPrintCallback & f,bool showFreq,UInt64 cpuFreq,const CTotalBenchRes & res)1852 static void PrintTotals(IBenchPrintCallback &f, bool showFreq, UInt64 cpuFreq, const CTotalBenchRes &res)
1853 {
1854 PrintSpaces(f, 1 + kFieldSize_Speed);
1855 // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1;
1856 UInt64 numIterations2 = res.NumIterations2; if (numIterations2 == 0) numIterations2 = 1;
1857 PrintResults(f, res.Usage / numIterations2, res.RPU / numIterations2, res.Rating / numIterations2, showFreq, cpuFreq);
1858 }
1859
1860
PrintHex(AString & s,UInt64 v)1861 static void PrintHex(AString &s, UInt64 v)
1862 {
1863 char temp[32];
1864 ConvertUInt64ToHex(v, temp);
1865 s += temp;
1866 }
1867
GetProcessThreadsInfo(const NSystem::CProcessAffinity & ti)1868 AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
1869 {
1870 AString s;
1871 // s.Add_UInt32(ti.numProcessThreads);
1872 if (ti.processAffinityMask != ti.systemAffinityMask)
1873 {
1874 // if (ti.numProcessThreads != ti.numSysThreads)
1875 {
1876 s += " / ";
1877 s.Add_UInt32(ti.GetNumSystemThreads());
1878 }
1879 s += " : ";
1880 PrintHex(s, ti.processAffinityMask);
1881 s += " / ";
1882 PrintHex(s, ti.systemAffinityMask);
1883 }
1884 return s;
1885 }
1886
1887
1888 extern bool g_LargePagesMode;
1889
1890
PrintRequirements(IBenchPrintCallback & f,const char * sizeString,bool size_Defined,UInt64 size,const char * threadsString,UInt32 numThreads)1891 static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString,
1892 bool size_Defined, UInt64 size, const char *threadsString, UInt32 numThreads)
1893 {
1894 f.Print("RAM ");
1895 f.Print(sizeString);
1896 if (size_Defined)
1897 PrintNumber(f, (size >> 20), 6);
1898 else
1899 f.Print(" ?");
1900 f.Print(" MB");
1901 if (g_LargePagesMode)
1902 f.Print(" LP");
1903 f.Print(", # ");
1904 f.Print(threadsString);
1905 PrintNumber(f, numThreads, 3);
1906 }
1907
1908
1909
1910 struct CBenchCallbackToPrint: public IBenchCallback
1911 {
1912 CBenchProps BenchProps;
1913 CTotalBenchRes EncodeRes;
1914 CTotalBenchRes DecodeRes;
1915 IBenchPrintCallback *_file;
1916 UInt32 DictSize;
1917
1918 bool Use2Columns;
1919 unsigned NameFieldSize;
1920
1921 bool ShowFreq;
1922 UInt64 CpuFreq;
1923
1924 unsigned EncodeWeight;
1925 unsigned DecodeWeight;
1926
CBenchCallbackToPrintCBenchCallbackToPrint1927 CBenchCallbackToPrint():
1928 Use2Columns(false),
1929 NameFieldSize(0),
1930 ShowFreq(false),
1931 CpuFreq(0),
1932 EncodeWeight(1),
1933 DecodeWeight(1)
1934 {}
1935
InitCBenchCallbackToPrint1936 void Init() { EncodeRes.Init(); DecodeRes.Init(); }
1937 void Print(const char *s);
1938 void NewLine();
1939
1940 HRESULT SetFreq(bool showFreq, UInt64 cpuFreq);
1941 HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
1942 HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
1943 };
1944
SetFreq(bool showFreq,UInt64 cpuFreq)1945 HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq)
1946 {
1947 ShowFreq = showFreq;
1948 CpuFreq = cpuFreq;
1949 return S_OK;
1950 }
1951
SetEncodeResult(const CBenchInfo & info,bool final)1952 HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final)
1953 {
1954 RINOK(_file->CheckBreak());
1955 if (final)
1956 {
1957 UInt64 rating = BenchProps.GetCompressRating(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations);
1958 PrintResults(_file, info,
1959 EncodeWeight, rating,
1960 ShowFreq, CpuFreq, &EncodeRes);
1961 if (!Use2Columns)
1962 _file->NewLine();
1963 }
1964 return S_OK;
1965 }
1966
1967 static const char * const kSep = " | ";
1968
SetDecodeResult(const CBenchInfo & info,bool final)1969 HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final)
1970 {
1971 RINOK(_file->CheckBreak());
1972 if (final)
1973 {
1974 UInt64 rating = BenchProps.GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
1975 if (Use2Columns)
1976 _file->Print(kSep);
1977 else
1978 PrintSpaces(*_file, NameFieldSize);
1979 CBenchInfo info2 = info;
1980 info2.UnpackSize *= info2.NumIterations;
1981 info2.PackSize *= info2.NumIterations;
1982 info2.NumIterations = 1;
1983 PrintResults(_file, info2,
1984 DecodeWeight, rating,
1985 ShowFreq, CpuFreq, &DecodeRes);
1986 }
1987 return S_OK;
1988 }
1989
Print(const char * s)1990 void CBenchCallbackToPrint::Print(const char *s)
1991 {
1992 _file->Print(s);
1993 }
1994
NewLine()1995 void CBenchCallbackToPrint::NewLine()
1996 {
1997 _file->NewLine();
1998 }
1999
PrintLeft(IBenchPrintCallback & f,const char * s,unsigned size)2000 void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size)
2001 {
2002 f.Print(s);
2003 int numSpaces = size - MyStringLen(s);
2004 if (numSpaces > 0)
2005 PrintSpaces(f, numSpaces);
2006 }
2007
PrintRight(IBenchPrintCallback & f,const char * s,unsigned size)2008 void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size)
2009 {
2010 int numSpaces = size - MyStringLen(s);
2011 if (numSpaces > 0)
2012 PrintSpaces(f, numSpaces);
2013 f.Print(s);
2014 }
2015
TotalBench(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,UInt32 numThreads,bool forceUnpackSize,size_t unpackSize,const Byte * fileData,IBenchPrintCallback * printCallback,CBenchCallbackToPrint * callback)2016 static HRESULT TotalBench(
2017 DECL_EXTERNAL_CODECS_LOC_VARS
2018 UInt64 complexInCommands,
2019 UInt32 numThreads,
2020 bool forceUnpackSize,
2021 size_t unpackSize,
2022 const Byte *fileData,
2023 IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback)
2024 {
2025 for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++)
2026 {
2027 const CBenchMethod &bench = g_Bench[i];
2028 PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
2029 callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
2030 callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
2031 callback->BenchProps.EncComplex = bench.EncComplex;
2032
2033 COneMethodInfo method;
2034 NCOM::CPropVariant propVariant;
2035 propVariant = bench.Name;
2036 RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant));
2037
2038 size_t unpackSize2 = unpackSize;
2039 if (!forceUnpackSize && bench.DictBits == 0)
2040 unpackSize2 = kFilterUnpackSize;
2041
2042 callback->EncodeWeight = bench.Weight;
2043 callback->DecodeWeight = bench.Weight;
2044
2045 HRESULT res = MethodBench(
2046 EXTERNAL_CODECS_LOC_VARS
2047 complexInCommands,
2048 false, numThreads, method,
2049 unpackSize2, fileData,
2050 bench.DictBits,
2051 printCallback, callback, &callback->BenchProps);
2052
2053 if (res == E_NOTIMPL)
2054 {
2055 // callback->Print(" ---");
2056 // we need additional empty line as line for decompression results
2057 if (!callback->Use2Columns)
2058 callback->NewLine();
2059 }
2060 else
2061 {
2062 RINOK(res);
2063 }
2064
2065 callback->NewLine();
2066 }
2067 return S_OK;
2068 }
2069
2070
FreqBench(UInt64 complexInCommands,UInt32 numThreads,IBenchPrintCallback * _file,bool showFreq,UInt64 specifiedFreq,UInt64 & cpuFreq,UInt32 & res)2071 static HRESULT FreqBench(
2072 UInt64 complexInCommands,
2073 UInt32 numThreads,
2074 IBenchPrintCallback *_file,
2075 bool showFreq,
2076 UInt64 specifiedFreq,
2077 UInt64 &cpuFreq,
2078 UInt32 &res)
2079 {
2080 res = 0;
2081 cpuFreq = 0;
2082
2083 UInt32 bufferSize = 1 << 20;
2084 UInt32 complexity = kNumFreqCommands;
2085 if (numThreads == 0)
2086 numThreads = 1;
2087
2088 #ifdef _7ZIP_ST
2089 numThreads = 1;
2090 #endif
2091
2092 UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);
2093 UInt64 numIterations = complexInCommands / complexity / bsize;
2094 if (numIterations == 0)
2095 numIterations = 1;
2096
2097 CBenchInfoCalc progressInfoSpec;
2098
2099 #ifndef _7ZIP_ST
2100 CFreqThreads threads;
2101 if (numThreads > 1)
2102 {
2103 threads.Items = new CFreqInfo[numThreads];
2104 UInt32 i;
2105 for (i = 0; i < numThreads; i++)
2106 {
2107 CFreqInfo &info = threads.Items[i];
2108 info.Callback = _file;
2109 info.CallbackRes = S_OK;
2110 info.NumIterations = numIterations;
2111 info.Size = bufferSize;
2112 }
2113 progressInfoSpec.SetStartTime();
2114 for (i = 0; i < numThreads; i++)
2115 {
2116 CFreqInfo &info = threads.Items[i];
2117 RINOK(info.Thread.Create(FreqThreadFunction, &info));
2118 threads.NumThreads++;
2119 }
2120 threads.WaitAll();
2121 for (i = 0; i < numThreads; i++)
2122 {
2123 RINOK(threads.Items[i].CallbackRes);
2124 }
2125 }
2126 else
2127 #endif
2128 {
2129 progressInfoSpec.SetStartTime();
2130 UInt32 sum = g_BenchCpuFreqTemp;
2131 for (UInt64 k = numIterations; k > 0; k--)
2132 {
2133 RINOK(_file->CheckBreak());
2134 sum = CountCpuFreq(sum, bufferSize, g_BenchCpuFreqTemp);
2135 }
2136 res += sum;
2137 }
2138
2139 CBenchInfo info;
2140 progressInfoSpec.SetFinishTime(info);
2141
2142 info.UnpackSize = 0;
2143 info.PackSize = 0;
2144 info.NumIterations = 1;
2145
2146 if (_file)
2147 {
2148 {
2149 UInt64 numCommands = (UInt64)numIterations * bufferSize * numThreads * complexity;
2150 UInt64 rating = info.GetSpeed(numCommands);
2151 cpuFreq = rating / numThreads;
2152 PrintResults(_file, info,
2153 0, // weight
2154 rating,
2155 showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : cpuFreq) : 0, NULL);
2156 }
2157 RINOK(_file->CheckBreak());
2158 }
2159
2160 return S_OK;
2161 }
2162
2163
2164
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)2165 static HRESULT CrcBench(
2166 DECL_EXTERNAL_CODECS_LOC_VARS
2167 UInt64 complexInCommands,
2168 UInt32 numThreads, UInt32 bufferSize,
2169 UInt64 &speed,
2170 UInt32 complexity, unsigned benchWeight,
2171 const UInt32 *checkSum,
2172 const COneMethodInfo &method,
2173 IBenchPrintCallback *_file,
2174 CTotalBenchRes *encodeRes,
2175 bool showFreq, UInt64 cpuFreq)
2176 {
2177 if (numThreads == 0)
2178 numThreads = 1;
2179
2180 #ifdef _7ZIP_ST
2181 numThreads = 1;
2182 #endif
2183
2184 const AString &methodName = method.MethodName;
2185 // methodName.RemoveChar(L'-');
2186 CMethodId hashID;
2187 if (!FindHashMethod(
2188 EXTERNAL_CODECS_LOC_VARS
2189 methodName, hashID))
2190 return E_NOTIMPL;
2191
2192 CBenchBuffer buffer;
2193 size_t totalSize = (size_t)bufferSize * numThreads;
2194 if (totalSize / numThreads != bufferSize)
2195 return E_OUTOFMEMORY;
2196 if (!buffer.Alloc(totalSize))
2197 return E_OUTOFMEMORY;
2198
2199 Byte *buf = buffer.Buffer;
2200 CBaseRandomGenerator RG;
2201 UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);
2202 UInt64 numIterations = complexInCommands * 256 / complexity / bsize;
2203 if (numIterations == 0)
2204 numIterations = 1;
2205
2206 CBenchInfoCalc progressInfoSpec;
2207
2208 #ifndef _7ZIP_ST
2209 CCrcThreads threads;
2210 if (numThreads > 1)
2211 {
2212 threads.Items = new CCrcInfo[numThreads];
2213
2214 UInt32 i;
2215 for (i = 0; i < numThreads; i++)
2216 {
2217 CCrcInfo &info = threads.Items[i];
2218 AString name;
2219 RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, info.Hasher));
2220 if (!info.Hasher)
2221 return E_NOTIMPL;
2222 CMyComPtr<ICompressSetCoderProperties> scp;
2223 info.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
2224 if (scp)
2225 {
2226 UInt64 reduceSize = 1;
2227 RINOK(method.SetCoderProps(scp, &reduceSize));
2228 }
2229
2230 Byte *data = buf + (size_t)bufferSize * i;
2231 info.Callback = _file;
2232 info.Data = data;
2233 info.NumIterations = numIterations;
2234 info.Size = bufferSize;
2235 /* info.Crc = */ RandGenCrc(data, bufferSize, RG);
2236 info.CheckSumDefined = false;
2237 if (checkSum)
2238 {
2239 info.CheckSum = *checkSum;
2240 info.CheckSumDefined = (checkSum && (i == 0));
2241 }
2242
2243 #ifdef USE_ALLOCA
2244 info.AllocaSize = (i * 16 * 21) & 0x7FF;
2245 #endif
2246 }
2247
2248 progressInfoSpec.SetStartTime();
2249
2250 for (i = 0; i < numThreads; i++)
2251 {
2252 CCrcInfo &info = threads.Items[i];
2253 RINOK(info.Thread.Create(CrcThreadFunction, &info));
2254 threads.NumThreads++;
2255 }
2256 threads.WaitAll();
2257 for (i = 0; i < numThreads; i++)
2258 {
2259 RINOK(threads.Items[i].Res);
2260 }
2261 }
2262 else
2263 #endif
2264 {
2265 /* UInt32 crc = */ RandGenCrc(buf, bufferSize, RG);
2266 progressInfoSpec.SetStartTime();
2267 CMyComPtr<IHasher> hasher;
2268 AString name;
2269 RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher));
2270 if (!hasher)
2271 return E_NOTIMPL;
2272 CMyComPtr<ICompressSetCoderProperties> scp;
2273 hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
2274 if (scp)
2275 {
2276 UInt64 reduceSize = 1;
2277 RINOK(method.SetCoderProps(scp, &reduceSize));
2278 }
2279 RINOK(CrcBig(buf, bufferSize, numIterations, checkSum, hasher, _file));
2280 }
2281
2282 CBenchInfo info;
2283 progressInfoSpec.SetFinishTime(info);
2284
2285 UInt64 unpSize = numIterations * bufferSize;
2286 UInt64 unpSizeThreads = unpSize * numThreads;
2287 info.UnpackSize = unpSizeThreads;
2288 info.PackSize = unpSizeThreads;
2289 info.NumIterations = 1;
2290
2291 if (_file)
2292 {
2293 {
2294 UInt64 numCommands = unpSizeThreads * complexity / 256;
2295 UInt64 rating = info.GetSpeed(numCommands);
2296 PrintResults(_file, info,
2297 benchWeight, rating,
2298 showFreq, cpuFreq, encodeRes);
2299 }
2300 RINOK(_file->CheckBreak());
2301 }
2302
2303 speed = info.GetSpeed(unpSizeThreads);
2304
2305 return S_OK;
2306 }
2307
TotalBench_Hash(DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands,UInt32 numThreads,UInt32 bufSize,IBenchPrintCallback * printCallback,CBenchCallbackToPrint * callback,CTotalBenchRes * encodeRes,bool showFreq,UInt64 cpuFreq)2308 static HRESULT TotalBench_Hash(
2309 DECL_EXTERNAL_CODECS_LOC_VARS
2310 UInt64 complexInCommands,
2311 UInt32 numThreads, UInt32 bufSize,
2312 IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback,
2313 CTotalBenchRes *encodeRes,
2314 bool showFreq, UInt64 cpuFreq)
2315 {
2316 for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++)
2317 {
2318 const CBenchHash &bench = g_Hash[i];
2319 PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
2320 // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
2321 // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
2322 // callback->BenchProps.EncComplex = bench.EncComplex;
2323
2324 COneMethodInfo method;
2325 NCOM::CPropVariant propVariant;
2326 propVariant = bench.Name;
2327 RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant));
2328
2329 UInt64 speed;
2330 HRESULT res = CrcBench(
2331 EXTERNAL_CODECS_LOC_VARS
2332 complexInCommands,
2333 numThreads, bufSize,
2334 speed,
2335 bench.Complex, bench.Weight,
2336 &bench.CheckSum, method,
2337 printCallback, encodeRes, showFreq, cpuFreq);
2338 if (res == E_NOTIMPL)
2339 {
2340 // callback->Print(" ---");
2341 }
2342 else
2343 {
2344 RINOK(res);
2345 }
2346 callback->NewLine();
2347 }
2348 return S_OK;
2349 }
2350
2351 struct CTempValues
2352 {
2353 UInt64 *Values;
CTempValuesCTempValues2354 CTempValues(UInt32 num) { Values = new UInt64[num]; }
~CTempValuesCTempValues2355 ~CTempValues() { delete []Values; }
2356 };
2357
ParseNumberString(const UString & s,NCOM::CPropVariant & prop)2358 static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
2359 {
2360 const wchar_t *end;
2361 UInt64 result = ConvertStringToUInt64(s, &end);
2362 if (*end != 0 || s.IsEmpty())
2363 prop = s;
2364 else if (result <= (UInt32)0xFFFFFFFF)
2365 prop = (UInt32)result;
2366 else
2367 prop = result;
2368 }
2369
GetNumThreadsNext(unsigned i,UInt32 numThreads)2370 static UInt32 GetNumThreadsNext(unsigned i, UInt32 numThreads)
2371 {
2372 if (i < 2)
2373 return i + 1;
2374 i -= 1;
2375 UInt32 num = (UInt32)(2 + (i & 1)) << (i >> 1);
2376 return (num <= numThreads) ? num : numThreads;
2377 }
2378
AreSameMethodNames(const char * fullName,const char * shortName)2379 static bool AreSameMethodNames(const char *fullName, const char *shortName)
2380 {
2381 return StringsAreEqualNoCase_Ascii(fullName, shortName);
2382 }
2383
2384
2385 #ifdef MY_CPU_X86_OR_AMD64
2386
PrintCpuChars(AString & s,UInt32 v)2387 static void PrintCpuChars(AString &s, UInt32 v)
2388 {
2389 for (int j = 0; j < 4; j++)
2390 {
2391 Byte b = (Byte)(v & 0xFF);
2392 v >>= 8;
2393 if (b == 0)
2394 break;
2395 s += (char)b;
2396 }
2397 }
2398
x86cpuid_to_String(const Cx86cpuid & c,AString & s)2399 static void x86cpuid_to_String(const Cx86cpuid &c, AString &s)
2400 {
2401 s.Empty();
2402
2403 UInt32 maxFunc2 = 0;
2404 UInt32 t[3];
2405
2406 MyCPUID(0x80000000, &maxFunc2, &t[0], &t[1], &t[2]);
2407
2408 bool fullNameIsAvail = (maxFunc2 >= 0x80000004);
2409
2410 if (!fullNameIsAvail)
2411 {
2412 for (int i = 0; i < 3; i++)
2413 PrintCpuChars(s, c.vendor[i]);
2414 }
2415 else
2416 {
2417 for (int i = 0; i < 3; i++)
2418 {
2419 UInt32 d[4] = { 0 };
2420 MyCPUID(0x80000002 + i, &d[0], &d[1], &d[2], &d[3]);
2421 for (int j = 0; j < 4; j++)
2422 PrintCpuChars(s, d[j]);
2423 }
2424 }
2425
2426 s.Add_Space_if_NotEmpty();
2427 {
2428 char temp[32];
2429 ConvertUInt32ToHex(c.ver, temp);
2430 s += '(';
2431 s += temp;
2432 s += ')';
2433 }
2434 }
2435
2436 #endif
2437
2438
2439
2440 static const char * const k_PROCESSOR_ARCHITECTURE[] =
2441 {
2442 "x86" // "INTEL"
2443 , "MIPS"
2444 , "ALPHA"
2445 , "PPC"
2446 , "SHX"
2447 , "ARM"
2448 , "IA64"
2449 , "ALPHA64"
2450 , "MSIL"
2451 , "x64" // "AMD64"
2452 , "IA32_ON_WIN64"
2453 , "NEUTRAL"
2454 , "ARM64"
2455 , "ARM32_ON_WIN64"
2456 };
2457
2458 #define MY__PROCESSOR_ARCHITECTURE_INTEL 0
2459 #define MY__PROCESSOR_ARCHITECTURE_AMD64 9
2460
2461
2462 #define MY__PROCESSOR_INTEL_PENTIUM 586
2463 #define MY__PROCESSOR_AMD_X8664 8664
2464
2465 /*
2466 static const CUInt32PCharPair k_PROCESSOR[] =
2467 {
2468 { 2200, "IA64" },
2469 { 8664, "x64" }
2470 };
2471
2472 #define PROCESSOR_INTEL_386 386
2473 #define PROCESSOR_INTEL_486 486
2474 #define PROCESSOR_INTEL_PENTIUM 586
2475 #define PROCESSOR_INTEL_860 860
2476 #define PROCESSOR_INTEL_IA64 2200
2477 #define PROCESSOR_AMD_X8664 8664
2478 #define PROCESSOR_MIPS_R2000 2000
2479 #define PROCESSOR_MIPS_R3000 3000
2480 #define PROCESSOR_MIPS_R4000 4000
2481 #define PROCESSOR_ALPHA_21064 21064
2482 #define PROCESSOR_PPC_601 601
2483 #define PROCESSOR_PPC_603 603
2484 #define PROCESSOR_PPC_604 604
2485 #define PROCESSOR_PPC_620 620
2486 #define PROCESSOR_HITACHI_SH3 10003
2487 #define PROCESSOR_HITACHI_SH3E 10004
2488 #define PROCESSOR_HITACHI_SH4 10005
2489 #define PROCESSOR_MOTOROLA_821 821
2490 #define PROCESSOR_SHx_SH3 103
2491 #define PROCESSOR_SHx_SH4 104
2492 #define PROCESSOR_STRONGARM 2577 // 0xA11
2493 #define PROCESSOR_ARM720 1824 // 0x720
2494 #define PROCESSOR_ARM820 2080 // 0x820
2495 #define PROCESSOR_ARM920 2336 // 0x920
2496 #define PROCESSOR_ARM_7TDMI 70001
2497 #define PROCESSOR_OPTIL 18767 // 0x494f
2498 */
2499
2500 #ifdef _WIN32
2501
2502 static const char * const k_PF[] =
2503 {
2504 "FP_ERRATA"
2505 , "FP_EMU"
2506 , "CMPXCHG"
2507 , "MMX"
2508 , "PPC_MOVEMEM_64BIT"
2509 , "ALPHA_BYTE"
2510 , "SSE"
2511 , "3DNOW"
2512 , "RDTSC"
2513 , "PAE"
2514 , "SSE2"
2515 , "SSE_DAZ"
2516 , "NX"
2517 , "SSE3"
2518 , "CMPXCHG16B"
2519 , "CMP8XCHG16"
2520 , "CHANNELS"
2521 , "XSAVE"
2522 , "ARM_VFP_32"
2523 , "ARM_NEON"
2524 , "L2AT"
2525 , "VIRT_FIRMWARE"
2526 , "RDWRFSGSBASE"
2527 , "FASTFAIL"
2528 , "ARM_DIVIDE"
2529 , "ARM_64BIT_LOADSTORE_ATOMIC"
2530 , "ARM_EXTERNAL_CACHE"
2531 , "ARM_FMAC"
2532 , "RDRAND"
2533 , "ARM_V8"
2534 , "ARM_V8_CRYPTO"
2535 , "ARM_V8_CRC32"
2536 , "RDTSCP"
2537 };
2538
2539 #endif
2540
2541
PrintSize(AString & s,UInt64 v)2542 static void PrintSize(AString &s, UInt64 v)
2543 {
2544 char c = 0;
2545 if ((v & 0x3FF) == 0) { v >>= 10; c = 'K';
2546 if ((v & 0x3FF) == 0) { v >>= 10; c = 'M';
2547 if ((v & 0x3FF) == 0) { v >>= 10; c = 'G';
2548 if ((v & 0x3FF) == 0) { v >>= 10; c = 'T';
2549 }}}}
2550 else
2551 {
2552 PrintHex(s, v);
2553 return;
2554 }
2555 char temp[32];
2556 ConvertUInt64ToString(v, temp);
2557 s += temp;
2558 if (c)
2559 s += c;
2560 }
2561
2562
PrintPage(AString & s,UInt32 v)2563 static void PrintPage(AString &s, UInt32 v)
2564 {
2565 if ((v & 0x3FF) == 0)
2566 {
2567 s.Add_UInt32(v >> 10);
2568 s += "K";
2569 }
2570 else
2571 s.Add_UInt32(v >> 10);
2572 }
2573
TypeToString2(const char * const table[],unsigned num,UInt32 value)2574 static AString TypeToString2(const char * const table[], unsigned num, UInt32 value)
2575 {
2576 char sz[16];
2577 const char *p = NULL;
2578 if (value < num)
2579 p = table[value];
2580 if (!p)
2581 {
2582 ConvertUInt32ToString(value, sz);
2583 p = sz;
2584 }
2585 return (AString)p;
2586 }
2587
2588 #ifdef _WIN32
2589
SysInfo_To_String(AString & s,const SYSTEM_INFO & si)2590 static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si)
2591 {
2592 s += TypeToString2(k_PROCESSOR_ARCHITECTURE, ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture);
2593
2594 if (!( si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == MY__PROCESSOR_INTEL_PENTIUM
2595 || si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == MY__PROCESSOR_AMD_X8664))
2596 {
2597 s += " ";
2598 // s += TypePairToString(k_PROCESSOR, ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType);
2599 s.Add_UInt32(si.dwProcessorType);
2600 }
2601 s += " ";
2602 PrintHex(s, si.wProcessorLevel);
2603 s += ".";
2604 PrintHex(s, si.wProcessorRevision);
2605 if ((UInt64)si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors))
2606 if ((UInt64)si.dwActiveProcessorMask + 1 != 0 || si.dwNumberOfProcessors != sizeof(UInt64) * 8)
2607 {
2608 s += " act:";
2609 PrintHex(s, si.dwActiveProcessorMask);
2610 }
2611 s += " cpus:";
2612 s.Add_UInt32(si.dwNumberOfProcessors);
2613 if (si.dwPageSize != 1 << 12)
2614 {
2615 s += " page:";
2616 PrintPage(s, si.dwPageSize);
2617 }
2618 if (si.dwAllocationGranularity != 1 << 16)
2619 {
2620 s += " gran:";
2621 PrintPage(s, si.dwAllocationGranularity);
2622 }
2623 s += " ";
2624
2625 DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress;
2626 UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1;
2627 const UInt32 kReserveSize = ((UInt32)1 << 16);
2628 if (minAdd != kReserveSize)
2629 {
2630 PrintSize(s, minAdd);
2631 s += "-";
2632 }
2633 else
2634 {
2635 if ((maxSize & (kReserveSize - 1)) == 0)
2636 maxSize += kReserveSize;
2637 }
2638 PrintSize(s, maxSize);
2639 }
2640
2641 #ifndef _WIN64
2642 typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo);
2643 #endif
2644
2645 #endif
2646
GetSysInfo(AString & s1,AString & s2)2647 void GetSysInfo(AString &s1, AString &s2)
2648 {
2649 s1.Empty();
2650 s2.Empty();
2651
2652 #ifdef _WIN32
2653 SYSTEM_INFO si;
2654 GetSystemInfo(&si);
2655 {
2656 SysInfo_To_String(s1, si);
2657 // s += " : ";
2658 }
2659
2660 #if !defined(_WIN64) && !defined(UNDER_CE)
2661 Func_GetNativeSystemInfo fn_GetNativeSystemInfo = (Func_GetNativeSystemInfo)GetProcAddress(
2662 GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
2663 if (fn_GetNativeSystemInfo)
2664 {
2665 SYSTEM_INFO si2;
2666 fn_GetNativeSystemInfo(&si2);
2667 // if (memcmp(&si, &si2, sizeof(si)) != 0)
2668 {
2669 // s += " - ";
2670 SysInfo_To_String(s2, si2);
2671 }
2672 }
2673 #endif
2674 #endif
2675 }
2676
2677
GetCpuName(AString & s)2678 void GetCpuName(AString &s)
2679 {
2680 s.Empty();
2681
2682 #ifdef MY_CPU_X86_OR_AMD64
2683 {
2684 Cx86cpuid cpuid;
2685 if (x86cpuid_CheckAndRead(&cpuid))
2686 {
2687 AString s2;
2688 x86cpuid_to_String(cpuid, s2);
2689 s += s2;
2690 }
2691 else
2692 {
2693 #ifdef MY_CPU_AMD64
2694 s += "x64";
2695 #else
2696 s += "x86";
2697 #endif
2698 }
2699 }
2700 #else
2701
2702 #ifdef MY_CPU_LE
2703 s += "LE";
2704 #elif defined(MY_CPU_BE)
2705 s += "BE";
2706 #endif
2707
2708 #endif
2709
2710 if (g_LargePagesMode)
2711 s += " (LP)";
2712 }
2713
2714
GetCpuFeatures(AString & s)2715 void GetCpuFeatures(AString &s)
2716 {
2717 s.Empty();
2718
2719 #ifdef _WIN32
2720 const unsigned kNumFeatures_Extra = 32; // we check also for unknown features
2721 const unsigned kNumFeatures = ARRAY_SIZE(k_PF) + kNumFeatures_Extra;
2722 for (unsigned i = 0; i < kNumFeatures; i++)
2723 {
2724 if (IsProcessorFeaturePresent(i))
2725 {
2726 s.Add_Space_if_NotEmpty();
2727 s += TypeToString2(k_PF, ARRAY_SIZE(k_PF), i);
2728 }
2729 }
2730 #endif
2731 }
2732
2733
2734 #ifdef _WIN32
2735 #ifndef UNDER_CE
2736
2737 typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *);
2738
My_RtlGetVersion(OSVERSIONINFOEXW * vi)2739 static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi)
2740 {
2741 HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
2742 if (!ntdll)
2743 return FALSE;
2744 Func_RtlGetVersion func = (Func_RtlGetVersion)GetProcAddress(ntdll, "RtlGetVersion");
2745 if (!func)
2746 return FALSE;
2747 func(vi);
2748 return TRUE;
2749 }
2750
2751 #endif
2752 #endif
2753
2754
Bench(DECL_EXTERNAL_CODECS_LOC_VARS IBenchPrintCallback * printCallback,IBenchCallback * benchCallback,const CObjectVector<CProperty> & props,UInt32 numIterations,bool multiDict)2755 HRESULT Bench(
2756 DECL_EXTERNAL_CODECS_LOC_VARS
2757 IBenchPrintCallback *printCallback,
2758 IBenchCallback *benchCallback,
2759 // IBenchFreqCallback *freqCallback,
2760 const CObjectVector<CProperty> &props,
2761 UInt32 numIterations,
2762 bool multiDict)
2763 {
2764 if (!CrcInternalTest())
2765 return S_FALSE;
2766
2767 UInt32 numCPUs = 1;
2768 UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29;
2769
2770 NSystem::CProcessAffinity threadsInfo;
2771 threadsInfo.InitST();
2772
2773 #ifndef _7ZIP_ST
2774
2775 if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0)
2776 numCPUs = threadsInfo.GetNumProcessThreads();
2777 else
2778 numCPUs = NSystem::GetNumberOfProcessors();
2779
2780 #endif
2781
2782 bool ramSize_Defined = NSystem::GetRamSize(ramSize);
2783
2784 UInt32 numThreadsSpecified = numCPUs;
2785
2786 UInt32 testTime = kComplexInSeconds;
2787
2788 UInt64 specifiedFreq = 0;
2789
2790 bool multiThreadTests = false;
2791
2792 COneMethodInfo method;
2793
2794 CBenchBuffer fileDataBuffer;
2795
2796 {
2797 unsigned i;
2798 for (i = 0; i < props.Size(); i++)
2799 {
2800 const CProperty &property = props[i];
2801 UString name (property.Name);
2802 name.MakeLower_Ascii();
2803
2804 if (name.IsEqualTo("file"))
2805 {
2806 if (property.Value.IsEmpty())
2807 return E_INVALIDARG;
2808
2809 #ifdef USE_WIN_FILE
2810
2811 NFile::NIO::CInFile file;
2812 if (!file.Open(us2fs(property.Value)))
2813 return E_INVALIDARG;
2814 UInt64 len;
2815 if (!file.GetLength(len))
2816 return E_FAIL;
2817 if (len >= ((UInt32)1 << 31) || len == 0)
2818 return E_INVALIDARG;
2819 if (!fileDataBuffer.Alloc((size_t)len))
2820 return E_OUTOFMEMORY;
2821 UInt32 processedSize;
2822 file.Read(fileDataBuffer.Buffer, (UInt32)len, processedSize);
2823 if (processedSize != len)
2824 return E_FAIL;
2825 if (printCallback)
2826 {
2827 printCallback->Print("file size =");
2828 PrintNumber(*printCallback, len, 0);
2829 printCallback->NewLine();
2830 }
2831 continue;
2832
2833 #else
2834
2835 return E_NOTIMPL;
2836
2837 #endif
2838 }
2839
2840 NCOM::CPropVariant propVariant;
2841 if (!property.Value.IsEmpty())
2842 ParseNumberString(property.Value, propVariant);
2843
2844 if (name.IsEqualTo("time"))
2845 {
2846 RINOK(ParsePropToUInt32(UString(), propVariant, testTime));
2847 continue;
2848 }
2849
2850 if (name.IsEqualTo("freq"))
2851 {
2852 UInt32 freq32 = 0;
2853 RINOK(ParsePropToUInt32(UString(), propVariant, freq32));
2854 if (freq32 == 0)
2855 return E_INVALIDARG;
2856 specifiedFreq = (UInt64)freq32 * 1000000;
2857
2858 if (printCallback)
2859 {
2860 printCallback->Print("freq=");
2861 PrintNumber(*printCallback, freq32, 0);
2862 printCallback->NewLine();
2863 }
2864
2865 continue;
2866 }
2867
2868 if (name.IsPrefixedBy_Ascii_NoCase("mt"))
2869 {
2870 UString s = name.Ptr(2);
2871 if (s.IsEqualTo("*")
2872 || s.IsEmpty() && propVariant.vt == VT_BSTR && StringsAreEqual_Ascii(propVariant.bstrVal, "*"))
2873 {
2874 multiThreadTests = true;
2875 continue;
2876 }
2877 #ifndef _7ZIP_ST
2878 RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified));
2879 #endif
2880 continue;
2881 }
2882
2883 RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));
2884 }
2885 }
2886
2887 if (printCallback)
2888 {
2889 #ifdef _WIN32
2890 #ifndef UNDER_CE
2891 {
2892 AString s;
2893 // OSVERSIONINFO vi;
2894 OSVERSIONINFOEXW vi;
2895 vi.dwOSVersionInfoSize = sizeof(vi);
2896 // if (::GetVersionEx(&vi))
2897 if (My_RtlGetVersion(&vi))
2898 {
2899 s += "Windows";
2900 if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
2901 s.Add_UInt32(vi.dwPlatformId);
2902 s += " "; s.Add_UInt32(vi.dwMajorVersion);
2903 s += "."; s.Add_UInt32(vi.dwMinorVersion);
2904 s += " "; s.Add_UInt32(vi.dwBuildNumber);
2905 // s += " "; s += GetAnsiString(vi.szCSDVersion);
2906 }
2907 printCallback->Print(s);
2908 printCallback->NewLine();
2909 }
2910 #endif
2911 #endif
2912
2913 {
2914 AString s1, s2;
2915 GetSysInfo(s1, s2);
2916 if (!s1.IsEmpty() || !s2.IsEmpty())
2917 {
2918 printCallback->Print(s1);
2919 if (s1 != s2 && !s2.IsEmpty())
2920 {
2921 printCallback->Print(" - ");
2922 printCallback->Print(s2);
2923 }
2924 printCallback->NewLine();
2925 }
2926 }
2927 {
2928 AString s;
2929 GetCpuFeatures(s);
2930 if (!s.IsEmpty())
2931 {
2932 printCallback->Print(s);
2933 printCallback->NewLine();
2934 }
2935 }
2936 {
2937 AString s;
2938 GetCpuName(s);
2939 if (!s.IsEmpty())
2940 {
2941 printCallback->Print(s);
2942 printCallback->NewLine();
2943 }
2944 }
2945 }
2946
2947 if (printCallback)
2948 {
2949 printCallback->Print("CPU Freq:");
2950 }
2951
2952 UInt64 complexInCommands = kComplexInCommands;
2953
2954 if (printCallback /* || freqCallback */)
2955 {
2956 UInt64 numMilCommands = 1 << 6;
2957 if (specifiedFreq != 0)
2958 {
2959 while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000))
2960 numMilCommands >>= 1;
2961 }
2962
2963 for (int jj = 0;; jj++)
2964 {
2965 if (printCallback)
2966 RINOK(printCallback->CheckBreak());
2967
2968 UInt64 start = ::GetTimeCount();
2969 UInt32 sum = (UInt32)start;
2970 sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp);
2971 const UInt64 realDelta = ::GetTimeCount() - start;
2972 start = realDelta;
2973 if (start == 0)
2974 start = 1;
2975 UInt64 freq = GetFreq();
2976 // mips is constant in some compilers
2977 const UInt64 mipsVal = numMilCommands * freq / start;
2978 if (printCallback)
2979 {
2980 if (realDelta == 0)
2981 {
2982 printCallback->Print(" -");
2983 }
2984 else
2985 {
2986 // PrintNumber(*printCallback, start, 0);
2987 PrintNumber(*printCallback, mipsVal, 5 + ((sum == 0xF1541213) ? 1 : 0));
2988 }
2989 }
2990 /*
2991 if (freqCallback)
2992 freqCallback->AddCpuFreq(mipsVal);
2993 */
2994
2995 if (jj >= 3)
2996 {
2997 SetComplexCommands(testTime, false, mipsVal * 1000000, complexInCommands);
2998 if (jj >= 8 || start >= freq)
2999 break;
3000 // break; // change it
3001 numMilCommands <<= 1;
3002 }
3003 }
3004 }
3005
3006 if (printCallback)
3007 {
3008 printCallback->NewLine();
3009 printCallback->NewLine();
3010 PrintRequirements(*printCallback, "size: ", ramSize_Defined, ramSize, "CPU hardware threads:", numCPUs);
3011 printCallback->Print(GetProcessThreadsInfo(threadsInfo));
3012 printCallback->NewLine();
3013 }
3014
3015 if (numThreadsSpecified < 1 || numThreadsSpecified > kNumThreadsMax)
3016 return E_INVALIDARG;
3017
3018 UInt32 dict;
3019 bool dictIsDefined = method.Get_DicSize(dict);
3020
3021 if (method.MethodName.IsEmpty())
3022 method.MethodName = "LZMA";
3023
3024 if (benchCallback)
3025 {
3026 CBenchProps benchProps;
3027 benchProps.SetLzmaCompexity();
3028 UInt32 dictSize = method.Get_Lzma_DicSize();
3029 UInt32 uncompressedDataSize = kAdditionalSize + dictSize;
3030 return MethodBench(
3031 EXTERNAL_CODECS_LOC_VARS
3032 complexInCommands,
3033 true, numThreadsSpecified,
3034 method,
3035 uncompressedDataSize, fileDataBuffer.Buffer,
3036 kOldLzmaDictBits, printCallback, benchCallback, &benchProps);
3037 }
3038
3039 AString methodName (method.MethodName);
3040 if (methodName.IsEqualTo_Ascii_NoCase("CRC"))
3041 methodName = "crc32";
3042 method.MethodName = methodName;
3043 CMethodId hashID;
3044
3045 if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID))
3046 {
3047 if (!printCallback)
3048 return S_FALSE;
3049 IBenchPrintCallback &f = *printCallback;
3050 if (!dictIsDefined)
3051 dict = (1 << 24);
3052
3053
3054 // methhodName.RemoveChar(L'-');
3055 UInt32 complexity = 10000;
3056 const UInt32 *checkSum = NULL;
3057 {
3058 unsigned i;
3059 for (i = 0; i < ARRAY_SIZE(g_Hash); i++)
3060 {
3061 const CBenchHash &h = g_Hash[i];
3062 AString benchMethod (h.Name);
3063 AString benchProps;
3064 int propPos = benchMethod.Find(':');
3065 if (propPos >= 0)
3066 {
3067 benchProps = benchMethod.Ptr(propPos + 1);
3068 benchMethod.DeleteFrom(propPos);
3069 }
3070
3071 if (AreSameMethodNames(benchMethod, methodName))
3072 {
3073 if (benchProps.IsEmpty()
3074 || benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps == "8" && method.PropsString.IsEmpty()
3075 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
3076 {
3077 complexity = h.Complex;
3078 checkSum = &h.CheckSum;
3079 if (method.PropsString.IsEqualTo_Ascii_NoCase(benchProps))
3080 break;
3081 }
3082 }
3083 }
3084 if (i == ARRAY_SIZE(g_Hash))
3085 return E_NOTIMPL;
3086 }
3087
3088 f.NewLine();
3089 f.Print("Size");
3090 const unsigned kFieldSize_CrcSpeed = 6;
3091 unsigned numThreadsTests = 0;
3092 for (;;)
3093 {
3094 UInt32 t = GetNumThreadsNext(numThreadsTests, numThreadsSpecified);
3095 PrintNumber(f, t, kFieldSize_CrcSpeed);
3096 numThreadsTests++;
3097 if (t >= numThreadsSpecified)
3098 break;
3099 }
3100 f.NewLine();
3101 f.NewLine();
3102 CTempValues speedTotals(numThreadsTests);
3103 {
3104 for (unsigned ti = 0; ti < numThreadsTests; ti++)
3105 speedTotals.Values[ti] = 0;
3106 }
3107
3108 UInt64 numSteps = 0;
3109 for (UInt32 i = 0; i < numIterations; i++)
3110 {
3111 for (unsigned pow = 10; pow < 32; pow++)
3112 {
3113 UInt32 bufSize = (UInt32)1 << pow;
3114 if (bufSize > dict)
3115 break;
3116 char s[16];
3117 ConvertUInt32ToString(pow, s);
3118 unsigned pos = MyStringLen(s);
3119 s[pos++] = ':';
3120 s[pos++] = ' ';
3121 s[pos] = 0;
3122 f.Print(s);
3123
3124 for (unsigned ti = 0; ti < numThreadsTests; ti++)
3125 {
3126 RINOK(f.CheckBreak());
3127 UInt32 t = GetNumThreadsNext(ti, numThreadsSpecified);
3128 UInt64 speed = 0;
3129 RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands,
3130 t, bufSize, speed,
3131 complexity,
3132 1, // benchWeight,
3133 (pow == kNumHashDictBits) ? checkSum : NULL, method, NULL, NULL, false, 0));
3134 PrintNumber(f, (speed >> 20), kFieldSize_CrcSpeed);
3135 speedTotals.Values[ti] += speed;
3136 }
3137 f.NewLine();
3138 numSteps++;
3139 }
3140 }
3141 if (numSteps != 0)
3142 {
3143 f.NewLine();
3144 f.Print("Avg:");
3145 for (unsigned ti = 0; ti < numThreadsTests; ti++)
3146 {
3147 PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), kFieldSize_CrcSpeed);
3148 }
3149 f.NewLine();
3150 }
3151 return S_OK;
3152 }
3153
3154 bool use2Columns = false;
3155
3156 bool totalBenchMode = (method.MethodName.IsEqualTo_Ascii_NoCase("*"));
3157 bool onlyHashBench = false;
3158 if (method.MethodName.IsEqualTo_Ascii_NoCase("hash"))
3159 {
3160 onlyHashBench = true;
3161 totalBenchMode = true;
3162 }
3163
3164 // ---------- Threads loop ----------
3165 for (unsigned threadsPassIndex = 0; threadsPassIndex < 3; threadsPassIndex++)
3166 {
3167
3168 UInt32 numThreads = numThreadsSpecified;
3169
3170 if (!multiThreadTests)
3171 {
3172 if (threadsPassIndex != 0)
3173 break;
3174 }
3175 else
3176 {
3177 numThreads = 1;
3178 if (threadsPassIndex != 0)
3179 {
3180 if (numCPUs < 2)
3181 break;
3182 numThreads = numCPUs;
3183 if (threadsPassIndex == 1)
3184 {
3185 if (numCPUs >= 4)
3186 numThreads = numCPUs / 2;
3187 }
3188 else if (numCPUs < 4)
3189 break;
3190 }
3191 }
3192
3193 CBenchCallbackToPrint callback;
3194 callback.Init();
3195 callback._file = printCallback;
3196
3197 IBenchPrintCallback &f = *printCallback;
3198
3199 if (threadsPassIndex > 0)
3200 {
3201 f.NewLine();
3202 f.NewLine();
3203 }
3204
3205 if (!dictIsDefined)
3206 {
3207 const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25);
3208 unsigned dicSizeLog = dicSizeLog_Main;
3209
3210 #ifdef UNDER_CE
3211 dicSizeLog = (UInt64)1 << 20;
3212 #endif
3213
3214 if (ramSize_Defined)
3215 for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
3216 if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize)
3217 break;
3218
3219 dict = (UInt32)1 << dicSizeLog;
3220
3221 if (totalBenchMode && dicSizeLog != dicSizeLog_Main)
3222 {
3223 f.Print("Dictionary reduced to: ");
3224 PrintNumber(f, dicSizeLog, 1);
3225 f.NewLine();
3226 }
3227 }
3228
3229 PrintRequirements(f, "usage:", true, GetBenchMemoryUsage(numThreads, dict, totalBenchMode), "Benchmark threads: ", numThreads);
3230 f.NewLine();
3231
3232 f.NewLine();
3233
3234 if (totalBenchMode)
3235 {
3236 callback.NameFieldSize = kFieldSize_Name;
3237 use2Columns = false;
3238 }
3239 else
3240 {
3241 callback.NameFieldSize = kFieldSize_SmallName;
3242 use2Columns = true;
3243 }
3244 callback.Use2Columns = use2Columns;
3245
3246 bool showFreq = false;
3247 UInt64 cpuFreq = 0;
3248
3249 if (totalBenchMode)
3250 {
3251 showFreq = true;
3252 }
3253
3254 unsigned fileldSize = kFieldSize_TotalSize;
3255 if (showFreq)
3256 fileldSize += kFieldSize_EUAndEffec;
3257
3258 if (use2Columns)
3259 {
3260 PrintSpaces(f, callback.NameFieldSize);
3261 PrintRight(f, "Compressing", fileldSize);
3262 f.Print(kSep);
3263 PrintRight(f, "Decompressing", fileldSize);
3264 }
3265 f.NewLine();
3266 PrintLeft(f, totalBenchMode ? "Method" : "Dict", callback.NameFieldSize);
3267
3268 int j;
3269
3270 for (j = 0; j < 2; j++)
3271 {
3272 PrintRight(f, "Speed", kFieldSize_Speed + 1);
3273 PrintRight(f, "Usage", kFieldSize_Usage + 1);
3274 PrintRight(f, "R/U", kFieldSize_RU + 1);
3275 PrintRight(f, "Rating", kFieldSize_Rating + 1);
3276 if (showFreq)
3277 {
3278 PrintRight(f, "E/U", kFieldSize_EU + 1);
3279 PrintRight(f, "Effec", kFieldSize_Effec + 1);
3280 }
3281 if (!use2Columns)
3282 break;
3283 if (j == 0)
3284 f.Print(kSep);
3285 }
3286
3287 f.NewLine();
3288 PrintSpaces(f, callback.NameFieldSize);
3289
3290 for (j = 0; j < 2; j++)
3291 {
3292 PrintRight(f, "KiB/s", kFieldSize_Speed + 1);
3293 PrintRight(f, "%", kFieldSize_Usage + 1);
3294 PrintRight(f, "MIPS", kFieldSize_RU + 1);
3295 PrintRight(f, "MIPS", kFieldSize_Rating + 1);
3296 if (showFreq)
3297 {
3298 PrintRight(f, "%", kFieldSize_EU + 1);
3299 PrintRight(f, "%", kFieldSize_Effec + 1);
3300 }
3301 if (!use2Columns)
3302 break;
3303 if (j == 0)
3304 f.Print(kSep);
3305 }
3306
3307 f.NewLine();
3308 f.NewLine();
3309
3310 if (specifiedFreq != 0)
3311 cpuFreq = specifiedFreq;
3312
3313
3314 if (totalBenchMode)
3315 {
3316 for (UInt32 i = 0; i < numIterations; i++)
3317 {
3318 if (i != 0)
3319 printCallback->NewLine();
3320 HRESULT res;
3321
3322 const unsigned kNumCpuTests = 3;
3323 for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++)
3324 {
3325 PrintLeft(f, "CPU", kFieldSize_Name);
3326 UInt32 resVal;
3327 RINOK(FreqBench(complexInCommands, numThreads, printCallback,
3328 (freqTest == kNumCpuTests - 1 || specifiedFreq != 0), // showFreq
3329 specifiedFreq,
3330 cpuFreq, resVal));
3331 callback.NewLine();
3332
3333 if (specifiedFreq != 0)
3334 cpuFreq = specifiedFreq;
3335
3336 if (freqTest == kNumCpuTests - 1)
3337 SetComplexCommands(testTime, specifiedFreq != 0, cpuFreq, complexInCommands);
3338 }
3339 callback.NewLine();
3340
3341 callback.SetFreq(true, cpuFreq);
3342
3343 if (!onlyHashBench)
3344 {
3345 res = TotalBench(EXTERNAL_CODECS_LOC_VARS
3346 complexInCommands, numThreads,
3347 dictIsDefined || fileDataBuffer.Buffer, // forceUnpackSize
3348 fileDataBuffer.Buffer ? fileDataBuffer.BufferSize : dict,
3349 fileDataBuffer.Buffer,
3350 printCallback, &callback);
3351 RINOK(res);
3352 }
3353
3354 res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads,
3355 1 << kNumHashDictBits, printCallback, &callback, &callback.EncodeRes, true, cpuFreq);
3356 RINOK(res);
3357
3358 callback.NewLine();
3359 {
3360 PrintLeft(f, "CPU", kFieldSize_Name);
3361 UInt32 resVal;
3362 UInt64 cpuFreqLastTemp = cpuFreq;
3363 RINOK(FreqBench(complexInCommands, numThreads, printCallback,
3364 specifiedFreq != 0, // showFreq
3365 specifiedFreq,
3366 cpuFreqLastTemp, resVal));
3367 callback.NewLine();
3368 }
3369 }
3370 }
3371 else
3372 {
3373 bool needSetComplexity = true;
3374 if (!methodName.IsEqualTo_Ascii_NoCase("LZMA"))
3375 {
3376 unsigned i;
3377 for (i = 0; i < ARRAY_SIZE(g_Bench); i++)
3378 {
3379 const CBenchMethod &h = g_Bench[i];
3380 AString benchMethod (h.Name);
3381 AString benchProps;
3382 int propPos = benchMethod.Find(':');
3383 if (propPos >= 0)
3384 {
3385 benchProps = benchMethod.Ptr(propPos + 1);
3386 benchMethod.DeleteFrom(propPos);
3387 }
3388
3389 if (AreSameMethodNames(benchMethod, methodName))
3390 {
3391 if (benchProps.IsEmpty()
3392 || benchProps == "x5" && method.PropsString.IsEmpty()
3393 || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
3394 {
3395 callback.BenchProps.EncComplex = h.EncComplex;
3396 callback.BenchProps.DecComplexCompr = h.DecComplexCompr;
3397 callback.BenchProps.DecComplexUnc = h.DecComplexUnc;;
3398 needSetComplexity = false;
3399 break;
3400 }
3401 }
3402 }
3403 if (i == ARRAY_SIZE(g_Bench))
3404 return E_NOTIMPL;
3405 }
3406 if (needSetComplexity)
3407 callback.BenchProps.SetLzmaCompexity();
3408
3409 for (unsigned i = 0; i < numIterations; i++)
3410 {
3411 const unsigned kStartDicLog = 22;
3412 unsigned pow = (dict < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
3413 if (!multiDict)
3414 pow = 31;
3415 while (((UInt32)1 << pow) > dict && pow > 0)
3416 pow--;
3417 for (; ((UInt32)1 << pow) <= dict; pow++)
3418 {
3419 char s[16];
3420 ConvertUInt32ToString(pow, s);
3421 unsigned pos = MyStringLen(s);
3422 s[pos++] = ':';
3423 s[pos] = 0;
3424 PrintLeft(f, s, kFieldSize_SmallName);
3425 callback.DictSize = (UInt32)1 << pow;
3426
3427 COneMethodInfo method2 = method;
3428
3429 if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA"))
3430 {
3431 // We add dictionary size property.
3432 // method2 can have two different dictionary size properties.
3433 // And last property is main.
3434 NCOM::CPropVariant propVariant = (UInt32)pow;
3435 RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant));
3436 }
3437
3438 size_t uncompressedDataSize;
3439 if (fileDataBuffer.Buffer)
3440 {
3441 uncompressedDataSize = fileDataBuffer.BufferSize;
3442 }
3443 else
3444 {
3445 uncompressedDataSize = callback.DictSize;
3446 if (uncompressedDataSize >= (1 << 18))
3447 uncompressedDataSize += kAdditionalSize;
3448 }
3449
3450 HRESULT res = MethodBench(
3451 EXTERNAL_CODECS_LOC_VARS
3452 complexInCommands,
3453 true, numThreads,
3454 method2,
3455 uncompressedDataSize, fileDataBuffer.Buffer,
3456 kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps);
3457 f.NewLine();
3458 RINOK(res);
3459 if (!multiDict)
3460 break;
3461 }
3462 }
3463 }
3464
3465 PrintChars(f, '-', callback.NameFieldSize + fileldSize);
3466
3467 if (use2Columns)
3468 {
3469 f.Print(kSep);
3470 PrintChars(f, '-', fileldSize);
3471 }
3472
3473 f.NewLine();
3474
3475 if (use2Columns)
3476 {
3477 PrintLeft(f, "Avr:", callback.NameFieldSize);
3478 PrintTotals(f, showFreq, cpuFreq, callback.EncodeRes);
3479 f.Print(kSep);
3480 PrintTotals(f, showFreq, cpuFreq, callback.DecodeRes);
3481 f.NewLine();
3482 }
3483
3484 PrintLeft(f, "Tot:", callback.NameFieldSize);
3485 CTotalBenchRes midRes;
3486 midRes.SetSum(callback.EncodeRes, callback.DecodeRes);
3487 PrintTotals(f, showFreq, cpuFreq, midRes);
3488 f.NewLine();
3489
3490 }
3491 return S_OK;
3492 }
3493