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 |
|
20 struct 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 |
|
45 struct 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 |
|
57 static void NormalizeVals(UInt64 &v1, UInt64 &v2) |
|
58 { |
|
59 while (v1 > 1000000) |
|
60 { |
|
61 v1 >>= 1; |
|
62 v2 >>= 1; |
|
63 } |
|
64 } |
|
65 |
|
66 static 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 |
|
75 static 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 |
|
85 static void PrintRating(FILE *f, UInt64 rating) |
|
86 { |
|
87 PrintNumber(f, rating / 1000000, 6); |
|
88 } |
|
89 |
|
90 static 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 |
|
98 static 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 |
|
111 static void PrintTotals(FILE *f, const CTotalBenchRes &res) |
|
112 { |
|
113 fprintf(f, " "); |
|
114 PrintResults(f, res.Usage, res.RPU, res.Rating); |
|
115 } |
|
116 |
|
117 |
|
118 HRESULT 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 |
|
133 static const char *kSep = " | "; |
|
134 |
|
135 |
|
136 HRESULT 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 |
|
155 static 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 |
|
162 HRESULT 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 |
|
246 struct CTempValues |
|
247 { |
|
248 UInt64 *Values; |
|
249 CTempValues(UInt32 num) { Values = new UInt64[num]; } |
|
250 ~CTempValues() { delete []Values; } |
|
251 }; |
|
252 |
|
253 HRESULT 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 } |
|