1// BenchCon.cpp
2
3#include "StdAfx.h"
4
5#include "../../../Common/IntToString.h"
6#include "../../../Common/MyCom.h"
7
8#if !defined(_7ZIP_ST) || defined(_WIN32)
9#include "../../../Windows/System.h"
10#endif
11
12#include "../Common/Bench.h"
13
14#include "BenchCon.h"
15#include "ConsoleClose.h"
16
17struct CTotalBenchRes
18{
19  UInt64 NumIterations;
20  UInt64 Rating;
21  UInt64 Usage;
22  UInt64 RPU;
23  void Init() { NumIterations = 0; Rating = 0; Usage = 0; RPU = 0; }
24  void Normalize()
25  {
26    if (NumIterations == 0)
27      return;
28    Rating /= NumIterations;
29    Usage /= NumIterations;
30    RPU /= NumIterations;
31    NumIterations = 1;
32  }
33  void SetMid(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
34  {
35    Rating = (r1.Rating + r2.Rating) / 2;
36    Usage = (r1.Usage + r2.Usage) / 2;
37    RPU = (r1.RPU + r2.RPU) / 2;
38    NumIterations = (r1.NumIterations + r2.NumIterations) / 2;
39  }
40};
41
42struct CBenchCallback: public IBenchCallback
43{
44  CTotalBenchRes EncodeRes;
45  CTotalBenchRes DecodeRes;
46  FILE *f;
47  void Init() { EncodeRes.Init(); DecodeRes.Init(); }
48  void Normalize() { EncodeRes.Normalize(); DecodeRes.Normalize(); }
49  UInt32 dictionarySize;
50  HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
51  HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
52};
53
54static void NormalizeVals(UInt64 &v1, UInt64 &v2)
55{
56  while (v1 > 1000000)
57  {
58    v1 >>= 1;
59    v2 >>= 1;
60  }
61}
62
63static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
64{
65  UInt64 elTime = elapsedTime;
66  NormalizeVals(freq, elTime);
67  if (elTime == 0)
68    elTime = 1;
69  return value * freq / elTime;
70}
71
72static void PrintNumber(FILE *f, UInt64 value, int size)
73{
74  char s[32];
75  ConvertUInt64ToString(value, s);
76  fprintf(f, " ");
77  for (int len = (int)strlen(s); len < size; len++)
78    fprintf(f, " ");
79  fputs(s, f);
80}
81
82static void PrintRating(FILE *f, UInt64 rating)
83{
84  PrintNumber(f, rating / 1000000, 6);
85}
86
87static void PrintResults(FILE *f, UInt64 usage, UInt64 rpu, UInt64 rating)
88{
89  PrintNumber(f, (usage + 5000) / 10000, 5);
90  PrintRating(f, rpu);
91  PrintRating(f, rating);
92}
93
94
95static void PrintResults(FILE *f, const CBenchInfo &info, UInt64 rating, CTotalBenchRes &res)
96{
97  UInt64 speed = MyMultDiv64(info.UnpackSize, info.GlobalTime, info.GlobalFreq);
98  PrintNumber(f, speed / 1024, 7);
99  UInt64 usage = GetUsage(info);
100  UInt64 rpu = GetRatingPerUsage(info, rating);
101  PrintResults(f, usage, rpu, rating);
102  res.NumIterations++;
103  res.RPU += rpu;
104  res.Rating += rating;
105  res.Usage += usage;
106}
107
108static void PrintTotals(FILE *f, const CTotalBenchRes &res)
109{
110  fprintf(f, "       ");
111  PrintResults(f, res.Usage, res.RPU, res.Rating);
112}
113
114
115HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
116{
117  if (NConsoleClose::TestBreakSignal())
118    return E_ABORT;
119  if (final)
120  {
121    UInt64 rating = GetCompressRating(dictionarySize, info.GlobalTime, info.GlobalFreq, info.UnpackSize);
122    PrintResults(f, info, rating, EncodeRes);
123  }
124  return S_OK;
125}
126
127static const char *kSep = "  | ";
128
129
130HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
131{
132  if (NConsoleClose::TestBreakSignal())
133    return E_ABORT;
134  if (final)
135  {
136    UInt64 rating = GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
137    fputs(kSep, f);
138    CBenchInfo info2 = info;
139    info2.UnpackSize *= info2.NumIterations;
140    info2.PackSize *= info2.NumIterations;
141    info2.NumIterations = 1;
142    PrintResults(f, info2, rating, DecodeRes);
143  }
144  return S_OK;
145}
146
147static void PrintRequirements(FILE *f, const char *sizeString, UInt64 size, const char *threadsString, UInt32 numThreads)
148{
149  fprintf(f, "\nRAM %s ", sizeString);
150  PrintNumber(f, (size >> 20), 5);
151  fprintf(f, " MB,  # %s %3d", threadsString, (unsigned int)numThreads);
152}
153
154HRESULT LzmaBenchCon(
155  DECL_EXTERNAL_CODECS_LOC_VARS
156  FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
157{
158  if (!CrcInternalTest())
159    return S_FALSE;
160  #ifndef _7ZIP_ST
161  UInt64 ramSize = NWindows::NSystem::GetRamSize();  //
162  UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
163  PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
164  if (numThreads == (UInt32)-1)
165    numThreads = numCPUs;
166  if (numThreads > 1)
167    numThreads &= ~1;
168  if (dictionary == (UInt32)-1)
169  {
170    int dicSizeLog;
171    for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
172      if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
173        break;
174    dictionary = (1 << dicSizeLog);
175  }
176  #else
177  if (dictionary == (UInt32)-1)
178    dictionary = (1 << 22);
179  numThreads = 1;
180  #endif
181
182  PrintRequirements(f, "usage:", GetBenchMemoryUsage(numThreads, dictionary), "Benchmark threads:   ", numThreads);
183
184  CBenchCallback callback;
185  callback.Init();
186  callback.f = f;
187
188  fprintf(f, "\n\nDict        Compressing          |        Decompressing\n   ");
189  int j;
190  for (j = 0; j < 2; j++)
191  {
192    fprintf(f, "   Speed Usage    R/U Rating");
193    if (j == 0)
194      fputs(kSep, f);
195  }
196  fprintf(f, "\n   ");
197  for (j = 0; j < 2; j++)
198  {
199    fprintf(f, "    KB/s     %%   MIPS   MIPS");
200    if (j == 0)
201      fputs(kSep, f);
202  }
203  fprintf(f, "\n\n");
204  for (UInt32 i = 0; i < numIterations; i++)
205  {
206    const int kStartDicLog = 22;
207    int pow = (dictionary < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
208    while (((UInt32)1 << pow) > dictionary)
209      pow--;
210    for (; ((UInt32)1 << pow) <= dictionary; pow++)
211    {
212      fprintf(f, "%2d:", pow);
213      callback.dictionarySize = (UInt32)1 << pow;
214      HRESULT res = LzmaBench(
215        EXTERNAL_CODECS_LOC_VARS
216        numThreads, callback.dictionarySize, &callback);
217      fprintf(f, "\n");
218      RINOK(res);
219    }
220  }
221  callback.Normalize();
222  fprintf(f, "----------------------------------------------------------------\nAvr:");
223  PrintTotals(f, callback.EncodeRes);
224  fprintf(f, "     ");
225  PrintTotals(f, callback.DecodeRes);
226  fprintf(f, "\nTot:");
227  CTotalBenchRes midRes;
228  midRes.SetMid(callback.EncodeRes, callback.DecodeRes);
229  PrintTotals(f, midRes);
230  fprintf(f, "\n");
231  return S_OK;
232}
233
234struct CTempValues
235{
236  UInt64 *Values;
237  CTempValues(UInt32 num) { Values = new UInt64[num]; }
238  ~CTempValues() { delete []Values; }
239};
240
241HRESULT CrcBenchCon(FILE *f, UInt32 numIterations, UInt32 numThreads, UInt32 dictionary)
242{
243  if (!CrcInternalTest())
244    return S_FALSE;
245
246  #ifndef _7ZIP_ST
247  UInt64 ramSize = NWindows::NSystem::GetRamSize();
248  UInt32 numCPUs = NWindows::NSystem::GetNumberOfProcessors();
249  PrintRequirements(f, "size: ", ramSize, "CPU hardware threads:", numCPUs);
250  if (numThreads == (UInt32)-1)
251    numThreads = numCPUs;
252  #else
253  numThreads = 1;
254  #endif
255  if (dictionary == (UInt32)-1)
256    dictionary = (1 << 24);
257
258  CTempValues speedTotals(numThreads);
259  fprintf(f, "\n\nSize");
260  for (UInt32 ti = 0; ti < numThreads; ti++)
261  {
262    fprintf(f, " %5d", ti + 1);
263    speedTotals.Values[ti] = 0;
264  }
265  fprintf(f, "\n\n");
266
267  UInt64 numSteps = 0;
268  for (UInt32 i = 0; i < numIterations; i++)
269  {
270    for (int pow = 10; pow < 32; pow++)
271    {
272      UInt32 bufSize = (UInt32)1 << pow;
273      if (bufSize > dictionary)
274        break;
275      fprintf(f, "%2d: ", pow);
276      UInt64 speed;
277      for (UInt32 ti = 0; ti < numThreads; ti++)
278      {
279        if (NConsoleClose::TestBreakSignal())
280          return E_ABORT;
281        RINOK(CrcBench(ti + 1, bufSize, speed));
282        PrintNumber(f, (speed >> 20), 5);
283        speedTotals.Values[ti] += speed;
284      }
285      fprintf(f, "\n");
286      numSteps++;
287    }
288  }
289  if (numSteps != 0)
290  {
291    fprintf(f, "\nAvg:");
292    for (UInt32 ti = 0; ti < numThreads; ti++)
293      PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), 5);
294    fprintf(f, "\n");
295  }
296  return S_OK;
297}
298