tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Bench.cpp (86837B)


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