1 // BenchmarkDialog.cpp
\r
5 #include "Common/IntToString.h"
\r
6 #include "Common/MyException.h"
\r
8 #include "Windows/Error.h"
\r
9 #include "Windows/System.h"
\r
10 #include "Windows/Thread.h"
\r
12 #include "../FileManager/HelpUtils.h"
\r
14 #include "BenchmarkDialog.h"
\r
16 using namespace NWindows;
\r
18 static LPCWSTR kHelpTopic = L"fm/benchmark.htm";
\r
20 static const UINT_PTR kTimerID = 4;
\r
21 static const UINT kTimerElapse = 1000;
\r
24 #include "../FileManager/LangUtils.h"
\r
27 using namespace NWindows;
\r
29 UString HResultToMessage(HRESULT errorCode);
\r
32 static CIDLangPair kIDLangPairs[] =
\r
34 { IDC_BENCHMARK_DICTIONARY, 0x02000D0C },
\r
35 { IDC_BENCHMARK_MEMORY, 0x03080001 },
\r
36 { IDC_BENCHMARK_NUM_THREADS, 0x02000D12 },
\r
37 { IDC_BENCHMARK_SPEED_LABEL, 0x03080004 },
\r
38 { IDC_BENCHMARK_RATING_LABEL, 0x03080005 },
\r
39 { IDC_BENCHMARK_COMPRESSING, 0x03080002 },
\r
40 { IDC_BENCHMARK_DECOMPRESSING, 0x03080003 },
\r
41 { IDC_BENCHMARK_CURRENT, 0x03080007 },
\r
42 { IDC_BENCHMARK_RESULTING, 0x03080008 },
\r
43 { IDC_BENCHMARK_CURRENT2, 0x03080007 },
\r
44 { IDC_BENCHMARK_RESULTING2, 0x03080008 },
\r
45 { IDC_BENCHMARK_TOTAL_RATING, 0x03080006 },
\r
46 { IDC_BENCHMARK_ELAPSED, 0x02000C01 },
\r
47 { IDC_BENCHMARK_SIZE, 0x02000C03 },
\r
48 { IDC_BENCHMARK_PASSES, 0x03080009 },
\r
49 // { IDC_BENCHMARK_ERRORS, 0x0308000A },
\r
50 { IDC_BENCHMARK_USAGE_LABEL, 0x0308000B },
\r
51 { IDC_BENCHMARK_RPU_LABEL, 0x0308000C },
\r
52 { IDC_BENCHMARK_COMBO_NUM_THREADS, 0x02000D12},
\r
54 { IDC_BUTTON_STOP, 0x02000714 },
\r
55 { IDC_BUTTON_RESTART, 0x02000715 },
\r
56 { IDHELP, 0x02000720 },
\r
57 { IDCANCEL, 0x02000710 }
\r
61 const LPCTSTR kProcessingString = TEXT("...");
\r
62 const LPCTSTR kMB = TEXT(" MB");
\r
63 const LPCTSTR kMIPS = TEXT(" MIPS");
\r
64 const LPCTSTR kKBs = TEXT(" KB/s");
\r
67 static const int kMinDicLogSize = 20;
\r
69 static const int kMinDicLogSize = 21;
\r
71 static const UInt32 kMinDicSize = (1 << kMinDicLogSize);
\r
72 static const UInt32 kMaxDicSize =
\r
79 bool CBenchmarkDialog::OnInit()
\r
82 LangSetWindowText(HWND(*this), 0x03080000);
\r
83 LangSetDlgItemsText(HWND(*this), kIDLangPairs, sizeof(kIDLangPairs) / sizeof(kIDLangPairs[0]));
\r
89 UInt32 numCPUs = NSystem::GetNumberOfProcessors();
\r
92 numCPUs = MyMin(numCPUs, (UInt32)(1 << 8));
\r
94 if (Sync.NumThreads == (UInt32)-1)
\r
96 Sync.NumThreads = numCPUs;
\r
97 if (Sync.NumThreads > 1)
\r
98 Sync.NumThreads &= ~1;
\r
100 m_NumThreads.Attach(GetItem(IDC_BENCHMARK_COMBO_NUM_THREADS));
\r
102 for (UInt32 num = 1; num <= numCPUs * 2;)
\r
105 ConvertUInt64ToString(num, s);
\r
106 int index = (int)m_NumThreads.AddString(s);
\r
107 m_NumThreads.SetItemData(index, num);
\r
108 if (num <= Sync.NumThreads)
\r
114 m_NumThreads.SetCurSel(cur);
\r
115 Sync.NumThreads = GetNumberOfThreads();
\r
117 m_Dictionary.Attach(GetItem(IDC_BENCHMARK_COMBO_DICTIONARY));
\r
119 UInt64 ramSize = NSystem::GetRamSize();
\r
122 const UInt32 kNormalizedCeSize = (16 << 20);
\r
123 if (ramSize > kNormalizedCeSize && ramSize < (33 << 20))
\r
124 ramSize = kNormalizedCeSize;
\r
127 if (Sync.DictionarySize == (UInt32)-1)
\r
130 for (dicSizeLog = 25; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
\r
131 if (GetBenchMemoryUsage(Sync.NumThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
\r
133 Sync.DictionarySize = (1 << dicSizeLog);
\r
135 if (Sync.DictionarySize < kMinDicSize)
\r
136 Sync.DictionarySize = kMinDicSize;
\r
137 if (Sync.DictionarySize > kMaxDicSize)
\r
138 Sync.DictionarySize = kMaxDicSize;
\r
140 for (int i = kMinDicLogSize; i <= 30; i++)
\r
141 for (int j = 0; j < 2; j++)
\r
143 UInt32 dictionary = (1 << i) + (j << (i - 1));
\r
144 if (dictionary > kMaxDicSize)
\r
147 ConvertUInt64ToString((dictionary >> 20), s);
\r
149 int index = (int)m_Dictionary.AddString(s);
\r
150 m_Dictionary.SetItemData(index, dictionary);
\r
151 if (dictionary <= Sync.DictionarySize)
\r
154 m_Dictionary.SetCurSel(cur);
\r
156 OnChangeSettings();
\r
158 Sync._startEvent.Set();
\r
159 _timer = SetTimer(kTimerID, kTimerElapse);
\r
161 NormalizePosition();
\r
162 return CModalDialog::OnInit();
\r
165 UInt32 CBenchmarkDialog::GetNumberOfThreads()
\r
167 return (UInt32)m_NumThreads.GetItemData(m_NumThreads.GetCurSel());
\r
170 UInt32 CBenchmarkDialog::OnChangeDictionary()
\r
172 UInt32 dictionary = (UInt32)m_Dictionary.GetItemData(m_Dictionary.GetCurSel());
\r
173 UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(), dictionary);
\r
174 memUsage = (memUsage + (1 << 20) - 1) >> 20;
\r
176 ConvertUInt64ToString(memUsage, s);
\r
178 SetItemText(IDC_BENCHMARK_MEMORY_VALUE, s);
\r
182 static const UInt32 g_IDs[] =
\r
184 IDC_BENCHMARK_COMPRESSING_USAGE,
\r
185 IDC_BENCHMARK_COMPRESSING_USAGE2,
\r
186 IDC_BENCHMARK_COMPRESSING_SPEED,
\r
187 IDC_BENCHMARK_COMPRESSING_SPEED2,
\r
188 IDC_BENCHMARK_COMPRESSING_RATING,
\r
189 IDC_BENCHMARK_COMPRESSING_RATING2,
\r
190 IDC_BENCHMARK_COMPRESSING_RPU,
\r
191 IDC_BENCHMARK_COMPRESSING_RPU2,
\r
193 IDC_BENCHMARK_DECOMPRESSING_SPEED,
\r
194 IDC_BENCHMARK_DECOMPRESSING_SPEED2,
\r
195 IDC_BENCHMARK_DECOMPRESSING_RATING,
\r
196 IDC_BENCHMARK_DECOMPRESSING_RATING2,
\r
197 IDC_BENCHMARK_DECOMPRESSING_USAGE,
\r
198 IDC_BENCHMARK_DECOMPRESSING_USAGE2,
\r
199 IDC_BENCHMARK_DECOMPRESSING_RPU,
\r
200 IDC_BENCHMARK_DECOMPRESSING_RPU2,
\r
202 IDC_BENCHMARK_TOTAL_USAGE_VALUE,
\r
203 IDC_BENCHMARK_TOTAL_RATING_VALUE,
\r
204 IDC_BENCHMARK_TOTAL_RPU_VALUE
\r
207 void CBenchmarkDialog::OnChangeSettings()
\r
209 EnableItem(IDC_BUTTON_STOP, true);
\r
210 UInt32 dictionary = OnChangeDictionary();
\r
211 TCHAR s[40] = { TEXT('/'), TEXT(' '), 0 };
\r
212 ConvertUInt64ToString(NSystem::GetNumberOfProcessors(), s + 2);
\r
213 SetItemText(IDC_BENCHMARK_HARDWARE_THREADS, s);
\r
214 for (int i = 0; i < sizeof(g_IDs) / sizeof(g_IDs[0]); i++)
\r
215 SetItemText(g_IDs[i], kProcessingString);
\r
216 _startTime = GetTickCount();
\r
218 NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
\r
220 Sync.DictionarySize = dictionary;
\r
221 Sync.Changed = true;
\r
222 Sync.NumThreads = GetNumberOfThreads();
\r
225 void CBenchmarkDialog::OnRestartButton()
\r
227 OnChangeSettings();
\r
230 void CBenchmarkDialog::OnStopButton()
\r
232 EnableItem(IDC_BUTTON_STOP, false);
\r
236 void CBenchmarkDialog::OnHelp()
\r
238 ShowHelpWindow(NULL, kHelpTopic);
\r
241 void CBenchmarkDialog::OnCancel()
\r
245 CModalDialog::OnCancel();
\r
248 static void GetTimeString(UInt64 timeValue, TCHAR *s)
\r
250 wsprintf(s, TEXT("%02d:%02d:%02d"),
\r
251 UInt32(timeValue / 3600),
\r
252 UInt32((timeValue / 60) % 60),
\r
253 UInt32(timeValue % 60));
\r
256 void CBenchmarkDialog::PrintTime()
\r
258 UInt32 curTime = ::GetTickCount();
\r
259 UInt32 elapsedTime = (curTime - _startTime);
\r
260 UInt32 elapsedSec = elapsedTime / 1000;
\r
261 if (elapsedSec != 0 && Sync.WasPaused())
\r
264 GetTimeString(elapsedSec, s);
\r
265 SetItemText(IDC_BENCHMARK_ELAPSED_VALUE, s);
\r
268 void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID)
\r
271 ConvertUInt64ToString(rating / 1000000, s);
\r
273 SetItemText(controlID, s);
\r
276 void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID)
\r
279 ConvertUInt64ToString((usage + 5000) / 10000, s);
\r
280 lstrcat(s, TEXT("%"));
\r
281 SetItemText(controlID, s);
\r
284 void CBenchmarkDialog::PrintResults(
\r
285 UInt32 dictionarySize,
\r
286 const CBenchInfo2 &info,
\r
287 UINT usageID, UINT speedID, UINT rpuID, UINT ratingID,
\r
288 bool decompressMode)
\r
290 if (info.GlobalTime == 0)
\r
293 UInt64 size = info.UnpackSize;
\r
296 UInt64 speed = size * info.GlobalFreq / info.GlobalTime;
\r
297 ConvertUInt64ToString(speed / 1024, s);
\r
299 SetItemText(speedID, s);
\r
302 if (decompressMode)
\r
303 rating = GetDecompressRating(info.GlobalTime, info.GlobalFreq, size, info.PackSize, 1);
\r
305 rating = GetCompressRating(dictionarySize, info.GlobalTime, info.GlobalFreq, size * info.NumIterations);
\r
307 PrintRating(rating, ratingID);
\r
308 PrintRating(GetRatingPerUsage(info, rating), rpuID);
\r
309 PrintUsage(GetUsage(info), usageID);
\r
312 bool CBenchmarkDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
\r
315 NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
\r
318 ConvertUInt64ToString((Sync.ProcessedSize >> 20), s);
\r
320 SetItemText(IDC_BENCHMARK_SIZE_VALUE, s);
\r
322 ConvertUInt64ToString(Sync.NumPasses, s);
\r
323 SetItemText(IDC_BENCHMARK_PASSES_VALUE, s);
\r
326 ConvertUInt64ToString(Sync.NumErrors, s);
\r
327 SetItemText(IDC_BENCHMARK_ERRORS_VALUE, s);
\r
331 UInt32 dicSizeTemp = (UInt32)MyMax(Sync.ProcessedSize, UInt64(1) << 20);
\r
332 dicSizeTemp = MyMin(dicSizeTemp, Sync.DictionarySize),
\r
333 PrintResults(dicSizeTemp,
\r
334 Sync.CompressingInfoTemp,
\r
335 IDC_BENCHMARK_COMPRESSING_USAGE,
\r
336 IDC_BENCHMARK_COMPRESSING_SPEED,
\r
337 IDC_BENCHMARK_COMPRESSING_RPU,
\r
338 IDC_BENCHMARK_COMPRESSING_RATING);
\r
343 Sync.DictionarySize,
\r
344 Sync.CompressingInfo,
\r
345 IDC_BENCHMARK_COMPRESSING_USAGE2,
\r
346 IDC_BENCHMARK_COMPRESSING_SPEED2,
\r
347 IDC_BENCHMARK_COMPRESSING_RPU2,
\r
348 IDC_BENCHMARK_COMPRESSING_RATING2);
\r
353 Sync.DictionarySize,
\r
354 Sync.DecompressingInfoTemp,
\r
355 IDC_BENCHMARK_DECOMPRESSING_USAGE,
\r
356 IDC_BENCHMARK_DECOMPRESSING_SPEED,
\r
357 IDC_BENCHMARK_DECOMPRESSING_RPU,
\r
358 IDC_BENCHMARK_DECOMPRESSING_RATING,
\r
363 Sync.DictionarySize,
\r
364 Sync.DecompressingInfo,
\r
365 IDC_BENCHMARK_DECOMPRESSING_USAGE2,
\r
366 IDC_BENCHMARK_DECOMPRESSING_SPEED2,
\r
367 IDC_BENCHMARK_DECOMPRESSING_RPU2,
\r
368 IDC_BENCHMARK_DECOMPRESSING_RATING2,
\r
370 if (Sync.DecompressingInfo.GlobalTime > 0 &&
\r
371 Sync.CompressingInfo.GlobalTime > 0)
\r
373 UInt64 comprRating = GetCompressRating(Sync.DictionarySize,
\r
374 Sync.CompressingInfo.GlobalTime, Sync.CompressingInfo.GlobalFreq, Sync.CompressingInfo.UnpackSize);
\r
375 UInt64 decomprRating = GetDecompressRating(Sync.DecompressingInfo.GlobalTime,
\r
376 Sync.DecompressingInfo.GlobalFreq, Sync.DecompressingInfo.UnpackSize,
\r
377 Sync.DecompressingInfo.PackSize, 1);
\r
378 PrintRating((comprRating + decomprRating) / 2, IDC_BENCHMARK_TOTAL_RATING_VALUE);
\r
380 GetRatingPerUsage(Sync.CompressingInfo, comprRating) +
\r
381 GetRatingPerUsage(Sync.DecompressingInfo, decomprRating)) / 2, IDC_BENCHMARK_TOTAL_RPU_VALUE);
\r
382 PrintUsage((GetUsage(Sync.CompressingInfo) + GetUsage(Sync.DecompressingInfo)) / 2, IDC_BENCHMARK_TOTAL_USAGE_VALUE);
\r
388 bool CBenchmarkDialog::OnCommand(int code, int itemID, LPARAM lParam)
\r
390 if (code == CBN_SELCHANGE &&
\r
391 (itemID == IDC_BENCHMARK_COMBO_DICTIONARY ||
\r
392 itemID == IDC_BENCHMARK_COMBO_NUM_THREADS))
\r
394 OnChangeSettings();
\r
397 return CModalDialog::OnCommand(code, itemID, lParam);
\r
400 bool CBenchmarkDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
\r
404 case IDC_BUTTON_RESTART:
\r
407 case IDC_BUTTON_STOP:
\r
411 return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
\r
414 struct CThreadBenchmark
\r
416 CBenchmarkDialog *BenchmarkDialog;
\r
418 DECL_EXTERNAL_CODECS_VARS
\r
419 // UInt32 dictionarySize;
\r
420 // UInt32 numThreads;
\r
424 static THREAD_FUNC_DECL MyThreadFunction(void *param)
\r
426 ((CThreadBenchmark *)param)->Result = ((CThreadBenchmark *)param)->Process();
\r
431 struct CBenchCallback: public IBenchCallback
\r
433 UInt32 dictionarySize;
\r
434 CProgressSyncInfo *Sync;
\r
435 HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
\r
436 HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
\r
439 HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
\r
441 NSynchronization::CCriticalSectionLock lock(Sync->CS);
\r
442 if (Sync->Changed || Sync->Paused || Sync->Stopped)
\r
444 Sync->ProcessedSize = info.UnpackSize;
\r
445 if (final && Sync->CompressingInfo.GlobalTime == 0)
\r
447 (CBenchInfo&)Sync->CompressingInfo = info;
\r
448 if (Sync->CompressingInfo.GlobalTime == 0)
\r
449 Sync->CompressingInfo.GlobalTime = 1;
\r
452 (CBenchInfo&)Sync->CompressingInfoTemp = info;
\r
457 HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
\r
459 NSynchronization::CCriticalSectionLock lock(Sync->CS);
\r
460 if (Sync->Changed || Sync->Paused || Sync->Stopped)
\r
462 CBenchInfo info2 = info;
\r
463 if (info2.NumIterations == 0)
\r
464 info2.NumIterations = 1;
\r
466 info2.UnpackSize *= info2.NumIterations;
\r
467 info2.PackSize *= info2.NumIterations;
\r
468 info2.NumIterations = 1;
\r
470 if (final && Sync->DecompressingInfo.GlobalTime == 0)
\r
472 (CBenchInfo&)Sync->DecompressingInfo = info2;
\r
473 if (Sync->DecompressingInfo.GlobalTime == 0)
\r
474 Sync->DecompressingInfo.GlobalTime = 1;
\r
477 (CBenchInfo&)Sync->DecompressingInfoTemp = info2;
\r
481 HRESULT CThreadBenchmark::Process()
\r
483 CProgressSyncInfo &sync = BenchmarkDialog->Sync;
\r
484 sync.WaitCreating();
\r
489 if (sync.WasStopped())
\r
491 if (sync.WasPaused())
\r
496 UInt32 dictionarySize;
\r
499 NSynchronization::CCriticalSectionLock lock(sync.CS);
\r
500 if (sync.Stopped || sync.Paused)
\r
504 dictionarySize = sync.DictionarySize;
\r
505 numThreads = sync.NumThreads;
\r
508 CBenchCallback callback;
\r
509 callback.dictionarySize = dictionarySize;
\r
510 callback.Sync = &sync;
\r
514 result = LzmaBench(
\r
515 EXTERNAL_CODECS_VARS
\r
516 numThreads, dictionarySize, &callback);
\r
523 if (result != S_OK)
\r
525 if (result != E_ABORT)
\r
527 // sync.NumErrors++;
\r
529 NSynchronization::CCriticalSectionLock lock(sync.CS);
\r
533 if (result == S_FALSE)
\r
534 message = L"Decoding error";
\r
535 else if (result == CLASS_E_CLASSNOTAVAILABLE)
\r
536 message = L"Can't find 7z.dll";
\r
538 message = HResultToMessage(result);
\r
539 BenchmarkDialog->MessageBoxError(message);
\r
544 NSynchronization::CCriticalSectionLock lock(sync.CS);
\r
550 catch(CSystemException &e)
\r
552 BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode));
\r
557 BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL));
\r
563 DECL_EXTERNAL_CODECS_LOC_VARS
\r
564 UInt32 numThreads, UInt32 dictionarySize, HWND hwndParent)
\r
566 CThreadBenchmark benchmarker;
\r
567 #ifdef EXTERNAL_CODECS
\r
568 benchmarker._codecsInfo = codecsInfo;
\r
569 benchmarker._externalCodecs = *externalCodecs;
\r
572 CBenchmarkDialog benchmarkDialog;
\r
573 benchmarkDialog.Sync.DictionarySize = dictionarySize;
\r
574 benchmarkDialog.Sync.NumThreads = numThreads;
\r
576 benchmarker.BenchmarkDialog = &benchmarkDialog;
\r
577 NWindows::CThread thread;
\r
578 RINOK(thread.Create(CThreadBenchmark::MyThreadFunction, &benchmarker));
\r
579 benchmarkDialog.Create(hwndParent);
\r
580 return thread.Wait();
\r