📄 lzmabench.cpp
字号:
// 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
extern "C"
{
#include "../../../../C/Alloc.h"
#include "../../../../C/7zCrc.h"
}
#include "../../../Common/MyCom.h"
#include "../../ICoder.h"
#ifdef BENCH_MT
#include "../../../Windows/Thread.h"
#include "../../../Windows/Synchronization.h"
#endif
#ifdef EXTERNAL_LZMA
#include "../../../Windows/PropVariant.h"
#else
#include "../LZMA/LZMADecoder.h"
#include "../LZMA/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 = 1000 + ((t * t * 7) >> (2 * kSubBits)); // AMD K8
UInt64 numCommandsForOne = 870 + ((t * t * 5) >> (2 * kSubBits)); // Intel Core2
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 * 216 + outSize * 14) * numIterations; // AMD K8
UInt64 numCommands = (inSize * 220 + outSize * 8) * numIterations; // Intel Core2
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -