diff options
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp | 3668 |
1 files changed, 2720 insertions, 948 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp index ecbacbc9c8e..5da9783d4e1 100644 --- a/3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp +++ b/3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp @@ -2,19 +2,24 @@ #include "StdAfx.h" -#include <stdio.h> +#include "../../../../C/CpuArch.h" + +// #include <stdio.h> #ifndef _WIN32 + #define USE_POSIX_TIME #define USE_POSIX_TIME2 -#endif +#endif // _WIN32 #ifdef USE_POSIX_TIME #include <time.h> +#include <unistd.h> #ifdef USE_POSIX_TIME2 #include <sys/time.h> +#include <sys/times.h> #endif -#endif +#endif // USE_POSIX_TIME #ifdef _WIN32 #define USE_ALLOCA @@ -29,37 +34,34 @@ #endif #include "../../../../C/7zCrc.h" -#include "../../../../C/Alloc.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Windows/System.h" +#include "../../../../C/RotateDefs.h" -#ifndef _7ZIP_ST +#ifndef Z7_ST #include "../../../Windows/Synchronization.h" #include "../../../Windows/Thread.h" #endif -#if defined(_WIN32) || defined(UNIX_USE_WIN_FILE) -#define USE_WIN_FILE -#endif - -#ifdef USE_WIN_FILE +#include "../../../Windows/FileFind.h" #include "../../../Windows/FileIO.h" -#endif - +#include "../../../Windows/SystemInfo.h" +#include "../../../Common/MyBuffer2.h" #include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Common/StringToInt.h" +#include "../../../Common/Wildcard.h" #include "../../Common/MethodProps.h" +#include "../../Common/StreamObjects.h" #include "../../Common/StreamUtils.h" #include "Bench.h" using namespace NWindows; +#ifndef Z7_ST static const UInt32 k_LZMA = 0x030101; +#endif static const UInt64 kComplexInCommands = (UInt64)1 << #ifdef UNDER_CE @@ -68,9 +70,9 @@ static const UInt64 kComplexInCommands = (UInt64)1 << 34; #endif -static const UInt32 kComplexInSeconds = 4; +static const UInt32 kComplexInMs = 4000; -static void SetComplexCommands(UInt32 complexInSeconds, +static void SetComplexCommandsMs(UInt32 complexInMs, bool isSpecifiedFreq, UInt64 cpuFreq, UInt64 &complexInCommands) { complexInCommands = kComplexInCommands; @@ -80,96 +82,80 @@ static void SetComplexCommands(UInt32 complexInSeconds, cpuFreq = kMinFreq; if (cpuFreq < kMaxFreq || isSpecifiedFreq) { - if (complexInSeconds != 0) - complexInCommands = complexInSeconds * cpuFreq; + if (complexInMs != 0) + complexInCommands = complexInMs * cpuFreq / 1000; else complexInCommands = cpuFreq >> 2; } } +// const UInt64 kBenchmarkUsageMult = 1000000; // for debug +static const unsigned kBenchmarkUsageMultBits = 16; +static const UInt64 kBenchmarkUsageMult = 1 << kBenchmarkUsageMultBits; + +UInt64 Benchmark_GetUsage_Percents(UInt64 usage) +{ + return (100 * usage + kBenchmarkUsageMult / 2) / kBenchmarkUsageMult; +} + static const unsigned kNumHashDictBits = 17; -static const UInt32 kFilterUnpackSize = (48 << 10); +static const UInt32 kFilterUnpackSize = (47 << 10); // + 5; // for test -static const unsigned kOldLzmaDictBits = 30; +static const unsigned kOldLzmaDictBits = 32; -static const UInt32 kAdditionalSize = (1 << 16); +// static const size_t kAdditionalSize = (size_t)1 << 32; // for debug +static const size_t kAdditionalSize = (size_t)1 << 16; static const UInt32 kCompressedAdditionalSize = (1 << 10); -static const UInt32 kMaxLzmaPropSize = 5; + +static const UInt32 kMaxMethodPropSize = (1 << 6); + + +#define ALLOC_WITH_HRESULT(_buffer_, _size_) \ + { (_buffer_)->Alloc(_size_); \ + if (_size_ && !(_buffer_)->IsAllocated()) return E_OUTOFMEMORY; } + class CBaseRandomGenerator { UInt32 A1; UInt32 A2; + UInt32 Salt; public: - CBaseRandomGenerator() { Init(); } + CBaseRandomGenerator(UInt32 salt = 0): Salt(salt) { Init(); } void Init() { A1 = 362436069; A2 = 521288629;} + Z7_FORCE_INLINE UInt32 GetRnd() { - return + return Salt ^ + ( ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) + - ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) ); + ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) ) + ); } }; -static const unsigned kBufferAlignment = 1 << 4; - -struct CBenchBuffer +Z7_NO_INLINE +static void RandGen(Byte *buf, size_t size) { - size_t BufferSize; - - #ifdef _WIN32 - - Byte *Buffer; - - CBenchBuffer(): BufferSize(0), Buffer(NULL) {} - ~CBenchBuffer() { ::MidFree(Buffer); } - - void AllocAlignedMask(size_t size, size_t) - { - ::MidFree(Buffer); - BufferSize = 0; - Buffer = (Byte *)::MidAlloc(size); - if (Buffer) - BufferSize = size; - } - - #else - - Byte *Buffer; - Byte *_bufBase; - - CBenchBuffer(): BufferSize(0), Buffer(NULL), _bufBase(NULL){} - ~CBenchBuffer() { ::MidFree(_bufBase); } - - void AllocAlignedMask(size_t size, size_t alignMask) + CBaseRandomGenerator RG; + const size_t size4 = size & ~((size_t)3); + size_t i; + for (i = 0; i < size4; i += 4) { - ::MidFree(_bufBase); - Buffer = NULL; - BufferSize = 0; - _bufBase = (Byte *)::MidAlloc(size + alignMask); - - if (_bufBase) - { - // Buffer = (Byte *)(((uintptr_t)_bufBase + alignMask) & ~(uintptr_t)alignMask); - Buffer = (Byte *)(((ptrdiff_t)_bufBase + alignMask) & ~(ptrdiff_t)alignMask); - BufferSize = size; - } + const UInt32 v = RG.GetRnd(); + SetUi32(buf + i, v) } - - #endif - - bool Alloc(size_t size) + UInt32 v = RG.GetRnd(); + for (; i < size; i++) { - if (Buffer && BufferSize == size) - return true; - AllocAlignedMask(size, kBufferAlignment - 1); - return (Buffer != NULL || size == 0); + buf[i] = (Byte)v; + v >>= 8; } -}; +} -class CBenchRandomGenerator: public CBenchBuffer +class CBenchRandomGenerator: public CMidAlignedBuffer { static UInt32 GetVal(UInt32 &res, unsigned numBits) { @@ -186,27 +172,33 @@ class CBenchRandomGenerator: public CBenchBuffer public: - void GenerateSimpleRandom(CBaseRandomGenerator *_RG_) + void GenerateSimpleRandom(UInt32 salt) { - CBaseRandomGenerator rg = *_RG_; - const size_t bufSize = BufferSize; - Byte *buf = Buffer; + CBaseRandomGenerator rg(salt); + const size_t bufSize = Size(); + Byte *buf = (Byte *)*this; for (size_t i = 0; i < bufSize; i++) buf[i] = (Byte)rg.GetRnd(); - *_RG_ = rg; } - void GenerateLz(unsigned dictBits, CBaseRandomGenerator *_RG_) + void GenerateLz(unsigned dictBits, UInt32 salt) { - CBaseRandomGenerator rg = *_RG_; - UInt32 pos = 0; - UInt32 rep0 = 1; - const size_t bufSize = BufferSize; - Byte *buf = Buffer; + CBaseRandomGenerator rg(salt); + size_t pos = 0; + size_t rep0 = 1; + const size_t bufSize = Size(); + Byte *buf = (Byte *)*this; unsigned posBits = 1; + + // printf("\n dictBits = %d\n", (UInt32)dictBits); + // printf("\n bufSize = 0x%p\n", (const void *)bufSize); while (pos < bufSize) { + /* + if (pos >= ((UInt32)1 << 31)) + printf(" %x\n", pos); + */ UInt32 r = rg.GetRnd(); if (GetVal(r, 1) == 0 || pos < 1024) buf[pos++] = (Byte)(r & 0xFF); @@ -219,7 +211,7 @@ public: { len += GetLen(r); - while (((UInt32)1 << posBits) < pos) + while (((size_t)1 << posBits) < pos) posBits++; unsigned numBitsMax = dictBits; @@ -233,11 +225,12 @@ public: for (;;) { - UInt32 ppp = GetVal(r, numLogBits) + kAddBits; + const UInt32 ppp = GetVal(r, numLogBits) + kAddBits; r = rg.GetRnd(); if (ppp > numBitsMax) continue; - rep0 = GetVal(r, ppp); + // rep0 = GetVal(r, ppp); + rep0 = r & (((size_t)1 << ppp) - 1); if (rep0 < pos) break; r = rg.GetRnd(); @@ -245,10 +238,11 @@ public: rep0++; } + // len *= 300; // for debug { - UInt32 rem = (UInt32)bufSize - pos; + const size_t rem = bufSize - pos; if (len > rem) - len = rem; + len = (UInt32)rem; } Byte *dest = buf + pos; const Byte *src = dest - rep0; @@ -257,51 +251,54 @@ public: *dest++ = *src++; } } - - *_RG_ = rg; + // printf("\n CRC = %x\n", CrcCalc(buf, bufSize)); } }; -class CBenchmarkInStream: - public ISequentialInStream, - public CMyUnknownImp -{ +Z7_CLASS_IMP_NOQIB_1( + CBenchmarkInStream + , ISequentialInStream +) const Byte *Data; size_t Pos; size_t Size; public: - MY_UNKNOWN_IMP void Init(const Byte *data, size_t size) { Data = data; Size = size; Pos = 0; } - STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + bool WasFinished() const { return Pos == Size; } }; -STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +Z7_COM7F_IMF(CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)) { - size_t remain = Size - Pos; - UInt32 kMaxBlockSize = (1 << 20); + const UInt32 kMaxBlockSize = (1 << 20); if (size > kMaxBlockSize) size = kMaxBlockSize; + const size_t remain = Size - Pos; if (size > remain) size = (UInt32)remain; - for (UInt32 i = 0; i < size; i++) - ((Byte *)data)[i] = Data[Pos + i]; + + if (size != 0) + memcpy(data, Data + Pos, size); + Pos += size; if (processedSize) *processedSize = size; return S_OK; } -class CBenchmarkOutStream: + +class CBenchmarkOutStream Z7_final: public ISequentialOutStream, - public CBenchBuffer, - public CMyUnknownImp + public CMyUnknownImp, + public CMidAlignedBuffer { + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(ISequentialOutStream) // bool _overflow; public: size_t Pos; @@ -319,23 +316,32 @@ public: Pos = 0; } - // void Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); } + void InitCrc() + { + Crc = CRC_INIT_VAL; + } - MY_UNKNOWN_IMP - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + void Calc(const void *data, size_t size) + { + Crc = CrcUpdate(Crc, data, size); + } + + size_t GetPos() const { return Pos; } + + // void Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); } }; -STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +Z7_COM7F_IMF(CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) { - size_t curSize = BufferSize - Pos; + size_t curSize = Size() - Pos; if (curSize > size) curSize = size; if (curSize != 0) { if (RealCopy) - memcpy(Buffer + Pos, data, curSize); + memcpy(((Byte *)*this) + Pos, data, curSize); if (CalcCrc) - Crc = CrcUpdate(Crc, data, curSize); + Calc(data, curSize); Pos += curSize; } if (processedSize) @@ -348,46 +354,51 @@ STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *p return S_OK; } -class CCrcOutStream: - public ISequentialOutStream, - public CMyUnknownImp -{ + +Z7_CLASS_IMP_NOQIB_1( + CCrcOutStream + , ISequentialOutStream +) public: bool CalcCrc; UInt32 Crc; - MY_UNKNOWN_IMP - - CCrcOutStream(): CalcCrc(true) {}; - void Init() { Crc = CRC_INIT_VAL; } - STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + UInt64 Pos; + + CCrcOutStream(): CalcCrc(true) {} + void Init() { Crc = CRC_INIT_VAL; Pos = 0; } + void Calc(const void *data, size_t size) + { + Crc = CrcUpdate(Crc, data, size); + } }; -STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +Z7_COM7F_IMF(CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) { if (CalcCrc) - Crc = CrcUpdate(Crc, data, size); + Calc(data, size); + Pos += size; if (processedSize) *processedSize = size; return S_OK; } +// #include "../../../../C/My_sys_time.h" + static UInt64 GetTimeCount() { #ifdef USE_POSIX_TIME #ifdef USE_POSIX_TIME2 timeval v; - if (gettimeofday(&v, 0) == 0) - return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec; + if (gettimeofday(&v, NULL) == 0) + return (UInt64)(v.tv_sec) * 1000000 + (UInt64)v.tv_usec; return (UInt64)time(NULL) * 1000000; #else return time(NULL); #endif #else - /* LARGE_INTEGER value; if (::QueryPerformanceCounter(&value)) - return value.QuadPart; - */ + return (UInt64)value.QuadPart; return GetTickCount(); #endif } @@ -401,15 +412,14 @@ static UInt64 GetFreq() return 1; #endif #else - /* LARGE_INTEGER value; if (::QueryPerformanceFrequency(&value)) - return value.QuadPart; - */ + return (UInt64)value.QuadPart; return 1000; #endif } + #ifdef USE_POSIX_TIME struct CUserTime @@ -419,58 +429,106 @@ struct CUserTime void Init() { - Prev = clock(); + // Prev = clock(); + Sum = 0; + Prev = 0; + Update(); Sum = 0; } - UInt64 GetUserTime() + void Update() { + tms t; + /* clock_t res = */ times(&t); + clock_t newVal = t.tms_utime + t.tms_stime; + Sum += (UInt64)(newVal - Prev); + Prev = newVal; + + /* clock_t v = clock(); - Sum += v - Prev; - Prev = v; + if (v != -1) + { + Sum += v - Prev; + Prev = v; + } + */ + } + UInt64 GetUserTime() + { + Update(); return Sum; } }; #else -static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } -UInt64 GetWinUserTime() -{ - FILETIME creationTime, exitTime, kernelTime, userTime; - if ( - #ifdef UNDER_CE - ::GetThreadTimes(::GetCurrentThread() - #else - ::GetProcessTimes(::GetCurrentProcess() - #endif - , &creationTime, &exitTime, &kernelTime, &userTime) != 0) - return GetTime64(userTime) + GetTime64(kernelTime); - return (UInt64)GetTickCount() * 10000; -} struct CUserTime { - UInt64 StartTime; + bool UseTick; + DWORD Prev_Tick; + UInt64 Prev; + UInt64 Sum; - void Init() { StartTime = GetWinUserTime(); } - UInt64 GetUserTime() { return GetWinUserTime() - StartTime; } + void Init() + { + UseTick = false; + Prev_Tick = 0; + Prev = 0; + Sum = 0; + Update(); + Sum = 0; + } + UInt64 GetUserTime() + { + Update(); + return Sum; + } + void Update(); }; +static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } + +void CUserTime::Update() +{ + DWORD new_Tick = GetTickCount(); + FILETIME creationTime, exitTime, kernelTime, userTime; + if (!UseTick && + #ifdef UNDER_CE + ::GetThreadTimes(::GetCurrentThread() + #else + ::GetProcessTimes(::GetCurrentProcess() + #endif + , &creationTime, &exitTime, &kernelTime, &userTime)) + { + UInt64 newVal = GetTime64(userTime) + GetTime64(kernelTime); + Sum += newVal - Prev; + Prev = newVal; + } + else + { + UseTick = true; + Sum += (UInt64)(new_Tick - (DWORD)Prev_Tick) * 10000; + } + Prev_Tick = new_Tick; +} + + #endif static UInt64 GetUserFreq() { #ifdef USE_POSIX_TIME - return CLOCKS_PER_SEC; + // return CLOCKS_PER_SEC; + return (UInt64)sysconf(_SC_CLK_TCK); #else return 10000000; #endif } -class CBenchProgressStatus +class CBenchProgressStatus Z7_final { - #ifndef _7ZIP_ST + #ifndef Z7_ST NSynchronization::CCriticalSection CS; #endif public: @@ -478,14 +536,14 @@ public: bool EncodeMode; void SetResult(HRESULT res) { - #ifndef _7ZIP_ST + #ifndef Z7_ST NSynchronization::CCriticalSectionLock lock(CS); #endif Res = res; } HRESULT GetResult() { - #ifndef _7ZIP_ST + #ifndef Z7_ST NSynchronization::CCriticalSectionLock lock(CS); #endif return Res; @@ -517,28 +575,44 @@ void CBenchInfoCalc::SetFinishTime(CBenchInfo &dest) dest.UserTime = UserTime.GetUserTime(); } -class CBenchProgressInfo: +class CBenchProgressInfo Z7_final: public ICompressProgressInfo, public CMyUnknownImp, public CBenchInfoCalc { + Z7_COM_UNKNOWN_IMP_0 + Z7_IFACE_COM7_IMP(ICompressProgressInfo) public: CBenchProgressStatus *Status; - HRESULT Res; IBenchCallback *Callback; - CBenchProgressInfo(): Callback(0) {} - MY_UNKNOWN_IMP - STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); + CBenchProgressInfo(): Callback(NULL) {} }; -STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) + +Z7_COM7F_IMF(CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) { HRESULT res = Status->GetResult(); if (res != S_OK) return res; if (!Callback) return res; + + /* + static UInt64 inSizePrev = 0; + static UInt64 outSizePrev = 0; + UInt64 delta1 = 0, delta2 = 0, val1 = 0, val2 = 0; + if (inSize) { val1 = *inSize; delta1 = val1 - inSizePrev; inSizePrev = val1; } + if (outSize) { val2 = *outSize; delta2 = val2 - outSizePrev; outSizePrev = val2; } + UInt64 percents = delta2 * 1000; + if (delta1 != 0) + percents /= delta1; + printf("=== %7d %7d %7d %7d ratio = %4d\n", + (unsigned)(val1 >> 10), (unsigned)(delta1 >> 10), + (unsigned)(val2 >> 10), (unsigned)(delta2 >> 10), + (unsigned)percents); + */ + CBenchInfo info; SetFinishTime(info); if (Status->EncodeMode) @@ -560,91 +634,168 @@ STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 static const unsigned kSubBits = 8; -static UInt32 GetLogSize(UInt32 size) +static unsigned GetLogSize(UInt64 size) +{ + unsigned i = 0; + for (;;) + { + i++; size >>= 1; if (size == 0) break; + } + return i; +} + + +static UInt32 GetLogSize_Sub(UInt64 size) +{ + if (size <= 1) + return 0; + const unsigned i = GetLogSize(size) - 1; + UInt32 v; + if (i <= kSubBits) + v = (UInt32)(size) << (kSubBits - i); + else + v = (UInt32)(size >> (i - kSubBits)); + return ((UInt32)i << kSubBits) + (v & (((UInt32)1 << kSubBits) - 1)); +} + + +static UInt64 Get_UInt64_from_double(double v) { - for (unsigned i = kSubBits; i < 32; i++) - for (UInt32 j = 0; j < (1 << kSubBits); j++) - if (size <= (((UInt32)1) << i) + (j << (i - kSubBits))) - return (i << kSubBits) + j; - return (32 << kSubBits); + const UInt64 kMaxVal = (UInt64)1 << 62; + if (v > (double)(Int64)kMaxVal) + return kMaxVal; + return (UInt64)v; } -static void NormalizeVals(UInt64 &v1, UInt64 &v2) +static UInt64 MyMultDiv64(UInt64 m1, UInt64 m2, UInt64 d) { - while (v1 > 1000000) + if (d == 0) + d = 1; + const double v = + (double)(Int64)m1 * + (double)(Int64)m2 / + (double)(Int64)d; + return Get_UInt64_from_double(v); + /* + unsigned n1 = GetLogSize(m1); + unsigned n2 = GetLogSize(m2); + while (n1 + n2 > 64) { - v1 >>= 1; - v2 >>= 1; + if (n1 >= n2) + { + m1 >>= 1; + n1--; + } + else + { + m2 >>= 1; + n2--; + } + d >>= 1; } + + if (d == 0) + d = 1; + return m1 * m2 / d; + */ } + UInt64 CBenchInfo::GetUsage() const { UInt64 userTime = UserTime; UInt64 userFreq = UserFreq; UInt64 globalTime = GlobalTime; UInt64 globalFreq = GlobalFreq; - NormalizeVals(userTime, userFreq); - NormalizeVals(globalFreq, globalTime); + if (userFreq == 0) userFreq = 1; if (globalTime == 0) globalTime = 1; - return userTime * globalFreq * 1000000 / userFreq / globalTime; + + const double v = + ((double)(Int64)userTime / (double)(Int64)userFreq) + * ((double)(Int64)globalFreq / (double)(Int64)globalTime) + * (double)(Int64)kBenchmarkUsageMult; + return Get_UInt64_from_double(v); + /* + return MyMultDiv64( + MyMultDiv64(kBenchmarkUsageMult, userTime, userFreq), + globalFreq, globalTime); + */ } + UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const { - UInt64 userTime = UserTime; - UInt64 userFreq = UserFreq; - UInt64 globalTime = GlobalTime; + if (UserTime == 0) + { + return 0; + // userTime = 1; + } UInt64 globalFreq = GlobalFreq; - NormalizeVals(userFreq, userTime); - NormalizeVals(globalTime, globalFreq); if (globalFreq == 0) globalFreq = 1; - if (userTime == 0) - userTime = 1; - return userFreq * globalTime / globalFreq * rating / userTime; + + const double v = + ((double)(Int64)GlobalTime / (double)(Int64)globalFreq) + * ((double)(Int64)UserFreq / (double)(Int64)UserTime) + * (double)(Int64)rating; + return Get_UInt64_from_double(v); + /* + return MyMultDiv64( + MyMultDiv64(rating, UserFreq, UserTime), + GlobalTime, globalFreq); + */ } -static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq) + +UInt64 CBenchInfo::GetSpeed(UInt64 numUnits) const { - UInt64 elTime = elapsedTime; - NormalizeVals(freq, elTime); - if (elTime == 0) - elTime = 1; - return value * freq / elTime; + return MyMultDiv64(numUnits, GlobalFreq, GlobalTime); } -UInt64 CBenchInfo::GetSpeed(UInt64 numCommands) const +static UInt64 GetNumCommands_from_Size_and_Complexity(UInt64 size, Int32 complexity) { - return MyMultDiv64(numCommands, GlobalTime, GlobalFreq); + return complexity >= 0 ? + size * (UInt32)complexity : + size / (UInt32)(-complexity); } struct CBenchProps { bool LzmaRatingMode; - UInt32 EncComplex; - UInt32 DecComplexCompr; - UInt32 DecComplexUnc; + Int32 EncComplex; + Int32 DecComplexCompr; + Int32 DecComplexUnc; + + unsigned KeySize; + + CBenchProps(): + LzmaRatingMode(false), + KeySize(0) + {} - CBenchProps(): LzmaRatingMode(false) {} void SetLzmaCompexity(); - UInt64 GeComprCommands(UInt64 unpackSize) + UInt64 GetNumCommands_Enc(UInt64 unpackSize) const { - return unpackSize * EncComplex; + const UInt32 kMinSize = 100; + if (unpackSize < kMinSize) + unpackSize = kMinSize; + return GetNumCommands_from_Size_and_Complexity(unpackSize, EncComplex); } - UInt64 GeDecomprCommands(UInt64 packSize, UInt64 unpackSize) + UInt64 GetNumCommands_Dec(UInt64 packSize, UInt64 unpackSize) const { - return (packSize * DecComplexCompr + unpackSize * DecComplexUnc); + return + GetNumCommands_from_Size_and_Complexity(packSize, DecComplexCompr) + + GetNumCommands_from_Size_and_Complexity(unpackSize, DecComplexUnc); } - UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size); - UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations); + UInt64 GetRating_Enc(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) const; + UInt64 GetRating_Dec(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) const; }; void CBenchProps::SetLzmaCompexity() @@ -655,63 +806,247 @@ void CBenchProps::SetLzmaCompexity() LzmaRatingMode = true; } -UInt64 CBenchProps::GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) +UInt64 CBenchProps::GetRating_Enc(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) const { if (dictSize < (1 << kBenchMinDicLogSize)) dictSize = (1 << kBenchMinDicLogSize); - UInt64 encComplex = EncComplex; + Int32 encComplex = EncComplex; if (LzmaRatingMode) { - UInt64 t = GetLogSize(dictSize) - (kBenchMinDicLogSize << kSubBits); + /* + for (UInt64 uu = 0; uu < (UInt64)0xf << 60;) + { + unsigned rr = GetLogSize_Sub(uu); + printf("\n%16I64x , log = %4x", uu, rr); + uu += 1; + uu += uu / 50; + } + */ + // throw 1; + const UInt32 t = GetLogSize_Sub(dictSize) - (kBenchMinDicLogSize << kSubBits); encComplex = 870 + ((t * t * 5) >> (2 * kSubBits)); } - UInt64 numCommands = (UInt64)size * encComplex; - return MyMultDiv64(numCommands, elapsedTime, freq); + const UInt64 numCommands = GetNumCommands_from_Size_and_Complexity(size, encComplex); + return MyMultDiv64(numCommands, freq, elapsedTime); } -UInt64 CBenchProps::GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) +UInt64 CBenchProps::GetRating_Dec(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) const { - UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * numIterations; - return MyMultDiv64(numCommands, elapsedTime, freq); + const UInt64 numCommands = GetNumCommands_Dec(inSize, outSize) * numIterations; + return MyMultDiv64(numCommands, freq, elapsedTime); } -UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) + + +UInt64 CBenchInfo::GetRating_LzmaEnc(UInt64 dictSize) const { CBenchProps props; props.SetLzmaCompexity(); - return props.GetCompressRating(dictSize, elapsedTime, freq, size); + return props.GetRating_Enc(dictSize, GlobalTime, GlobalFreq, UnpackSize * NumIterations); } -UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) +UInt64 CBenchInfo::GetRating_LzmaDec() const { CBenchProps props; props.SetLzmaCompexity(); - return props.GetDecompressRating(elapsedTime, freq, outSize, inSize, numIterations); + return props.GetRating_Dec(GlobalTime, GlobalFreq, UnpackSize, PackSize, NumIterations); +} + + +#ifndef Z7_ST + +#define NUM_CPU_LEVELS_MAX 3 + +struct CAffinityMode +{ + unsigned NumBundleThreads; + unsigned NumLevels; + unsigned NumCoreThreads; + unsigned NumCores; + // unsigned DivideNum; + UInt32 Sizes[NUM_CPU_LEVELS_MAX]; + + void SetLevels(unsigned numCores, unsigned numCoreThreads); + DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const; + bool NeedAffinity() const { return NumBundleThreads != 0; } + + WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const + { + if (NeedAffinity()) + { + CCpuSet cpuSet; + GetAffinityMask(bundleIndex, &cpuSet); + return thread.Create_With_CpuSet(startAddress, parameter, &cpuSet); + } + return thread.Create(startAddress, parameter); + } + + CAffinityMode(): + NumBundleThreads(0), + NumLevels(0), + NumCoreThreads(1) + // DivideNum(1) + {} +}; + +void CAffinityMode::SetLevels(unsigned numCores, unsigned numCoreThreads) +{ + NumCores = numCores; + NumCoreThreads = numCoreThreads; + NumLevels = 0; + if (numCoreThreads == 0 || numCores == 0 || numCores % numCoreThreads != 0) + return; + UInt32 c = numCores / numCoreThreads; + UInt32 c2 = 1; + while ((c & 1) == 0) + { + c >>= 1; + c2 <<= 1; + } + if (c2 != 1) + Sizes[NumLevels++] = c2; + if (c != 1) + Sizes[NumLevels++] = c; + if (numCoreThreads != 1) + Sizes[NumLevels++] = numCoreThreads; + if (NumLevels == 0) + Sizes[NumLevels++] = 1; + + /* + printf("\n Cores:"); + for (unsigned i = 0; i < NumLevels; i++) + { + printf(" %d", Sizes[i]); + } + printf("\n"); + */ +} + + +DWORD_PTR CAffinityMode::GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const +{ + CpuSet_Zero(cpuSet); + + if (NumLevels == 0) + return 0; + + // printf("\n%2d", bundleIndex); + + /* + UInt32 low = 0; + if (DivideNum != 1) + { + low = bundleIndex % DivideNum; + bundleIndex /= DivideNum; + } + */ + + UInt32 numGroups = NumCores / NumBundleThreads; + UInt32 m = bundleIndex % numGroups; + UInt32 v = 0; + for (unsigned i = 0; i < NumLevels; i++) + { + UInt32 size = Sizes[i]; + while ((size & 1) == 0) + { + v *= 2; + v |= (m & 1); + m >>= 1; + size >>= 1; + } + v *= size; + v += m % size; + m /= size; + } + + // UInt32 nb = NumBundleThreads / DivideNum; + UInt32 nb = NumBundleThreads; + + DWORD_PTR mask = ((DWORD_PTR)1 << nb) - 1; + // v += low; + mask <<= v; + + // printf(" %2d %8x \n ", v, (unsigned)mask); + #ifdef _WIN32 + *cpuSet = mask; + #else + { + for (unsigned k = 0; k < nb; k++) + CpuSet_Set(cpuSet, v + k); + } + #endif + + return mask; } -struct CEncoderInfo; -struct CEncoderInfo +struct CBenchSyncCommon +{ + bool ExitMode; + NSynchronization::CManualResetEvent StartEvent; + + CBenchSyncCommon(): ExitMode(false) {} +}; + +#endif + + + +enum E_CheckCrcMode { - #ifndef _7ZIP_ST + k_CheckCrcMode_Never = 0, + k_CheckCrcMode_Always = 1, + k_CheckCrcMode_FirstPass = 2 +}; + +class CEncoderInfo; + +class CEncoderInfo Z7_final +{ + Z7_CLASS_NO_COPY(CEncoderInfo) + +public: + + #ifndef Z7_ST NWindows::CThread thread[2]; + NSynchronization::CManualResetEvent ReadyEvent; UInt32 NumDecoderSubThreads; + CBenchSyncCommon *Common; + UInt32 EncoderIndex; + UInt32 NumEncoderInternalThreads; + CAffinityMode AffinityMode; + bool IsGlobalMtMode; // if more than one benchmark encoder threads #endif + CMyComPtr<ICompressCoder> _encoder; CMyComPtr<ICompressFilter> _encoderFilter; CBenchProgressInfo *progressInfoSpec[2]; CMyComPtr<ICompressProgressInfo> progressInfo[2]; UInt64 NumIterations; + UInt32 Salt; + #ifdef USE_ALLOCA size_t AllocaSize; #endif + unsigned KeySize; Byte _key[32]; Byte _iv[16]; + + HRESULT Set_Key_and_IV(ICryptoProperties *cp) + { + RINOK(cp->SetKey(_key, KeySize)) + return cp->SetInitVector(_iv, sizeof(_iv)); + } + Byte _psw[16]; - bool CheckCrc_Enc; - bool CheckCrc_Dec; + + bool CheckCrc_Enc; /* = 1, if we want to check packed data crcs after each pass + used for filter and usual coders */ + bool UseRealData_Enc; /* = 1, if we want to use only original data for each pass + used only for filter */ + E_CheckCrcMode CheckCrcMode_Dec; struct CDecoderInfo { @@ -741,28 +1076,41 @@ struct CEncoderInfo const Byte *fileData; CBenchRandomGenerator rg; - CBenchBuffer rgCopy; // it must be 16-byte aligned !!! - CBenchmarkOutStream *propStreamSpec; + CMidAlignedBuffer rgCopy; // it must be 16-byte aligned !!! + + // CBenchmarkOutStream *propStreamSpec; + Byte propsData[kMaxMethodPropSize]; + CBufPtrSeqOutStream *propStreamSpec; CMyComPtr<ISequentialOutStream> propStream; - // for decode + unsigned generateDictBits; COneMethodInfo _method; + + // for decode size_t _uncompressedDataSize; - HRESULT Init( - const COneMethodInfo &method, - unsigned generateDictBits, - CBaseRandomGenerator *rg); + HRESULT Generate(); HRESULT Encode(); HRESULT Decode(UInt32 decoderIndex); CEncoderInfo(): - fileData(NULL), + #ifndef Z7_ST + Common(NULL), + IsGlobalMtMode(true), + #endif + Salt(0), + KeySize(0), CheckCrc_Enc(true), - CheckCrc_Dec(true), - outStreamSpec(0), callback(0), printCallback(0), propStreamSpec(0) {} + UseRealData_Enc(true), + CheckCrcMode_Dec(k_CheckCrcMode_Always), + outStreamSpec(NULL), + callback(NULL), + printCallback(NULL), + fileData(NULL), + propStreamSpec(NULL) + {} - #ifndef _7ZIP_ST + #ifndef Z7_ST static THREAD_FUNC_DECL EncodeThreadFunction(void *param) { @@ -775,15 +1123,16 @@ struct CEncoderInfo #endif res = encoder->Encode(); - encoder->Results[0] = res; } catch(...) { res = E_FAIL; } + encoder->Results[0] = res; if (res != S_OK) encoder->progressInfoSpec[0]->Status->SetResult(res); - return 0; + encoder->ReadyEvent.Set(); + return THREAD_FUNC_RET_ZERO; } static THREAD_FUNC_DECL DecodeThreadFunction(void *param) @@ -796,12 +1145,18 @@ struct CEncoderInfo CEncoderInfo *encoder = decoder->Encoder; encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex); - return 0; + return THREAD_FUNC_RET_ZERO; } HRESULT CreateEncoderThread() { - return thread[0].Create(EncodeThreadFunction, this); + WRes res = 0; + if (!ReadyEvent.IsCreated()) + res = ReadyEvent.Create(); + if (res == 0) + res = AffinityMode.CreateThread_WithAffinity(thread[0], EncodeThreadFunction, this, + EncoderIndex); + return HRESULT_FROM_WIN32(res); } HRESULT CreateDecoderThread(unsigned index, bool callbackMode @@ -819,66 +1174,99 @@ struct CEncoderInfo #endif decoder.CallbackMode = callbackMode; - return thread[index].Create(DecodeThreadFunction, &decoder); + + WRes res = AffinityMode.CreateThread_WithAffinity(thread[index], DecodeThreadFunction, &decoder, + // EncoderIndex * NumEncoderInternalThreads + index + EncoderIndex + ); + + return HRESULT_FROM_WIN32(res); } #endif }; -HRESULT CEncoderInfo::Init( - const COneMethodInfo &method, - unsigned generateDictBits, - CBaseRandomGenerator *rgLoc) + + +static size_t GetBenchCompressedSize(size_t bufferSize) +{ + return kCompressedAdditionalSize + bufferSize + bufferSize / 16; + // kBufferSize / 2; +} + + +HRESULT CEncoderInfo::Generate() { + const COneMethodInfo &method = _method; + // we need extra space, if input data is already compressed - const size_t kCompressedBufferSize = - kCompressedAdditionalSize + - kBufferSize + kBufferSize / 16; - // kBufferSize / 2; + const size_t kCompressedBufferSize = _encoderFilter ? + kBufferSize : + GetBenchCompressedSize(kBufferSize); if (kCompressedBufferSize < kBufferSize) return E_FAIL; uncompressedDataPtr = fileData; - - if (!fileData) + if (fileData) { - if (!rg.Alloc(kBufferSize)) - return E_OUTOFMEMORY; - + #if !defined(Z7_ST) + if (IsGlobalMtMode) + { + /* we copy the data to local buffer of thread to eliminate + using of shared buffer by different threads */ + ALLOC_WITH_HRESULT(&rg, kBufferSize) + memcpy((Byte *)rg, fileData, kBufferSize); + uncompressedDataPtr = (const Byte *)rg; + } + #endif + } + else + { + ALLOC_WITH_HRESULT(&rg, kBufferSize) // DWORD ttt = GetTickCount(); if (generateDictBits == 0) - rg.GenerateSimpleRandom(rgLoc); + rg.GenerateSimpleRandom(Salt); else - rg.GenerateLz(generateDictBits, rgLoc); + { + if (generateDictBits >= sizeof(size_t) * 8 + && kBufferSize > ((size_t)1 << (sizeof(size_t) * 8 - 1))) + return E_INVALIDARG; + rg.GenerateLz(generateDictBits, Salt); + // return E_ABORT; // for debug + } // printf("\n%d\n ", GetTickCount() - ttt); - crc = CrcCalc(rg.Buffer, rg.BufferSize); - uncompressedDataPtr = rg.Buffer; + crc = CrcCalc((const Byte *)rg, rg.Size()); + uncompressedDataPtr = (const Byte *)rg; } - - if (_encoderFilter) + + if (!outStream) { - if (!rgCopy.Alloc(kBufferSize)) - return E_OUTOFMEMORY; + outStreamSpec = new CBenchmarkOutStream; + outStream = outStreamSpec; } + ALLOC_WITH_HRESULT(outStreamSpec, kCompressedBufferSize) - outStreamSpec = new CBenchmarkOutStream; - outStream = outStreamSpec; - if (!outStreamSpec->Alloc(kCompressedBufferSize)) - return E_OUTOFMEMORY; + if (_encoderFilter) + { + /* we try to reduce the number of memcpy() in main encoding loop. + so we copy data to temp buffers here */ + ALLOC_WITH_HRESULT(&rgCopy, kBufferSize) + memcpy((Byte *)*outStreamSpec, uncompressedDataPtr, kBufferSize); + memcpy((Byte *)rgCopy, uncompressedDataPtr, kBufferSize); + } - propStreamSpec = 0; if (!propStream) { - propStreamSpec = new CBenchmarkOutStream; + propStreamSpec = new CBufPtrSeqOutStream; // CBenchmarkOutStream; propStream = propStreamSpec; } - if (!propStreamSpec->Alloc(kMaxLzmaPropSize)) - return E_OUTOFMEMORY; - propStreamSpec->Init(true, false); + // ALLOC_WITH_HRESULT_2(propStreamSpec, kMaxMethodPropSize); + // propStreamSpec->Init(true, false); + propStreamSpec->Init(propsData, sizeof(propsData)); CMyComPtr<IUnknown> coder; @@ -891,8 +1279,23 @@ HRESULT CEncoderInfo::Init( coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); if (scp) { - UInt64 reduceSize = kBufferSize; - RINOK(method.SetCoderProps(scp, &reduceSize)); + const UInt64 reduceSize = kBufferSize; + + /* in posix new thread uses same affinity as parent thread, + so we don't need to send affinity to coder in posix */ + UInt64 affMask; + #if !defined(Z7_ST) && defined(_WIN32) + { + CCpuSet cpuSet; + affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet); + } + #else + affMask = 0; + #endif + // affMask <<= 3; // debug line: to test no affinity in coder; + // affMask = 0; + + RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, (affMask != 0 ? &affMask : NULL))) } else { @@ -904,7 +1307,7 @@ HRESULT CEncoderInfo::Init( coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps); if (writeCoderProps) { - RINOK(writeCoderProps->WriteCoderProperties(propStream)); + RINOK(writeCoderProps->WriteCoderProperties(propStream)) } { @@ -912,7 +1315,7 @@ HRESULT CEncoderInfo::Init( coder.QueryInterface(IID_ICryptoSetPassword, &sp); if (sp) { - RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))); + RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))) // we must call encoding one time to calculate password key for key cache. // it must be after WriteCoderProperties! @@ -934,7 +1337,7 @@ HRESULT CEncoderInfo::Init( CMyComPtr<ISequentialOutStream> crcStream = crcStreamSpec; crcStreamSpec->Init(); - RINOK(_encoder->Code(inStream, crcStream, 0, 0, NULL)); + RINOK(_encoder->Code(inStream, crcStream, NULL, NULL, NULL)) } } } @@ -944,19 +1347,22 @@ HRESULT CEncoderInfo::Init( } -static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size) +static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size, UInt32 *crc) { while (size != 0) { - UInt32 cur = (UInt32)1 << 31; + UInt32 cur = crc ? 1 << 17 : 1 << 24; if (cur > size) cur = (UInt32)size; UInt32 processed = filter->Filter(data, cur); - data += processed; - // if (processed > size) (in AES filter), we must fill last block with zeros. - // but it is not important for benchmark. So we just copy that data without filtering. + /* if (processed > size) (in AES filter), we must fill last block with zeros. + but it is not important for benchmark. So we just copy that data without filtering. + if (processed == 0) then filter can't process more */ if (processed > size || processed == 0) - break; + processed = (UInt32)size; + if (crc) + *crc = CrcUpdate(*crc, data, processed); + data += processed; size -= processed; } } @@ -964,6 +1370,32 @@ static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size) HRESULT CEncoderInfo::Encode() { + // printf("\nCEncoderInfo::Generate\n"); + + RINOK(Generate()) + + // printf("\n2222\n"); + + #ifndef Z7_ST + if (Common) + { + Results[0] = S_OK; + WRes wres = ReadyEvent.Set(); + if (wres == 0) + wres = Common->StartEvent.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + if (Common->ExitMode) + return S_OK; + } + else + #endif + { + CBenchProgressInfo *bpi = progressInfoSpec[0]; + bpi->SetStartTime(); + } + + CBenchInfo &bi = progressInfoSpec[0]->BenchInfo; bi.UnpackSize = 0; bi.PackSize = 0; @@ -976,52 +1408,116 @@ HRESULT CEncoderInfo::Encode() coder.QueryInterface(IID_ICryptoProperties, &cp); CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; CMyComPtr<ISequentialInStream> inStream = inStreamSpec; - UInt64 prev = 0; - - UInt32 crcPrev = 0; if (cp) { - RINOK(cp->SetKey(_key, sizeof(_key))); - RINOK(cp->SetInitVector(_iv, sizeof(_iv))); + RINOK(Set_Key_and_IV(cp)) + } + + compressedSize = 0; + if (_encoderFilter) + compressedSize = kBufferSize; + + // CBenchmarkOutStream *outStreamSpec = this->outStreamSpec; + UInt64 prev = 0; + + const UInt32 mask = (CheckCrc_Enc ? 0 : 0xFFFF); + const bool useCrc = (mask < NumIterations); + bool crcPrev_defined = false; + UInt32 crcPrev = 0; + + bool useRealData_Enc = UseRealData_Enc; + bool data_Was_Changed = false; + if (useRealData_Enc) + { + /* we want memcpy() for each iteration including first iteration. + So results will be equal for different number of iterations */ + data_Was_Changed = true; } - for (UInt64 i = 0; i < NumIterations; i++) + const UInt64 numIterations = NumIterations; + UInt64 i = numIterations; + // printCallback->NewLine(); + + while (i != 0) { - if (printCallback && bi.UnpackSize - prev > (1 << 20)) + i--; + if (printCallback && bi.UnpackSize - prev >= (1 << 26)) { - RINOK(printCallback->CheckBreak()); prev = bi.UnpackSize; + RINOK(printCallback->CheckBreak()) } + + /* + CBenchInfo info; + progressInfoSpec[0]->SetStartTime(); + */ - bool isLast = (i == NumIterations - 1); - bool calcCrc = ((isLast || (i & 0x7F) == 0 || CheckCrc_Enc) && NumIterations != 1); - outStreamSpec->Init(isLast, calcCrc); - + bool calcCrc = false; + if (useCrc) + calcCrc = (((UInt32)i & mask) == 0); + if (_encoderFilter) { - memcpy(rgCopy.Buffer, uncompressedDataPtr, kBufferSize); + Byte *filterData = rgCopy; + if (i == numIterations - 1 || calcCrc || useRealData_Enc) + { + filterData = (Byte *)*outStreamSpec; + if (data_Was_Changed) + memcpy(filterData, uncompressedDataPtr, kBufferSize); + data_Was_Changed = true; + } _encoderFilter->Init(); - My_FilterBench(_encoderFilter, rgCopy.Buffer, kBufferSize); - RINOK(WriteStream(outStream, rgCopy.Buffer, kBufferSize)); + if (calcCrc) + outStreamSpec->InitCrc(); + My_FilterBench(_encoderFilter, filterData, kBufferSize, + calcCrc ? &outStreamSpec->Crc : NULL); } else { + outStreamSpec->Init(true, calcCrc); // write real data for speed consistency at any number of iterations inStreamSpec->Init(uncompressedDataPtr, kBufferSize); - RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0])); + RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0])) + if (!inStreamSpec->WasFinished()) + return E_FAIL; + if (compressedSize != outStreamSpec->Pos) + { + if (compressedSize != 0) + return E_FAIL; + compressedSize = outStreamSpec->Pos; + } } // outStreamSpec->Print(); - UInt32 crcNew = CRC_GET_DIGEST(outStreamSpec->Crc); - if (i == 0) - crcPrev = crcNew; - else if (calcCrc && crcPrev != crcNew) - return E_FAIL; + if (calcCrc) + { + const UInt32 crc2 = CRC_GET_DIGEST(outStreamSpec->Crc); + if (crcPrev_defined && crcPrev != crc2) + return E_FAIL; + crcPrev = crc2; + crcPrev_defined = true; + } - compressedSize = outStreamSpec->Pos; bi.UnpackSize += kBufferSize; bi.PackSize += compressedSize; + + /* + { + progressInfoSpec[0]->SetFinishTime(info); + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = 1; + + info.UnpackSize = kBufferSize; + info.PackSize = compressedSize; + // printf("\n%7d\n", encoder.compressedSize); + + RINOK(callback->SetEncodeResult(info, true)) + printCallback->NewLine(); + } + */ + } _encoder.Release(); @@ -1047,7 +1543,7 @@ HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) CMyComPtr<ICompressSetDecoderProperties2> setDecProps; coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps); - if (!setDecProps && propStreamSpec->Pos != 0) + if (!setDecProps && propStreamSpec->GetPos() != 0) return E_FAIL; CCrcOutStream *crcOutStreamSpec = new CCrcOutStream; @@ -1057,13 +1553,13 @@ HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) pi->BenchInfo.UnpackSize = 0; pi->BenchInfo.PackSize = 0; - #ifndef _7ZIP_ST + #ifndef Z7_ST { CMyComPtr<ICompressSetCoderMt> setCoderMt; coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); if (setCoderMt) { - RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads)); + RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads)) } } #endif @@ -1072,8 +1568,8 @@ HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); if (scp) { - UInt64 reduceSize = _uncompressedDataSize; - RINOK(_method.SetCoderProps(scp, &reduceSize)); + const UInt64 reduceSize = _uncompressedDataSize; + RINOK(_method.SetCoderProps(scp, &reduceSize)) } CMyComPtr<ICryptoProperties> cp; @@ -1081,7 +1577,10 @@ HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) if (setDecProps) { - RINOK(setDecProps->SetDecoderProperties2(propStreamSpec->Buffer, (UInt32)propStreamSpec->Pos)); + RINOK(setDecProps->SetDecoderProperties2( + /* (const Byte *)*propStreamSpec, */ + propsData, + (UInt32)propStreamSpec->GetPos())) } { @@ -1089,7 +1588,7 @@ HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) coder.QueryInterface(IID_ICryptoSetPassword, &sp); if (sp) { - RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))); + RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw))) } } @@ -1097,40 +1596,90 @@ HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) if (cp) { - RINOK(cp->SetKey(_key, sizeof(_key))); - RINOK(cp->SetInitVector(_iv, sizeof(_iv))); + RINOK(Set_Key_and_IV(cp)) } - for (UInt64 i = 0; i < NumIterations; i++) + CMyComPtr<ICompressSetFinishMode> setFinishMode; + + if (_decoderFilter) { - if (printCallback && pi->BenchInfo.UnpackSize - prev > (1 << 20)) + if (compressedSize > rgCopy.Size()) + return E_FAIL; + } + else + { + decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + } + + const UInt64 numIterations = NumIterations; + const E_CheckCrcMode checkCrcMode = CheckCrcMode_Dec; + + for (UInt64 i = 0; i < numIterations; i++) + { + if (printCallback && pi->BenchInfo.UnpackSize - prev >= (1 << 26)) { - RINOK(printCallback->CheckBreak()); + RINOK(printCallback->CheckBreak()) prev = pi->BenchInfo.UnpackSize; } - inStreamSpec->Init(outStreamSpec->Buffer, compressedSize); + const UInt64 outSize = kBufferSize; + bool calcCrc = (checkCrcMode != k_CheckCrcMode_Never); + crcOutStreamSpec->Init(); - - UInt64 outSize = kBufferSize; - crcOutStreamSpec->CalcCrc = ((i & 0x7F) == 0 || CheckCrc_Dec); - + if (_decoderFilter) { - if (compressedSize > rgCopy.BufferSize) - return E_FAIL; - memcpy(rgCopy.Buffer, outStreamSpec->Buffer, compressedSize); + Byte *filterData = (Byte *)*outStreamSpec; + if (calcCrc) + { + calcCrc = (i == 0); + if (checkCrcMode == k_CheckCrcMode_Always) + { + calcCrc = true; + memcpy((Byte *)rgCopy, (const Byte *)*outStreamSpec, compressedSize); + filterData = rgCopy; + } + } _decoderFilter->Init(); - My_FilterBench(_decoderFilter, rgCopy.Buffer, compressedSize); - RINOK(WriteStream(crcOutStream, rgCopy.Buffer, compressedSize)); + My_FilterBench(_decoderFilter, filterData, compressedSize, + calcCrc ? &crcOutStreamSpec->Crc : NULL); } else { - RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex])); + crcOutStreamSpec->CalcCrc = calcCrc; + inStreamSpec->Init((const Byte *)*outStreamSpec, compressedSize); + + if (setFinishMode) + { + RINOK(setFinishMode->SetFinishMode(BoolToUInt(true))) + } + + RINOK(decoder->Code(inStream, crcOutStream, NULL, &outSize, progressInfo[decoderIndex])) + + if (setFinishMode) + { + if (!inStreamSpec->WasFinished()) + return S_FALSE; + + CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize; + decoder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize); + + if (getInStreamProcessedSize) + { + UInt64 processed; + RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed)) + if (processed != compressedSize) + return S_FALSE; + } + } + + if (crcOutStreamSpec->Pos != outSize) + return S_FALSE; } - if (crcOutStreamSpec->CalcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc) + if (calcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc) return S_FALSE; + pi->BenchInfo.UnpackSize += kBufferSize; pi->BenchInfo.PackSize += compressedSize; } @@ -1146,7 +1695,7 @@ static const UInt32 kNumThreadsMax = (1 << 12); struct CBenchEncoders { CEncoderInfo *encoders; - CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; } + CBenchEncoders(UInt32 num): encoders(NULL) { encoders = new CEncoderInfo[num]; } ~CBenchEncoders() { delete []encoders; } }; @@ -1160,19 +1709,74 @@ static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands) } + +#ifndef Z7_ST + +// ---------- CBenchThreadsFlusher ---------- + +struct CBenchThreadsFlusher +{ + CBenchEncoders *EncodersSpec; + CBenchSyncCommon Common; + unsigned NumThreads; + bool NeedClose; + + CBenchThreadsFlusher(): NumThreads(0), NeedClose(false) {} + + ~CBenchThreadsFlusher() + { + StartAndWait(true); + } + + WRes StartAndWait(bool exitMode = false); +}; + + +WRes CBenchThreadsFlusher::StartAndWait(bool exitMode) +{ + if (!NeedClose) + return 0; + + Common.ExitMode = exitMode; + WRes res = Common.StartEvent.Set(); + + for (unsigned i = 0; i < NumThreads; i++) + { + NWindows::CThread &t = EncodersSpec->encoders[i].thread[0]; + if (t.IsCreated()) + { + WRes res2 = t.Wait_Close(); + if (res == 0) + res = res2; + } + } + NeedClose = false; + return res; +} + +#endif // Z7_ST + + + +static void SetPseudoRand(Byte *data, size_t size, UInt32 startValue) +{ + for (size_t i = 0; i < size; i++) + { + data[i] = (Byte)startValue; + startValue++; + } +} + + + static HRESULT MethodBench( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands, - bool - #ifndef _7ZIP_ST - oldLzmaBenchMode - #endif - , - UInt32 - #ifndef _7ZIP_ST - numThreads - #endif - , + #ifndef Z7_ST + bool oldLzmaBenchMode, + UInt32 numThreads, + const CAffinityMode *affinityMode, + #endif const COneMethodInfo &method2, size_t uncompressedDataSize, const Byte *fileData, @@ -1185,9 +1789,12 @@ static HRESULT MethodBench( COneMethodInfo method = method2; UInt64 methodId; UInt32 numStreams; - if (!FindMethod( + bool isFilter; + const int codecIndex = FindMethod_Index( EXTERNAL_CODECS_LOC_VARS - method.MethodName, methodId, numStreams)) + method.MethodName, true, + methodId, numStreams, isFilter); + if (codecIndex < 0) return E_NOTIMPL; if (numStreams != 1) return E_INVALIDARG; @@ -1195,21 +1802,24 @@ static HRESULT MethodBench( UInt32 numEncoderThreads = 1; UInt32 numSubDecoderThreads = 1; - #ifndef _7ZIP_ST + #ifndef Z7_ST numEncoderThreads = numThreads; - if (oldLzmaBenchMode && methodId == k_LZMA) + if (oldLzmaBenchMode) + if (methodId == k_LZMA) { - bool fixedNumber; - UInt32 numLzmaThreads = method.Get_Lzma_NumThreads(fixedNumber); - if (!fixedNumber && numThreads == 1) + if (numThreads == 1 && method.Get_NumThreads() < 0) method.AddProp_NumThreads(1); + const UInt32 numLzmaThreads = method.Get_Lzma_NumThreads(); if (numThreads > 1 && numLzmaThreads > 1) { - numEncoderThreads = numThreads / 2; + numEncoderThreads = (numThreads + 1) / 2; // 20.03 numSubDecoderThreads = 2; } } + + const bool mtEncMode = (numEncoderThreads > 1) || affinityMode->NeedAffinity(); + #endif CBenchEncoders encodersSpec(numEncoderThreads); @@ -1220,37 +1830,65 @@ static HRESULT MethodBench( for (i = 0; i < numEncoderThreads; i++) { CEncoderInfo &encoder = encoders[i]; - encoder.callback = (i == 0) ? callback : 0; + encoder.callback = (i == 0) ? callback : NULL; encoder.printCallback = printCallback; + #ifndef Z7_ST + encoder.EncoderIndex = i; + encoder.NumEncoderInternalThreads = numSubDecoderThreads; + encoder.AffinityMode = *affinityMode; + + /* + if (numSubDecoderThreads > 1) + if (encoder.AffinityMode.NeedAffinity() + && encoder.AffinityMode.NumBundleThreads == 1) + { + // if old LZMA benchmark uses two threads in coder, we increase (NumBundleThreads) for old LZMA benchmark uses two threads instead of one + if (encoder.AffinityMode.NumBundleThreads * 2 <= encoder.AffinityMode.NumCores) + encoder.AffinityMode.NumBundleThreads *= 2; + } + */ + + #endif + { CCreatedCoder cod; - RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodId, true, encoder._encoderFilter, cod)); + RINOK(CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)codecIndex, true, encoder._encoderFilter, cod)) encoder._encoder = cod.Coder; if (!encoder._encoder && !encoder._encoderFilter) return E_NOTIMPL; } - encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30 ; - encoder.CheckCrc_Dec = (benchProps->DecComplexCompr + benchProps->DecComplexUnc) > 30 ; - - memset(encoder._iv, 0, sizeof(encoder._iv)); - memset(encoder._key, 0, sizeof(encoder._key)); - memset(encoder._psw, 0, sizeof(encoder._psw)); + SetPseudoRand(encoder._iv, sizeof(encoder._iv), 17); + SetPseudoRand(encoder._key, sizeof(encoder._key), 51); + SetPseudoRand(encoder._psw, sizeof(encoder._psw), 123); for (UInt32 j = 0; j < numSubDecoderThreads; j++) { CCreatedCoder cod; CMyComPtr<ICompressCoder> &decoder = encoder._decoders[j]; - RINOK(CreateCoder(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod)); + RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod)) decoder = cod.Coder; if (!encoder._decoderFilter && !decoder) return E_NOTIMPL; } - } - CBaseRandomGenerator rg; - rg.Init(); + encoder.UseRealData_Enc = + encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30; + + encoder.CheckCrcMode_Dec = k_CheckCrcMode_Always; + if (benchProps->DecComplexCompr + + benchProps->DecComplexUnc <= 30) + encoder.CheckCrcMode_Dec = + k_CheckCrcMode_FirstPass; // for filters + // k_CheckCrcMode_Never; // for debug + // k_CheckCrcMode_Always; // for debug + if (fileData) + { + encoder.UseRealData_Enc = true; + encoder.CheckCrcMode_Dec = k_CheckCrcMode_Always; + } + } UInt32 crc = 0; if (fileData) @@ -1260,22 +1898,41 @@ static HRESULT MethodBench( { CEncoderInfo &encoder = encoders[i]; encoder._method = method; + encoder.generateDictBits = generateDictBits; encoder._uncompressedDataSize = uncompressedDataSize; encoder.kBufferSize = uncompressedDataSize; encoder.fileData = fileData; encoder.crc = crc; - - RINOK(encoders[i].Init(method, generateDictBits, &rg)); } CBenchProgressStatus status; status.Res = S_OK; status.EncodeMode = true; + #ifndef Z7_ST + CBenchThreadsFlusher encoderFlusher; + if (mtEncMode) + { + WRes wres = encoderFlusher.Common.StartEvent.Create(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + encoderFlusher.NumThreads = numEncoderThreads; + encoderFlusher.EncodersSpec = &encodersSpec; + encoderFlusher.NeedClose = true; + } + #endif + for (i = 0; i < numEncoderThreads; i++) { CEncoderInfo &encoder = encoders[i]; - encoder.NumIterations = GetNumIterations(benchProps->GeComprCommands(uncompressedDataSize), complexInCommands); + encoder.NumIterations = GetNumIterations(benchProps->GetNumCommands_Enc(uncompressedDataSize), complexInCommands); + // encoder.NumIterations = 3; + encoder.Salt = g_CrcTable[i & 0xFF]; + encoder.Salt ^= (g_CrcTable[(i >> 8) & 0xFF] << 3); + // (g_CrcTable[0] == 0), and (encoder.Salt == 0) for first thread + // printf(" %8x", encoder.Salt); + + encoder.KeySize = benchProps->KeySize; for (int j = 0; j < 2; j++) { @@ -1290,32 +1947,53 @@ static HRESULT MethodBench( CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; bpi->Callback = callback; bpi->BenchInfo.NumIterations = numEncoderThreads; - bpi->SetStartTime(); } - #ifndef _7ZIP_ST - if (numEncoderThreads > 1) + #ifndef Z7_ST + if (mtEncMode) { #ifdef USE_ALLOCA encoder.AllocaSize = (i * 16 * 21) & 0x7FF; #endif + encoder.Common = &encoderFlusher.Common; + encoder.IsGlobalMtMode = numEncoderThreads > 1; RINOK(encoder.CreateEncoderThread()) } - else #endif + } + + if (printCallback) + { + RINOK(printCallback->CheckBreak()) + } + + #ifndef Z7_ST + if (mtEncMode) + { + for (i = 0; i < numEncoderThreads; i++) { - RINOK(encoder.Encode()); + CEncoderInfo &encoder = encoders[i]; + const WRes wres = encoder.ReadyEvent.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + RINOK(encoder.Results[0]) } + + CBenchProgressInfo *bpi = encoders[0].progressInfoSpec[0]; + bpi->SetStartTime(); + + const WRes wres = encoderFlusher.StartAndWait(); + if (status.Res == 0 && wres != 0) + return HRESULT_FROM_WIN32(wres); } - - #ifndef _7ZIP_ST - if (numEncoderThreads > 1) - for (i = 0; i < numEncoderThreads; i++) - encoders[i].thread[0].Wait(); + else #endif + { + RINOK(encoders[0].Encode()) + } - RINOK(status.Res); + RINOK(status.Res) CBenchInfo info; @@ -1326,26 +2004,47 @@ static HRESULT MethodBench( for (i = 0; i < numEncoderThreads; i++) { - CEncoderInfo &encoder = encoders[i]; + const CEncoderInfo &encoder = encoders[i]; info.UnpackSize += encoder.kBufferSize; info.PackSize += encoder.compressedSize; + // printf("\n%7d\n", encoder.compressedSize); } - RINOK(callback->SetEncodeResult(info, true)); + RINOK(callback->SetEncodeResult(info, true)) + + + // ---------- Decode ---------- + status.Res = S_OK; status.EncodeMode = false; - UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; + const UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; + #ifndef Z7_ST + const bool mtDecoderMode = (numDecoderThreads > 1) || affinityMode->NeedAffinity(); + #endif for (i = 0; i < numEncoderThreads; i++) { CEncoderInfo &encoder = encoders[i]; + /* + #ifndef Z7_ST + // encoder.affinityMode = *affinityMode; + if (encoder.NumEncoderInternalThreads != 1) + encoder.AffinityMode.DivideNum = encoder.NumEncoderInternalThreads; + #endif + */ + + if (i == 0) { - encoder.NumIterations = GetNumIterations(benchProps->GeDecomprCommands(encoder.compressedSize, encoder.kBufferSize), complexInCommands); + encoder.NumIterations = GetNumIterations( + benchProps->GetNumCommands_Dec( + encoder.compressedSize, + encoder.kBufferSize), + complexInCommands); CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; bpi->Callback = callback; bpi->BenchInfo.NumIterations = numDecoderThreads; @@ -1354,50 +2053,61 @@ static HRESULT MethodBench( else encoder.NumIterations = encoders[0].NumIterations; - #ifndef _7ZIP_ST + #ifndef Z7_ST { int numSubThreads = method.Get_NumThreads(); - encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : numSubThreads; + encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : (unsigned)numSubThreads; } - if (numDecoderThreads > 1) + if (mtDecoderMode) { for (UInt32 j = 0; j < numSubDecoderThreads; j++) { - HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0) + const HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0) #ifdef USE_ALLOCA , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF #endif ); - RINOK(res); + RINOK(res) } } else #endif { - RINOK(encoder.Decode(0)); + RINOK(encoder.Decode(0)) } } - #ifndef _7ZIP_ST - HRESULT res = S_OK; - if (numDecoderThreads > 1) + #ifndef Z7_ST + if (mtDecoderMode) + { + WRes wres = 0; + HRESULT res = S_OK; for (i = 0; i < numEncoderThreads; i++) for (UInt32 j = 0; j < numSubDecoderThreads; j++) { CEncoderInfo &encoder = encoders[i]; - encoder.thread[j].Wait(); - if (encoder.Results[j] != S_OK) - res = encoder.Results[j]; + const WRes wres2 = encoder.thread[j]. + // Wait(); // later we can get thread times from thread in UNDER_CE + Wait_Close(); + if (wres == 0 && wres2 != 0) + wres = wres2; + const HRESULT res2 = encoder.Results[j]; + if (res == 0 && res2 != 0) + res = res2; } - RINOK(res); - #endif - - RINOK(status.Res); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + RINOK(res) + } + #endif // Z7_ST + + RINOK(status.Res) encoders[0].progressInfoSpec[0]->SetFinishTime(info); - - #ifndef _7ZIP_ST + + /* + #ifndef Z7_ST #ifdef UNDER_CE - if (numDecoderThreads > 1) + if (mtDecoderMode) for (i = 0; i < numEncoderThreads; i++) for (UInt32 j = 0; j < numSubDecoderThreads; j++) { @@ -1407,6 +2117,7 @@ static HRESULT MethodBench( } #endif #endif + */ info.UnpackSize = 0; info.PackSize = 0; @@ -1414,21 +2125,41 @@ static HRESULT MethodBench( for (i = 0; i < numEncoderThreads; i++) { - CEncoderInfo &encoder = encoders[i]; + const CEncoderInfo &encoder = encoders[i]; info.UnpackSize += encoder.kBufferSize; info.PackSize += encoder.compressedSize; } - RINOK(callback->SetDecodeResult(info, false)); - RINOK(callback->SetDecodeResult(info, true)); + // RINOK(callback->SetDecodeResult(info, false)) // why we called before 21.03 ?? + RINOK(callback->SetDecodeResult(info, true)) return S_OK; } -static inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary) + +static inline UInt64 GetDictSizeFromLog(unsigned dictSizeLog) +{ + /* + if (dictSizeLog < 32) + return (UInt32)1 << dictSizeLog; + else + return (UInt32)(Int32)-1; + */ + return (UInt64)1 << dictSizeLog; +} + + +// it's limit of current LZMA implementation that can be changed later +#define kLzmaMaxDictSize ((UInt32)15 << 28) + +static inline UInt64 GetLZMAUsage(bool multiThread, int btMode, UInt64 dict) { - UInt32 hs = dictionary - 1; + if (dict == 0) + dict = 1; + if (dict > kLzmaMaxDictSize) + dict = kLzmaMaxDictSize; + UInt32 hs = (UInt32)dict - 1; hs |= (hs >> 1); hs |= (hs >> 2); hs |= (hs >> 4); @@ -1438,53 +2169,158 @@ static inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary) if (hs > (1 << 24)) hs >>= 1; hs++; - return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 + + hs += (1 << 16); + + const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16); + UInt64 blockSize = (UInt64)dict + (1 << 16) + + (multiThread ? (1 << 20) : 0); + blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2)); + if (blockSize >= kBlockSizeMax) + blockSize = kBlockSizeMax; + + UInt64 son = (UInt64)dict; + if (btMode) + son *= 2; + const UInt64 v = (hs + son) * 4 + blockSize + (1 << 20) + (multiThread ? (6 << 20) : 0); + + // printf("\nGetLZMAUsage = %d\n", (UInt32)(v >> 20)); + // printf("\nblockSize = %d\n", (UInt32)(blockSize >> 20)); + return v; } -UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench) + +UInt64 GetBenchMemoryUsage(UInt32 numThreads, int level, UInt64 dictionary, bool totalBench) { - const UInt32 kBufferSize = dictionary; - const UInt32 kCompressedBufferSize = kBufferSize; // / 2; - bool lzmaMt = (totalBench || numThreads > 1); + const size_t kBufferSize = (size_t)dictionary + kAdditionalSize; + const UInt64 kCompressedBufferSize = GetBenchCompressedSize(kBufferSize); // / 2; + if (level < 0) + level = 5; + const int algo = (level < 5 ? 0 : 1); + const int btMode = (algo == 0 ? 0 : 1); + UInt32 numBigThreads = numThreads; - if (!totalBench && lzmaMt) - numBigThreads /= 2; + bool lzmaMt = (totalBench || (numThreads > 1 && btMode)); + if (btMode) + { + if (!totalBench && lzmaMt) + numBigThreads /= 2; + } return ((UInt64)kBufferSize + kCompressedBufferSize + - GetLZMAUsage(lzmaMt, dictionary) + (2 << 20)) * numBigThreads; + GetLZMAUsage(lzmaMt, btMode, dictionary) + (2 << 20)) * numBigThreads; } -static HRESULT CrcBig(const void *data, UInt32 size, UInt64 numIterations, +static UInt64 GetBenchMemoryUsage_Hash(UInt32 numThreads, UInt64 dictionary) +{ + // dictionary += (dictionary >> 9); // for page tables (virtual memory) + return (UInt64)(dictionary + (1 << 15)) * numThreads + (2 << 20); +} + + +// ---------- CRC and HASH ---------- + +struct CCrcInfo_Base +{ + CMidAlignedBuffer Buffer; + const Byte *Data; + size_t Size; + bool CreateLocalBuf; + UInt32 CheckSum_Res; + + CCrcInfo_Base(): CreateLocalBuf(true), CheckSum_Res(0) {} + + HRESULT Generate(const Byte *data, size_t size); + HRESULT CrcProcess(UInt64 numIterations, + const UInt32 *checkSum, IHasher *hf, + IBenchPrintCallback *callback); +}; + + +HRESULT CCrcInfo_Base::Generate(const Byte *data, size_t size) +{ + Size = size; + Data = data; + if (!data || CreateLocalBuf) + { + ALLOC_WITH_HRESULT(&Buffer, size) + Data = Buffer; + } + if (!data) + RandGen(Buffer, size); + else if (CreateLocalBuf && size != 0) + memcpy(Buffer, data, size); + return S_OK; +} + + +HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations, const UInt32 *checkSum, IHasher *hf, IBenchPrintCallback *callback) { + MY_ALIGN(16) Byte hash[64]; - UInt64 i; - for (i = 0; i < sizeof(hash); i++) - hash[i] = 0; - for (i = 0; i < numIterations; i++) + memset(hash, 0, sizeof(hash)); + + CheckSum_Res = 0; + + const UInt32 hashSize = hf->GetDigestSize(); + if (hashSize > sizeof(hash)) + return S_FALSE; + + const Byte *buf = Data; + const size_t size = Size; + UInt32 checkSum_Prev = 0; + + UInt64 prev = 0; + UInt64 cur = 0; + + for (UInt64 i = 0; i < numIterations; i++) { - if (callback && (i & 0xFF) == 0) + hf->Init(); + size_t pos = 0; + do { - RINOK(callback->CheckBreak()); + const size_t rem = size - pos; + const UInt32 kStep = ((UInt32)1 << 31); + const UInt32 curSize = (rem < kStep) ? (UInt32)rem : kStep; + hf->Update(buf + pos, curSize); + pos += curSize; } - hf->Init(); - hf->Update(data, size); + while (pos != size); + hf->Final(hash); - UInt32 hashSize = hf->GetDigestSize(); - if (hashSize > sizeof(hash)) - return S_FALSE; UInt32 sum = 0; for (UInt32 j = 0; j < hashSize; j += 4) - sum ^= GetUi32(hash + j); - if (checkSum && sum != *checkSum) { - return S_FALSE; + sum = rotlFixed(sum, 11); + sum += GetUi32(hash + j); + } + if (checkSum) + { + if (sum != *checkSum) + return S_FALSE; + } + else + { + checkSum_Prev = sum; + checkSum = &checkSum_Prev; + } + if (callback) + { + cur += size; + if (cur - prev >= ((UInt32)1 << 30)) + { + prev = cur; + RINOK(callback->CheckBreak()) + } } } + CheckSum_Res = checkSum_Prev; return S_OK; } +extern +UInt32 g_BenchCpuFreqTemp; // we need non-static variavble to disable compiler optimization UInt32 g_BenchCpuFreqTemp = 1; #define YY1 sum += val; sum ^= val; @@ -1507,24 +2343,29 @@ static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val) EXTERN_C_END -#ifndef _7ZIP_ST +#ifndef Z7_ST -struct CFreqInfo +struct CBaseThreadInfo { NWindows::CThread Thread; IBenchPrintCallback *Callback; HRESULT CallbackRes; - UInt32 ValRes; - UInt32 Size; - UInt64 NumIterations; - void Wait() + WRes Wait_If_Created() { - Thread.Wait(); - Thread.Close(); + if (!Thread.IsCreated()) + return 0; + return Thread.Wait_Close(); } }; +struct CFreqInfo: public CBaseThreadInfo +{ + UInt32 ValRes; + UInt32 Size; + UInt64 NumIterations; +}; + static THREAD_FUNC_DECL FreqThreadFunction(void *param) { CFreqInfo *p = (CFreqInfo *)param; @@ -1532,13 +2373,16 @@ static THREAD_FUNC_DECL FreqThreadFunction(void *param) UInt32 sum = g_BenchCpuFreqTemp; for (UInt64 k = p->NumIterations; k > 0; k--) { - p->CallbackRes = p->Callback->CheckBreak(); - if (p->CallbackRes != S_OK) - return 0; + if (p->Callback) + { + p->CallbackRes = p->Callback->CheckBreak(); + if (p->CallbackRes != S_OK) + break; + } sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp); } p->ValRes = sum; - return 0; + return THREAD_FUNC_RET_ZERO; } struct CFreqThreads @@ -1546,13 +2390,21 @@ struct CFreqThreads CFreqInfo *Items; UInt32 NumThreads; - CFreqThreads(): Items(0), NumThreads(0) {} - void WaitAll() + CFreqThreads(): Items(NULL), NumThreads(0) {} + + WRes WaitAll() { + WRes wres = 0; for (UInt32 i = 0; i < NumThreads; i++) - Items[i].Wait(); + { + WRes wres2 = Items[i].Wait_If_Created(); + if (wres == 0 && wres2 != 0) + wres = wres2; + } NumThreads = 0; + return wres; } + ~CFreqThreads() { WaitAll(); @@ -1560,30 +2412,95 @@ struct CFreqThreads } }; -struct CCrcInfo -{ - NWindows::CThread Thread; - IBenchPrintCallback *Callback; - HRESULT CallbackRes; +static THREAD_FUNC_DECL CrcThreadFunction(void *param); + +struct CCrcInfo: public CBaseThreadInfo +{ const Byte *Data; - UInt32 Size; + size_t Size; UInt64 NumIterations; bool CheckSumDefined; UInt32 CheckSum; CMyComPtr<IHasher> Hasher; HRESULT Res; + UInt32 CheckSum_Res; + + #ifndef Z7_ST + NSynchronization::CManualResetEvent ReadyEvent; + UInt32 ThreadIndex; + CBenchSyncCommon *Common; + CAffinityMode AffinityMode; + #endif + + // we want to call CCrcInfo_Base::Buffer.Free() in main thread. + // so we uses non-local CCrcInfo_Base. + CCrcInfo_Base crcib; + + HRESULT CreateThread() + { + WRes res = 0; + if (!ReadyEvent.IsCreated()) + res = ReadyEvent.Create(); + if (res == 0) + res = AffinityMode.CreateThread_WithAffinity(Thread, CrcThreadFunction, this, + ThreadIndex); + return HRESULT_FROM_WIN32(res); + } #ifdef USE_ALLOCA size_t AllocaSize; #endif - void Wait() + void Process(); + + CCrcInfo(): Res(E_FAIL) {} +}; + +static const bool k_Crc_CreateLocalBuf_For_File = true; // for total BW test +// static const bool k_Crc_CreateLocalBuf_For_File = false; // for shared memory read test + +void CCrcInfo::Process() +{ + crcib.CreateLocalBuf = k_Crc_CreateLocalBuf_For_File; + // we can use additional Generate() passes to reduce some time effects for new page allocation + // for (unsigned y = 0; y < 10; y++) + Res = crcib.Generate(Data, Size); + + // if (Common) { - Thread.Wait(); - Thread.Close(); + WRes wres = ReadyEvent.Set(); + if (wres != 0) + { + if (Res == 0) + Res = HRESULT_FROM_WIN32(wres); + return; + } + if (Res != 0) + return; + + wres = Common->StartEvent.Lock(); + + if (wres != 0) + { + Res = HRESULT_FROM_WIN32(wres); + return; + } + if (Common->ExitMode) + return; } -}; + + Res = crcib.CrcProcess(NumIterations, + CheckSumDefined ? &CheckSum : NULL, Hasher, + Callback); + CheckSum_Res = crcib.CheckSum_Res; + /* + We don't want to include the time of slow CCrcInfo_Base::Buffer.Free() + to time of benchmark. So we don't free Buffer here + */ + // crcib.Buffer.Free(); +} + static THREAD_FUNC_DECL CrcThreadFunction(void *param) { @@ -1592,73 +2509,87 @@ static THREAD_FUNC_DECL CrcThreadFunction(void *param) #ifdef USE_ALLOCA alloca(p->AllocaSize); #endif - - p->Res = CrcBig(p->Data, p->Size, p->NumIterations, - p->CheckSumDefined ? &p->CheckSum : NULL, p->Hasher, - p->Callback); - return 0; + p->Process(); + return THREAD_FUNC_RET_ZERO; } + struct CCrcThreads { CCrcInfo *Items; - UInt32 NumThreads; + unsigned NumThreads; + CBenchSyncCommon Common; + bool NeedClose; + + CCrcThreads(): Items(NULL), NumThreads(0), NeedClose(false) {} + + WRes StartAndWait(bool exitMode = false); - CCrcThreads(): Items(0), NumThreads(0) {} - void WaitAll() - { - for (UInt32 i = 0; i < NumThreads; i++) - Items[i].Wait(); - NumThreads = 0; - } ~CCrcThreads() { - WaitAll(); + StartAndWait(true); delete []Items; } }; -#endif -static UInt32 CrcCalc1(const Byte *buf, UInt32 size) +WRes CCrcThreads::StartAndWait(bool exitMode) { - UInt32 crc = CRC_INIT_VAL;; - for (UInt32 i = 0; i < size; i++) - crc = CRC_UPDATE_BYTE(crc, buf[i]); - return CRC_GET_DIGEST(crc); + if (!NeedClose) + return 0; + + Common.ExitMode = exitMode; + WRes wres = Common.StartEvent.Set(); + + for (unsigned i = 0; i < NumThreads; i++) + { + WRes wres2 = Items[i].Wait_If_Created(); + if (wres == 0 && wres2 != 0) + wres = wres2; + } + NumThreads = 0; + NeedClose = false; + return wres; } -static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG) +#endif + + +static UInt32 CrcCalc1(const Byte *buf, size_t size) { - for (UInt32 i = 0; i < size; i++) - buf[i] = (Byte)RG.GetRnd(); + UInt32 crc = CRC_INIT_VAL; + for (size_t i = 0; i < size; i++) + crc = CRC_UPDATE_BYTE(crc, buf[i]); + return CRC_GET_DIGEST(crc); } -static UInt32 RandGenCrc(Byte *buf, UInt32 size, CBaseRandomGenerator &RG) +/* +static UInt32 RandGenCrc(Byte *buf, size_t size, CBaseRandomGenerator &RG) { RandGen(buf, size, RG); return CrcCalc1(buf, size); } +*/ -bool CrcInternalTest() +static bool CrcInternalTest() { - CBenchBuffer buffer; - const UInt32 kBufferSize0 = (1 << 8); - const UInt32 kBufferSize1 = (1 << 10); - const UInt32 kCheckSize = (1 << 5); - if (!buffer.Alloc(kBufferSize0 + kBufferSize1)) + CAlignedBuffer buffer; + const size_t kBufferSize0 = (1 << 8); + const size_t kBufferSize1 = (1 << 10); + const unsigned kCheckSize = (1 << 5); + buffer.Alloc(kBufferSize0 + kBufferSize1); + if (!buffer.IsAllocated()) return false; - Byte *buf = buffer.Buffer; - UInt32 i; + Byte *buf = (Byte *)buffer; + size_t i; for (i = 0; i < kBufferSize0; i++) buf[i] = (Byte)i; UInt32 crc1 = CrcCalc1(buf, kBufferSize0); if (crc1 != 0x29058C73) return false; - CBaseRandomGenerator RG; - RandGen(buf + kBufferSize0, kBufferSize1, RG); + RandGen(buf + kBufferSize0, kBufferSize1); for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++) - for (UInt32 j = 0; j < kCheckSize; j++) + for (unsigned j = 0; j < kCheckSize; j++) if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j)) return false; return true; @@ -1668,15 +2599,29 @@ struct CBenchMethod { unsigned Weight; unsigned DictBits; - UInt32 EncComplex; - UInt32 DecComplexCompr; - UInt32 DecComplexUnc; + Int32 EncComplex; + Int32 DecComplexCompr; + Int32 DecComplexUnc; const char *Name; + // unsigned KeySize; }; +// #define USE_SW_CMPLX + +#ifdef USE_SW_CMPLX +#define CMPLX(x) ((x) * 1000) +#else +#define CMPLX(x) (x) +#endif + static const CBenchMethod g_Bench[] = { - { 40, 17, 357, 145, 20, "LZMA:x1" }, + // { 40, 17, 357, 145, 20, "LZMA:x1" }, + // { 20, 18, 360, 145, 20, "LZMA2:x1:mt2" }, + + { 20, 18, 360, 145, 20, "LZMA:x1" }, + { 20, 22, 600, 145, 20, "LZMA:x3" }, + { 80, 24, 1220, 145, 20, "LZMA:x5:mt1" }, { 80, 24, 1220, 145, 20, "LZMA:x5:mt2" }, @@ -1690,14 +2635,46 @@ static const CBenchMethod g_Bench[] = { 10, 19, 815, 122, 122, "BZip2:x5:mt2" }, { 10, 19, 2530, 122, 122, "BZip2:x7" }, + // { 10, 18, 1010, 0, 1150, "PPMDZip:x1" }, { 10, 18, 1010, 0, 1150, "PPMD:x1" }, + // { 10, 22, 1655, 0, 1830, "PPMDZip:x5" }, { 10, 22, 1655, 0, 1830, "PPMD:x5" }, - { 2, 0, 6, 0, 6, "Delta:4" }, - { 2, 0, 4, 0, 4, "BCJ" }, + // { 2, 0, -16, 0, -16, "Swap2" }, + { 2, 0, -16, 0, -16, "Swap4" }, + // { 2, 0, 3, 0, 4, "Delta:1" }, + // { 2, 0, 3, 0, 4, "Delta:2" }, + // { 2, 0, 3, 0, 4, "Delta:3" }, + { 2, 0, 3, 0, 4, "Delta:4" }, + // { 2, 0, 3, 0, 4, "Delta:8" }, + // { 2, 0, 3, 0, 4, "Delta:32" }, + + { 2, 0, 2, 0, 2, "BCJ" }, + { 2, 0, 1, 0, 1, "ARM64" }, + + // { 10, 0, 18, 0, 18, "AES128CBC:1" }, + // { 10, 0, 21, 0, 21, "AES192CBC:1" }, { 10, 0, 24, 0, 24, "AES256CBC:1" }, - { 2, 0, 8, 0, 2, "AES256CBC:2" } + + // { 10, 0, 18, 0, 18, "AES128CTR:1" }, + // { 10, 0, 21, 0, 21, "AES192CTR:1" }, + // { 10, 0, 24, 0, 24, "AES256CTR:1" }, + // { 2, 0, CMPLX(6), 0, CMPLX(1), "AES128CBC:2" }, + // { 2, 0, CMPLX(7), 0, CMPLX(1), "AES192CBC:2" }, + { 2, 0, CMPLX(8), 0, CMPLX(1), "AES256CBC:2" }, + + // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES128CTR:2" }, + // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES192CTR:2" }, + // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES256CTR:2" }, + + // { 1, 0, CMPLX(6), 0, CMPLX(1), "AES128CBC:3" }, + // { 1, 0, CMPLX(7), 0, CMPLX(1), "AES192CBC:3" }, + { 1, 0, CMPLX(8), 0, CMPLX(1), "AES256CBC:3" } + + // { 1, 0, CMPLX(1), 0, CMPLX(1), "AES128CTR:3" }, + // { 1, 0, CMPLX(1), 0, CMPLX(1), "AES192CTR:3" }, + // { 1, 0, CMPLX(1), 0, CMPLX(1), "AES256CTR:3" }, }; struct CBenchHash @@ -1708,36 +2685,27 @@ struct CBenchHash const char *Name; }; -static const CBenchHash g_Hash[] = -{ - { 1, 1820, 0x8F8FEDAB, "CRC32:1" }, - { 10, 558, 0x8F8FEDAB, "CRC32:4" }, - { 10, 339, 0x8F8FEDAB, "CRC32:8" }, - { 10, 512, 0xDF1C17CC, "CRC64" }, - { 10, 5100, 0x2D79FF2E, "SHA256" }, - { 10, 2340, 0x4C25132B, "SHA1" }, - { 2, 5500, 0xE084E913, "BLAKE2sp" } -}; +// #define ARM_CRC_MUL 100 +#define ARM_CRC_MUL 1 -struct CTotalBenchRes -{ - // UInt64 NumIterations1; // for Usage - UInt64 NumIterations2; // for Rating / RPU +#define k_Hash_Complex_Mult 256 - UInt64 Rating; - UInt64 Usage; - UInt64 RPU; +static const CBenchHash g_Hash[] = +{ + // { 1, 1820, 0x21e207bb, "CRC32:1" }, + // { 10, 558, 0x21e207bb, "CRC32:4" }, + { 20, 339, 0x21e207bb, "CRC32:8" } , + { 2, 128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" }, + { 2, 64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" }, + { 10, 512, 0x41b901d1, "CRC64" }, - void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; } - - void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2) - { - Rating = (r1.Rating + r2.Rating); - Usage = (r1.Usage + r2.Usage); - RPU = (r1.RPU + r2.RPU); - // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1); - NumIterations2 = (r1.NumIterations2 + r2.NumIterations2); - } + { 10, 5100, 0x7913ba03, "SHA256:1" }, + { 2, CMPLX((32 * 4 + 1) * 4 + 4), 0x7913ba03, "SHA256:2" }, + + { 10, 2340, 0xff769021, "SHA1:1" }, + { 2, CMPLX((20 * 6 + 1) * 4 + 4), 0xff769021, "SHA1:2" }, + + { 2, 5500, 0x85189d02, "BLAKE2sp" } }; static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size) @@ -1754,9 +2722,11 @@ static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size) unsigned len = (unsigned)strlen(s + startPos); if (size > len) { - startPos -= (size - len); - if (startPos < 0) + size -= len; + if (startPos < size) startPos = 0; + else + startPos -= size; } f.Print(s + startPos); } @@ -1769,6 +2739,8 @@ static const unsigned kFieldSize_RU = 6; static const unsigned kFieldSize_Rating = 6; static const unsigned kFieldSize_EU = 5; static const unsigned kFieldSize_Effec = 5; +static const unsigned kFieldSize_CrcSpeed = 8; + static const unsigned kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating; static const unsigned kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec; @@ -1782,7 +2754,10 @@ static void PrintRating(IBenchPrintCallback &f, UInt64 rating, unsigned size) static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, unsigned size) { - PrintNumber(f, (val * 100 + divider / 2) / divider, size); + UInt64 v = 0; + if (divider != 0) + v = (val * 100 + divider / 2) / divider; + PrintNumber(f, v, size); } static void PrintChars(IBenchPrintCallback &f, char c, unsigned size) @@ -1798,9 +2773,14 @@ static void PrintSpaces(IBenchPrintCallback &f, unsigned size) PrintChars(f, ' ', size); } +static void PrintUsage(IBenchPrintCallback &f, UInt64 usage, unsigned size) +{ + PrintNumber(f, Benchmark_GetUsage_Percents(usage), size); +} + static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq) { - PrintNumber(f, (usage + 5000) / 10000, kFieldSize_Usage); + PrintUsage(f, usage, kFieldSize_Usage); PrintRating(f, rpu, kFieldSize_RU); PrintRating(f, rating, kFieldSize_Rating); if (showFreq) @@ -1809,15 +2789,39 @@ static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt6 PrintSpaces(f, kFieldSize_EUAndEffec); else { - UInt64 ddd = cpuFreq * usage / 100; - if (ddd == 0) - ddd = 1; - PrintPercents(f, (rating * 10000), ddd, kFieldSize_EU); + PrintPercents(f, rating, cpuFreq * usage / kBenchmarkUsageMult, kFieldSize_EU); PrintPercents(f, rating, cpuFreq, kFieldSize_Effec); } } } + +void CTotalBenchRes::Generate_From_BenchInfo(const CBenchInfo &info) +{ + Speed = info.GetUnpackSizeSpeed(); + Usage = info.GetUsage(); + RPU = info.GetRatingPerUsage(Rating); +} + +void CTotalBenchRes::Mult_For_Weight(unsigned weight) +{ + NumIterations2 *= weight; + RPU *= weight; + Rating *= weight; + Usage *= weight; + Speed *= weight; +} + +void CTotalBenchRes::Update_With_Res(const CTotalBenchRes &r) +{ + Rating += r.Rating; + Usage += r.Usage; + RPU += r.RPU; + Speed += r.Speed; + // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1); + NumIterations2 += r.NumIterations2; +} + static void PrintResults(IBenchPrintCallback *f, const CBenchInfo &info, unsigned weight, @@ -1825,39 +2829,126 @@ static void PrintResults(IBenchPrintCallback *f, bool showFreq, UInt64 cpuFreq, CTotalBenchRes *res) { - UInt64 speed = info.GetSpeed(info.UnpackSize * info.NumIterations); + CTotalBenchRes t; + t.Rating = rating; + t.NumIterations2 = 1; + t.Generate_From_BenchInfo(info); + if (f) { - if (speed != 0) - PrintNumber(*f, speed / 1024, kFieldSize_Speed); + if (t.Speed != 0) + PrintNumber(*f, t.Speed / 1024, kFieldSize_Speed); else PrintSpaces(*f, 1 + kFieldSize_Speed); } - UInt64 usage = info.GetUsage(); - UInt64 rpu = info.GetRatingPerUsage(rating); if (f) { - PrintResults(*f, usage, rpu, rating, showFreq, cpuFreq); + PrintResults(*f, t.Usage, t.RPU, rating, showFreq, cpuFreq); } if (res) { // res->NumIterations1++; - res->NumIterations2 += weight; - res->RPU += (rpu * weight); - res->Rating += (rating * weight); - res->Usage += (usage * weight); + t.Mult_For_Weight(weight); + res->Update_With_Res(t); } } -static void PrintTotals(IBenchPrintCallback &f, bool showFreq, UInt64 cpuFreq, const CTotalBenchRes &res) +static void PrintTotals(IBenchPrintCallback &f, + bool showFreq, UInt64 cpuFreq, bool showSpeed, const CTotalBenchRes &res) { - PrintSpaces(f, 1 + kFieldSize_Speed); + const UInt64 numIterations2 = res.NumIterations2 ? res.NumIterations2 : 1; + const UInt64 speed = res.Speed / numIterations2; + if (showSpeed && speed != 0) + PrintNumber(f, speed / 1024, kFieldSize_Speed); + else + PrintSpaces(f, 1 + kFieldSize_Speed); + + // PrintSpaces(f, 1 + kFieldSize_Speed); // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1; - UInt64 numIterations2 = res.NumIterations2; if (numIterations2 == 0) numIterations2 = 1; PrintResults(f, res.Usage / numIterations2, res.RPU / numIterations2, res.Rating / numIterations2, showFreq, cpuFreq); } + +static void PrintHex(AString &s, UInt64 v) +{ + char temp[32]; + ConvertUInt64ToHex(v, temp); + s += temp; +} + +AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti) +{ + AString s; + // s.Add_UInt32(ti.numProcessThreads); + unsigned numSysThreads = ti.GetNumSystemThreads(); + if (ti.GetNumProcessThreads() != numSysThreads) + { + // if (ti.numProcessThreads != ti.numSysThreads) + { + s += " / "; + s.Add_UInt32(numSysThreads); + } + s += " : "; + #ifdef _WIN32 + PrintHex(s, ti.processAffinityMask); + s += " / "; + PrintHex(s, ti.systemAffinityMask); + #else + unsigned i = (numSysThreads + 3) & ~(unsigned)3; + if (i == 0) + i = 4; + for (; i >= 4; ) + { + i -= 4; + unsigned val = 0; + for (unsigned k = 0; k < 4; k++) + { + const unsigned bit = (ti.IsCpuSet(i + k) ? 1 : 0); + val += (bit << k); + } + PrintHex(s, val); + } + #endif + } + return s; +} + + +#ifdef Z7_LARGE_PAGES + +#ifdef _WIN32 +extern bool g_LargePagesMode; +extern "C" +{ + extern SIZE_T g_LargePageSize; +} +#endif + +void Add_LargePages_String(AString &s) +{ + #ifdef _WIN32 + if (g_LargePagesMode || g_LargePageSize != 0) + { + s.Add_OptSpaced("(LP-"); + PrintSize_KMGT_Or_Hex(s, g_LargePageSize); + #ifdef MY_CPU_X86_OR_AMD64 + if (CPU_IsSupported_PageGB()) + s += "-1G"; + #endif + if (!g_LargePagesMode) + s += "-NA"; + s += ")"; + } + #else + s += ""; + #endif +} + +#endif + + + static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString, bool size_Defined, UInt64 size, const char *threadsString, UInt32 numThreads) { @@ -1867,36 +2958,51 @@ static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString, PrintNumber(f, (size >> 20), 6); else f.Print(" ?"); - f.Print(" MB, # "); + f.Print(" MB"); + + #ifdef Z7_LARGE_PAGES + { + AString s; + Add_LargePages_String(s); + f.Print(s); + } + #endif + + f.Print(", # "); f.Print(threadsString); PrintNumber(f, numThreads, 3); - f.NewLine(); } -struct CBenchCallbackToPrint: public IBenchCallback -{ - CBenchProps BenchProps; - CTotalBenchRes EncodeRes; - CTotalBenchRes DecodeRes; - IBenchPrintCallback *_file; - UInt32 DictSize; - bool Use2Columns; - unsigned NameFieldSize; +struct CBenchCallbackToPrint Z7_final: public IBenchCallback +{ + bool NeedPrint; + bool Use2Columns; bool ShowFreq; - UInt64 CpuFreq; + unsigned NameFieldSize; unsigned EncodeWeight; unsigned DecodeWeight; + UInt64 CpuFreq; + UInt64 DictSize; + + IBenchPrintCallback *_file; + CBenchProps BenchProps; + CTotalBenchRes EncodeRes; + CTotalBenchRes DecodeRes; + + CBenchInfo BenchInfo_Results[2]; + CBenchCallbackToPrint(): + NeedPrint(true), Use2Columns(false), - NameFieldSize(0), ShowFreq(false), - CpuFreq(0), + NameFieldSize(0), EncodeWeight(1), - DecodeWeight(1) + DecodeWeight(1), + CpuFreq(0) {} void Init() { EncodeRes.Init(); DecodeRes.Init(); } @@ -1904,8 +3010,8 @@ struct CBenchCallbackToPrint: public IBenchCallback void NewLine(); HRESULT SetFreq(bool showFreq, UInt64 cpuFreq); - HRESULT SetEncodeResult(const CBenchInfo &info, bool final); - HRESULT SetDecodeResult(const CBenchInfo &info, bool final); + HRESULT SetEncodeResult(const CBenchInfo &info, bool final) Z7_override; + HRESULT SetDecodeResult(const CBenchInfo &info, bool final) Z7_override; }; HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq) @@ -1917,10 +3023,13 @@ HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq) HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final) { - RINOK(_file->CheckBreak()); + RINOK(_file->CheckBreak()) + if (final) + BenchInfo_Results[0] = info; if (final) + if (NeedPrint) { - UInt64 rating = BenchProps.GetCompressRating(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations); + const UInt64 rating = BenchProps.GetRating_Enc(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations); PrintResults(_file, info, EncodeWeight, rating, ShowFreq, CpuFreq, &EncodeRes); @@ -1930,14 +3039,17 @@ HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool fina return S_OK; } -static const char *kSep = " | "; +static const char * const kSep = " | "; HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final) { - RINOK(_file->CheckBreak()); + RINOK(_file->CheckBreak()) if (final) + BenchInfo_Results[1] = info; + if (final) + if (NeedPrint) { - UInt64 rating = BenchProps.GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations); + const UInt64 rating = BenchProps.GetRating_Dec(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations); if (Use2Columns) _file->Print(kSep); else @@ -1963,35 +3075,58 @@ void CBenchCallbackToPrint::NewLine() _file->NewLine(); } -void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size) +static void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size) { f.Print(s); - int numSpaces = size - MyStringLen(s); + int numSpaces = (int)size - (int)MyStringLen(s); if (numSpaces > 0) - PrintSpaces(f, numSpaces); + PrintSpaces(f, (unsigned)numSpaces); } -void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size) +static void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size) { - int numSpaces = size - MyStringLen(s); + int numSpaces = (int)size - (int)MyStringLen(s); if (numSpaces > 0) - PrintSpaces(f, numSpaces); + PrintSpaces(f, (unsigned)numSpaces); f.Print(s); } + +static bool DoesWildcardMatchName_NoCase(const AString &mask, const char *name) +{ + UString wildc = GetUnicodeString(mask); + UString bname = GetUnicodeString(name); + wildc.MakeLower_Ascii(); + bname.MakeLower_Ascii(); + return DoesWildcardMatchName(wildc, bname); +} + + static HRESULT TotalBench( DECL_EXTERNAL_CODECS_LOC_VARS + const COneMethodInfo &methodMask, UInt64 complexInCommands, + #ifndef Z7_ST UInt32 numThreads, + const CAffinityMode *affinityMode, + #endif bool forceUnpackSize, size_t unpackSize, const Byte *fileData, IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback) { - for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++) + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) { const CBenchMethod &bench = g_Bench[i]; + if (!DoesWildcardMatchName_NoCase(methodMask.MethodName, bench.Name)) + continue; PrintLeft(*callback->_file, bench.Name, kFieldSize_Name); + { + unsigned keySize = 32; + if (IsString1PrefixedByString2(bench.Name, "AES128")) keySize = 16; + else if (IsString1PrefixedByString2(bench.Name, "AES192")) keySize = 24; + callback->BenchProps.KeySize = keySize; + } callback->BenchProps.DecComplexUnc = bench.DecComplexUnc; callback->BenchProps.DecComplexCompr = bench.DecComplexCompr; callback->BenchProps.EncComplex = bench.EncComplex; @@ -1999,7 +3134,7 @@ static HRESULT TotalBench( COneMethodInfo method; NCOM::CPropVariant propVariant; propVariant = bench.Name; - RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)); + RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)) size_t unpackSize2 = unpackSize; if (!forceUnpackSize && bench.DictBits == 0) @@ -2008,10 +3143,13 @@ static HRESULT TotalBench( callback->EncodeWeight = bench.Weight; callback->DecodeWeight = bench.Weight; - HRESULT res = MethodBench( + const HRESULT res = MethodBench( EXTERNAL_CODECS_LOC_VARS complexInCommands, - false, numThreads, method, + #ifndef Z7_ST + false, numThreads, affinityMode, + #endif + method, unpackSize2, fileData, bench.DictBits, printCallback, callback, &callback->BenchProps); @@ -2025,7 +3163,7 @@ static HRESULT TotalBench( } else { - RINOK(res); + RINOK(res) } callback->NewLine(); @@ -2034,38 +3172,67 @@ static HRESULT TotalBench( } -static HRESULT FreqBench( - UInt64 complexInCommands, - UInt32 numThreads, - IBenchPrintCallback *_file, - bool showFreq, - UInt64 specifiedFreq, - UInt64 &cpuFreq, - UInt32 &res) +struct CFreqBench +{ + // in: + UInt64 complexInCommands; + UInt32 numThreads; + bool showFreq; + UInt64 specifiedFreq; + + // out: + UInt64 CpuFreqRes; + UInt64 UsageRes; + UInt32 res; + + CFreqBench() + {} + + HRESULT FreqBench(IBenchPrintCallback *_file + #ifndef Z7_ST + , const CAffinityMode *affinityMode + #endif + ); +}; + + +HRESULT CFreqBench::FreqBench(IBenchPrintCallback *_file + #ifndef Z7_ST + , const CAffinityMode *affinityMode + #endif + ) { res = 0; - cpuFreq = 0; + CpuFreqRes = 0; + UsageRes = 0; - UInt32 bufferSize = 1 << 20; - UInt32 complexity = kNumFreqCommands; if (numThreads == 0) numThreads = 1; - #ifdef _7ZIP_ST + #ifdef Z7_ST numThreads = 1; #endif - UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize); - UInt64 numIterations = complexInCommands / complexity / bsize; - if (numIterations == 0) + const UInt32 complexity = kNumFreqCommands; + UInt64 numIterations = complexInCommands / complexity; + UInt32 numIterations2 = 1 << 30; + if (numIterations > numIterations2) + numIterations /= numIterations2; + else + { + numIterations2 = (UInt32)numIterations; numIterations = 1; + } CBenchInfoCalc progressInfoSpec; - #ifndef _7ZIP_ST - CFreqThreads threads; - if (numThreads > 1) + #ifndef Z7_ST + + bool mtMode = (numThreads > 1) || affinityMode->NeedAffinity(); + + if (mtMode) { + CFreqThreads threads; threads.Items = new CFreqInfo[numThreads]; UInt32 i; for (i = 0; i < numThreads; i++) @@ -2074,19 +3241,25 @@ static HRESULT FreqBench( info.Callback = _file; info.CallbackRes = S_OK; info.NumIterations = numIterations; - info.Size = bufferSize; + info.Size = numIterations2; } progressInfoSpec.SetStartTime(); for (i = 0; i < numThreads; i++) { + // Sleep(10); CFreqInfo &info = threads.Items[i]; - RINOK(info.Thread.Create(FreqThreadFunction, &info)); - threads.NumThreads++; + WRes wres = affinityMode->CreateThread_WithAffinity(info.Thread, FreqThreadFunction, &info, i); + if (info.Thread.IsCreated()) + threads.NumThreads++; + if (wres != 0) + return HRESULT_FROM_WIN32(wres); } - threads.WaitAll(); + WRes wres = threads.WaitAll(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); for (i = 0; i < numThreads; i++) { - RINOK(threads.Items[i].CallbackRes); + RINOK(threads.Items[i].CallbackRes) } } else @@ -2096,11 +3269,20 @@ static HRESULT FreqBench( UInt32 sum = g_BenchCpuFreqTemp; for (UInt64 k = numIterations; k > 0; k--) { - RINOK(_file->CheckBreak()); - sum = CountCpuFreq(sum, bufferSize, g_BenchCpuFreqTemp); + sum = CountCpuFreq(sum, numIterations2, g_BenchCpuFreqTemp); + if (_file) + { + RINOK(_file->CheckBreak()) + } } res += sum; } + + if (res == 0x12345678) + if (_file) + { + RINOK(_file->CheckBreak()) + } CBenchInfo info; progressInfoSpec.SetFinishTime(info); @@ -2109,18 +3291,18 @@ static HRESULT FreqBench( info.PackSize = 0; info.NumIterations = 1; + const UInt64 numCommands = (UInt64)numIterations * numIterations2 * numThreads * complexity; + const UInt64 rating = info.GetSpeed(numCommands); + CpuFreqRes = rating / numThreads; + UsageRes = info.GetUsage(); + if (_file) { - { - UInt64 numCommands = (UInt64)numIterations * bufferSize * numThreads * complexity; - UInt64 rating = info.GetSpeed(numCommands); - cpuFreq = rating / numThreads; - PrintResults(_file, info, + PrintResults(_file, info, 0, // weight rating, - showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : cpuFreq) : 0, NULL); - } - RINOK(_file->CheckBreak()); + showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : CpuFreqRes) : 0, NULL); + RINOK(_file->CheckBreak()) } return S_OK; @@ -2131,23 +3313,32 @@ static HRESULT FreqBench( static HRESULT CrcBench( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands, - UInt32 numThreads, UInt32 bufferSize, + UInt32 numThreads, + const size_t bufferSize, + const Byte *fileData, + UInt64 &speed, + UInt64 &usage, + UInt32 complexity, unsigned benchWeight, const UInt32 *checkSum, const COneMethodInfo &method, IBenchPrintCallback *_file, + #ifndef Z7_ST + const CAffinityMode *affinityMode, + #endif + bool showRating, CTotalBenchRes *encodeRes, bool showFreq, UInt64 cpuFreq) { if (numThreads == 0) numThreads = 1; - #ifdef _7ZIP_ST + #ifdef Z7_ST numThreads = 1; #endif - AString methodName = method.MethodName; + const AString &methodName = method.MethodName; // methodName.RemoveChar(L'-'); CMethodId hashID; if (!FindHashMethod( @@ -2155,98 +3346,131 @@ static HRESULT CrcBench( methodName, hashID)) return E_NOTIMPL; - CBenchBuffer buffer; - size_t totalSize = (size_t)bufferSize * numThreads; - if (totalSize / numThreads != bufferSize) - return E_OUTOFMEMORY; - if (!buffer.Alloc(totalSize)) - return E_OUTOFMEMORY; + /* + // if will generate random data in each thread, instead of global data + CMidAlignedBuffer buffer; + if (!fileData) + { + ALLOC_WITH_HRESULT(&buffer, bufferSize) + RandGen(buffer, bufferSize); + fileData = buffer; + } + */ - Byte *buf = buffer.Buffer; - CBaseRandomGenerator RG; - UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize); - UInt64 numIterations = complexInCommands * 256 / complexity / bsize; + const size_t bsize = (bufferSize == 0 ? 1 : bufferSize); + UInt64 numIterations = complexInCommands * k_Hash_Complex_Mult / complexity / bsize; if (numIterations == 0) numIterations = 1; CBenchInfoCalc progressInfoSpec; + CBenchInfo info; + + #ifndef Z7_ST + bool mtEncMode = (numThreads > 1) || affinityMode->NeedAffinity(); - #ifndef _7ZIP_ST - CCrcThreads threads; - if (numThreads > 1) + if (mtEncMode) { + CCrcThreads threads; threads.Items = new CCrcInfo[numThreads]; - + { + WRes wres = threads.Common.StartEvent.Create(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + threads.NeedClose = true; + } + UInt32 i; for (i = 0; i < numThreads; i++) { - CCrcInfo &info = threads.Items[i]; + CCrcInfo &ci = threads.Items[i]; AString name; - RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, info.Hasher)); - if (!info.Hasher) + RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, ci.Hasher)) + if (!ci.Hasher) return E_NOTIMPL; CMyComPtr<ICompressSetCoderProperties> scp; - info.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); + ci.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); if (scp) { - UInt64 reduceSize = 1; - RINOK(method.SetCoderProps(scp, &reduceSize)); + RINOK(method.SetCoderProps(scp)) } - Byte *data = buf + (size_t)bufferSize * i; - info.Callback = _file; - info.Data = data; - info.NumIterations = numIterations; - info.Size = bufferSize; - /* info.Crc = */ RandGenCrc(data, bufferSize, RG); - info.CheckSumDefined = false; + ci.Callback = _file; + ci.Data = fileData; + ci.NumIterations = numIterations; + ci.Size = bufferSize; + ci.CheckSumDefined = false; if (checkSum) { - info.CheckSum = *checkSum; - info.CheckSumDefined = (checkSum && (i == 0)); + ci.CheckSum = *checkSum; + ci.CheckSumDefined = true; } #ifdef USE_ALLOCA - info.AllocaSize = (i * 16 * 21) & 0x7FF; + ci.AllocaSize = (i * 16 * 21) & 0x7FF; #endif } - progressInfoSpec.SetStartTime(); + for (i = 0; i < numThreads; i++) + { + CCrcInfo &ci = threads.Items[i]; + ci.ThreadIndex = i; + ci.Common = &threads.Common; + ci.AffinityMode = *affinityMode; + HRESULT hres = ci.CreateThread(); + if (ci.Thread.IsCreated()) + threads.NumThreads++; + if (hres != 0) + return hres; + } for (i = 0; i < numThreads; i++) { - CCrcInfo &info = threads.Items[i]; - RINOK(info.Thread.Create(CrcThreadFunction, &info)); - threads.NumThreads++; + CCrcInfo &ci = threads.Items[i]; + WRes wres = ci.ReadyEvent.Lock(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + RINOK(ci.Res) } - threads.WaitAll(); + + progressInfoSpec.SetStartTime(); + + WRes wres = threads.StartAndWait(); + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + + progressInfoSpec.SetFinishTime(info); + for (i = 0; i < numThreads; i++) { - RINOK(threads.Items[i].Res); + RINOK(threads.Items[i].Res) + if (i != 0) + if (threads.Items[i].CheckSum_Res != + threads.Items[i - 1].CheckSum_Res) + return S_FALSE; } } else #endif { - /* UInt32 crc = */ RandGenCrc(buf, bufferSize, RG); - progressInfoSpec.SetStartTime(); CMyComPtr<IHasher> hasher; AString name; - RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher)); + RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher)) if (!hasher) return E_NOTIMPL; CMyComPtr<ICompressSetCoderProperties> scp; hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp); if (scp) { - UInt64 reduceSize = 1; - RINOK(method.SetCoderProps(scp, &reduceSize)); + RINOK(method.SetCoderProps(scp)) } - RINOK(CrcBig(buf, bufferSize, numIterations, checkSum, hasher, _file)); + CCrcInfo_Base crcib; + crcib.CreateLocalBuf = false; + RINOK(crcib.Generate(fileData, bufferSize)) + progressInfoSpec.SetStartTime(); + RINOK(crcib.CrcProcess(numIterations, checkSum, hasher, _file)) + progressInfoSpec.SetFinishTime(info); } - CBenchInfo info; - progressInfoSpec.SetFinishTime(info); UInt64 unpSize = numIterations * bufferSize; UInt64 unpSizeThreads = unpSize * numThreads; @@ -2256,32 +3480,47 @@ static HRESULT CrcBench( if (_file) { + if (showRating) { - UInt64 numCommands = unpSizeThreads * complexity / 256; - UInt64 rating = info.GetSpeed(numCommands); + UInt64 unpSizeThreads2 = unpSizeThreads; + if (unpSizeThreads2 == 0) + unpSizeThreads2 = numIterations * 1 * numThreads; + const UInt64 numCommands = unpSizeThreads2 * complexity / 256; + const UInt64 rating = info.GetSpeed(numCommands); PrintResults(_file, info, benchWeight, rating, showFreq, cpuFreq, encodeRes); } - RINOK(_file->CheckBreak()); + RINOK(_file->CheckBreak()) } speed = info.GetSpeed(unpSizeThreads); + usage = info.GetUsage(); return S_OK; } + + static HRESULT TotalBench_Hash( DECL_EXTERNAL_CODECS_LOC_VARS + const COneMethodInfo &methodMask, UInt64 complexInCommands, - UInt32 numThreads, UInt32 bufSize, + UInt32 numThreads, + size_t bufSize, + const Byte *fileData, IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback, + #ifndef Z7_ST + const CAffinityMode *affinityMode, + #endif CTotalBenchRes *encodeRes, bool showFreq, UInt64 cpuFreq) { - for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++) + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Hash); i++) { const CBenchHash &bench = g_Hash[i]; + if (!DoesWildcardMatchName_NoCase(methodMask.MethodName, bench.Name)) + continue; PrintLeft(*callback->_file, bench.Name, kFieldSize_Name); // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc; // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr; @@ -2290,24 +3529,31 @@ static HRESULT TotalBench_Hash( COneMethodInfo method; NCOM::CPropVariant propVariant; propVariant = bench.Name; - RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)); + RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)) - UInt64 speed; - HRESULT res = CrcBench( + UInt64 speed, usage; + + const HRESULT res = CrcBench( EXTERNAL_CODECS_LOC_VARS complexInCommands, - numThreads, bufSize, - speed, + numThreads, bufSize, fileData, + speed, usage, bench.Complex, bench.Weight, - &bench.CheckSum, method, - printCallback, encodeRes, showFreq, cpuFreq); + (!fileData && bufSize == (1 << kNumHashDictBits)) ? &bench.CheckSum : NULL, + method, + printCallback, + #ifndef Z7_ST + affinityMode, + #endif + true, // showRating + encodeRes, showFreq, cpuFreq); if (res == E_NOTIMPL) { // callback->Print(" ---"); } else { - RINOK(res); + RINOK(res) } callback->NewLine(); } @@ -2317,7 +3563,8 @@ static HRESULT TotalBench_Hash( struct CTempValues { UInt64 *Values; - CTempValues(UInt32 num) { Values = new UInt64[num]; } + CTempValues(): Values(NULL) {} + void Alloc(UInt32 num) { Values = new UInt64[num]; } ~CTempValues() { delete []Values; } }; @@ -2333,110 +3580,41 @@ static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) prop = result; } -static UInt32 GetNumThreadsNext(unsigned i, UInt32 numThreads) -{ - if (i < 2) - return i + 1; - i -= 1; - UInt32 num = (UInt32)(2 + (i & 1)) << (i >> 1); - return (num <= numThreads) ? num : numThreads; -} static bool AreSameMethodNames(const char *fullName, const char *shortName) { - for (;;) - { - char c2 = *shortName++; - if (c2 == 0) - return true; - char c1 = *fullName++; - if (MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2)) - return false; - } + return StringsAreEqualNoCase_Ascii(fullName, shortName); } -#ifdef MY_CPU_X86_OR_AMD64 -static void PrintCpuChars(AString &s, UInt32 v) -{ - for (int j = 0; j < 4; j++) - { - Byte b = (Byte)(v & 0xFF); - v >>= 8; - if (b == 0) - break; - s += (char)b; - } -} -static void x86cpuid_to_String(const Cx86cpuid &c, AString &s) +static void Print_Usage_and_Threads(IBenchPrintCallback &f, UInt64 usage, UInt32 threads) { - s.Empty(); - - UInt32 maxFunc2 = 0; - UInt32 t[3]; - - MyCPUID(0x80000000, &maxFunc2, &t[0], &t[1], &t[2]); - - bool fullNameIsAvail = (maxFunc2 >= 0x80000004); - - if (!fullNameIsAvail) - { - for (int i = 0; i < 3; i++) - PrintCpuChars(s, c.vendor[i]); - } - else - { - for (int i = 0; i < 3; i++) - { - UInt32 d[4] = { 0 }; - MyCPUID(0x80000002 + i, &d[0], &d[1], &d[2], &d[3]); - for (int j = 0; j < 4; j++) - PrintCpuChars(s, d[j]); - } - } - - s.Add_Space_if_NotEmpty(); - { - char temp[32]; - ConvertUInt32ToHex(c.ver, temp); - s += '('; - s += temp; - s += ')'; - } + PrintRequirements(f, "usage:", true, usage, "Benchmark threads: ", threads); } -#endif - -void GetCpuName(AString &s) +static void Print_Delimiter(IBenchPrintCallback &f) { - s.Empty(); + f.Print(" |"); +} - #ifdef MY_CPU_X86_OR_AMD64 - { - Cx86cpuid cpuid; - if (x86cpuid_CheckAndRead(&cpuid)) - { - x86cpuid_to_String(cpuid, s); - return; - } - #ifdef MY_CPU_AMD64 - s = "x64"; - #else - s = "x86"; - #endif - } - #else - - #ifdef MY_CPU_LE - s = "LE"; - #elif defined(MY_CPU_BE) - s = "BE"; - #endif +static void Print_Pow(IBenchPrintCallback &f, unsigned pow) +{ + char s[16]; + ConvertUInt32ToString(pow, s); + unsigned pos = MyStringLen(s); + s[pos++] = ':'; + s[pos] = 0; + PrintLeft(f, s, kFieldSize_SmallName); // 4 +} - #endif +static void Bench_BW_Print_Usage_Speed(IBenchPrintCallback &f, + UInt64 usage, UInt64 speed) +{ + PrintUsage(f, usage, kFieldSize_Usage); + PrintNumber(f, speed / 1000000, kFieldSize_CrcSpeed); } @@ -2446,38 +3624,87 @@ HRESULT Bench( IBenchCallback *benchCallback, const CObjectVector<CProperty> &props, UInt32 numIterations, - bool multiDict) + bool multiDict, + IBenchFreqCallback *freqCallback) { if (!CrcInternalTest()) - return S_FALSE; + return E_FAIL; UInt32 numCPUs = 1; UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29; - #ifndef _7ZIP_ST - numCPUs = NSystem::GetNumberOfProcessors(); + NSystem::CProcessAffinity threadsInfo; + threadsInfo.InitST(); + + #ifndef Z7_ST + + if (threadsInfo.Get() && threadsInfo.GetNumProcessThreads() != 0) + numCPUs = threadsInfo.GetNumProcessThreads(); + else + numCPUs = NSystem::GetNumberOfProcessors(); + #endif + + // numCPUs = 24; + /* + { + DWORD_PTR mask = (1 << 0); + DWORD_PTR old = SetThreadAffinityMask(GetCurrentThread(), mask); + old = old; + DWORD_PTR old2 = SetThreadAffinityMask(GetCurrentThread(), mask); + old2 = old2; + return 0; + } + */ bool ramSize_Defined = NSystem::GetRamSize(ramSize); UInt32 numThreadsSpecified = numCPUs; - - UInt32 testTime = kComplexInSeconds; - + bool needSetComplexity = false; + UInt32 testTimeMs = kComplexInMs; + UInt32 startDicLog = 22; + bool startDicLog_Defined = false; UInt64 specifiedFreq = 0; - bool multiThreadTests = false; + UInt64 complexInCommands = kComplexInCommands; + UInt32 numThreads_Start = 1; + + #ifndef Z7_ST + CAffinityMode affinityMode; + #endif + COneMethodInfo method; - CBenchBuffer fileDataBuffer; + CMidAlignedBuffer fileDataBuffer; + bool use_fileData = false; + bool isFixedDict = false; { unsigned i; + + if (printCallback) + { + for (i = 0; i < props.Size(); i++) + { + const CProperty &property = props[i]; + printCallback->Print(" "); + printCallback->Print(GetAnsiString(property.Name)); + if (!property.Value.IsEmpty()) + { + printCallback->Print("="); + printCallback->Print(GetAnsiString(property.Value)); + } + } + if (!props.IsEmpty()) + printCallback->NewLine(); + } + + for (i = 0; i < props.Size(); i++) { const CProperty &property = props[i]; - UString name = property.Name; + UString name (property.Name); name.MakeLower_Ascii(); if (name.IsEqualTo("file")) @@ -2485,36 +3712,38 @@ HRESULT Bench( if (property.Value.IsEmpty()) return E_INVALIDARG; - #ifdef USE_WIN_FILE - NFile::NIO::CInFile file; if (!file.Open(us2fs(property.Value))) - return E_INVALIDARG; - UInt64 len; - if (!file.GetLength(len)) - return E_FAIL; - if (len >= ((UInt32)1 << 31) || len == 0) - return E_INVALIDARG; - if (!fileDataBuffer.Alloc((size_t)len)) - return E_OUTOFMEMORY; - UInt32 processedSize; - file.Read(fileDataBuffer.Buffer, (UInt32)len, processedSize); - if (processedSize != len) - return E_FAIL; - if (printCallback) + return GetLastError_noZero_HRESULT(); + size_t len; { - printCallback->Print("file size ="); - // printCallback->Print(GetOemString(property.Value)); - PrintNumber(*printCallback, len, 0); - printCallback->NewLine(); + UInt64 len64; + if (!file.GetLength(len64)) + return GetLastError_noZero_HRESULT(); + if (printCallback) + { + printCallback->Print("file size ="); + PrintNumber(*printCallback, len64, 0); + printCallback->NewLine(); + } + len = (size_t)len64; + if (len != len64) + return E_INVALIDARG; } - continue; - #else + // (len == 0) is allowed. Also it's allowed if Alloc(0) returns NULL here - return E_NOTIMPL; + ALLOC_WITH_HRESULT(&fileDataBuffer, len) + use_fileData = true; - #endif + { + size_t processed; + if (!file.ReadFull((Byte *)fileDataBuffer, len, processed)) + return GetLastError_noZero_HRESULT(); + if (processed != len) + return E_FAIL; + } + continue; } NCOM::CPropVariant propVariant; @@ -2523,14 +3752,65 @@ HRESULT Bench( if (name.IsEqualTo("time")) { - RINOK(ParsePropToUInt32(L"", propVariant, testTime)); + RINOK(ParsePropToUInt32(UString(), propVariant, testTimeMs)) + needSetComplexity = true; + testTimeMs *= 1000; continue; } - + + if (name.IsEqualTo("timems")) + { + RINOK(ParsePropToUInt32(UString(), propVariant, testTimeMs)) + needSetComplexity = true; + continue; + } + + if (name.IsEqualTo("tic")) + { + UInt32 v; + RINOK(ParsePropToUInt32(UString(), propVariant, v)) + if (v >= 64) + return E_INVALIDARG; + complexInCommands = (UInt64)1 << v; + continue; + } + + const bool isCurrent_fixedDict = name.IsEqualTo("df"); + if (isCurrent_fixedDict) + isFixedDict = true; + if (isCurrent_fixedDict || name.IsEqualTo("ds")) + { + RINOK(ParsePropToUInt32(UString(), propVariant, startDicLog)) + if (startDicLog > 32) + return E_INVALIDARG; + startDicLog_Defined = true; + continue; + } + + if (name.IsEqualTo("mts")) + { + RINOK(ParsePropToUInt32(UString(), propVariant, numThreads_Start)) + continue; + } + + if (name.IsEqualTo("af")) + { + UInt32 bundle; + RINOK(ParsePropToUInt32(UString(), propVariant, bundle)) + if (bundle > 0 && bundle < numCPUs) + { + #ifndef Z7_ST + affinityMode.SetLevels(numCPUs, 2); + affinityMode.NumBundleThreads = bundle; + #endif + } + continue; + } + if (name.IsEqualTo("freq")) { UInt32 freq32 = 0; - RINOK(ParsePropToUInt32(L"", propVariant, freq32)); + RINOK(ParsePropToUInt32(UString(), propVariant, freq32)) if (freq32 == 0) return E_INVALIDARG; specifiedFreq = (UInt64)freq32 * 1000000; @@ -2547,46 +3827,48 @@ HRESULT Bench( if (name.IsPrefixedBy_Ascii_NoCase("mt")) { - UString s = name.Ptr(2); - if (s == L"*") + const UString s = name.Ptr(2); + if (s.IsEqualTo("*") + || (s.IsEmpty() + && propVariant.vt == VT_BSTR + && StringsAreEqual_Ascii(propVariant.bstrVal, "*"))) { multiThreadTests = true; continue; } - if (s.IsEmpty() && propVariant.vt == VT_BSTR) - { - if (wcscmp(propVariant.bstrVal, L"*") == 0) - { - multiThreadTests = true; - continue; - } - } - #ifndef _7ZIP_ST - RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified)); + #ifndef Z7_ST + RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified)) #endif continue; } - RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant)); + RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant)) } } if (printCallback) { AString s; - GetCpuName(s); + + #ifndef _WIN32 + s += "Compiler: "; + GetCompiler(s); + printCallback->Print(s); + printCallback->NewLine(); + s.Empty(); + #endif + + GetSystemInfoText(s); printCallback->Print(s); printCallback->NewLine(); } if (printCallback) { - printCallback->Print("CPU Freq:"); + printCallback->Print("1T CPU Freq (MHz):"); } - UInt64 complexInCommands = kComplexInCommands; - - if (printCallback /* || benchCallback */) + if (printCallback || freqCallback) { UInt64 numMilCommands = 1 << 6; if (specifiedFreq != 0) @@ -2598,17 +3880,23 @@ HRESULT Bench( for (int jj = 0;; jj++) { if (printCallback) - RINOK(printCallback->CheckBreak()); + RINOK(printCallback->CheckBreak()) UInt64 start = ::GetTimeCount(); UInt32 sum = (UInt32)start; sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp); + if (sum == 0xF1541213) + if (printCallback) + printCallback->Print(""); const UInt64 realDelta = ::GetTimeCount() - start; start = realDelta; if (start == 0) start = 1; - UInt64 freq = GetFreq(); + if (start > (UInt64)1 << 61) + start = 1; + const UInt64 freq = GetFreq(); // mips is constant in some compilers + const UInt64 hz = MyMultDiv64(numMilCommands * 1000000, freq, start); const UInt64 mipsVal = numMilCommands * freq / start; if (printCallback) { @@ -2619,172 +3907,570 @@ HRESULT Bench( else { // PrintNumber(*printCallback, start, 0); - PrintNumber(*printCallback, mipsVal, 5 + ((sum == 0xF1541213) ? 1 : 0)); + PrintNumber(*printCallback, mipsVal, 5); } } - /* - if (benchCallback) - benchCallback->AddCpuFreq(mipsVal); - */ + if (freqCallback) + { + RINOK(freqCallback->AddCpuFreq(1, hz, kBenchmarkUsageMult)) + } + + if (jj >= 1) + { + bool needStop = (numMilCommands >= (1 << + #ifdef _DEBUG + 7 + #else + 11 + #endif + )); + if (start >= freq * 16) + { + printCallback->Print(" (Cmplx)"); + if (!freqCallback) // we don't want complexity change for old gui lzma benchmark + { + needSetComplexity = true; + } + needStop = true; + } + if (needSetComplexity) + SetComplexCommandsMs(testTimeMs, false, mipsVal * 1000000, complexInCommands); + if (needStop) + break; + numMilCommands <<= 1; + } + } + if (freqCallback) + { + RINOK(freqCallback->FreqsFinished(1)) + } + } + + if (numThreadsSpecified >= 2) + if (printCallback || freqCallback) + { + if (printCallback) + printCallback->NewLine(); - if (jj >= 3) + /* it can show incorrect frequency for HT threads. + so we reduce freq test to (numCPUs / 2) */ + + UInt32 numThreads = numThreadsSpecified >= numCPUs / 2 ? numCPUs / 2: numThreadsSpecified; + if (numThreads < 1) + numThreads = 1; + + if (printCallback) + { + char s[128]; + ConvertUInt64ToString(numThreads, s); + printCallback->Print(s); + printCallback->Print("T CPU Freq (MHz):"); + } + UInt64 numMilCommands = 1 << + #ifdef _DEBUG + 7; + #else + 10; + #endif + + if (specifiedFreq != 0) + { + while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000)) + numMilCommands >>= 1; + } + + // for (int jj = 0;; jj++) + for (;;) + { + if (printCallback) + RINOK(printCallback->CheckBreak()) + + { + // PrintLeft(f, "CPU", kFieldSize_Name); + + // UInt32 resVal; + + CFreqBench fb; + fb.complexInCommands = numMilCommands * 1000000; + fb.numThreads = numThreads; + // showFreq; + // fb.showFreq = (freqTest == kNumCpuTests - 1 || specifiedFreq != 0); + fb.showFreq = true; + fb.specifiedFreq = 1; + + const HRESULT res = fb.FreqBench(NULL /* printCallback */ + #ifndef Z7_ST + , &affinityMode + #endif + ); + RINOK(res) + + if (freqCallback) + { + RINOK(freqCallback->AddCpuFreq(numThreads, fb.CpuFreqRes, fb.UsageRes)) + } + + if (printCallback) + { + /* + if (realDelta == 0) + { + printCallback->Print(" -"); + } + else + */ + { + // PrintNumber(*printCallback, start, 0); + PrintUsage(*printCallback, fb.UsageRes, 3); + printCallback->Print("%"); + PrintNumber(*printCallback, fb.CpuFreqRes / 1000000, 0); + printCallback->Print(" "); + + // PrintNumber(*printCallback, fb.UsageRes, 5); + } + } + } + // if (jj >= 1) { - SetComplexCommands(testTime, false, mipsVal * 1000000, complexInCommands); - if (jj >= 8 || start >= freq) + const bool needStop = (numMilCommands >= (1 << + #ifdef _DEBUG + 7 + #else + 11 + #endif + )); + if (needStop) break; - // break; // change it numMilCommands <<= 1; } } + if (freqCallback) + { + RINOK(freqCallback->FreqsFinished(numThreads)) + } } + if (printCallback) { printCallback->NewLine(); printCallback->NewLine(); PrintRequirements(*printCallback, "size: ", ramSize_Defined, ramSize, "CPU hardware threads:", numCPUs); + printCallback->Print(GetProcessThreadsInfo(threadsInfo)); + printCallback->NewLine(); } if (numThreadsSpecified < 1 || numThreadsSpecified > kNumThreadsMax) return E_INVALIDARG; - UInt32 dict; - bool dictIsDefined = method.Get_DicSize(dict); + UInt64 dict = (UInt64)1 << startDicLog; + const bool dictIsDefined = (isFixedDict || method.Get_DicSize(dict)); + + const unsigned level = method.GetLevel(); - if (method.MethodName.IsEmpty()) - method.MethodName = "LZMA"; + AString &methodName = method.MethodName; + const AString original_MethodName = methodName; + if (methodName.IsEmpty()) + methodName = "LZMA"; if (benchCallback) { CBenchProps benchProps; benchProps.SetLzmaCompexity(); - UInt32 dictSize = method.Get_Lzma_DicSize(); - UInt32 uncompressedDataSize = kAdditionalSize + dictSize; + const UInt64 dictSize = method.Get_Lzma_DicSize(); + + size_t uncompressedDataSize; + if (use_fileData) + { + uncompressedDataSize = fileDataBuffer.Size(); + } + else + { + uncompressedDataSize = kAdditionalSize + (size_t)dictSize; + if (uncompressedDataSize < dictSize) + return E_INVALIDARG; + } + return MethodBench( EXTERNAL_CODECS_LOC_VARS complexInCommands, + #ifndef Z7_ST true, numThreadsSpecified, + &affinityMode, + #endif method, - uncompressedDataSize, fileDataBuffer.Buffer, + uncompressedDataSize, (const Byte *)fileDataBuffer, kOldLzmaDictBits, printCallback, benchCallback, &benchProps); } - AString methodName = method.MethodName; if (methodName.IsEqualTo_Ascii_NoCase("CRC")) methodName = "crc32"; - method.MethodName = methodName; + CMethodId hashID; - - if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID)) + const bool isHashMethod = FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID); + int codecIndex = -1; + bool isFilter = false; + if (!isHashMethod) + { + UInt32 numStreams; + codecIndex = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS original_MethodName, + true, // encode + hashID, numStreams, isFilter); + // we can allow non filter for BW tests + if (!isFilter) codecIndex = -1; + } + + CBenchCallbackToPrint callback; + callback.Init(); + callback._file = printCallback; + + if (isHashMethod || codecIndex != -1) { if (!printCallback) return S_FALSE; IBenchPrintCallback &f = *printCallback; + + UInt64 dict64 = dict; if (!dictIsDefined) - dict = (1 << 24); + dict64 = (1 << 27); + if (use_fileData) + { + if (!dictIsDefined) + dict64 = fileDataBuffer.Size(); + else if (dict64 > fileDataBuffer.Size()) + dict64 = fileDataBuffer.Size(); + } + for (;;) + { + const int index = method.FindProp(NCoderPropID::kDictionarySize); + if (index < 0) + break; + method.Props.Delete((unsigned)index); + } - // methhodName.RemoveChar(L'-'); - UInt32 complexity = 10000; + // methodName.RemoveChar(L'-'); + Int32 complexity = 16 * k_Hash_Complex_Mult; // for unknown hash method const UInt32 *checkSum = NULL; + int benchIndex = -1; + + if (isHashMethod) { - for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++) + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Hash); i++) { const CBenchHash &h = g_Hash[i]; - AString s = h.Name; - AString hProp; - int propPos = s.Find(':'); + AString benchMethod (h.Name); + AString benchProps; + const int propPos = benchMethod.Find(':'); if (propPos >= 0) { - hProp = s.Ptr(propPos + 1); - s.DeleteFrom(propPos); + benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); + benchMethod.DeleteFrom((unsigned)propPos); } - if (AreSameMethodNames(s, methodName)) + if (AreSameMethodNames(benchMethod, methodName)) { - complexity = h.Complex; - checkSum = &h.CheckSum; - if (method.PropsString.IsEqualTo_Ascii_NoCase(hProp)) - break; + const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps); + /* + bool isMainMethod = method.PropsString.IsEmpty(); + if (isMainMethod) + isMainMethod = !checkSum + || (benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps.IsEqualTo_Ascii_NoCase("8")); + if (sameProps || isMainMethod) + */ + { + complexity = (Int32)h.Complex; + checkSum = &h.CheckSum; + if (sameProps) + break; + /* + if property. is not specified, we use the complexity + for latest fastest method (crc32:64) + */ + } + } + } + // if (!checkSum) return E_NOTIMPL; + } + else + { + for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) + { + const CBenchMethod &bench = g_Bench[i]; + AString benchMethod (bench.Name); + AString benchProps; + const int propPos = benchMethod.Find(':'); + if (propPos >= 0) + { + benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); + benchMethod.DeleteFrom((unsigned)propPos); + } + + if (AreSameMethodNames(benchMethod, methodName)) + { + const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps); + // bool isMainMethod = method.PropsString.IsEmpty(); + // if (sameProps || isMainMethod) + { + benchIndex = (int)i; + if (sameProps) + break; + } } } + // if (benchIndex < 0) return E_NOTIMPL; } - f.NewLine(); - f.Print("Size"); - const unsigned kFieldSize_CrcSpeed = 6; - unsigned numThreadsTests = 0; - for (;;) { - UInt32 t = GetNumThreadsNext(numThreadsTests, numThreadsSpecified); - PrintNumber(f, t, kFieldSize_CrcSpeed); - numThreadsTests++; - if (t >= numThreadsSpecified) - break; + /* we count usage only for crc and filter. non-filters are not supported */ + UInt64 usage = (1 << 20); + UInt64 bufSize = dict64; + UInt32 numBlocks = isHashMethod ? 1 : 3; + if (use_fileData) + { + usage += fileDataBuffer.Size(); + if (bufSize > fileDataBuffer.Size()) + bufSize = fileDataBuffer.Size(); + if (isHashMethod) + { + numBlocks = 0; + #ifndef Z7_ST + if (numThreadsSpecified != 1) + numBlocks = (k_Crc_CreateLocalBuf_For_File ? 1 : 0); + #endif + } + } + usage += numThreadsSpecified * bufSize * numBlocks; + Print_Usage_and_Threads(f, usage, numThreadsSpecified); } + + CUIntVector numThreadsVector; + { + unsigned nt = numThreads_Start; + for (;;) + { + if (nt > numThreadsSpecified) + break; + numThreadsVector.Add(nt); + const unsigned next = nt * 2; + const UInt32 ntHalf= numThreadsSpecified / 2; + if (ntHalf > nt && ntHalf < next) + numThreadsVector.Add(ntHalf); + if (numThreadsSpecified > nt && numThreadsSpecified < next) + numThreadsVector.Add(numThreadsSpecified); + nt = next; + } + } + + unsigned numColumns = isHashMethod ? 1 : 2; + CTempValues speedTotals; + CTempValues usageTotals; + { + const unsigned numItems = numThreadsVector.Size() * numColumns; + speedTotals.Alloc(numItems); + usageTotals.Alloc(numItems); + for (unsigned i = 0; i < numItems; i++) + { + speedTotals.Values[i] = 0; + usageTotals.Values[i] = 0; + } + } + f.NewLine(); - f.NewLine(); - CTempValues speedTotals(numThreadsTests); + for (unsigned line = 0; line < 3; line++) { - for (unsigned ti = 0; ti < numThreadsTests; ti++) - speedTotals.Values[ti] = 0; + f.NewLine(); + f.Print(line == 0 ? "THRD" : line == 1 ? " " : "Size"); + FOR_VECTOR (ti, numThreadsVector) + { + if (ti != 0) + Print_Delimiter(f); + if (line == 0) + { + PrintSpaces(f, (kFieldSize_CrcSpeed + kFieldSize_Usage + 2) * (numColumns - 1)); + PrintNumber(f, numThreadsVector[ti], 1 + kFieldSize_Usage + kFieldSize_CrcSpeed); + } + else + { + for (unsigned c = 0; c < numColumns; c++) + { + PrintRight(f, line == 1 ? "Usage" : "%", kFieldSize_Usage + 1); + PrintRight(f, line == 1 ? "BW" : "MB/s", kFieldSize_CrcSpeed + 1); + } + } + } } - + f.NewLine(); + UInt64 numSteps = 0; - for (UInt32 i = 0; i < numIterations; i++) + + // for (UInt32 iter = 0; iter < numIterations; iter++) + // { + unsigned pow = 10; // kNumHashDictBits + if (startDicLog_Defined) + pow = startDicLog; + + // #define NUM_SUB_BITS 2 + // pow <<= NUM_SUB_BITS; + for (;; pow++) { - for (unsigned pow = 10; pow < 32; pow++) + const UInt64 bufSize = (UInt64)1 << pow; + // UInt64 bufSize = (UInt64)1 << (pow >> NUM_SUB_BITS); + // bufSize += ((UInt64)pow & ((1 << NUM_SUB_BITS) - 1)) << ((pow >> NUM_SUB_BITS) - NUM_SUB_BITS); + + size_t dataSize = fileDataBuffer.Size(); + if (dataSize > bufSize || !use_fileData) + dataSize = (size_t)bufSize; + + for (UInt32 iter = 0; iter < numIterations; iter++) { - UInt32 bufSize = (UInt32)1 << pow; - if (bufSize > dict) - break; - char s[16]; - ConvertUInt32ToString(pow, s); - unsigned pos = MyStringLen(s); - s[pos++] = ':'; - s[pos++] = ' '; - s[pos] = 0; - f.Print(s); - - for (unsigned ti = 0; ti < numThreadsTests; ti++) + Print_Pow(f, pow); + // PrintNumber(f, bufSize >> 10, 4); + + FOR_VECTOR (ti, numThreadsVector) { - RINOK(f.CheckBreak()); - UInt32 t = GetNumThreadsNext(ti, numThreadsSpecified); - UInt64 speed = 0; - RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, - t, bufSize, speed, - complexity, + RINOK(f.CheckBreak()) + const UInt32 numThreads = numThreadsVector[ti]; + if (isHashMethod) + { + UInt64 speed = 0; + UInt64 usage = 0; + const HRESULT res = CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, + numThreads, + dataSize, (const Byte *)fileDataBuffer, + speed, usage, + (UInt32)complexity, 1, // benchWeight, - (pow == kNumHashDictBits) ? checkSum : NULL, method, NULL, NULL, false, 0)); - PrintNumber(f, (speed >> 20), kFieldSize_CrcSpeed); - speedTotals.Values[ti] += speed; + (pow == kNumHashDictBits && !use_fileData) ? checkSum : NULL, + method, + &f, + #ifndef Z7_ST + &affinityMode, + #endif + false, // showRating + NULL, false, 0); + RINOK(res) + + if (ti != 0) + Print_Delimiter(f); + + Bench_BW_Print_Usage_Speed(f, usage, speed); + speedTotals.Values[ti] += speed; + usageTotals.Values[ti] += usage; + } + else + { + { + unsigned keySize = 32; + if (IsString1PrefixedByString2(methodName, "AES128")) keySize = 16; + else if (IsString1PrefixedByString2(methodName, "AES192")) keySize = 24; + callback.BenchProps.KeySize = keySize; + } + + COneMethodInfo method2 = method; + unsigned bench_DictBits; + + if (benchIndex >= 0) + { + const CBenchMethod &bench = g_Bench[benchIndex]; + callback.BenchProps.EncComplex = bench.EncComplex; + callback.BenchProps.DecComplexUnc = bench.DecComplexUnc; + callback.BenchProps.DecComplexCompr = bench.DecComplexCompr; + bench_DictBits = bench.DictBits; + // bench_DictBits = kOldLzmaDictBits; = 32 default : for debug + } + else + { + bench_DictBits = kOldLzmaDictBits; // = 32 default + if (isFilter) + { + const unsigned k_UnknownCoderComplexity = 4; + callback.BenchProps.EncComplex = k_UnknownCoderComplexity; + callback.BenchProps.DecComplexUnc = k_UnknownCoderComplexity; + } + else + { + callback.BenchProps.EncComplex = 1 << 10; + callback.BenchProps.DecComplexUnc = 1 << 6; + } + callback.BenchProps.DecComplexCompr = 0; + } + callback.NeedPrint = false; + + if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA")) + { + const NCOM::CPropVariant propVariant = (UInt32)pow; + RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant)) + } + + const HRESULT res = MethodBench( + EXTERNAL_CODECS_LOC_VARS + complexInCommands, + #ifndef Z7_ST + false, // oldLzmaBenchMode + numThreadsVector[ti], + &affinityMode, + #endif + method2, + dataSize, (const Byte *)fileDataBuffer, + bench_DictBits, + printCallback, + &callback, + &callback.BenchProps); + RINOK(res) + + if (ti != 0) + Print_Delimiter(f); + + for (unsigned i = 0; i < 2; i++) + { + const CBenchInfo &bi = callback.BenchInfo_Results[i]; + const UInt64 usage = bi.GetUsage(); + const UInt64 speed = bi.GetUnpackSizeSpeed(); + usageTotals.Values[ti * 2 + i] += usage; + speedTotals.Values[ti * 2 + i] += speed; + Bench_BW_Print_Usage_Speed(f, usage, speed); + } + } } + f.NewLine(); numSteps++; } + if (dataSize >= dict64) + break; } + if (numSteps != 0) { - f.NewLine(); f.Print("Avg:"); - for (unsigned ti = 0; ti < numThreadsTests; ti++) + for (unsigned ti = 0; ti < numThreadsVector.Size(); ti++) { - PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), kFieldSize_CrcSpeed); + if (ti != 0) + Print_Delimiter(f); + for (unsigned i = 0; i < numColumns; i++) + Bench_BW_Print_Usage_Speed(f, + usageTotals.Values[ti * numColumns + i] / numSteps, + speedTotals.Values[ti * numColumns + i] / numSteps); } f.NewLine(); } + return S_OK; } bool use2Columns = false; - bool totalBenchMode = (method.MethodName.IsEqualTo_Ascii_NoCase("*")); + bool totalBenchMode = false; bool onlyHashBench = false; - if (method.MethodName.IsEqualTo_Ascii_NoCase("hash")) + if (methodName.IsEqualTo_Ascii_NoCase("hash")) { onlyHashBench = true; + methodName = "*"; totalBenchMode = true; } + else if (methodName.Find('*') >= 0) + totalBenchMode = true; // ---------- Threads loop ---------- for (unsigned threadsPassIndex = 0; threadsPassIndex < 3; threadsPassIndex++) @@ -2815,10 +4501,6 @@ HRESULT Bench( } } - CBenchCallbackToPrint callback; - callback.Init(); - callback._file = printCallback; - IBenchPrintCallback &f = *printCallback; if (threadsPassIndex > 0) @@ -2827,7 +4509,7 @@ HRESULT Bench( f.NewLine(); } - if (!dictIsDefined) + if (!dictIsDefined && !onlyHashBench) { const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25); unsigned dicSizeLog = dicSizeLog_Main; @@ -2838,10 +4520,10 @@ HRESULT Bench( if (ramSize_Defined) for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) - if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize) + if (GetBenchMemoryUsage(numThreads, (int)level, ((UInt64)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize) break; - dict = (UInt32)1 << dicSizeLog; + dict = (UInt64)1 << dicSizeLog; if (totalBenchMode && dicSizeLog != dicSizeLog_Main) { @@ -2851,7 +4533,13 @@ HRESULT Bench( } } - PrintRequirements(f, "usage:", true, GetBenchMemoryUsage(numThreads, dict, totalBenchMode), "Benchmark threads: ", numThreads); + Print_Usage_and_Threads(f, + onlyHashBench ? + GetBenchMemoryUsage_Hash(numThreads, dict) : + GetBenchMemoryUsage(numThreads, (int)level, dict, totalBenchMode), + numThreads); + + f.NewLine(); f.NewLine(); @@ -2934,6 +4622,7 @@ HRESULT Bench( if (specifiedFreq != 0) cpuFreq = specifiedFreq; + // bool showTotalSpeed = false; if (totalBenchMode) { @@ -2941,96 +4630,171 @@ HRESULT Bench( { if (i != 0) printCallback->NewLine(); - HRESULT res; const unsigned kNumCpuTests = 3; for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++) { PrintLeft(f, "CPU", kFieldSize_Name); - UInt32 resVal; - RINOK(FreqBench(complexInCommands, numThreads, printCallback, - (freqTest == kNumCpuTests - 1 || specifiedFreq != 0), // showFreq - specifiedFreq, - cpuFreq, resVal)); + + // UInt32 resVal; + + CFreqBench fb; + fb.complexInCommands = complexInCommands; + fb.numThreads = numThreads; + // showFreq; + fb.showFreq = (freqTest == kNumCpuTests - 1 || specifiedFreq != 0); + fb.specifiedFreq = specifiedFreq; + + const HRESULT res = fb.FreqBench(printCallback + #ifndef Z7_ST + , &affinityMode + #endif + ); + RINOK(res) + + cpuFreq = fb.CpuFreqRes; callback.NewLine(); if (specifiedFreq != 0) cpuFreq = specifiedFreq; + if (testTimeMs >= 1000) if (freqTest == kNumCpuTests - 1) - SetComplexCommands(testTime, specifiedFreq != 0, cpuFreq, complexInCommands); + { + // SetComplexCommandsMs(testTimeMs, specifiedFreq != 0, cpuFreq, complexInCommands); + } } callback.NewLine(); + // return S_OK; // change it + callback.SetFreq(true, cpuFreq); if (!onlyHashBench) { - res = TotalBench(EXTERNAL_CODECS_LOC_VARS - complexInCommands, numThreads, - dictIsDefined || fileDataBuffer.Buffer, // forceUnpackSize - fileDataBuffer.Buffer ? fileDataBuffer.BufferSize : dict, - fileDataBuffer.Buffer, + size_t dataSize = (size_t)dict; + if (use_fileData) + { + dataSize = fileDataBuffer.Size(); + if (dictIsDefined && dataSize > dict) + dataSize = (size_t)dict; + } + + const HRESULT res = TotalBench(EXTERNAL_CODECS_LOC_VARS + method, complexInCommands, + #ifndef Z7_ST + numThreads, + &affinityMode, + #endif + dictIsDefined || use_fileData, // forceUnpackSize + dataSize, + (const Byte *)fileDataBuffer, printCallback, &callback); - RINOK(res); + RINOK(res) } - res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads, - 1 << kNumHashDictBits, printCallback, &callback, &callback.EncodeRes, true, cpuFreq); - RINOK(res); + { + size_t dataSize = (size_t)1 << kNumHashDictBits; + if (dictIsDefined) + { + dataSize = (size_t)dict; + if (dataSize != dict) + return E_OUTOFMEMORY; + } + if (use_fileData) + { + dataSize = fileDataBuffer.Size(); + if (dictIsDefined && dataSize > dict) + dataSize = (size_t)dict; + } + + const HRESULT res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS + method, complexInCommands, + numThreads, + dataSize, (const Byte *)fileDataBuffer, + printCallback, &callback, + #ifndef Z7_ST + &affinityMode, + #endif + &callback.EncodeRes, true, cpuFreq); + RINOK(res) + } callback.NewLine(); { PrintLeft(f, "CPU", kFieldSize_Name); - UInt32 resVal; - UInt64 cpuFreqLastTemp = cpuFreq; - RINOK(FreqBench(complexInCommands, numThreads, printCallback, - specifiedFreq != 0, // showFreq - specifiedFreq, - cpuFreqLastTemp, resVal)); + + CFreqBench fb; + fb.complexInCommands = complexInCommands; + fb.numThreads = numThreads; + // showFreq; + fb.showFreq = (specifiedFreq != 0); + fb.specifiedFreq = specifiedFreq; + + const HRESULT res = fb.FreqBench(printCallback + #ifndef Z7_ST + , &affinityMode + #endif + ); + RINOK(res) callback.NewLine(); } } } else { - bool needSetComplexity = true; + needSetComplexity = true; if (!methodName.IsEqualTo_Ascii_NoCase("LZMA")) { - for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++) + unsigned i; + for (i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++) { const CBenchMethod &h = g_Bench[i]; - AString s = h.Name; - if (AreSameMethodNames(h.Name, methodName)) + AString benchMethod (h.Name); + AString benchProps; + const int propPos = benchMethod.Find(':'); + if (propPos >= 0) { - callback.BenchProps.EncComplex = h.EncComplex; - callback.BenchProps.DecComplexCompr = h.DecComplexCompr; - callback.BenchProps.DecComplexUnc = h.DecComplexUnc;; - needSetComplexity = false; - break; + benchProps = benchMethod.Ptr((unsigned)(propPos + 1)); + benchMethod.DeleteFrom((unsigned)propPos); + } + + if (AreSameMethodNames(benchMethod, methodName)) + { + if (benchProps.IsEmpty() + || (benchProps == "x5" && method.PropsString.IsEmpty()) + || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps)) + { + callback.BenchProps.EncComplex = h.EncComplex; + callback.BenchProps.DecComplexCompr = h.DecComplexCompr; + callback.BenchProps.DecComplexUnc = h.DecComplexUnc; + needSetComplexity = false; + break; + } } } + /* + if (i == Z7_ARRAY_SIZE(g_Bench)) + return E_NOTIMPL; + */ } if (needSetComplexity) callback.BenchProps.SetLzmaCompexity(); + if (startDicLog < kBenchMinDicLogSize) + startDicLog = kBenchMinDicLogSize; + for (unsigned i = 0; i < numIterations; i++) { - const unsigned kStartDicLog = 22; - unsigned pow = (dict < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog; + unsigned pow = (dict < GetDictSizeFromLog(startDicLog)) ? kBenchMinDicLogSize : (unsigned)startDicLog; if (!multiDict) - pow = 31; - while (((UInt32)1 << pow) > dict && pow > 0) + pow = 32; + while (GetDictSizeFromLog(pow) > dict && pow > 0) pow--; - for (; ((UInt32)1 << pow) <= dict; pow++) + for (; GetDictSizeFromLog(pow) <= dict; pow++) { - char s[16]; - ConvertUInt32ToString(pow, s); - unsigned pos = MyStringLen(s); - s[pos++] = ':'; - s[pos] = 0; - PrintLeft(f, s, kFieldSize_SmallName); - callback.DictSize = (UInt32)1 << pow; + Print_Pow(f, pow); + callback.DictSize = (UInt64)1 << pow; COneMethodInfo method2 = method; @@ -3040,30 +4804,35 @@ HRESULT Bench( // method2 can have two different dictionary size properties. // And last property is main. NCOM::CPropVariant propVariant = (UInt32)pow; - RINOK(method2.ParseMethodFromPROPVARIANT(L"d", propVariant)); + RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant)) } size_t uncompressedDataSize; - if (fileDataBuffer.Buffer) + if (use_fileData) { - uncompressedDataSize = fileDataBuffer.BufferSize; + uncompressedDataSize = fileDataBuffer.Size(); } else { - uncompressedDataSize = callback.DictSize; + uncompressedDataSize = (size_t)callback.DictSize; + if (uncompressedDataSize != callback.DictSize) + return E_OUTOFMEMORY; if (uncompressedDataSize >= (1 << 18)) uncompressedDataSize += kAdditionalSize; } - HRESULT res = MethodBench( + const HRESULT res = MethodBench( EXTERNAL_CODECS_LOC_VARS complexInCommands, + #ifndef Z7_ST true, numThreads, + &affinityMode, + #endif method2, - uncompressedDataSize, fileDataBuffer.Buffer, + uncompressedDataSize, (const Byte *)fileDataBuffer, kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps); f.NewLine(); - RINOK(res); + RINOK(res) if (!multiDict) break; } @@ -3083,16 +4852,19 @@ HRESULT Bench( if (use2Columns) { PrintLeft(f, "Avr:", callback.NameFieldSize); - PrintTotals(f, showFreq, cpuFreq, callback.EncodeRes); + PrintTotals(f, showFreq, cpuFreq, !totalBenchMode, callback.EncodeRes); f.Print(kSep); - PrintTotals(f, showFreq, cpuFreq, callback.DecodeRes); + PrintTotals(f, showFreq, cpuFreq, !totalBenchMode, callback.DecodeRes); f.NewLine(); } PrintLeft(f, "Tot:", callback.NameFieldSize); CTotalBenchRes midRes; - midRes.SetSum(callback.EncodeRes, callback.DecodeRes); - PrintTotals(f, showFreq, cpuFreq, midRes); + midRes = callback.EncodeRes; + midRes.Update_With_Res(callback.DecodeRes); + + // midRes.SetSum(callback.EncodeRes, callback.DecodeRes); + PrintTotals(f, showFreq, cpuFreq, false, midRes); f.NewLine(); } |