diff options
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone')
5 files changed, 1928 insertions, 0 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp new file mode 100644 index 000000000..e34e2ed72 --- /dev/null +++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaAlone.cpp @@ -0,0 +1,531 @@ +// LzmaAlone.cpp + +#include "StdAfx.h" + +#include "../../../Common/MyWindows.h" +#include "../../../Common/MyInitGuid.h" + +#include <stdio.h> + +#if defined(_WIN32) || defined(OS2) || defined(MSDOS) +#include <fcntl.h> +#include <io.h> +#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY) +#else +#define MY_SET_BINARY_MODE(file) +#endif + +#include "../../../Common/CommandLineParser.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/StringToInt.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/StreamUtils.h" + +#include "../LzmaDecoder.h" +#include "../LzmaEncoder.h" + +#include "LzmaBenchCon.h" + +#ifndef _7ZIP_ST +#include "../../../Windows/System.h" +#endif + +#include "../../../../C/7zVersion.h" +#include "../../../../C/Alloc.h" +#include "../../../../C/LzmaUtil/Lzma86Dec.h" +#include "../../../../C/LzmaUtil/Lzma86Enc.h" + +using namespace NCommandLineParser; + +#ifdef _WIN32 +bool g_IsNT = false; +static inline bool IsItWindowsNT() +{ + OSVERSIONINFO versionInfo; + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + if (!::GetVersionEx(&versionInfo)) + return false; + return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); +} +#endif + +static const char *kCantAllocate = "Can not allocate memory"; +static const char *kReadError = "Read error"; +static const char *kWriteError = "Write error"; + +namespace NKey { +enum Enum +{ + kHelp1 = 0, + kHelp2, + kAlgo, + kDict, + kFb, + kMc, + kLc, + kLp, + kPb, + kMatchFinder, + kMultiThread, + kEOS, + kStdIn, + kStdOut, + kFilter86 +}; +} + +static const CSwitchForm kSwitchForms[] = +{ + { L"?", NSwitchType::kSimple, false }, + { L"H", NSwitchType::kSimple, false }, + { L"A", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"D", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"FB", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"MC", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"LC", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"LP", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"PB", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"MF", NSwitchType::kUnLimitedPostString, false, 1 }, + { L"MT", NSwitchType::kUnLimitedPostString, false, 0 }, + { L"EOS", NSwitchType::kSimple, false }, + { L"SI", NSwitchType::kSimple, false }, + { L"SO", NSwitchType::kSimple, false }, + { L"F86", NSwitchType::kPostChar, false, 0, 0, L"+" } +}; + +static const int kNumSwitches = sizeof(kSwitchForms) / sizeof(kSwitchForms[0]); + +static void PrintHelp() +{ + fprintf(stderr, "\nUsage: LZMA <e|d> inputFile outputFile [<switches>...]\n" + " e: encode file\n" + " d: decode file\n" + " b: Benchmark\n" + "<Switches>\n" + " -a{N}: set compression mode - [0, 1], default: 1 (max)\n" + " -d{N}: set dictionary size - [12, 30], default: 23 (8MB)\n" + " -fb{N}: set number of fast bytes - [5, 273], default: 128\n" + " -mc{N}: set number of cycles for match finder\n" + " -lc{N}: set number of literal context bits - [0, 8], default: 3\n" + " -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" + " -pb{N}: set number of pos bits - [0, 4], default: 2\n" + " -mf{MF_ID}: set Match Finder: [bt2, bt3, bt4, hc4], default: bt4\n" + " -mt{N}: set number of CPU threads\n" + " -eos: write End Of Stream marker\n" + " -si: read data from stdin\n" + " -so: write data to stdout\n" + ); +} + +static void PrintHelpAndExit(const char *s) +{ + fprintf(stderr, "\nError: %s\n\n", s); + PrintHelp(); + throw -1; +} + +static void IncorrectCommand() +{ + PrintHelpAndExit("Incorrect command"); +} + +static void WriteArgumentsToStringList(int numArguments, const char *arguments[], + UStringVector &strings) +{ + for(int i = 1; i < numArguments; i++) + strings.Add(MultiByteToUnicodeString(arguments[i])); +} + +static bool GetNumber(const wchar_t *s, UInt32 &value) +{ + value = 0; + if (MyStringLen(s) == 0) + return false; + const wchar_t *end; + UInt64 res = ConvertStringToUInt64(s, &end); + if (*end != L'\0') + return false; + if (res > 0xFFFFFFFF) + return false; + value = UInt32(res); + return true; +} + +static void ParseUInt32(const CParser &parser, int index, UInt32 &res) +{ + if (parser[index].ThereIs) + if (!GetNumber(parser[index].PostStrings[0], res)) + IncorrectCommand(); +} + +int main2(int n, const char *args[]) +{ + #ifdef _WIN32 + g_IsNT = IsItWindowsNT(); + #endif + + fprintf(stderr, "\nLZMA " MY_VERSION_COPYRIGHT_DATE "\n"); + + if (n == 1) + { + PrintHelp(); + return 0; + } + + bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 4); + if (unsupportedTypes) + { + fprintf(stderr, "Unsupported base types. Edit Common/Types.h and recompile"); + return 1; + } + + UStringVector commandStrings; + WriteArgumentsToStringList(n, args, commandStrings); + CParser parser(kNumSwitches); + try + { + parser.ParseStrings(kSwitchForms, commandStrings); + } + catch(...) + { + IncorrectCommand(); + } + + if(parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs) + { + PrintHelp(); + return 0; + } + const UStringVector &nonSwitchStrings = parser.NonSwitchStrings; + + int paramIndex = 0; + if (paramIndex >= nonSwitchStrings.Size()) + IncorrectCommand(); + const UString &command = nonSwitchStrings[paramIndex++]; + + bool dictDefined = false; + UInt32 dict = (UInt32)-1; + if(parser[NKey::kDict].ThereIs) + { + UInt32 dicLog; + if (!GetNumber(parser[NKey::kDict].PostStrings[0], dicLog)) + IncorrectCommand(); + dict = 1 << dicLog; + dictDefined = true; + } + UString mf = L"BT4"; + if (parser[NKey::kMatchFinder].ThereIs) + mf = parser[NKey::kMatchFinder].PostStrings[0]; + + UInt32 numThreads = (UInt32)-1; + + #ifndef _7ZIP_ST + if (parser[NKey::kMultiThread].ThereIs) + { + UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors(); + const UString &s = parser[NKey::kMultiThread].PostStrings[0]; + if (s.IsEmpty()) + numThreads = numCPUs; + else + if (!GetNumber(s, numThreads)) + IncorrectCommand(); + } + #endif + + if (command.CompareNoCase(L"b") == 0) + { + const UInt32 kNumDefaultItereations = 1; + UInt32 numIterations = kNumDefaultItereations; + { + if (paramIndex < nonSwitchStrings.Size()) + if (!GetNumber(nonSwitchStrings[paramIndex++], numIterations)) + numIterations = kNumDefaultItereations; + } + return LzmaBenchCon(stderr, numIterations, numThreads, dict); + } + + if (numThreads == (UInt32)-1) + numThreads = 1; + + bool encodeMode = false; + if (command.CompareNoCase(L"e") == 0) + encodeMode = true; + else if (command.CompareNoCase(L"d") == 0) + encodeMode = false; + else + IncorrectCommand(); + + bool stdInMode = parser[NKey::kStdIn].ThereIs; + bool stdOutMode = parser[NKey::kStdOut].ThereIs; + + CMyComPtr<ISequentialInStream> inStream; + CInFileStream *inStreamSpec = 0; + if (stdInMode) + { + inStream = new CStdInFileStream; + MY_SET_BINARY_MODE(stdin); + } + else + { + if (paramIndex >= nonSwitchStrings.Size()) + IncorrectCommand(); + const UString &inputName = nonSwitchStrings[paramIndex++]; + inStreamSpec = new CInFileStream; + inStream = inStreamSpec; + if (!inStreamSpec->Open(GetSystemString(inputName))) + { + fprintf(stderr, "\nError: can not open input file %s\n", + (const char *)GetOemString(inputName)); + return 1; + } + } + + CMyComPtr<ISequentialOutStream> outStream; + COutFileStream *outStreamSpec = NULL; + if (stdOutMode) + { + outStream = new CStdOutFileStream; + MY_SET_BINARY_MODE(stdout); + } + else + { + if (paramIndex >= nonSwitchStrings.Size()) + IncorrectCommand(); + const UString &outputName = nonSwitchStrings[paramIndex++]; + outStreamSpec = new COutFileStream; + outStream = outStreamSpec; + if (!outStreamSpec->Create(GetSystemString(outputName), true)) + { + fprintf(stderr, "\nError: can not open output file %s\n", + (const char *)GetOemString(outputName)); + return 1; + } + } + + if (parser[NKey::kFilter86].ThereIs) + { + // -f86 switch is for x86 filtered mode: BCJ + LZMA. + if (parser[NKey::kEOS].ThereIs || stdInMode) + throw "Can not use stdin in this mode"; + UInt64 fileSize; + inStreamSpec->File.GetLength(fileSize); + if (fileSize > 0xF0000000) + throw "File is too big"; + size_t inSize = (size_t)fileSize; + Byte *inBuffer = 0; + if (inSize != 0) + { + inBuffer = (Byte *)MyAlloc((size_t)inSize); + if (inBuffer == 0) + throw kCantAllocate; + } + + if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK) + throw "Can not read"; + + Byte *outBuffer = 0; + size_t outSize; + if (encodeMode) + { + // we allocate 105% of original size for output buffer + outSize = (size_t)fileSize / 20 * 21 + (1 << 16); + if (outSize != 0) + { + outBuffer = (Byte *)MyAlloc((size_t)outSize); + if (outBuffer == 0) + throw kCantAllocate; + } + if (!dictDefined) + dict = 1 << 23; + int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize, + 5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO); + if (res != 0) + { + fprintf(stderr, "\nEncoder error = %d\n", (int)res); + return 1; + } + } + else + { + UInt64 outSize64; + if (Lzma86_GetUnpackSize(inBuffer, inSize, &outSize64) != 0) + throw "data error"; + outSize = (size_t)outSize64; + if (outSize != outSize64) + throw "too big"; + if (outSize != 0) + { + outBuffer = (Byte *)MyAlloc(outSize); + if (outBuffer == 0) + throw kCantAllocate; + } + int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize); + if (inSize != (size_t)fileSize) + throw "incorrect processed size"; + if (res != 0) + throw "LzmaDecoder error"; + } + if (WriteStream(outStream, outBuffer, outSize) != S_OK) + throw kWriteError; + MyFree(outBuffer); + MyFree(inBuffer); + return 0; + } + + + UInt64 fileSize; + if (encodeMode) + { + NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder; + CMyComPtr<ICompressCoder> encoder = encoderSpec; + + if (!dictDefined) + dict = 1 << 23; + + UInt32 pb = 2; + UInt32 lc = 3; // = 0; for 32-bit data + UInt32 lp = 0; // = 2; for 32-bit data + UInt32 algo = 1; + UInt32 fb = 128; + UInt32 mc = 16 + fb / 2; + bool mcDefined = false; + + bool eos = parser[NKey::kEOS].ThereIs || stdInMode; + + ParseUInt32(parser, NKey::kAlgo, algo); + ParseUInt32(parser, NKey::kFb, fb); + ParseUInt32(parser, NKey::kLc, lc); + ParseUInt32(parser, NKey::kLp, lp); + ParseUInt32(parser, NKey::kPb, pb); + + mcDefined = parser[NKey::kMc].ThereIs; + if (mcDefined) + if (!GetNumber(parser[NKey::kMc].PostStrings[0], mc)) + IncorrectCommand(); + + PROPID propIDs[] = + { + NCoderPropID::kDictionarySize, + NCoderPropID::kPosStateBits, + NCoderPropID::kLitContextBits, + NCoderPropID::kLitPosBits, + NCoderPropID::kAlgorithm, + NCoderPropID::kNumFastBytes, + NCoderPropID::kMatchFinder, + NCoderPropID::kEndMarker, + NCoderPropID::kNumThreads, + NCoderPropID::kMatchFinderCycles, + }; + const int kNumPropsMax = sizeof(propIDs) / sizeof(propIDs[0]); + + PROPVARIANT props[kNumPropsMax]; + for (int p = 0; p < 6; p++) + props[p].vt = VT_UI4; + + props[0].ulVal = (UInt32)dict; + props[1].ulVal = (UInt32)pb; + props[2].ulVal = (UInt32)lc; + props[3].ulVal = (UInt32)lp; + props[4].ulVal = (UInt32)algo; + props[5].ulVal = (UInt32)fb; + + props[6].vt = VT_BSTR; + props[6].bstrVal = (BSTR)(const wchar_t *)mf; + + props[7].vt = VT_BOOL; + props[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE; + + props[8].vt = VT_UI4; + props[8].ulVal = (UInt32)numThreads; + + // it must be last in property list + props[9].vt = VT_UI4; + props[9].ulVal = (UInt32)mc; + + int numProps = kNumPropsMax; + if (!mcDefined) + numProps--; + + if (encoderSpec->SetCoderProperties(propIDs, props, numProps) != S_OK) + IncorrectCommand(); + encoderSpec->WriteCoderProperties(outStream); + + if (eos || stdInMode) + fileSize = (UInt64)(Int64)-1; + else + inStreamSpec->File.GetLength(fileSize); + + for (int i = 0; i < 8; i++) + { + Byte b = Byte(fileSize >> (8 * i)); + if (outStream->Write(&b, 1, 0) != S_OK) + { + fprintf(stderr, kWriteError); + return 1; + } + } + HRESULT result = encoder->Code(inStream, outStream, 0, 0, 0); + if (result == E_OUTOFMEMORY) + { + fprintf(stderr, "\nError: Can not allocate memory\n"); + return 1; + } + else if (result != S_OK) + { + fprintf(stderr, "\nEncoder error = %X\n", (unsigned int)result); + return 1; + } + } + else + { + NCompress::NLzma::CDecoder *decoderSpec = new NCompress::NLzma::CDecoder; + CMyComPtr<ICompressCoder> decoder = decoderSpec; + decoderSpec->FinishStream = true; + const UInt32 kPropertiesSize = 5; + Byte header[kPropertiesSize + 8]; + if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK) + { + fprintf(stderr, kReadError); + return 1; + } + if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK) + { + fprintf(stderr, "SetDecoderProperties error"); + return 1; + } + fileSize = 0; + for (int i = 0; i < 8; i++) + fileSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i); + + if (decoder->Code(inStream, outStream, 0, (fileSize == (UInt64)(Int64)-1) ? 0 : &fileSize, 0) != S_OK) + { + fprintf(stderr, "Decoder error"); + return 1; + } + } + if (outStreamSpec != NULL) + { + if (outStreamSpec->Close() != S_OK) + { + fprintf(stderr, "File closing error"); + return 1; + } + } + return 0; +} + +int MY_CDECL main(int n, const char *args[]) +{ + try { return main2(n, args); } + catch(const char *s) + { + fprintf(stderr, "\nError: %s\n", s); + return 1; + } + catch(...) + { + fprintf(stderr, "\nError\n"); + return 1; + } +} diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp new file mode 100644 index 000000000..6a325fe06 --- /dev/null +++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.cpp @@ -0,0 +1,1018 @@ +// LzmaBench.cpp + +#include "StdAfx.h" + +#include "LzmaBench.h" + +#ifndef _WIN32 +#define USE_POSIX_TIME +#define USE_POSIX_TIME2 +#endif + +#ifdef USE_POSIX_TIME +#include <time.h> +#ifdef USE_POSIX_TIME2 +#include <sys/time.h> +#endif +#endif + +#ifdef _WIN32 +#define USE_ALLOCA +#endif + +#ifdef USE_ALLOCA +#ifdef _WIN32 +#include <malloc.h> +#else +#include <stdlib.h> +#endif +#endif + +#include "../../../../C/7zCrc.h" +#include "../../../../C/Alloc.h" + +#include "../../../Common/MyCom.h" + +#ifdef BENCH_MT +#include "../../../Windows/Synchronization.h" +#include "../../../Windows/Thread.h" +#endif + +#ifdef EXTERNAL_LZMA +#include "../../../Windows/PropVariant.h" +#include "../../ICoder.h" +#else +#include "../LzmaDecoder.h" +#include "../LzmaEncoder.h" +#endif + +static const UInt32 kUncompressMinBlockSize = 1 << 26; +static const UInt32 kAdditionalSize = (1 << 16); +static const UInt32 kCompressedAdditionalSize = (1 << 10); +static const UInt32 kMaxLzmaPropSize = 5; + +class CBaseRandomGenerator +{ + UInt32 A1; + UInt32 A2; +public: + CBaseRandomGenerator() { Init(); } + void Init() { A1 = 362436069; A2 = 521288629;} + UInt32 GetRnd() + { + return + ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) + + ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) ); + } +}; + +class CBenchBuffer +{ +public: + size_t BufferSize; + Byte *Buffer; + CBenchBuffer(): Buffer(0) {} + virtual ~CBenchBuffer() { Free(); } + void Free() + { + ::MidFree(Buffer); + Buffer = 0; + } + bool Alloc(size_t bufferSize) + { + if (Buffer != 0 && BufferSize == bufferSize) + return true; + Free(); + Buffer = (Byte *)::MidAlloc(bufferSize); + BufferSize = bufferSize; + return (Buffer != 0); + } +}; + +class CBenchRandomGenerator: public CBenchBuffer +{ + CBaseRandomGenerator *RG; +public: + void Set(CBaseRandomGenerator *rg) { RG = rg; } + UInt32 GetVal(UInt32 &res, int numBits) + { + UInt32 val = res & (((UInt32)1 << numBits) - 1); + res >>= numBits; + return val; + } + UInt32 GetLen(UInt32 &res) + { + UInt32 len = GetVal(res, 2); + return GetVal(res, 1 + len); + } + void Generate() + { + UInt32 pos = 0; + UInt32 rep0 = 1; + while (pos < BufferSize) + { + UInt32 res = RG->GetRnd(); + res >>= 1; + if (GetVal(res, 1) == 0 || pos < 1024) + Buffer[pos++] = (Byte)(res & 0xFF); + else + { + UInt32 len; + len = 1 + GetLen(res); + if (GetVal(res, 3) != 0) + { + len += GetLen(res); + do + { + UInt32 ppp = GetVal(res, 5) + 6; + res = RG->GetRnd(); + if (ppp > 30) + continue; + rep0 = /* (1 << ppp) +*/ GetVal(res, ppp); + res = RG->GetRnd(); + } + while (rep0 >= pos); + rep0++; + } + + for (UInt32 i = 0; i < len && pos < BufferSize; i++, pos++) + Buffer[pos] = Buffer[pos - rep0]; + } + } + } +}; + + +class CBenchmarkInStream: + public ISequentialInStream, + public CMyUnknownImp +{ + const Byte *Data; + size_t Pos; + size_t Size; +public: + MY_UNKNOWN_IMP + void Init(const Byte *data, size_t size) + { + Data = data; + Size = size; + Pos = 0; + } + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + size_t remain = Size - Pos; + UInt32 kMaxBlockSize = (1 << 20); + if (size > kMaxBlockSize) + size = kMaxBlockSize; + if (size > remain) + size = (UInt32)remain; + for (UInt32 i = 0; i < size; i++) + ((Byte *)data)[i] = Data[Pos + i]; + Pos += size; + if(processedSize != NULL) + *processedSize = size; + return S_OK; +} + +class CBenchmarkOutStream: + public ISequentialOutStream, + public CBenchBuffer, + public CMyUnknownImp +{ + // bool _overflow; +public: + UInt32 Pos; + // CBenchmarkOutStream(): _overflow(false) {} + void Init() + { + // _overflow = false; + Pos = 0; + } + MY_UNKNOWN_IMP + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + size_t curSize = BufferSize - Pos; + if (curSize > size) + curSize = size; + memcpy(Buffer + Pos, data, curSize); + Pos += (UInt32)curSize; + if(processedSize != NULL) + *processedSize = (UInt32)curSize; + if (curSize != size) + { + // _overflow = true; + return E_FAIL; + } + return S_OK; +} + +class CCrcOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + UInt32 Crc; + MY_UNKNOWN_IMP + void Init() { Crc = CRC_INIT_VAL; } + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + Crc = CrcUpdate(Crc, data, size); + if (processedSize != NULL) + *processedSize = size; + return S_OK; +} + +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)time(NULL) * 1000000; + #else + return time(NULL); + #endif + #else + /* + LARGE_INTEGER value; + if (::QueryPerformanceCounter(&value)) + return value.QuadPart; + */ + return GetTickCount(); + #endif +} + +static UInt64 GetFreq() +{ + #ifdef USE_POSIX_TIME + #ifdef USE_POSIX_TIME2 + return 1000000; + #else + return 1; + #endif + #else + /* + LARGE_INTEGER value; + if (::QueryPerformanceFrequency(&value)) + return value.QuadPart; + */ + return 1000; + #endif +} + +#ifndef USE_POSIX_TIME +static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; } +#endif +static UInt64 GetUserTime() +{ + #ifdef USE_POSIX_TIME + return clock(); + #else + FILETIME creationTime, exitTime, kernelTime, userTime; + if (::GetProcessTimes(::GetCurrentProcess(), &creationTime, &exitTime, &kernelTime, &userTime) != 0) + return GetTime64(userTime) + GetTime64(kernelTime); + return (UInt64)GetTickCount() * 10000; + #endif +} + +static UInt64 GetUserFreq() +{ + #ifdef USE_POSIX_TIME + return CLOCKS_PER_SEC; + #else + return 10000000; + #endif +} + +class CBenchProgressStatus +{ + #ifdef BENCH_MT + NWindows::NSynchronization::CCriticalSection CS; + #endif +public: + HRESULT Res; + bool EncodeMode; + void SetResult(HRESULT res) + { + #ifdef BENCH_MT + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + #endif + Res = res; + } + HRESULT GetResult() + { + #ifdef BENCH_MT + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + #endif + return Res; + } +}; + +class CBenchProgressInfo: + public ICompressProgressInfo, + public CMyUnknownImp +{ +public: + CBenchProgressStatus *Status; + CBenchInfo BenchInfo; + HRESULT Res; + IBenchCallback *callback; + CBenchProgressInfo(): callback(0) {} + MY_UNKNOWN_IMP + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +void SetStartTime(CBenchInfo &bi) +{ + bi.GlobalFreq = GetFreq(); + bi.UserFreq = GetUserFreq(); + bi.GlobalTime = ::GetTimeCount(); + bi.UserTime = ::GetUserTime(); +} + +void SetFinishTime(const CBenchInfo &biStart, CBenchInfo &dest) +{ + dest.GlobalFreq = GetFreq(); + dest.UserFreq = GetUserFreq(); + dest.GlobalTime = ::GetTimeCount() - biStart.GlobalTime; + dest.UserTime = ::GetUserTime() - biStart.UserTime; +} + +STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + HRESULT res = Status->GetResult(); + if (res != S_OK) + return res; + if (!callback) + return res; + CBenchInfo info = BenchInfo; + SetFinishTime(BenchInfo, info); + if (Status->EncodeMode) + { + info.UnpackSize = *inSize; + info.PackSize = *outSize; + res = callback->SetEncodeResult(info, false); + } + else + { + info.PackSize = BenchInfo.PackSize + *inSize; + info.UnpackSize = BenchInfo.UnpackSize + *outSize; + res = callback->SetDecodeResult(info, false); + } + if (res != S_OK) + Status->SetResult(res); + return res; +} + +static const int kSubBits = 8; + +static UInt32 GetLogSize(UInt32 size) +{ + for (int 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); +} + +static void NormalizeVals(UInt64 &v1, UInt64 &v2) +{ + while (v1 > 1000000) + { + v1 >>= 1; + v2 >>= 1; + } +} + +UInt64 GetUsage(const CBenchInfo &info) +{ + UInt64 userTime = info.UserTime; + UInt64 userFreq = info.UserFreq; + UInt64 globalTime = info.GlobalTime; + UInt64 globalFreq = info.GlobalFreq; + NormalizeVals(userTime, userFreq); + NormalizeVals(globalFreq, globalTime); + if (userFreq == 0) + userFreq = 1; + if (globalTime == 0) + globalTime = 1; + return userTime * globalFreq * 1000000 / userFreq / globalTime; +} + +UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating) +{ + UInt64 userTime = info.UserTime; + UInt64 userFreq = info.UserFreq; + UInt64 globalTime = info.GlobalTime; + UInt64 globalFreq = info.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; +} + +UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size) +{ + UInt64 t = GetLogSize(dictionarySize) - (kBenchMinDicLogSize << kSubBits); + UInt64 numCommandsForOne = 870 + ((t * t * 5) >> (2 * kSubBits)); + UInt64 numCommands = (UInt64)(size) * numCommandsForOne; + return MyMultDiv64(numCommands, elapsedTime, freq); +} + +UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations) +{ + UInt64 numCommands = (inSize * 200 + outSize * 4) * numIterations; + return MyMultDiv64(numCommands, elapsedTime, freq); +} + +#ifdef EXTERNAL_LZMA +typedef UInt32 (WINAPI * CreateObjectPointer)(const GUID *clsID, + const GUID *interfaceID, void **outObject); +#endif + +struct CEncoderInfo; + +struct CEncoderInfo +{ + #ifdef BENCH_MT + NWindows::CThread thread[2]; + #endif + CMyComPtr<ICompressCoder> encoder; + CBenchProgressInfo *progressInfoSpec[2]; + CMyComPtr<ICompressProgressInfo> progressInfo[2]; + UInt32 NumIterations; + #ifdef USE_ALLOCA + size_t AllocaSize; + #endif + + struct CDecoderInfo + { + CEncoderInfo *Encoder; + UInt32 DecoderIndex; + #ifdef USE_ALLOCA + size_t AllocaSize; + #endif + bool CallbackMode; + }; + CDecoderInfo decodersInfo[2]; + + CMyComPtr<ICompressCoder> decoders[2]; + HRESULT Results[2]; + CBenchmarkOutStream *outStreamSpec; + CMyComPtr<ISequentialOutStream> outStream; + IBenchCallback *callback; + UInt32 crc; + UInt32 kBufferSize; + UInt32 compressedSize; + CBenchRandomGenerator rg; + CBenchmarkOutStream *propStreamSpec; + CMyComPtr<ISequentialOutStream> propStream; + HRESULT Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rg); + HRESULT Encode(); + HRESULT Decode(UInt32 decoderIndex); + + CEncoderInfo(): outStreamSpec(0), callback(0), propStreamSpec(0) {} + + #ifdef BENCH_MT + static THREAD_FUNC_DECL EncodeThreadFunction(void *param) + { + CEncoderInfo *encoder = (CEncoderInfo *)param; + #ifdef USE_ALLOCA + alloca(encoder->AllocaSize); + #endif + HRESULT res = encoder->Encode(); + encoder->Results[0] = res; + if (res != S_OK) + encoder->progressInfoSpec[0]->Status->SetResult(res); + + return 0; + } + static THREAD_FUNC_DECL DecodeThreadFunction(void *param) + { + CDecoderInfo *decoder = (CDecoderInfo *)param; + #ifdef USE_ALLOCA + alloca(decoder->AllocaSize); + #endif + CEncoderInfo *encoder = decoder->Encoder; + encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex); + return 0; + } + + HRESULT CreateEncoderThread() + { + return thread[0].Create(EncodeThreadFunction, this); + } + + HRESULT CreateDecoderThread(int index, bool callbackMode + #ifdef USE_ALLOCA + , size_t allocaSize + #endif + ) + { + CDecoderInfo &decoder = decodersInfo[index]; + decoder.DecoderIndex = index; + decoder.Encoder = this; + #ifdef USE_ALLOCA + decoder.AllocaSize = allocaSize; + #endif + decoder.CallbackMode = callbackMode; + return thread[index].Create(DecodeThreadFunction, &decoder); + } + #endif +}; + +HRESULT CEncoderInfo::Init(UInt32 dictionarySize, UInt32 numThreads, CBaseRandomGenerator *rgLoc) +{ + rg.Set(rgLoc); + kBufferSize = dictionarySize + kAdditionalSize; + UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize; + if (!rg.Alloc(kBufferSize)) + return E_OUTOFMEMORY; + rg.Generate(); + crc = CrcCalc(rg.Buffer, rg.BufferSize); + + outStreamSpec = new CBenchmarkOutStream; + if (!outStreamSpec->Alloc(kCompressedBufferSize)) + return E_OUTOFMEMORY; + + outStream = outStreamSpec; + + propStreamSpec = 0; + if (!propStream) + { + propStreamSpec = new CBenchmarkOutStream; + propStream = propStreamSpec; + } + if (!propStreamSpec->Alloc(kMaxLzmaPropSize)) + return E_OUTOFMEMORY; + propStreamSpec->Init(); + + PROPID propIDs[] = + { + NCoderPropID::kDictionarySize, + NCoderPropID::kNumThreads + }; + const int kNumProps = sizeof(propIDs) / sizeof(propIDs[0]); + PROPVARIANT props[kNumProps]; + props[0].vt = VT_UI4; + props[0].ulVal = dictionarySize; + + props[1].vt = VT_UI4; + props[1].ulVal = numThreads; + + { + CMyComPtr<ICompressSetCoderProperties> setCoderProperties; + RINOK(encoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProperties)); + if (!setCoderProperties) + return E_FAIL; + RINOK(setCoderProperties->SetCoderProperties(propIDs, props, kNumProps)); + + CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties; + encoder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProperties); + if (writeCoderProperties) + { + RINOK(writeCoderProperties->WriteCoderProperties(propStream)); + } + } + return S_OK; +} + +HRESULT CEncoderInfo::Encode() +{ + CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; + CMyComPtr<ISequentialInStream> inStream = inStreamSpec; + inStreamSpec->Init(rg.Buffer, rg.BufferSize); + outStreamSpec->Init(); + + RINOK(encoder->Code(inStream, outStream, 0, 0, progressInfo[0])); + compressedSize = outStreamSpec->Pos; + encoder.Release(); + return S_OK; +} + +HRESULT CEncoderInfo::Decode(UInt32 decoderIndex) +{ + CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream; + CMyComPtr<ISequentialInStream> inStream = inStreamSpec; + CMyComPtr<ICompressCoder> &decoder = decoders[decoderIndex]; + + CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties; + decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &compressSetDecoderProperties); + if (!compressSetDecoderProperties) + return E_FAIL; + + CCrcOutStream *crcOutStreamSpec = new CCrcOutStream; + CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec; + + CBenchProgressInfo *pi = progressInfoSpec[decoderIndex]; + pi->BenchInfo.UnpackSize = 0; + pi->BenchInfo.PackSize = 0; + + for (UInt32 j = 0; j < NumIterations; j++) + { + inStreamSpec->Init(outStreamSpec->Buffer, compressedSize); + crcOutStreamSpec->Init(); + + RINOK(compressSetDecoderProperties->SetDecoderProperties2(propStreamSpec->Buffer, propStreamSpec->Pos)); + UInt64 outSize = kBufferSize; + RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex])); + if (CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc) + return S_FALSE; + pi->BenchInfo.UnpackSize += kBufferSize; + pi->BenchInfo.PackSize += compressedSize; + } + decoder.Release(); + return S_OK; +} + +static const UInt32 kNumThreadsMax = (1 << 16); + +struct CBenchEncoders +{ + CEncoderInfo *encoders; + CBenchEncoders(UInt32 num): encoders(0) { encoders = new CEncoderInfo[num]; } + ~CBenchEncoders() { delete []encoders; } +}; + +HRESULT LzmaBench( + #ifdef EXTERNAL_LZMA + CCodecs *codecs, + #endif + UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback) +{ + UInt32 numEncoderThreads = + #ifdef BENCH_MT + (numThreads > 1 ? numThreads / 2 : 1); + #else + 1; + #endif + UInt32 numSubDecoderThreads = + #ifdef BENCH_MT + (numThreads > 1 ? 2 : 1); + #else + 1; + #endif + if (dictionarySize < (1 << kBenchMinDicLogSize) || numThreads < 1 || numEncoderThreads > kNumThreadsMax) + { + return E_INVALIDARG; + } + + CBenchEncoders encodersSpec(numEncoderThreads); + CEncoderInfo *encoders = encodersSpec.encoders; + + #ifdef EXTERNAL_LZMA + UString name = L"LZMA"; + #endif + + UInt32 i; + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + encoder.callback = (i == 0) ? callback : 0; + + #ifdef EXTERNAL_LZMA + RINOK(codecs->CreateCoder(name, true, encoder.encoder)); + #else + encoder.encoder = new NCompress::NLzma::CEncoder; + #endif + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + #ifdef EXTERNAL_LZMA + RINOK(codecs->CreateCoder(name, false, encoder.decoders[j])); + #else + encoder.decoders[j] = new NCompress::NLzma::CDecoder; + #endif + } + } + + CBaseRandomGenerator rg; + rg.Init(); + for (i = 0; i < numEncoderThreads; i++) + { + RINOK(encoders[i].Init(dictionarySize, numThreads, &rg)); + } + + CBenchProgressStatus status; + status.Res = S_OK; + status.EncodeMode = true; + + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + for (int j = 0; j < 2; j++) + { + encoder.progressInfo[j] = encoder.progressInfoSpec[j] = new CBenchProgressInfo; + encoder.progressInfoSpec[j]->Status = &status; + } + if (i == 0) + { + encoder.progressInfoSpec[0]->callback = callback; + encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numEncoderThreads; + SetStartTime(encoder.progressInfoSpec[0]->BenchInfo); + } + + #ifdef BENCH_MT + if (numEncoderThreads > 1) + { + #ifdef USE_ALLOCA + encoder.AllocaSize = (i * 16 * 21) & 0x7FF; + #endif + RINOK(encoder.CreateEncoderThread()) + } + else + #endif + { + RINOK(encoder.Encode()); + } + } + #ifdef BENCH_MT + if (numEncoderThreads > 1) + for (i = 0; i < numEncoderThreads; i++) + encoders[i].thread[0].Wait(); + #endif + + RINOK(status.Res); + + CBenchInfo info; + + SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info); + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = 1; // progressInfoSpec->NumIterations; + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + info.UnpackSize += encoder.kBufferSize; + info.PackSize += encoder.compressedSize; + } + RINOK(callback->SetEncodeResult(info, true)); + + + status.Res = S_OK; + status.EncodeMode = false; + + UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads; + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + encoder.NumIterations = 2 + kUncompressMinBlockSize / encoder.kBufferSize; + + if (i == 0) + { + encoder.progressInfoSpec[0]->callback = callback; + encoder.progressInfoSpec[0]->BenchInfo.NumIterations = numDecoderThreads; + SetStartTime(encoder.progressInfoSpec[0]->BenchInfo); + } + + #ifdef BENCH_MT + if (numDecoderThreads > 1) + { + for (UInt32 j = 0; j < numSubDecoderThreads; j++) + { + HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0) + #ifdef USE_ALLOCA + , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF + #endif + ); + RINOK(res); + } + } + else + #endif + { + RINOK(encoder.Decode(0)); + } + } + #ifdef BENCH_MT + HRESULT res = S_OK; + if (numDecoderThreads > 1) + 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]; + } + RINOK(res); + #endif + RINOK(status.Res); + SetFinishTime(encoders[0].progressInfoSpec[0]->BenchInfo, info); + info.UnpackSize = 0; + info.PackSize = 0; + info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations; + for (i = 0; i < numEncoderThreads; i++) + { + CEncoderInfo &encoder = encoders[i]; + info.UnpackSize += encoder.kBufferSize; + info.PackSize += encoder.compressedSize; + } + RINOK(callback->SetDecodeResult(info, false)); + RINOK(callback->SetDecodeResult(info, true)); + return S_OK; +} + + +inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary) +{ + UInt32 hs = dictionary - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; + if (hs > (1 << 24)) + hs >>= 1; + hs++; + return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 + + (1 << 20) + (multiThread ? (6 << 20) : 0); +} + +UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary) +{ + const UInt32 kBufferSize = dictionary; + const UInt32 kCompressedBufferSize = (kBufferSize / 2); + UInt32 numSubThreads = (numThreads > 1) ? 2 : 1; + UInt32 numBigThreads = numThreads / numSubThreads; + return (kBufferSize + kCompressedBufferSize + + GetLZMAUsage((numThreads > 1), dictionary) + (2 << 20)) * numBigThreads; +} + +static bool CrcBig(const void *data, UInt32 size, UInt32 numCycles, UInt32 crcBase) +{ + for (UInt32 i = 0; i < numCycles; i++) + if (CrcCalc(data, size) != crcBase) + return false; + return true; +} + +#ifdef BENCH_MT +struct CCrcInfo +{ + NWindows::CThread Thread; + const Byte *Data; + UInt32 Size; + UInt32 NumCycles; + UInt32 Crc; + bool Res; + void Wait() + { + Thread.Wait(); + Thread.Close(); + } +}; + +static THREAD_FUNC_DECL CrcThreadFunction(void *param) +{ + CCrcInfo *p = (CCrcInfo *)param; + p->Res = CrcBig(p->Data, p->Size, p->NumCycles, p->Crc); + return 0; +} + +struct CCrcThreads +{ + UInt32 NumThreads; + CCrcInfo *Items; + CCrcThreads(): Items(0), NumThreads(0) {} + void WaitAll() + { + for (UInt32 i = 0; i < NumThreads; i++) + Items[i].Wait(); + NumThreads = 0; + } + ~CCrcThreads() + { + WaitAll(); + delete []Items; + } +}; +#endif + +static UInt32 CrcCalc1(const Byte *buf, UInt32 size) +{ + UInt32 crc = CRC_INIT_VAL;; + for (UInt32 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) +{ + RandGen(buf, size, RG); + return CrcCalc1(buf, size); +} + +bool CrcInternalTest() +{ + CBenchBuffer buffer; + const UInt32 kBufferSize0 = (1 << 8); + const UInt32 kBufferSize1 = (1 << 10); + const UInt32 kCheckSize = (1 << 5); + if (!buffer.Alloc(kBufferSize0 + kBufferSize1)) + return false; + Byte *buf = buffer.Buffer; + UInt32 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); + for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++) + for (UInt32 j = 0; j < kCheckSize; j++) + if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j)) + return false; + return true; +} + +HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed) +{ + if (numThreads == 0) + numThreads = 1; + + CBenchBuffer buffer; + size_t totalSize = (size_t)bufferSize * numThreads; + if (totalSize / numThreads != bufferSize) + return E_OUTOFMEMORY; + if (!buffer.Alloc(totalSize)) + return E_OUTOFMEMORY; + + Byte *buf = buffer.Buffer; + CBaseRandomGenerator RG; + UInt32 numCycles = ((UInt32)1 << 30) / ((bufferSize >> 2) + 1) + 1; + + UInt64 timeVal; + #ifdef BENCH_MT + CCrcThreads threads; + if (numThreads > 1) + { + threads.Items = new CCrcInfo[numThreads]; + UInt32 i; + for (i = 0; i < numThreads; i++) + { + CCrcInfo &info = threads.Items[i]; + Byte *data = buf + (size_t)bufferSize * i; + info.Data = data; + info.NumCycles = numCycles; + info.Size = bufferSize; + info.Crc = RandGenCrc(data, bufferSize, RG); + } + timeVal = GetTimeCount(); + for (i = 0; i < numThreads; i++) + { + CCrcInfo &info = threads.Items[i]; + RINOK(info.Thread.Create(CrcThreadFunction, &info)); + threads.NumThreads++; + } + threads.WaitAll(); + for (i = 0; i < numThreads; i++) + if (!threads.Items[i].Res) + return S_FALSE; + } + else + #endif + { + UInt32 crc = RandGenCrc(buf, bufferSize, RG); + timeVal = GetTimeCount(); + if (!CrcBig(buf, bufferSize, numCycles, crc)) + return S_FALSE; + } + timeVal = GetTimeCount() - timeVal; + if (timeVal == 0) + timeVal = 1; + + UInt64 size = (UInt64)numCycles * totalSize; + speed = MyMultDiv64(size, timeVal, GetFreq()); + return S_OK; +} + diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h new file mode 100644 index 000000000..f8aeb6be3 --- /dev/null +++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBench.h @@ -0,0 +1,48 @@ +// LzmaBench.h + +#ifndef __LZMABENCH_H +#define __LZMABENCH_H + +#include <stdio.h> +#include "../../../Common/Types.h" +#ifdef EXTERNAL_LZMA +#include "../../UI/Common/LoadCodecs.h" +#endif + +struct CBenchInfo +{ + UInt64 GlobalTime; + UInt64 GlobalFreq; + UInt64 UserTime; + UInt64 UserFreq; + UInt64 UnpackSize; + UInt64 PackSize; + UInt32 NumIterations; + CBenchInfo(): NumIterations(0) {} +}; + +struct IBenchCallback +{ + virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0; + virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0; +}; + +UInt64 GetUsage(const CBenchInfo &benchOnfo); +UInt64 GetRatingPerUsage(const CBenchInfo &info, UInt64 rating); +UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 freq, UInt64 size); +UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt32 numIterations); + +HRESULT LzmaBench( + #ifdef EXTERNAL_LZMA + CCodecs *codecs, + #endif + UInt32 numThreads, UInt32 dictionarySize, IBenchCallback *callback); + +const int kBenchMinDicLogSize = 18; + +UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary); + +bool CrcInternalTest(); +HRESULT CrcBench(UInt32 numThreads, UInt32 bufferSize, UInt64 &speed); + +#endif diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp new file mode 100644 index 000000000..b1c455e97 --- /dev/null +++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.cpp @@ -0,0 +1,311 @@ +// LzmaBenchCon.cpp + +#include "StdAfx.h" + +#include <stdio.h> + +#include "LzmaBench.h" +#include "LzmaBenchCon.h" +#include "../../../Common/IntToString.h" + +#if defined(BENCH_MT) || defined(_WIN32) +#include "../../../Windows/System.h" +#endif + +#ifdef BREAK_HANDLER +#include "../../UI/Console/ConsoleClose.h" +#endif +#include "../../../Common/MyCom.h" + +struct CTotalBenchRes +{ + UInt64 NumIterations; + UInt64 Rating; + UInt64 Usage; + UInt64 RPU; + void Init() { NumIterations = 0; Rating = 0; Usage = 0; RPU = 0; } + void Normalize() + { + if (NumIterations == 0) + return; + Rating /= NumIterations; + Usage /= NumIterations; + RPU /= NumIterations; + NumIterations = 1; + } + void SetMid(const CTotalBenchRes &r1, const CTotalBenchRes &r2) + { + Rating = (r1.Rating + r2.Rating) / 2; + Usage = (r1.Usage + r2.Usage) / 2; + RPU = (r1.RPU + r2.RPU) / 2; + NumIterations = (r1.NumIterations + r2.NumIterations) / 2; + } +}; + +struct CBenchCallback: public IBenchCallback +{ + CTotalBenchRes EncodeRes; + CTotalBenchRes DecodeRes; + FILE *f; + void Init() { EncodeRes.Init(); DecodeRes.Init(); } + void Normalize() { EncodeRes.Normalize(); DecodeRes.Normalize(); } + UInt32 dictionarySize; + HRESULT SetEncodeResult(const CBenchInfo &info, bool final); + HRESULT SetDecodeResult(const CBenchInfo &info, bool final); +}; + +static void NormalizeVals(UInt64 &v1, UInt64 &v2) +{ + while (v1 > 1000000) + { + v1 >>= 1; + v2 >>= 1; + } +} + +static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq) +{ + UInt64 elTime = elapsedTime; + NormalizeVals(freq, elTime); + if (elTime == 0) + elTime = 1; + return value * freq / elTime; +} + +static void PrintNumber(FILE *f, UInt64 value, int size) +{ + char s[32]; + ConvertUInt64ToString(value, s); + fprintf(f, " "); + for (int len = (int)strlen(s); len < size; len++) + fprintf(f, " "); + fprintf(f, "%s", s); +} + +static void PrintRating(FILE *f, UInt64 rating) +{ + PrintNumber(f, rating / 1000000, 6); +} + +static void PrintResults(FILE *f, UInt64 usage, UInt64 rpu, UInt64 rating) +{ + PrintNumber(f, (usage + 5000) / 10000, 5); + PrintRating(f, rpu); + PrintRating(f, rating); +} + + +static void PrintResults(FILE *f, const CBenchInfo &info, UInt64 rating, CTotalBenchRes &res) +{ + UInt64 speed = MyMultDiv64(info.UnpackSize, info.GlobalTime, info.GlobalFreq); + PrintNumber(f, speed / 1024, 7); + UInt64 usage = GetUsage(info); + UInt64 rpu = GetRatingPerUsage(info, rating); + PrintResults(f, usage, rpu, rating); + res.NumIterations++; + res.RPU += rpu; + res.Rating += rating; + res.Usage += usage; +} + +static void PrintTotals(FILE *f, const CTotalBenchRes &res) +{ + fprintf(f, " "); + PrintResults(f, res.Usage, res.RPU, res.Rating); +} + + +HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final) +{ + #ifdef BREAK_HANDLER + if (NConsoleClose::TestBreakSignal()) + return E_ABORT; + #endif + + if (final) + { + UInt64 rating = GetCompressRating(dictionarySize, info.GlobalTime, info.GlobalFreq, info.UnpackSize); + PrintResults(f, info, rating, EncodeRes); + } + return S_OK; +} + +static const char *kSep = " | "; + + +HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final) +{ + #ifdef BREAK_HANDLER + if (NConsoleClose::TestBreakSignal()) + return E_ABORT; + #endif + if (final) + { + UInt64 rating = GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations); + fprintf(f, kSep); + CBenchInfo info2 = info; + info2.UnpackSize *= info2.NumIterations; + info2.PackSize *= info2.NumIterations; + info2.NumIterations = 1; + PrintResults(f, info2, rating, DecodeRes); + } + return S_OK; +} + +static void PrintRequirements(FILE *f, const char *sizeString, UInt64 size, const char *threadsString, UInt32 numThreads) +{ + fprintf(f, "\nRAM %s ", sizeString); + PrintNumber(f, (size >> 20), 5); + fprintf(f, " MB, # %s %3d", threadsString, (unsigned int)numThreads); +} + +HRESULT LzmaBenchCon( + #ifdef EXTERNAL_LZMA + CCodecs *codecs, + #endif + FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary) +{ + if (!CrcInternalTest()) + return S_FALSE; + #ifdef BENCH_MT + UInt64 ramSize = NWindows::NSystem::GetRamSize(); // + UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors(); + PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs); + if (numThreads == (UInt32)-1) + numThreads = numCPUs; + if (numThreads > 1) + numThreads &= ~1; + if (dictionary == (UInt32)-1) + { + int dicSizeLog; + for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) + if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize) + break; + dictionary = (1 << dicSizeLog); + } + #else + if (dictionary == (UInt32)-1) + dictionary = (1 << 22); + numThreads = 1; + #endif + + PrintRequirements(f, "usage:", GetBenchMemoryUsage(numThreads, dictionary), "Benchmark threads: ", numThreads); + + CBenchCallback callback; + callback.Init(); + callback.f = f; + + fprintf(f, "\n\nDict Compressing | Decompressing\n "); + int j; + for (j = 0; j < 2; j++) + { + fprintf(f, " Speed Usage R/U Rating"); + if (j == 0) + fprintf(f, kSep); + } + fprintf(f, "\n "); + for (j = 0; j < 2; j++) + { + fprintf(f, " KB/s %% MIPS MIPS"); + if (j == 0) + fprintf(f, kSep); + } + fprintf(f, "\n\n"); + for (UInt32 i = 0; i < numIterations; i++) + { + const int kStartDicLog = 22; + int pow = (dictionary < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog; + while (((UInt32)1 << pow) > dictionary) + pow--; + for (; ((UInt32)1 << pow) <= dictionary; pow++) + { + fprintf(f, "%2d:", pow); + callback.dictionarySize = (UInt32)1 << pow; + HRESULT res = LzmaBench( + #ifdef EXTERNAL_LZMA + codecs, + #endif + numThreads, callback.dictionarySize, &callback); + fprintf(f, "\n"); + RINOK(res); + } + } + callback.Normalize(); + fprintf(f, "----------------------------------------------------------------\nAvr:"); + PrintTotals(f, callback.EncodeRes); + fprintf(f, " "); + PrintTotals(f, callback.DecodeRes); + fprintf(f, "\nTot:"); + CTotalBenchRes midRes; + midRes.SetMid(callback.EncodeRes, callback.DecodeRes); + PrintTotals(f, midRes); + fprintf(f, "\n"); + return S_OK; +} + +struct CTempValues +{ + UInt64 *Values; + CTempValues(UInt32 num) { Values = new UInt64[num]; } + ~CTempValues() { delete []Values; } +}; + +HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary) +{ + if (!CrcInternalTest()) + return S_FALSE; + + #ifdef BENCH_MT + UInt64 ramSize = NWindows::NSystem::GetRamSize(); + UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors(); + PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs); + if (numThreads == (UInt32)-1) + numThreads = numCPUs; + #else + numThreads = 1; + #endif + if (dictionary == (UInt32)-1) + dictionary = (1 << 24); + + CTempValues speedTotals(numThreads); + fprintf(f, "\n\nSize"); + for (UInt32 ti = 0; ti < numThreads; ti++) + { + fprintf(f, " %5d", ti + 1); + speedTotals.Values[ti] = 0; + } + fprintf(f, "\n\n"); + + UInt64 numSteps = 0; + for (UInt32 i = 0; i < numIterations; i++) + { + for (int pow = 10; pow < 32; pow++) + { + UInt32 bufSize = (UInt32)1 << pow; + if (bufSize > dictionary) + break; + fprintf(f, "%2d: ", pow); + UInt64 speed; + for (UInt32 ti = 0; ti < numThreads; ti++) + { + #ifdef BREAK_HANDLER + if (NConsoleClose::TestBreakSignal()) + return E_ABORT; + #endif + RINOK(CrcBench(ti + 1, bufSize, speed)); + PrintNumber(f, (speed >> 20), 5); + speedTotals.Values[ti] += speed; + } + fprintf(f, "\n"); + numSteps++; + } + } + if (numSteps != 0) + { + fprintf(f, "\nAvg:"); + for (UInt32 ti = 0; ti < numThreads; ti++) + PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), 5); + fprintf(f, "\n"); + } + return S_OK; +} diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h new file mode 100644 index 000000000..ea8539d19 --- /dev/null +++ b/src/libs/7zip/unix/CPP/7zip/Compress/LZMA_Alone/LzmaBenchCon.h @@ -0,0 +1,20 @@ +// LzmaBenchCon.h + +#ifndef __LZMABENCHCON_H +#define __LZMABENCHCON_H + +#include <stdio.h> +#include "../../../Common/Types.h" +#ifdef EXTERNAL_LZMA +#include "../../UI/Common/LoadCodecs.h" +#endif +HRESULT LzmaBenchCon( + #ifdef EXTERNAL_LZMA + CCodecs *codecs, + #endif + FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary); + +HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary); + +#endif + |