diff options
author | 2023-05-04 02:41:16 +1000 | |
---|---|---|
committer | 2023-05-04 02:41:16 +1000 | |
commit | a504bde3a7462b54fafd5cfc2f52e58d0f3218e1 (patch) | |
tree | 8b3108d572b1a0873a6cdbb4e8af1f17179545c3 /3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp | |
parent | befb9bf4a8cfdb2b693a32e32535b5eac522c5d8 (diff) |
3rdparty/lzma: Updated to LZMA SDK version 22.01
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp | 3039 |
1 files changed, 2261 insertions, 778 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/Bench.cpp index ecbacbc9c8e..cc0cfd0c433 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,33 @@ #endif #include "../../../../C/7zCrc.h" -#include "../../../../C/Alloc.h" -#include "../../../../C/CpuArch.h" - -#include "../../../Windows/System.h" +#include "../../../../C/RotateDefs.h" #ifndef _7ZIP_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/FileIO.h" -#endif - +#include "../../../Windows/FileFind.h" +#include "../../../Windows/SystemInfo.h" #include "../../../Common/IntToString.h" +#include "../../../Common/MyBuffer2.h" #include "../../../Common/StringConvert.h" #include "../../../Common/StringToInt.h" #include "../../Common/MethodProps.h" +#include "../../Common/StreamObjects.h" #include "../../Common/StreamUtils.h" #include "Bench.h" using namespace NWindows; +#ifndef _7ZIP_ST static const UInt32 k_LZMA = 0x030101; +#endif static const UInt64 kComplexInCommands = (UInt64)1 << #ifdef UNDER_CE @@ -68,9 +69,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 +81,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;} + MY_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 +MY_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 +171,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 +210,7 @@ public: { len += GetLen(r); - while (((UInt32)1 << posBits) < pos) + while (((size_t)1 << posBits) < pos) posBits++; unsigned numBitsMax = dictBits; @@ -233,11 +224,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 +237,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,8 +250,7 @@ public: *dest++ = *src++; } } - - *_RG_ = rg; + // printf("\n CRC = %x\n", CrcCalc(buf, bufSize)); } }; @@ -270,6 +262,7 @@ class CBenchmarkInStream: const Byte *Data; size_t Pos; size_t Size; + public: MY_UNKNOWN_IMP void Init(const Byte *data, size_t size) @@ -278,19 +271,22 @@ public: Size = size; Pos = 0; } + bool WasFinished() const { return Pos == Size; } STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); }; STDMETHODIMP 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; @@ -299,7 +295,7 @@ STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processed class CBenchmarkOutStream: public ISequentialOutStream, - public CBenchBuffer, + public CMidAlignedBuffer, public CMyUnknownImp { // bool _overflow; @@ -319,6 +315,18 @@ public: Pos = 0; } + void InitCrc() + { + Crc = CRC_INIT_VAL; + } + + 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); } MY_UNKNOWN_IMP @@ -327,15 +335,15 @@ public: STDMETHODIMP 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,6 +356,7 @@ STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *p return S_OK; } + class CCrcOutStream: public ISequentialOutStream, public CMyUnknownImp @@ -355,39 +364,46 @@ class CCrcOutStream: public: bool CalcCrc; UInt32 Crc; + UInt64 Pos; + MY_UNKNOWN_IMP CCrcOutStream(): CalcCrc(true) {}; - void Init() { Crc = CRC_INIT_VAL; } + void Init() { Crc = CRC_INIT_VAL; Pos = 0; } + void Calc(const void *data, size_t size) + { + Crc = CrcUpdate(Crc, data, size); + } STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); }; STDMETHODIMP 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; + 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 +417,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,50 +434,98 @@ 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 @@ -524,14 +587,14 @@ class CBenchProgressInfo: { public: CBenchProgressStatus *Status; - HRESULT Res; IBenchCallback *Callback; - CBenchProgressInfo(): Callback(0) {} + CBenchProgressInfo(): Callback(NULL) {} MY_UNKNOWN_IMP STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); }; + STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) { HRESULT res = Status->GetResult(); @@ -539,6 +602,22 @@ STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 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,66 +639,125 @@ STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 static const unsigned kSubBits = 8; -static UInt32 GetLogSize(UInt32 size) +static unsigned GetLogSize(UInt64 size) { - 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); + unsigned i = 0; + for (;;) + { + i++; size >>= 1; if (size == 0) break; + } + return i; } -static void NormalizeVals(UInt64 &v1, UInt64 &v2) + +static UInt32 GetLogSize_Sub(UInt64 size) { - while (v1 > 1000000) + 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) +{ + const UInt64 kMaxVal = (UInt64)1 << 62; + if (v > (double)(Int64)kMaxVal) + return kMaxVal; + return (UInt64)v; +} + +static UInt64 MyMultDiv64(UInt64 m1, UInt64 m2, UInt64 d) +{ + 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; -} -static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq) -{ - UInt64 elTime = elapsedTime; - NormalizeVals(freq, elTime); - if (elTime == 0) - elTime = 1; - return value * freq / elTime; + 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); + */ } -UInt64 CBenchInfo::GetSpeed(UInt64 numCommands) const + +UInt64 CBenchInfo::GetSpeed(UInt64 numUnits) const { - return MyMultDiv64(numCommands, GlobalTime, GlobalFreq); + return MyMultDiv64(numUnits, GlobalFreq, GlobalTime); } struct CBenchProps @@ -630,11 +768,20 @@ struct CBenchProps UInt32 DecComplexCompr; UInt32 DecComplexUnc; - CBenchProps(): LzmaRatingMode(false) {} + unsigned KeySize; + + CBenchProps(): + LzmaRatingMode(false), + KeySize(0) + {} + void SetLzmaCompexity(); UInt64 GeComprCommands(UInt64 unpackSize) { + const UInt32 kMinSize = 100; + if (unpackSize < kMinSize) + unpackSize = kMinSize; return unpackSize * EncComplex; } @@ -643,7 +790,7 @@ struct CBenchProps return (packSize * DecComplexCompr + unpackSize * DecComplexUnc); } - UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size); + UInt64 GetCompressRating(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size); UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations); }; @@ -655,61 +802,234 @@ void CBenchProps::SetLzmaCompexity() LzmaRatingMode = true; } -UInt64 CBenchProps::GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) +UInt64 CBenchProps::GetCompressRating(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) { if (dictSize < (1 << kBenchMinDicLogSize)) dictSize = (1 << kBenchMinDicLogSize); UInt64 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 = (UInt64)size * encComplex; + return MyMultDiv64(numCommands, freq, elapsedTime); } UInt64 CBenchProps::GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) { - UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * numIterations; - return MyMultDiv64(numCommands, elapsedTime, freq); + const UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * 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.GetCompressRating(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.GetDecompressRating(GlobalTime, GlobalFreq, UnpackSize, PackSize, NumIterations); +} + + +#ifndef _7ZIP_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 + + + +class CEncoderInfo; + +class CEncoderInfo { + CLASS_NO_COPY(CEncoderInfo) + +public: + #ifndef _7ZIP_ST NWindows::CThread thread[2]; + NSynchronization::CManualResetEvent ReadyEvent; UInt32 NumDecoderSubThreads; + CBenchSyncCommon *Common; + UInt32 EncoderIndex; + UInt32 NumEncoderInternalThreads; + CAffinityMode AffinityMode; #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; @@ -741,26 +1061,37 @@ 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 _7ZIP_ST + Common(NULL), + #endif + Salt(0), + KeySize(0), CheckCrc_Enc(true), CheckCrc_Dec(true), - outStreamSpec(0), callback(0), printCallback(0), propStreamSpec(0) {} + outStreamSpec(NULL), + callback(NULL), + printCallback(NULL), + fileData(NULL), + propStreamSpec(NULL) + {} #ifndef _7ZIP_ST @@ -775,14 +1106,15 @@ 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); + encoder->ReadyEvent.Set(); return 0; } @@ -801,7 +1133,13 @@ struct CEncoderInfo 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,23 +1157,34 @@ 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 = GetBenchCompressedSize(kBufferSize); if (kCompressedBufferSize < kBufferSize) return E_FAIL; @@ -844,41 +1193,47 @@ HRESULT CEncoderInfo::Init( if (!fileData) { - if (!rg.Alloc(kBufferSize)) - return E_OUTOFMEMORY; + 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 (!rgCopy.Alloc(kBufferSize)) - return E_OUTOFMEMORY; + ALLOC_WITH_HRESULT(&rgCopy, kBufferSize); } - outStreamSpec = new CBenchmarkOutStream; - outStream = outStreamSpec; - if (!outStreamSpec->Alloc(kCompressedBufferSize)) - return E_OUTOFMEMORY; + if (!outStream) + { + outStreamSpec = new CBenchmarkOutStream; + outStream = outStreamSpec; + } + + ALLOC_WITH_HRESULT(outStreamSpec, kCompressedBufferSize) - 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 +1246,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(_7ZIP_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 { @@ -964,6 +1334,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 _7ZIP_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 +1372,100 @@ 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)); } - for (UInt64 i = 0; i < NumIterations; i++) + compressedSize = 0; + if (_encoderFilter) + compressedSize = kBufferSize; + + // CBenchmarkOutStream *outStreamSpec = this->outStreamSpec; + UInt64 prev = 0; + const UInt32 mask = (CheckCrc_Enc ? 0 : 0xFFF); + bool useCrc = (mask < NumIterations); + bool crcPrev_defined = false; + UInt32 crcPrev = 0; + UInt64 i = NumIterations; + // printCallback->NewLine(); + + while (i != 0) { - if (printCallback && bi.UnpackSize - prev > (1 << 20)) + i--; + if (printCallback && bi.UnpackSize - prev >= (1 << 24)) { RINOK(printCallback->CheckBreak()); prev = bi.UnpackSize; } + + /* + 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); + // if (needRealData) + memcpy((Byte *)*outStreamSpec, uncompressedDataPtr, kBufferSize); _encoderFilter->Init(); - My_FilterBench(_encoderFilter, rgCopy.Buffer, kBufferSize); - RINOK(WriteStream(outStream, rgCopy.Buffer, kBufferSize)); + My_FilterBench(_encoderFilter, (Byte *)*outStreamSpec, kBufferSize); + if (calcCrc) + { + outStreamSpec->InitCrc(); + outStreamSpec->Calc((Byte *)*outStreamSpec, kBufferSize); + } } 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])); + 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 +1491,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; @@ -1072,7 +1516,7 @@ HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) coder.QueryInterface(IID_ICompressSetCoderProperties, &scp); if (scp) { - UInt64 reduceSize = _uncompressedDataSize; + const UInt64 reduceSize = _uncompressedDataSize; RINOK(_method.SetCoderProps(scp, &reduceSize)); } @@ -1081,7 +1525,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())); } { @@ -1097,40 +1544,84 @@ 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 (compressedSize > rgCopy.Size()) + return E_FAIL; + } + else { - if (printCallback && pi->BenchInfo.UnpackSize - prev > (1 << 20)) + decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode); + } + + const UInt64 numIterations = this->NumIterations; + const UInt32 mask = (CheckCrc_Dec ? 0 : 0xFFF); + + for (UInt64 i = 0; i < numIterations; i++) + { + if (printCallback && pi->BenchInfo.UnpackSize - prev >= (1 << 24)) { RINOK(printCallback->CheckBreak()); prev = pi->BenchInfo.UnpackSize; } - inStreamSpec->Init(outStreamSpec->Buffer, compressedSize); + const UInt64 outSize = kBufferSize; + bool calcCrc = false; + if (((UInt32)i & mask) == 0) + calcCrc = true; 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); + if (calcCrc) // for pure filter speed test without multi-iteration consistency + // if (needRealData) + memcpy((Byte *)rgCopy, (const Byte *)*outStreamSpec, compressedSize); _decoderFilter->Init(); - My_FilterBench(_decoderFilter, rgCopy.Buffer, compressedSize); - RINOK(WriteStream(crcOutStream, rgCopy.Buffer, compressedSize)); + My_FilterBench(_decoderFilter, (Byte *)rgCopy, compressedSize); + if (calcCrc) + crcOutStreamSpec->Calc((const Byte *)rgCopy, compressedSize); } else { + crcOutStreamSpec->CalcCrc = calcCrc; + inStreamSpec->Init((const Byte *)*outStreamSpec, compressedSize); + + if (setFinishMode) + { + RINOK(setFinishMode->SetFinishMode(BoolToUInt(true))); + } + RINOK(decoder->Code(inStream, crcOutStream, 0, &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 +1637,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 +1651,74 @@ static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands) } + +#ifndef _7ZIP_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 // _7ZIP_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 _7ZIP_ST + bool oldLzmaBenchMode, + UInt32 numThreads, + const CAffinityMode *affinityMode, + #endif const COneMethodInfo &method2, size_t uncompressedDataSize, const Byte *fileData, @@ -1185,9 +1731,11 @@ static HRESULT MethodBench( COneMethodInfo method = method2; UInt64 methodId; UInt32 numStreams; - if (!FindMethod( + const int codecIndex = FindMethod_Index( EXTERNAL_CODECS_LOC_VARS - method.MethodName, methodId, numStreams)) + method.MethodName, true, + methodId, numStreams); + if (codecIndex < 0) return E_NOTIMPL; if (numStreams != 1) return E_INVALIDARG; @@ -1198,18 +1746,21 @@ static HRESULT MethodBench( #ifndef _7ZIP_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; } } + + bool mtEncMode = (numEncoderThreads > 1) || affinityMode->NeedAffinity(); + #endif CBenchEncoders encodersSpec(numEncoderThreads); @@ -1223,35 +1774,50 @@ static HRESULT MethodBench( encoder.callback = (i == 0) ? callback : 0; encoder.printCallback = printCallback; + #ifndef _7ZIP_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 ; + 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(); - UInt32 crc = 0; if (fileData) crc = CrcCalc(fileData, uncompressedDataSize); @@ -1260,22 +1826,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 _7ZIP_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 = 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,30 +1875,50 @@ static HRESULT MethodBench( CBenchProgressInfo *bpi = encoder.progressInfoSpec[0]; bpi->Callback = callback; bpi->BenchInfo.NumIterations = numEncoderThreads; - bpi->SetStartTime(); } #ifndef _7ZIP_ST - if (numEncoderThreads > 1) + if (mtEncMode) { #ifdef USE_ALLOCA encoder.AllocaSize = (i * 16 * 21) & 0x7FF; #endif + encoder.Common = &encoderFlusher.Common; RINOK(encoder.CreateEncoderThread()) } - else #endif - { - RINOK(encoder.Encode()); - } } - + + if (printCallback) + { + RINOK(printCallback->CheckBreak()); + } + #ifndef _7ZIP_ST - if (numEncoderThreads > 1) + if (mtEncMode) + { for (i = 0; i < numEncoderThreads; i++) - encoders[i].thread[0].Wait(); + { + CEncoderInfo &encoder = encoders[i]; + 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(); + + WRes wres = encoderFlusher.StartAndWait(); + if (status.Res == 0 && wres != 0) + return HRESULT_FROM_WIN32(wres); + } + else #endif + { + RINOK(encoders[0].Encode()); + } RINOK(status.Res); @@ -1329,20 +1934,37 @@ static HRESULT MethodBench( CEncoderInfo &encoder = encoders[i]; info.UnpackSize += encoder.kBufferSize; info.PackSize += encoder.compressedSize; + // printf("\n%7d\n", encoder.compressedSize); } RINOK(callback->SetEncodeResult(info, true)); + + + // ---------- Decode ---------- + status.Res = S_OK; status.EncodeMode = false; - UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; + const UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; + #ifndef _7ZIP_ST + const bool mtDecoderMode = (numDecoderThreads > 1) || affinityMode->NeedAffinity(); + #endif for (i = 0; i < numEncoderThreads; i++) { CEncoderInfo &encoder = encoders[i]; + /* + #ifndef _7ZIP_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); @@ -1357,9 +1979,9 @@ static HRESULT MethodBench( #ifndef _7ZIP_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++) { @@ -1379,25 +2001,36 @@ static HRESULT MethodBench( } #ifndef _7ZIP_ST - HRESULT res = S_OK; - if (numDecoderThreads > 1) + 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]; + 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; + HRESULT res2 = encoder.Results[j]; + if (res == 0 && res2 != 0) + res = res2; } - RINOK(res); - #endif - + if (wres != 0) + return HRESULT_FROM_WIN32(wres); + RINOK(res); + } + #endif // _7ZIP_ST + RINOK(status.Res); encoders[0].progressInfoSpec[0]->SetFinishTime(info); - + + /* #ifndef _7ZIP_ST #ifdef UNDER_CE - if (numDecoderThreads > 1) + if (mtDecoderMode) for (i = 0; i < numEncoderThreads; i++) for (UInt32 j = 0; j < numSubDecoderThreads; j++) { @@ -1407,6 +2040,7 @@ static HRESULT MethodBench( } #endif #endif + */ info.UnpackSize = 0; info.PackSize = 0; @@ -1419,16 +2053,36 @@ static HRESULT MethodBench( info.PackSize += encoder.compressedSize; } - RINOK(callback->SetDecodeResult(info, false)); + // 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) { - UInt32 hs = dictionary - 1; + /* + 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) +{ + 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 +2092,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 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; } -static HRESULT CrcBig(const void *data, UInt32 size, UInt64 numIterations, + +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; @@ -1509,22 +2268,27 @@ EXTERN_C_END #ifndef _7ZIP_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,9 +2296,12 @@ 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) + return 0; + } sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp); } p->ValRes = sum; @@ -1546,13 +2313,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 +2335,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 _7ZIP_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 +2432,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); + p->Process(); return 0; } + 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; } }; + +WRes CCrcThreads::StartAndWait(bool exitMode) +{ + 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; +} + #endif -static UInt32 CrcCalc1(const Byte *buf, UInt32 size) + +static UInt32 CrcCalc1(const Byte *buf, size_t size) { UInt32 crc = CRC_INIT_VAL;; - for (UInt32 i = 0; i < size; i++) + for (size_t i = 0; i < size; i++) crc = CRC_UPDATE_BYTE(crc, buf[i]); return CRC_GET_DIGEST(crc); } -static void RandGen(Byte *buf, UInt32 size, CBaseRandomGenerator &RG) -{ - for (UInt32 i = 0; i < size; i++) - buf[i] = (Byte)RG.GetRnd(); -} - -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; @@ -1672,11 +2526,25 @@ struct CBenchMethod UInt32 DecComplexCompr; UInt32 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 +2558,42 @@ 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, 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, 4, 0, 4, "BCJ" }, + // { 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 +2604,25 @@ 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 +static const CBenchHash g_Hash[] = { - // UInt64 NumIterations1; // for Usage - UInt64 NumIterations2; // for Rating / RPU - - UInt64 Rating; - UInt64 Usage; - UInt64 RPU; + { 1, 1820, 0x21e207bb, "CRC32:1" }, + { 10, 558, 0x21e207bb, "CRC32:4" }, + { 10, 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 +2639,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); } @@ -1782,7 +2669,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 +2688,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 +2704,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 +2744,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 _7ZIP_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,19 +2873,30 @@ static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString, PrintNumber(f, (size >> 20), 6); else f.Print(" ?"); - f.Print(" MB, # "); + f.Print(" MB"); + + #ifdef _7ZIP_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; + UInt64 DictSize; bool Use2Columns; unsigned NameFieldSize; @@ -1930,7 +2947,7 @@ 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) { @@ -1963,26 +2980,29 @@ 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 HRESULT TotalBench( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands, + #ifndef _7ZIP_ST UInt32 numThreads, + const CAffinityMode *affinityMode, + #endif bool forceUnpackSize, size_t unpackSize, const Byte *fileData, @@ -1992,6 +3012,12 @@ static HRESULT TotalBench( { const CBenchMethod &bench = g_Bench[i]; 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; @@ -2011,7 +3037,10 @@ static HRESULT TotalBench( HRESULT res = MethodBench( EXTERNAL_CODECS_LOC_VARS complexInCommands, - false, numThreads, method, + #ifndef _7ZIP_ST + false, numThreads, affinityMode, + #endif + method, unpackSize2, fileData, bench.DictBits, printCallback, callback, &callback->BenchProps); @@ -2034,20 +3063,40 @@ 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 _7ZIP_ST + , const CAffinityMode *affinityMode + #endif + ); +}; + + +HRESULT CFreqBench::FreqBench(IBenchPrintCallback *_file + #ifndef _7ZIP_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; @@ -2055,17 +3104,26 @@ static HRESULT FreqBench( 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) + + bool mtMode = (numThreads > 1) || affinityMode->NeedAffinity(); + + if (mtMode) { + CFreqThreads threads; threads.Items = new CFreqInfo[numThreads]; UInt32 i; for (i = 0; i < numThreads; i++) @@ -2074,16 +3132,22 @@ 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); @@ -2096,11 +3160,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,17 +3182,17 @@ 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); - } + showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : CpuFreqRes) : 0, NULL); RINOK(_file->CheckBreak()); } @@ -2131,12 +3204,21 @@ 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 _7ZIP_ST + const CAffinityMode *affinityMode, + #endif + bool showRating, CTotalBenchRes *encodeRes, bool showFreq, UInt64 cpuFreq) { @@ -2147,7 +3229,7 @@ static HRESULT CrcBench( numThreads = 1; #endif - AString methodName = method.MethodName; + const AString &methodName = method.MethodName; // methodName.RemoveChar(L'-'); CMethodId hashID; if (!FindHashMethod( @@ -2155,81 +3237,112 @@ 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); + const size_t bsize = (bufferSize == 0 ? 1 : bufferSize); UInt64 numIterations = complexInCommands * 256 / complexity / bsize; if (numIterations == 0) numIterations = 1; CBenchInfoCalc progressInfoSpec; + CBenchInfo info; #ifndef _7ZIP_ST - CCrcThreads threads; - if (numThreads > 1) + bool mtEncMode = (numThreads > 1) || affinityMode->NeedAffinity(); + + 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); + 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)); @@ -2239,14 +3352,16 @@ static HRESULT CrcBench( 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,9 +3371,13 @@ 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); @@ -2267,15 +3386,23 @@ static HRESULT CrcBench( } speed = info.GetSpeed(unpSizeThreads); + usage = info.GetUsage(); return S_OK; } + + static HRESULT TotalBench_Hash( DECL_EXTERNAL_CODECS_LOC_VARS UInt64 complexInCommands, - UInt32 numThreads, UInt32 bufSize, + UInt32 numThreads, + size_t bufSize, + const Byte *fileData, IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback, + #ifndef _7ZIP_ST + const CAffinityMode *affinityMode, + #endif CTotalBenchRes *encodeRes, bool showFreq, UInt64 cpuFreq) { @@ -2292,15 +3419,22 @@ static HRESULT TotalBench_Hash( propVariant = bench.Name; RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant)); - UInt64 speed; + UInt64 speed, usage; + 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 _7ZIP_ST + affinityMode, + #endif + true, // showRating + encodeRes, showFreq, cpuFreq); if (res == E_NOTIMPL) { // callback->Print(" ---"); @@ -2333,110 +3467,18 @@ 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 += ')'; - } -} - -#endif - - -void GetCpuName(AString &s) -{ - s.Empty(); - - #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 - - #endif + PrintRequirements(f, "usage:", true, usage, "Benchmark threads: ", threads); } @@ -2446,38 +3488,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; + NSystem::CProcessAffinity threadsInfo; + threadsInfo.InitST(); + #ifndef _7ZIP_ST - numCPUs = NSystem::GetNumberOfProcessors(); + + 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 _7ZIP_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 +3576,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 +3616,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 _7ZIP_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; @@ -2548,19 +3692,14 @@ HRESULT Bench( if (name.IsPrefixedBy_Ascii_NoCase("mt")) { UString s = name.Ptr(2); - if (s == L"*") + 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)); #endif @@ -2574,19 +3713,26 @@ HRESULT Bench( 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) @@ -2603,12 +3749,18 @@ HRESULT Bench( 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,37 +3771,159 @@ 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(); + + /* 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 << 10; + if (specifiedFreq != 0) + { + while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000)) + numMilCommands >>= 1; + } + + for (int jj = 0;; jj++) + { + if (printCallback) + RINOK(printCallback->CheckBreak()); - if (jj >= 3) { - SetComplexCommands(testTime, false, mipsVal * 1000000, complexInCommands); - if (jj >= 8 || start >= freq) + // 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; + + HRESULT res = fb.FreqBench(NULL /* printCallback */ + #ifndef _7ZIP_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) + { + 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 int level = method.GetLevel(); if (method.MethodName.IsEmpty()) method.MethodName = "LZMA"; @@ -2658,18 +3932,33 @@ HRESULT Bench( { 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 _7ZIP_ST true, numThreadsSpecified, + &affinityMode, + #endif method, - uncompressedDataSize, fileDataBuffer.Buffer, + uncompressedDataSize, (const Byte *)fileDataBuffer, kOldLzmaDictBits, printCallback, benchCallback, &benchProps); } - AString methodName = method.MethodName; + AString methodName (method.MethodName); if (methodName.IsEqualTo_Ascii_NoCase("CRC")) methodName = "crc32"; method.MethodName = methodName; @@ -2680,96 +3969,199 @@ HRESULT Bench( if (!printCallback) return S_FALSE; IBenchPrintCallback &f = *printCallback; - if (!dictIsDefined) - dict = (1 << 24); + UInt64 dict64 = dict; + if (!dictIsDefined) + dict64 = (1 << 27); + if (use_fileData) + { + if (!dictIsDefined) + dict64 = fileDataBuffer.Size(); + else if (dict64 > fileDataBuffer.Size()) + dict64 = fileDataBuffer.Size(); + } // methhodName.RemoveChar(L'-'); UInt32 complexity = 10000; const UInt32 *checkSum = NULL; { - for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++) + unsigned i; + for (i = 0; i < 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; + 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; + bool isMainMathed = method.PropsString.IsEmpty(); + if (isMainMathed) + isMainMathed = !checkSum + || (benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps.IsEqualTo_Ascii_NoCase("8")); + const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps); + if (sameProps || isMainMathed) + { + complexity = h.Complex; + checkSum = &h.CheckSum; + if (sameProps) + break; + } } } + if (!checkSum) + return E_NOTIMPL; } + { + UInt64 usage = 1 << 20; + UInt64 bufSize = dict64; + if (use_fileData) + { + usage += fileDataBuffer.Size(); + if (bufSize > fileDataBuffer.Size()) + bufSize = fileDataBuffer.Size(); + #ifndef _7ZIP_ST + if (numThreadsSpecified != 1) + usage += bufSize * numThreadsSpecified * (k_Crc_CreateLocalBuf_For_File ? 1 : 0); + #endif + } + else + usage += numThreadsSpecified * bufSize; + Print_Usage_and_Threads(f, usage, numThreadsSpecified); + } + 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; + + const unsigned kFieldSize_CrcSpeed = 7; + CUIntVector numThreadsVector; + { + unsigned nt = numThreads_Start; + for (;;) + { + if (nt > numThreadsSpecified) + break; + numThreadsVector.Add(nt); + unsigned next = nt * 2; + UInt32 ntHalf= numThreadsSpecified / 2; + if (ntHalf > nt && ntHalf < next) + numThreadsVector.Add(ntHalf); + if (numThreadsSpecified > nt && numThreadsSpecified < next) + numThreadsVector.Add(numThreadsSpecified); + nt = next; + } + { + f.NewLine(); + f.Print("THRD"); + FOR_VECTOR (ti, numThreadsVector) + { + PrintNumber(f, numThreadsVector[ti], 1 + kFieldSize_Usage + kFieldSize_CrcSpeed); + } + } + { + f.NewLine(); + f.Print(" "); + FOR_VECTOR (ti, numThreadsVector) + { + PrintRight(f, "Usage", kFieldSize_Usage + 1); + PrintRight(f, "BW", kFieldSize_CrcSpeed + 1); + } + } + { + f.NewLine(); + f.Print("Size"); + FOR_VECTOR (ti, numThreadsVector) + { + PrintRight(f, "%", kFieldSize_Usage + 1); + PrintRight(f, "MB/s", kFieldSize_CrcSpeed + 1); + } + } } + f.NewLine(); f.NewLine(); - CTempValues speedTotals(numThreadsTests); + + CTempValues speedTotals(numThreadsVector.Size()); + CTempValues usageTotals(numThreadsVector.Size()); { - for (unsigned ti = 0; ti < numThreadsTests; ti++) + FOR_VECTOR (ti, numThreadsVector) + { speedTotals.Values[ti] = 0; + usageTotals.Values[ti] = 0; + } } UInt64 numSteps = 0; + for (UInt32 i = 0; i < numIterations; i++) { - for (unsigned pow = 10; pow < 32; pow++) + unsigned pow = 10; // kNumHashDictBits + if (startDicLog_Defined) + pow = startDicLog; + for (;; pow++) { - UInt32 bufSize = (UInt32)1 << pow; - if (bufSize > dict) - break; + const UInt64 bufSize = (UInt64)1 << pow; char s[16]; ConvertUInt32ToString(pow, s); unsigned pos = MyStringLen(s); s[pos++] = ':'; s[pos++] = ' '; s[pos] = 0; - f.Print(s); + PrintRight(f, s, 4); + + size_t dataSize = fileDataBuffer.Size(); + if (dataSize > bufSize || !use_fileData) + dataSize = (size_t)bufSize; - for (unsigned ti = 0; ti < numThreadsTests; ti++) + FOR_VECTOR (ti, numThreadsVector) { RINOK(f.CheckBreak()); - UInt32 t = GetNumThreadsNext(ti, numThreadsSpecified); + const UInt32 t = numThreadsVector[ti]; UInt64 speed = 0; - RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, - t, bufSize, speed, + UInt64 usage = 0; + + HRESULT res = CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands, + t, + dataSize, (const Byte *)fileDataBuffer, + speed, usage, complexity, 1, // benchWeight, - (pow == kNumHashDictBits) ? checkSum : NULL, method, NULL, NULL, false, 0)); - PrintNumber(f, (speed >> 20), kFieldSize_CrcSpeed); + (pow == kNumHashDictBits && !use_fileData) ? checkSum : NULL, + method, + &f, + #ifndef _7ZIP_ST + &affinityMode, + #endif + false, // showRating + NULL, false, 0); + + RINOK(res); + + PrintUsage(f, usage, kFieldSize_Usage); + PrintNumber(f, speed / 1000000, kFieldSize_CrcSpeed); speedTotals.Values[ti] += speed; + usageTotals.Values[ti] += usage; } + 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); + PrintUsage(f, usageTotals.Values[ti] / numSteps, kFieldSize_Usage); + PrintNumber(f, speedTotals.Values[ti] / numSteps / 1000000, kFieldSize_CrcSpeed); } f.NewLine(); } @@ -2827,7 +4219,7 @@ HRESULT Bench( f.NewLine(); } - if (!dictIsDefined) + if (!dictIsDefined && !onlyHashBench) { const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25); unsigned dicSizeLog = dicSizeLog_Main; @@ -2838,10 +4230,10 @@ HRESULT Bench( if (ramSize_Defined) for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) - if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize) + if (GetBenchMemoryUsage(numThreads, level, ((UInt64)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize) break; - dict = (UInt32)1 << dicSizeLog; + dict = (UInt64)1 << dicSizeLog; if (totalBenchMode && dicSizeLog != dicSizeLog_Main) { @@ -2851,7 +4243,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, level, dict, totalBenchMode), + numThreads); + + f.NewLine(); f.NewLine(); @@ -2934,6 +4332,7 @@ HRESULT Bench( if (specifiedFreq != 0) cpuFreq = specifiedFreq; + // bool showTotalSpeed = false; if (totalBenchMode) { @@ -2941,88 +4340,164 @@ 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; + + HRESULT res = fb.FreqBench(printCallback + #ifndef _7ZIP_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; + } + + HRESULT res = TotalBench(EXTERNAL_CODECS_LOC_VARS + complexInCommands, + #ifndef _7ZIP_ST + numThreads, + &affinityMode, + #endif + dictIsDefined || use_fileData, // forceUnpackSize + dataSize, + (const Byte *)fileDataBuffer, printCallback, &callback); 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; + } + + HRESULT res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads, + dataSize, (const Byte *)fileDataBuffer, + printCallback, &callback, + #ifndef _7ZIP_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; + + HRESULT res = fb.FreqBench(printCallback + #ifndef _7ZIP_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 < 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; + 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 == 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); @@ -3030,7 +4505,7 @@ HRESULT Bench( s[pos++] = ':'; s[pos] = 0; PrintLeft(f, s, kFieldSize_SmallName); - callback.DictSize = (UInt32)1 << pow; + callback.DictSize = (UInt64)1 << pow; COneMethodInfo method2 = method; @@ -3040,17 +4515,19 @@ 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; } @@ -3058,9 +4535,12 @@ HRESULT Bench( HRESULT res = MethodBench( EXTERNAL_CODECS_LOC_VARS complexInCommands, + #ifndef _7ZIP_ST true, numThreads, + &affinityMode, + #endif method2, - uncompressedDataSize, fileDataBuffer.Buffer, + uncompressedDataSize, (const Byte *)fileDataBuffer, kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps); f.NewLine(); RINOK(res); @@ -3083,16 +4563,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(); } |