// BenchCon.cpp | |
#include "StdAfx.h" | |
#include "../../../Common/IntToString.h" | |
#include "../../../Common/MyCom.h" | |
#if !defined(_7ZIP_ST) || defined(_WIN32) | |
#include "../../../Windows/System.h" | |
#endif | |
#include "../Common/Bench.h" | |
#include "BenchCon.h" | |
#include "ConsoleClose.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, " "); | |
fputs(s, f); | |
} | |
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) | |
{ | |
if (NConsoleClose::TestBreakSignal()) | |
return E_ABORT; | |
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) | |
{ | |
if (NConsoleClose::TestBreakSignal()) | |
return E_ABORT; | |
if (final) | |
{ | |
UInt64 rating = GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations); | |
fputs(kSep, f); | |
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( | |
DECL_EXTERNAL_CODECS_LOC_VARS | |
FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary) | |
{ | |
if (!CrcInternalTest()) | |
return S_FALSE; | |
#ifndef _7ZIP_ST | |
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) | |
fputs(kSep, f); | |
} | |
fprintf(f, "\n "); | |
for (j = 0; j < 2; j++) | |
{ | |
fprintf(f, " KB/s %% MIPS MIPS"); | |
if (j == 0) | |
fputs(kSep, f); | |
} | |
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( | |
EXTERNAL_CODECS_LOC_VARS | |
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; | |
#ifndef _7ZIP_ST | |
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++) | |
{ | |
if (NConsoleClose::TestBreakSignal()) | |
return E_ABORT; | |
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; | |
} |