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 
17 struct CTotalBenchRes
18 {
19   UInt64 NumIterations;
20   UInt64 Rating;
21   UInt64 Usage;
22   UInt64 RPU;
InitCTotalBenchRes23   void Init() { NumIterations = 0; Rating = 0; Usage = 0; RPU = 0; }
NormalizeCTotalBenchRes24   void Normalize()
25   {
26     if (NumIterations == 0)
27       return;
28     Rating /= NumIterations;
29     Usage /= NumIterations;
30     RPU /= NumIterations;
31     NumIterations = 1;
32   }
SetMidCTotalBenchRes33   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 
42 struct CBenchCallback: public IBenchCallback
43 {
44   CTotalBenchRes EncodeRes;
45   CTotalBenchRes DecodeRes;
46   FILE *f;
InitCBenchCallback47   void Init() { EncodeRes.Init(); DecodeRes.Init(); }
NormalizeCBenchCallback48   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 
NormalizeVals(UInt64 & v1,UInt64 & v2)54 static void NormalizeVals(UInt64 &v1, UInt64 &v2)
55 {
56   while (v1 > 1000000)
57   {
58     v1 >>= 1;
59     v2 >>= 1;
60   }
61 }
62 
MyMultDiv64(UInt64 value,UInt64 elapsedTime,UInt64 freq)63 static 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 
PrintNumber(FILE * f,UInt64 value,int size)72 static 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 
PrintRating(FILE * f,UInt64 rating)82 static void PrintRating(FILE *f, UInt64 rating)
83 {
84   PrintNumber(f, rating / 1000000, 6);
85 }
86 
PrintResults(FILE * f,UInt64 usage,UInt64 rpu,UInt64 rating)87 static 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 
PrintResults(FILE * f,const CBenchInfo & info,UInt64 rating,CTotalBenchRes & res)95 static 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 
PrintTotals(FILE * f,const CTotalBenchRes & res)108 static void PrintTotals(FILE *f, const CTotalBenchRes &res)
109 {
110   fprintf(f, "       ");
111   PrintResults(f, res.Usage, res.RPU, res.Rating);
112 }
113 
114 
SetEncodeResult(const CBenchInfo & info,bool final)115 HRESULT 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 
127 static const char *kSep = "  | ";
128 
129 
SetDecodeResult(const CBenchInfo & info,bool final)130 HRESULT 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 
PrintRequirements(FILE * f,const char * sizeString,UInt64 size,const char * threadsString,UInt32 numThreads)147 static 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 
LzmaBenchCon(DECL_EXTERNAL_CODECS_LOC_VARS FILE * f,UInt32 numIterations,UInt32 numThreads,UInt32 dictionary)154 HRESULT 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 
234 struct CTempValues
235 {
236   UInt64 *Values;
CTempValuesCTempValues237   CTempValues(UInt32 num) { Values = new UInt64[num]; }
~CTempValuesCTempValues238   ~CTempValues() { delete []Values; }
239 };
240 
CrcBenchCon(FILE * f,UInt32 numIterations,UInt32 numThreads,UInt32 dictionary)241 HRESULT 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