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