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