1 // BenchmarkDialog.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../../C/CpuArch.h"
6
7 #include "../../../Common/Defs.h"
8 #include "../../../Common/IntToString.h"
9 #include "../../../Common/MyException.h"
10 #include "../../../Common/StringConvert.h"
11 #include "../../../Common/StringToInt.h"
12
13 #include "../../../Windows/Synchronization.h"
14 #include "../../../Windows/System.h"
15 #include "../../../Windows/Thread.h"
16 #include "../../../Windows/SystemInfo.h"
17
18 #include "../../../Windows/Control/ComboBox.h"
19 #include "../../../Windows/Control/Edit.h"
20
21 #include "../../Common/MethodProps.h"
22
23 #include "../FileManager/DialogSize.h"
24 #include "../FileManager/HelpUtils.h"
25 #include "../FileManager/LangUtils.h"
26 #include "../FileManager/resourceGui.h"
27
28 #include "../../MyVersion.h"
29
30 #include "../Common/Bench.h"
31
32 #include "BenchmarkDialogRes.h"
33 #include "BenchmarkDialog.h"
34
35 using namespace NWindows;
36
37 #define kHelpTopic "fm/benchmark.htm"
38
39 static const UINT_PTR kTimerID = 4;
40 static const UINT kTimerElapse = 1000; // 1000
41
42 // use PRINT_ITER_TIME to show time of each iteration in log box
43 // #define PRINT_ITER_TIME
44
45 static const unsigned kRatingVector_NumBundlesMax = 20;
46
47 enum MyBenchMessages
48 {
49 k_Message_Finished = WM_APP + 1
50 };
51
52 enum My_Message_WPARAM
53 {
54 k_Msg_WPARM_Thread_Finished = 0,
55 k_Msg_WPARM_Iter_Finished,
56 k_Msg_WPARM_Enc1_Finished
57 };
58
59
60 struct CBenchPassResult
61 {
62 CTotalBenchRes Enc;
63 CTotalBenchRes Dec;
64 #ifdef PRINT_ITER_TIME
65 DWORD Ticks;
66 #endif
67 // CBenchInfo EncInfo; // for debug
68 // CBenchPassResult() {};
69 };
70
71
72 struct CTotalBenchRes2: public CTotalBenchRes
73 {
74 UInt64 UnpackSize;
75
InitCTotalBenchRes276 void Init()
77 {
78 CTotalBenchRes::Init();
79 UnpackSize = 0;
80 }
81
SetFrom_BenchInfoCTotalBenchRes282 void SetFrom_BenchInfo(const CBenchInfo &info)
83 {
84 NumIterations2 = 1;
85 Generate_From_BenchInfo(info);
86 UnpackSize = info.Get_UnpackSize_Full();
87 }
88
Update_With_Res2CTotalBenchRes289 void Update_With_Res2(const CTotalBenchRes2 &r)
90 {
91 Update_With_Res(r);
92 UnpackSize += r.UnpackSize;
93 }
94 };
95
96
97 struct CSyncData
98 {
99 UInt32 NumPasses_Finished;
100
101 // UInt64 NumEncProgress; // for debug
102 // UInt64 NumDecProgress; // for debug
103 // CBenchInfo EncInfo; // for debug
104
105 CTotalBenchRes2 Enc_BenchRes_1;
106 CTotalBenchRes2 Enc_BenchRes;
107
108 CTotalBenchRes2 Dec_BenchRes_1;
109 CTotalBenchRes2 Dec_BenchRes;
110
111 #ifdef PRINT_ITER_TIME
112 DWORD TotalTicks;
113 #endif
114
115 int RatingVector_DeletedIndex;
116 // UInt64 RatingVector_NumDeleted;
117
118 bool BenchWasFinished; // all passes were finished
119 bool NeedPrint_Freq;
120 bool NeedPrint_RatingVector;
121 bool NeedPrint_Enc_1;
122 bool NeedPrint_Enc;
123 bool NeedPrint_Dec_1;
124 bool NeedPrint_Dec;
125 bool NeedPrint_Tot; // intermediate Total was updated after current pass
126
127 void Init();
128 };
129
130
Init()131 void CSyncData::Init()
132 {
133 NumPasses_Finished = 0;
134
135 // NumEncProgress = 0;
136 // NumDecProgress = 0;
137
138 Enc_BenchRes.Init();
139 Enc_BenchRes_1.Init();
140 Dec_BenchRes.Init();
141 Dec_BenchRes_1.Init();
142
143 #ifdef PRINT_ITER_TIME
144 TotalTicks = 0;
145 #endif
146
147 RatingVector_DeletedIndex = -1;
148 // RatingVector_NumDeleted = 0;
149
150 BenchWasFinished =
151 NeedPrint_Freq =
152 NeedPrint_RatingVector =
153 NeedPrint_Enc_1 =
154 NeedPrint_Enc =
155 NeedPrint_Dec_1 =
156 NeedPrint_Dec =
157 NeedPrint_Tot = false;
158 }
159
160
161 struct CBenchProgressSync
162 {
163 bool Exit; // GUI asks BenchThread to Exit, and BenchThread reads that variable
164 UInt32 NumThreads;
165 UInt64 DictSize;
166 UInt32 NumPasses_Limit;
167 int Level;
168
169 // must be written by benchmark thread, read by GUI thread */
170 CSyncData sd;
171 CRecordVector<CBenchPassResult> RatingVector;
172
173 NWindows::NSynchronization::CCriticalSection CS;
174
175 AString Text;
176 bool TextWasChanged;
177
178 /* BenchFinish_Task_HRESULT - for result from benchmark code
179 BenchFinish_Thread_HRESULT - for Exceptions and service errors
180 these arreos must be shown even if user escapes benchmark */
181
182 HRESULT BenchFinish_Task_HRESULT;
183 HRESULT BenchFinish_Thread_HRESULT;
184
185 UInt32 NumFreqThreadsPrev;
186 UString FreqString_Sync;
187 UString FreqString_GUI;
188
CBenchProgressSyncCBenchProgressSync189 CBenchProgressSync()
190 {
191 NumPasses_Limit = 1;
192 }
193
194 void Init();
195
SendExitCBenchProgressSync196 void SendExit()
197 {
198 NWindows::NSynchronization::CCriticalSectionLock lock(CS);
199 Exit = true;
200 }
201 };
202
203
Init()204 void CBenchProgressSync::Init()
205 {
206 Exit = false;
207
208 BenchFinish_Task_HRESULT = S_OK;
209 BenchFinish_Thread_HRESULT = S_OK;
210
211 sd.Init();
212 RatingVector.Clear();
213
214 NumFreqThreadsPrev = 0;
215 FreqString_Sync.Empty();
216 FreqString_GUI.Empty();
217
218 Text.Empty();
219 TextWasChanged = true;
220 }
221
222
223
224 struct CMyFont
225 {
226 HFONT _font;
CMyFontCMyFont227 CMyFont(): _font(NULL) {}
~CMyFontCMyFont228 ~CMyFont()
229 {
230 if (_font)
231 DeleteObject(_font);
232 }
CreateCMyFont233 void Create(const LOGFONT *lplf)
234 {
235 _font = CreateFontIndirect(lplf);
236 }
237 };
238
239
240 class CBenchmarkDialog;
241
242 struct CThreadBenchmark
243 {
244 CBenchmarkDialog *BenchmarkDialog;
245 DECL_EXTERNAL_CODECS_LOC_VARS_DECL
246 // HRESULT Result;
247
248 HRESULT Process();
MyThreadFunctionCThreadBenchmark249 static THREAD_FUNC_DECL MyThreadFunction(void *param)
250 {
251 /* ((CThreadBenchmark *)param)->Result = */
252 ((CThreadBenchmark *)param)->Process();
253 return 0;
254 }
255 };
256
257
258 class CBenchmarkDialog:
259 public NWindows::NControl::CModalDialog
260 {
261 NWindows::NControl::CComboBox m_Dictionary;
262 NWindows::NControl::CComboBox m_NumThreads;
263 NWindows::NControl::CComboBox m_NumPasses;
264 NWindows::NControl::CEdit _consoleEdit;
265 UINT_PTR _timer;
266
267 UInt32 _startTime;
268 UInt32 _finishTime;
269 bool _finishTime_WasSet;
270
271 bool WasStopped_in_GUI;
272 bool ExitWasAsked_in_GUI;
273 bool NeedRestart;
274
275 CMyFont _font;
276
277 UInt64 RamSize;
278 UInt64 RamSize_Limit;
279 bool RamSize_Defined;
280
281 UInt32 NumPasses_Finished_Prev;
282
283 UString ElapsedSec_Prev;
284
InitSyncNew()285 void InitSyncNew()
286 {
287 NumPasses_Finished_Prev = (UInt32)(Int32)-1;
288 ElapsedSec_Prev.Empty();
289 Sync.Init();
290 }
291
292 virtual bool OnInit() Z7_override;
293 virtual bool OnDestroy() Z7_override;
294 virtual bool OnSize(WPARAM /* wParam */, int xSize, int ySize) Z7_override;
295 virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override;
296 virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override;
297 virtual void OnHelp() Z7_override;
298 virtual void OnCancel() Z7_override;
299 virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override;
300 virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
301
302 void Disable_Stop_Button();
303 void OnStopButton();
304 void RestartBenchmark();
305 void StartBenchmark();
306
307 void UpdateGui();
308
309 void PrintTime();
310 void PrintRating(UInt64 rating, UINT controlID);
311 void PrintUsage(UInt64 usage, UINT controlID);
312 void PrintBenchRes(const CTotalBenchRes2 &info, const UINT ids[]);
313
314 UInt32 GetNumberOfThreads();
315 size_t OnChangeDictionary();
316
317 void SetItemText_Number(unsigned itemID, UInt64 val, LPCTSTR post = NULL);
318 void Print_MemUsage(UString &s, UInt64 memUsage) const;
IsMemoryUsageOK(UInt64 memUsage) const319 bool IsMemoryUsageOK(UInt64 memUsage) const
320 { return memUsage + (1 << 20) <= RamSize_Limit; }
321
322 void MyKillTimer();
323
SendExit_Status(const wchar_t * message)324 void SendExit_Status(const wchar_t *message)
325 {
326 SetItemText(IDT_BENCH_ERROR_MESSAGE, message);
327 Sync.SendExit();
328 }
329
330 public:
331 CBenchProgressSync Sync;
332
333 bool TotalMode;
334 CObjectVector<CProperty> Props;
335
336 CSysString Bench2Text;
337
338 NWindows::CThread _thread;
339 CThreadBenchmark _threadBenchmark;
340
CBenchmarkDialog()341 CBenchmarkDialog():
342 _timer(0),
343 WasStopped_in_GUI(false),
344 ExitWasAsked_in_GUI(false),
345 NeedRestart(false),
346 TotalMode(false)
347 {}
348
349 ~CBenchmarkDialog() Z7_DESTRUCTOR_override;
350
PostMsg_Finish(WPARAM wparam)351 bool PostMsg_Finish(WPARAM wparam)
352 {
353 if ((HWND)*this)
354 return PostMsg(k_Message_Finished, wparam);
355 // the (HWND)*this is NULL only for some internal code failure
356 return true;
357 }
358
Create(HWND wndParent=NULL)359 INT_PTR Create(HWND wndParent = NULL)
360 {
361 BIG_DIALOG_SIZE(332, 228);
362 return CModalDialog::Create(TotalMode ? IDD_BENCH_TOTAL : SIZED_DIALOG(IDD_BENCH), wndParent);
363 }
MessageBoxError(LPCWSTR message)364 void MessageBoxError(LPCWSTR message)
365 {
366 MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR);
367 }
MessageBoxError_Status(LPCWSTR message)368 void MessageBoxError_Status(LPCWSTR message)
369 {
370 UString s ("ERROR: ");
371 s += message;
372 MessageBoxError(s);
373 SetItemText(IDT_BENCH_ERROR_MESSAGE, s);
374 }
375 };
376
377
378
379
380
381
382
383
384
385 UString HResultToMessage(HRESULT errorCode);
386
387 #ifdef Z7_LANG
388 static const UInt32 kLangIDs[] =
389 {
390 IDT_BENCH_DICTIONARY,
391 IDT_BENCH_MEMORY,
392 IDT_BENCH_NUM_THREADS,
393 IDT_BENCH_SIZE,
394 IDT_BENCH_RATING_LABEL,
395 IDT_BENCH_USAGE_LABEL,
396 IDT_BENCH_RPU_LABEL,
397 IDG_BENCH_COMPRESSING,
398 IDG_BENCH_DECOMPRESSING,
399 IDG_BENCH_TOTAL_RATING,
400 IDT_BENCH_CURRENT,
401 IDT_BENCH_RESULTING,
402 IDT_BENCH_ELAPSED,
403 IDT_BENCH_PASSES,
404 IDB_STOP,
405 IDB_RESTART
406 };
407
408 static const UInt32 kLangIDs_RemoveColon[] =
409 {
410 IDT_BENCH_SPEED
411 };
412
413 #endif
414
415 static LPCTSTR const kProcessingString = TEXT("...");
416 static LPCTSTR const kGB = TEXT(" GB");
417 static LPCTSTR const kMB = TEXT(" MB");
418 static LPCTSTR const kKB = TEXT(" KB");
419 // static LPCTSTR const kMIPS = TEXT(" MIPS");
420 static LPCTSTR const kKBs = TEXT(" KB/s");
421
422 static const unsigned kMinDicLogSize = 18;
423
424 static const UInt32 kMinDicSize = (UInt32)1 << kMinDicLogSize;
425 static const size_t kMaxDicSize = (size_t)1 << (22 + sizeof(size_t) / 4 * 5);
426 // static const size_t kMaxDicSize = (size_t)1 << 16;
427 /*
428 #ifdef MY_CPU_64BIT
429 (UInt32)(Int32)-1; // we can use it, if we want 4 GB buffer
430 // (UInt32)15 << 28;
431 #else
432 (UInt32)1 << 27;
433 #endif
434 */
435
436
ComboBox_Add_UInt32(NWindows::NControl::CComboBox & cb,UInt32 v)437 static int ComboBox_Add_UInt32(NWindows::NControl::CComboBox &cb, UInt32 v)
438 {
439 TCHAR s[16];
440 ConvertUInt32ToString(v, s);
441 const int index = (int)cb.AddString(s);
442 cb.SetItemData(index, (LPARAM)v);
443 return index;
444 }
445
446
OnInit()447 bool CBenchmarkDialog::OnInit()
448 {
449 #ifdef Z7_LANG
450 LangSetWindowText(*this, IDD_BENCH);
451 LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
452 LangSetDlgItems_RemoveColon(*this, kLangIDs_RemoveColon, Z7_ARRAY_SIZE(kLangIDs_RemoveColon));
453 LangSetDlgItemText(*this, IDT_BENCH_CURRENT2, IDT_BENCH_CURRENT);
454 LangSetDlgItemText(*this, IDT_BENCH_RESULTING2, IDT_BENCH_RESULTING);
455 #endif
456
457 InitSyncNew();
458
459 if (TotalMode)
460 {
461 _consoleEdit.Attach(GetItem(IDE_BENCH2_EDIT));
462 LOGFONT f;
463 memset(&f, 0, sizeof(f));
464 f.lfHeight = 14;
465 f.lfWidth = 0;
466 f.lfWeight = FW_DONTCARE;
467 f.lfCharSet = DEFAULT_CHARSET;
468 f.lfOutPrecision = OUT_DEFAULT_PRECIS;
469 f.lfClipPrecision = CLIP_DEFAULT_PRECIS;
470 f.lfQuality = DEFAULT_QUALITY;
471
472 f.lfPitchAndFamily = FIXED_PITCH;
473 // MyStringCopy(f.lfFaceName, TEXT(""));
474 // f.lfFaceName[0] = 0;
475 _font.Create(&f);
476 if (_font._font)
477 _consoleEdit.SendMsg(WM_SETFONT, (WPARAM)_font._font, TRUE);
478 }
479
480 UInt32 numCPUs = 1;
481
482 {
483 AString s ("/ ");
484
485 NSystem::CProcessAffinity threadsInfo;
486 threadsInfo.InitST();
487
488 #ifndef Z7_ST
489 if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0)
490 numCPUs = threadsInfo.GetNumProcessThreads();
491 else
492 numCPUs = NSystem::GetNumberOfProcessors();
493 #endif
494
495 s.Add_UInt32(numCPUs);
496 s += GetProcessThreadsInfo(threadsInfo);
497 SetItemTextA(IDT_BENCH_HARDWARE_THREADS, s);
498
499 {
500 AString s2;
501 GetSysInfo(s, s2);
502 SetItemTextA(IDT_BENCH_SYS1, s);
503 if (s != s2 && !s2.IsEmpty())
504 SetItemTextA(IDT_BENCH_SYS2, s2);
505 }
506 {
507 GetCpuName_MultiLine(s);
508 SetItemTextA(IDT_BENCH_CPU, s);
509 }
510 {
511 GetOsInfoText(s);
512 s += " : ";
513 AddCpuFeatures(s);
514 SetItemTextA(IDT_BENCH_CPU_FEATURE, s);
515 }
516
517 s = "7-Zip " MY_VERSION_CPU;
518 SetItemTextA(IDT_BENCH_VER, s);
519 }
520
521
522 // ----- Num Threads ----------
523
524 if (numCPUs < 1)
525 numCPUs = 1;
526 numCPUs = MyMin(numCPUs, (UInt32)(1 << 6)); // it's WIN32 limit
527
528 UInt32 numThreads = Sync.NumThreads;
529
530 if (numThreads == (UInt32)(Int32)-1)
531 numThreads = numCPUs;
532 if (numThreads > 1)
533 numThreads &= ~(UInt32)1;
534 const UInt32 kNumThreadsMax = (1 << 12);
535 if (numThreads > kNumThreadsMax)
536 numThreads = kNumThreadsMax;
537
538 m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS));
539 const UInt32 numTheads_Combo = numCPUs * 2;
540 UInt32 v = 1;
541 int cur = 0;
542 for (; v <= numTheads_Combo;)
543 {
544 int index = ComboBox_Add_UInt32(m_NumThreads, v);
545 const UInt32 vNext = v + (v < 2 ? 1 : 2);
546 if (v <= numThreads)
547 if (numThreads < vNext || vNext > numTheads_Combo)
548 {
549 if (v != numThreads)
550 index = ComboBox_Add_UInt32(m_NumThreads, numThreads);
551 cur = index;
552 }
553 v = vNext;
554 }
555 m_NumThreads.SetCurSel(cur);
556 Sync.NumThreads = GetNumberOfThreads();
557
558
559 // ----- Dictionary ----------
560
561 m_Dictionary.Attach(GetItem(IDC_BENCH_DICTIONARY));
562
563 RamSize = (UInt64)(sizeof(size_t)) << 29;
564 RamSize_Defined = NSystem::GetRamSize(RamSize);
565
566
567 #ifdef UNDER_CE
568 const UInt32 kNormalizedCeSize = (16 << 20);
569 if (RamSize > kNormalizedCeSize && RamSize < (33 << 20))
570 RamSize = kNormalizedCeSize;
571 #endif
572 RamSize_Limit = RamSize / 16 * 15;
573
574 if (Sync.DictSize == (UInt64)(Int64)-1)
575 {
576 unsigned dicSizeLog = 25;
577 #ifdef UNDER_CE
578 dicSizeLog = 20;
579 #endif
580 if (RamSize_Defined)
581 for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
582 if (IsMemoryUsageOK(GetBenchMemoryUsage(
583 Sync.NumThreads, Sync.Level, (UInt64)1 << dicSizeLog, TotalMode)))
584 break;
585 Sync.DictSize = (UInt64)1 << dicSizeLog;
586 }
587
588 if (Sync.DictSize < kMinDicSize) Sync.DictSize = kMinDicSize;
589 if (Sync.DictSize > kMaxDicSize) Sync.DictSize = kMaxDicSize;
590
591 cur = 0;
592 for (unsigned i = (kMinDicLogSize - 1) * 2; i <= (32 - 1) * 2; i++)
593 {
594 const size_t dict = (size_t)(2 + (i & 1)) << (i / 2);
595 // if (i == (32 - 1) * 2) dict = kMaxDicSize;
596 TCHAR s[32];
597 const TCHAR *post;
598 UInt32 d;
599 if (dict >= ((UInt32)1 << 31)) { d = (UInt32)(dict >> 30); post = kGB; }
600 else if (dict >= ((UInt32)1 << 21)) { d = (UInt32)(dict >> 20); post = kMB; }
601 else { d = (UInt32)(dict >> 10); post = kKB; }
602 ConvertUInt32ToString(d, s);
603 lstrcat(s, post);
604 const int index = (int)m_Dictionary.AddString(s);
605 m_Dictionary.SetItemData(index, (LPARAM)dict);
606 if (dict <= Sync.DictSize)
607 cur = index;
608 if (dict >= kMaxDicSize)
609 break;
610 }
611 m_Dictionary.SetCurSel(cur);
612
613
614 // ----- Num Passes ----------
615
616 m_NumPasses.Attach(GetItem(IDC_BENCH_NUM_PASSES));
617 cur = 0;
618 v = 1;
619 for (;;)
620 {
621 int index = ComboBox_Add_UInt32(m_NumPasses, v);
622 const bool isLast = (v >= 10000000);
623 UInt32 vNext = v * 10;
624 if (v < 2) vNext = 2;
625 else if (v < 5) vNext = 5;
626 else if (v < 10) vNext = 10;
627
628 if (v <= Sync.NumPasses_Limit)
629 if (isLast || Sync.NumPasses_Limit < vNext)
630 {
631 if (v != Sync.NumPasses_Limit)
632 index = ComboBox_Add_UInt32(m_NumPasses, Sync.NumPasses_Limit);
633 cur = index;
634 }
635 v = vNext;
636 if (isLast)
637 break;
638 }
639 m_NumPasses.SetCurSel(cur);
640
641 if (TotalMode)
642 NormalizeSize(true);
643 else
644 NormalizePosition();
645
646 RestartBenchmark();
647
648 return CModalDialog::OnInit();
649 }
650
651
OnSize(WPARAM,int xSize,int ySize)652 bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
653 {
654 int mx, my;
655 GetMargins(8, mx, my);
656
657 if (!TotalMode)
658 {
659 RECT rect;
660 GetClientRectOfItem(IDT_BENCH_LOG, rect);
661 int x = xSize - rect.left - mx;
662 int y = ySize - rect.top - my;
663 if (x < 0) x = 0;
664 if (y < 0) y = 0;
665 MoveItem(IDT_BENCH_LOG, rect.left, rect.top, x, y, true);
666 return false;
667 }
668
669 int bx1, bx2, by;
670
671 GetItemSizes(IDCANCEL, bx1, by);
672 GetItemSizes(IDHELP, bx2, by);
673
674 {
675 int y = ySize - my - by;
676 int x = xSize - mx - bx1;
677
678 InvalidateRect(NULL);
679
680 MoveItem(IDCANCEL, x, y, bx1, by);
681 MoveItem(IDHELP, x - mx - bx2, y, bx2, by);
682 }
683
684 if (_consoleEdit)
685 {
686 int yPos = ySize - my - by;
687 RECT rect;
688 GetClientRectOfItem(IDE_BENCH2_EDIT, rect);
689 int y = rect.top;
690 int ySize2 = yPos - my - y;
691 const int kMinYSize = 20;
692 int xx = xSize - mx * 2;
693 if (ySize2 < kMinYSize)
694 {
695 ySize2 = kMinYSize;
696 }
697 _consoleEdit.Move(mx, y, xx, ySize2);
698 }
699 return false;
700 }
701
702
GetNumberOfThreads()703 UInt32 CBenchmarkDialog::GetNumberOfThreads()
704 {
705 return (UInt32)m_NumThreads.GetItemData_of_CurSel();
706 }
707
708
709 #define UINT_TO_STR_3(s, val) { \
710 s[0] = (wchar_t)('0' + (val) / 100); \
711 s[1] = (wchar_t)('0' + (val) % 100 / 10); \
712 s[2] = (wchar_t)('0' + (val) % 10); \
713 s += 3; s[0] = 0; }
714
NumberToDot3(UInt64 val,WCHAR * s)715 static WCHAR *NumberToDot3(UInt64 val, WCHAR *s)
716 {
717 s = ConvertUInt64ToString(val / 1000, s);
718 const UInt32 rem = (UInt32)(val % 1000);
719 *s++ = '.';
720 UINT_TO_STR_3(s, rem)
721 return s;
722 }
723
SetItemText_Number(unsigned itemID,UInt64 val,LPCTSTR post)724 void CBenchmarkDialog::SetItemText_Number(unsigned itemID, UInt64 val, LPCTSTR post)
725 {
726 TCHAR s[64];
727 ConvertUInt64ToString(val, s);
728 if (post)
729 lstrcat(s, post);
730 SetItemText(itemID, s);
731 }
732
AddSize_MB(UString & s,UInt64 size)733 static void AddSize_MB(UString &s, UInt64 size)
734 {
735 s.Add_UInt64((size + (1 << 20) - 1) >> 20);
736 s += kMB;
737 }
738
Print_MemUsage(UString & s,UInt64 memUsage) const739 void CBenchmarkDialog::Print_MemUsage(UString &s, UInt64 memUsage) const
740 {
741 AddSize_MB(s, memUsage);
742 if (RamSize_Defined)
743 {
744 s += " / ";
745 AddSize_MB(s, RamSize);
746 }
747 }
748
OnChangeDictionary()749 size_t CBenchmarkDialog::OnChangeDictionary()
750 {
751 const size_t dict = (size_t)m_Dictionary.GetItemData_of_CurSel();
752 const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(),
753 Sync.Level,
754 dict,
755 false); // totalBench mode
756
757 UString s;
758 Print_MemUsage(s, memUsage);
759
760 #ifdef Z7_LARGE_PAGES
761 {
762 AString s2;
763 Add_LargePages_String(s2);
764 if (!s2.IsEmpty())
765 {
766 s.Add_Space();
767 s += s2;
768 }
769 }
770 #endif
771
772 SetItemText(IDT_BENCH_MEMORY_VAL, s);
773
774 return dict;
775 }
776
777
778 static const UInt32 g_IDs[] =
779 {
780 IDT_BENCH_COMPRESS_SIZE1,
781 IDT_BENCH_COMPRESS_SIZE2,
782 IDT_BENCH_COMPRESS_USAGE1,
783 IDT_BENCH_COMPRESS_USAGE2,
784 IDT_BENCH_COMPRESS_SPEED1,
785 IDT_BENCH_COMPRESS_SPEED2,
786 IDT_BENCH_COMPRESS_RATING1,
787 IDT_BENCH_COMPRESS_RATING2,
788 IDT_BENCH_COMPRESS_RPU1,
789 IDT_BENCH_COMPRESS_RPU2,
790
791 IDT_BENCH_DECOMPR_SIZE1,
792 IDT_BENCH_DECOMPR_SIZE2,
793 IDT_BENCH_DECOMPR_SPEED1,
794 IDT_BENCH_DECOMPR_SPEED2,
795 IDT_BENCH_DECOMPR_RATING1,
796 IDT_BENCH_DECOMPR_RATING2,
797 IDT_BENCH_DECOMPR_USAGE1,
798 IDT_BENCH_DECOMPR_USAGE2,
799 IDT_BENCH_DECOMPR_RPU1,
800 IDT_BENCH_DECOMPR_RPU2,
801
802 IDT_BENCH_TOTAL_USAGE_VAL,
803 IDT_BENCH_TOTAL_RATING_VAL,
804 IDT_BENCH_TOTAL_RPU_VAL
805 };
806
807
808 static const unsigned k_Ids_Enc_1[] = {
809 IDT_BENCH_COMPRESS_USAGE1,
810 IDT_BENCH_COMPRESS_SPEED1,
811 IDT_BENCH_COMPRESS_RPU1,
812 IDT_BENCH_COMPRESS_RATING1,
813 IDT_BENCH_COMPRESS_SIZE1 };
814
815 static const unsigned k_Ids_Enc[] = {
816 IDT_BENCH_COMPRESS_USAGE2,
817 IDT_BENCH_COMPRESS_SPEED2,
818 IDT_BENCH_COMPRESS_RPU2,
819 IDT_BENCH_COMPRESS_RATING2,
820 IDT_BENCH_COMPRESS_SIZE2 };
821
822 static const unsigned k_Ids_Dec_1[] = {
823 IDT_BENCH_DECOMPR_USAGE1,
824 IDT_BENCH_DECOMPR_SPEED1,
825 IDT_BENCH_DECOMPR_RPU1,
826 IDT_BENCH_DECOMPR_RATING1,
827 IDT_BENCH_DECOMPR_SIZE1 };
828
829 static const unsigned k_Ids_Dec[] = {
830 IDT_BENCH_DECOMPR_USAGE2,
831 IDT_BENCH_DECOMPR_SPEED2,
832 IDT_BENCH_DECOMPR_RPU2,
833 IDT_BENCH_DECOMPR_RATING2,
834 IDT_BENCH_DECOMPR_SIZE2 };
835
836 static const unsigned k_Ids_Tot[] = {
837 IDT_BENCH_TOTAL_USAGE_VAL,
838 0,
839 IDT_BENCH_TOTAL_RPU_VAL,
840 IDT_BENCH_TOTAL_RATING_VAL,
841 0 };
842
843
MyKillTimer()844 void CBenchmarkDialog::MyKillTimer()
845 {
846 if (_timer != 0)
847 {
848 KillTimer(kTimerID);
849 _timer = 0;
850 }
851 }
852
853
OnDestroy()854 bool CBenchmarkDialog::OnDestroy()
855 {
856 /* actually timer was removed before.
857 also the timer must be removed by Windows, when window will be removed. */
858 MyKillTimer(); // it's optional code
859 return false; // we return (false) to perform default dialog operation
860 }
861
862 void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString);
863
StartBenchmark()864 void CBenchmarkDialog::StartBenchmark()
865 {
866 NeedRestart = false;
867 WasStopped_in_GUI = false;
868
869 SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE);
870
871 MyKillTimer(); // optional code. timer was killed before
872
873 const size_t dict = OnChangeDictionary();
874 const UInt32 numThreads = GetNumberOfThreads();
875 const UInt32 numPasses = (UInt32)m_NumPasses.GetItemData_of_CurSel();
876
877 for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_IDs); i++)
878 SetItemText(g_IDs[i], kProcessingString);
879
880 SetItemText_Empty(IDT_BENCH_LOG);
881 SetItemText_Empty(IDT_BENCH_ELAPSED_VAL);
882 SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE);
883
884 const UInt64 memUsage = GetBenchMemoryUsage(numThreads, Sync.Level, dict,
885 false); // totalBench
886 if (!IsMemoryUsageOK(memUsage))
887 {
888 UString s2;
889 LangString_OnlyFromLangFile(IDS_MEM_REQUIRED_MEM_SIZE, s2);
890 if (s2.IsEmpty())
891 {
892 s2 = LangString(IDT_BENCH_MEMORY);
893 if (s2.IsEmpty())
894 GetItemText(IDT_BENCH_MEMORY, s2);
895 s2.RemoveChar(L':');
896 }
897 UString s;
898 SetErrorMessage_MemUsage(s, memUsage, RamSize, RamSize_Limit, s2);
899 MessageBoxError_Status(s);
900 return;
901 }
902
903 EnableItem(IDB_STOP, true);
904
905 _startTime = GetTickCount();
906 _finishTime = _startTime;
907 _finishTime_WasSet = false;
908
909 {
910 NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
911 InitSyncNew();
912 Sync.DictSize = dict;
913 Sync.NumThreads = numThreads;
914 Sync.NumPasses_Limit = numPasses;
915 }
916
917 PrintTime();
918
919 _timer = SetTimer(kTimerID, kTimerElapse);
920 if (_thread.Create(CThreadBenchmark::MyThreadFunction, &_threadBenchmark) != 0)
921 {
922 MyKillTimer();
923 MessageBoxError_Status(L"Can't create thread");
924 }
925 return;
926 }
927
928
RestartBenchmark()929 void CBenchmarkDialog::RestartBenchmark()
930 {
931 if (ExitWasAsked_in_GUI)
932 return;
933
934 if (_thread.IsCreated())
935 {
936 NeedRestart = true;
937 SendExit_Status(L"Stop for restart ...");
938 }
939 else
940 StartBenchmark();
941 }
942
943
Disable_Stop_Button()944 void CBenchmarkDialog::Disable_Stop_Button()
945 {
946 // if we disable focused button, then focus will be lost
947 if (GetFocus() == GetItem(IDB_STOP))
948 {
949 // SendMsg_NextDlgCtl_Prev();
950 SendMsg_NextDlgCtl_CtlId(IDB_RESTART);
951 }
952 EnableItem(IDB_STOP, false);
953 }
954
955
OnStopButton()956 void CBenchmarkDialog::OnStopButton()
957 {
958 if (ExitWasAsked_in_GUI)
959 return;
960
961 Disable_Stop_Button();
962
963 WasStopped_in_GUI = true;
964 if (_thread.IsCreated())
965 {
966 SendExit_Status(L"Stop ...");
967 }
968 }
969
970
971
OnCancel()972 void CBenchmarkDialog::OnCancel()
973 {
974 ExitWasAsked_in_GUI = true;
975
976 /*
977 SendMsg_NextDlgCtl_Prev();
978 EnableItem(IDCANCEL, false);
979 */
980
981 if (_thread.IsCreated())
982 SendExit_Status(L"Cancel ...");
983 else
984 CModalDialog::OnCancel();
985 }
986
987
OnHelp()988 void CBenchmarkDialog::OnHelp()
989 {
990 ShowHelpWindow(kHelpTopic);
991 }
992
993
994
995 // void GetTimeString(UInt64 timeValue, wchar_t *s);
996
PrintTime()997 void CBenchmarkDialog::PrintTime()
998 {
999 const UInt32 curTime =
1000 _finishTime_WasSet ?
1001 _finishTime :
1002 ::GetTickCount();
1003
1004 const UInt32 elapsedTime = (curTime - _startTime);
1005
1006 WCHAR s[64];
1007
1008 WCHAR *p = ConvertUInt32ToString(elapsedTime / 1000, s);
1009
1010 if (_finishTime_WasSet)
1011 {
1012 *p++ = '.';
1013 UINT_TO_STR_3(p, elapsedTime % 1000)
1014 }
1015
1016 // p = NumberToDot3((UInt64)elapsedTime, s);
1017
1018 MyStringCopy(p, L" s");
1019
1020 // if (WasStopped_in_GUI) wcscat(s, L" X"); // for debug
1021
1022 if (s == ElapsedSec_Prev)
1023 return;
1024
1025 ElapsedSec_Prev = s;
1026
1027 // static cnt = 0; cnt++; wcscat(s, L" ");
1028 // UString s2; s2.Add_UInt32(cnt); wcscat(s, s2.Ptr());
1029
1030 SetItemText(IDT_BENCH_ELAPSED_VAL, s);
1031 }
1032
1033
GetMips(UInt64 ips)1034 static UInt64 GetMips(UInt64 ips)
1035 {
1036 return (ips + 500000) / 1000000;
1037 }
1038
1039
GetUsagePercents(UInt64 usage)1040 static UInt64 GetUsagePercents(UInt64 usage)
1041 {
1042 return Benchmark_GetUsage_Percents(usage);
1043 }
1044
1045
GetRating(const CTotalBenchRes & info)1046 static UInt32 GetRating(const CTotalBenchRes &info)
1047 {
1048 UInt64 numIter = info.NumIterations2;
1049 if (numIter == 0)
1050 numIter = 1000000;
1051 const UInt64 rating64 = GetMips(info.Rating / numIter);
1052 // return rating64;
1053 UInt32 rating32 = (UInt32)rating64;
1054 if (rating32 != rating64)
1055 rating32 = (UInt32)(Int32)-1;
1056 return rating32;
1057 }
1058
1059
AddUsageString(UString & s,const CTotalBenchRes & info)1060 static void AddUsageString(UString &s, const CTotalBenchRes &info)
1061 {
1062 UInt64 numIter = info.NumIterations2;
1063 if (numIter == 0)
1064 numIter = 1000000;
1065 UInt64 usage = GetUsagePercents(info.Usage / numIter);
1066
1067 wchar_t w[64];
1068 ConvertUInt64ToString(usage, w);
1069 unsigned len = MyStringLen(w);
1070 while (len < 5)
1071 {
1072 s.Add_Space();
1073 len++;
1074 }
1075 s += w;
1076 s += "%";
1077 }
1078
1079
Add_Dot3String(UString & s,UInt64 val)1080 static void Add_Dot3String(UString &s, UInt64 val)
1081 {
1082 WCHAR temp[32];
1083 NumberToDot3(val, temp);
1084 s += temp;
1085 }
1086
1087
AddRatingString(UString & s,const CTotalBenchRes & info)1088 static void AddRatingString(UString &s, const CTotalBenchRes &info)
1089 {
1090 // AddUsageString(s, info);
1091 // s.Add_Space();
1092 // s.Add_UInt32(GetRating(info));
1093 Add_Dot3String(s, GetRating(info));
1094 }
1095
1096
AddRatingsLine(UString & s,const CTotalBenchRes & enc,const CTotalBenchRes & dec,DWORD ticks)1097 static void AddRatingsLine(UString &s, const CTotalBenchRes &enc, const CTotalBenchRes &dec
1098 #ifdef PRINT_ITER_TIME
1099 , DWORD ticks
1100 #endif
1101 )
1102 {
1103 // AddUsageString(s, enc); s.Add_Space();
1104
1105 AddRatingString(s, enc);
1106 s += " ";
1107 AddRatingString(s, dec);
1108
1109 CTotalBenchRes tot_BenchRes;
1110 tot_BenchRes.SetSum(enc, dec);
1111
1112 s += " ";
1113 AddRatingString(s, tot_BenchRes);
1114
1115 s.Add_Space(); AddUsageString(s, tot_BenchRes);
1116
1117
1118 #ifdef PRINT_ITER_TIME
1119 s.Add_Space();
1120 {
1121 Add_Dot3String(s, ticks;
1122 s += " s";
1123 // s.Add_UInt32(ticks); s += " ms";
1124 }
1125 #endif
1126 }
1127
1128
1129 void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID)
1130 {
1131 // SetItemText_Number(controlID, GetMips(rating), kMIPS);
1132 WCHAR s[64];
1133 MyStringCopy(NumberToDot3(GetMips(rating), s), L" GIPS");
1134 SetItemText(controlID, s);
1135 }
1136
1137 void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID)
1138 {
1139 SetItemText_Number(controlID, GetUsagePercents(usage), TEXT("%"));
1140 }
1141
1142
1143 // void SetItemText_Number
1144
1145 void CBenchmarkDialog::PrintBenchRes(
1146 const CTotalBenchRes2 &info,
1147 const UINT ids[])
1148 {
1149 if (info.NumIterations2 == 0)
1150 return;
1151 if (ids[1] != 0)
1152 SetItemText_Number(ids[1], (info.Speed >> 10) / info.NumIterations2, kKBs);
1153 PrintRating(info.Rating / info.NumIterations2, ids[3]);
1154 PrintRating(info.RPU / info.NumIterations2, ids[2]);
1155 PrintUsage(info.Usage / info.NumIterations2, ids[0]);
1156 if (ids[4] != 0)
1157 {
1158 UInt64 val = info.UnpackSize;
1159 LPCTSTR kPostfix;
1160 if (val >= ((UInt64)1 << 40))
1161 {
1162 kPostfix = kGB;
1163 val >>= 30;
1164 }
1165 else
1166 {
1167 kPostfix = kMB;
1168 val >>= 20;
1169 }
1170 SetItemText_Number(ids[4], val, kPostfix);
1171 }
1172 }
1173
1174
1175 // static UInt32 k_Message_Finished_cnt = 0;
1176 // static UInt32 k_OnTimer_cnt = 0;
1177
1178 bool CBenchmarkDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
1179 {
1180 if (message != k_Message_Finished)
1181 return CModalDialog::OnMessage(message, wParam, lParam);
1182
1183 {
1184 if (wParam == k_Msg_WPARM_Thread_Finished)
1185 {
1186 _finishTime = GetTickCount();
1187 _finishTime_WasSet = true;
1188 MyKillTimer();
1189
1190 if (_thread.Wait_Close() != 0)
1191 {
1192 MessageBoxError_Status(L"Thread Wait Error");
1193 }
1194
1195 if (!WasStopped_in_GUI)
1196 {
1197 WasStopped_in_GUI = true;
1198 Disable_Stop_Button();
1199 }
1200
1201 HRESULT res = Sync.BenchFinish_Thread_HRESULT;
1202 if (res != S_OK)
1203 // if (!ExitWasAsked_in_GUI || res != E_ABORT)
1204 MessageBoxError_Status(HResultToMessage(res));
1205
1206 if (ExitWasAsked_in_GUI)
1207 {
1208 // SetItemText(IDT_BENCH_ERROR_MESSAGE, "before CModalDialog::OnCancel()");
1209 // Sleep (2000);
1210 // MessageBoxError(L"test");
1211 CModalDialog::OnCancel();
1212 return true;
1213 }
1214
1215 SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE);
1216
1217 res = Sync.BenchFinish_Task_HRESULT;
1218 if (res != S_OK)
1219 {
1220 if (!WasStopped_in_GUI || res != E_ABORT)
1221 {
1222 UString m;
1223 if (res == S_FALSE)
1224 m = "Decoding error";
1225 else if (res == CLASS_E_CLASSNOTAVAILABLE)
1226 m = "Can't find 7z.dll";
1227 else
1228 m = HResultToMessage(res);
1229 MessageBoxError_Status(m);
1230 }
1231 }
1232
1233 if (NeedRestart)
1234 {
1235 StartBenchmark();
1236 return true;
1237 }
1238 }
1239 // k_Message_Finished_cnt++;
1240 UpdateGui();
1241 return true;
1242 }
1243 }
1244
1245
1246 bool CBenchmarkDialog::OnTimer(WPARAM timerID, LPARAM /* callback */)
1247 {
1248 // k_OnTimer_cnt++;
1249 if (timerID == kTimerID)
1250 UpdateGui();
1251 return true;
1252 }
1253
1254
1255 void CBenchmarkDialog::UpdateGui()
1256 {
1257 PrintTime();
1258
1259 if (TotalMode)
1260 {
1261 bool wasChanged = false;
1262 {
1263 NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
1264
1265 if (Sync.TextWasChanged)
1266 {
1267 wasChanged = true;
1268 Bench2Text += Sync.Text;
1269 Sync.Text.Empty();
1270 Sync.TextWasChanged = false;
1271 }
1272 }
1273 if (wasChanged)
1274 _consoleEdit.SetText(Bench2Text);
1275 return;
1276 }
1277
1278 CSyncData sd;
1279 CRecordVector<CBenchPassResult> RatingVector;
1280
1281 {
1282 NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
1283 sd = Sync.sd;
1284
1285 if (sd.NeedPrint_RatingVector)
1286 RatingVector = Sync.RatingVector;
1287
1288 if (sd.NeedPrint_Freq)
1289 {
1290 Sync.FreqString_GUI = Sync.FreqString_Sync;
1291 sd.NeedPrint_RatingVector = true;
1292 }
1293
1294 Sync.sd.NeedPrint_RatingVector = false;
1295 Sync.sd.NeedPrint_Enc_1 = false;
1296 Sync.sd.NeedPrint_Enc = false;
1297 Sync.sd.NeedPrint_Dec_1 = false;
1298 Sync.sd.NeedPrint_Dec = false;
1299 Sync.sd.NeedPrint_Tot = false;
1300 Sync.sd.NeedPrint_Freq = false;
1301 }
1302
1303 if (sd.NumPasses_Finished != NumPasses_Finished_Prev)
1304 {
1305 SetItemText_Number(IDT_BENCH_PASSES_VAL, sd.NumPasses_Finished, TEXT(" /"));
1306 NumPasses_Finished_Prev = sd.NumPasses_Finished;
1307 }
1308
1309 if (sd.NeedPrint_Enc_1) PrintBenchRes(sd.Enc_BenchRes_1, k_Ids_Enc_1);
1310 if (sd.NeedPrint_Enc) PrintBenchRes(sd.Enc_BenchRes, k_Ids_Enc);
1311 if (sd.NeedPrint_Dec_1) PrintBenchRes(sd.Dec_BenchRes_1, k_Ids_Dec_1);
1312 if (sd.NeedPrint_Dec) PrintBenchRes(sd.Dec_BenchRes, k_Ids_Dec);
1313
1314 if (sd.BenchWasFinished && sd.NeedPrint_Tot)
1315 {
1316 CTotalBenchRes2 tot_BenchRes = sd.Enc_BenchRes;
1317 tot_BenchRes.Update_With_Res2(sd.Dec_BenchRes);
1318 PrintBenchRes(tot_BenchRes, k_Ids_Tot);
1319 }
1320
1321
1322 if (sd.NeedPrint_RatingVector)
1323 // for (unsigned k = 0; k < 1; k++)
1324 {
1325 UString s;
1326 s += Sync.FreqString_GUI;
1327 if (!RatingVector.IsEmpty())
1328 {
1329 if (!s.IsEmpty())
1330 s.Add_LF();
1331 s += "Compr Decompr Total CPU"
1332 #ifdef PRINT_ITER_TIME
1333 " Time"
1334 #endif
1335 ;
1336 s.Add_LF();
1337 }
1338 // s += "GIPS GIPS GIPS % s"; s.Add_LF();
1339 for (unsigned i = 0; i < RatingVector.Size(); i++)
1340 {
1341 if (i != 0)
1342 s.Add_LF();
1343 if ((int)i == sd.RatingVector_DeletedIndex)
1344 {
1345 s += "...";
1346 s.Add_LF();
1347 }
1348 const CBenchPassResult &pair = RatingVector[i];
1349 /*
1350 s += "g:"; s.Add_UInt32((UInt32)pair.EncInfo.GlobalTime);
1351 s += " u:"; s.Add_UInt32((UInt32)pair.EncInfo.UserTime);
1352 s.Add_Space();
1353 */
1354 AddRatingsLine(s, pair.Enc, pair.Dec
1355 #ifdef PRINT_ITER_TIME
1356 , pair.Ticks
1357 #endif
1358 );
1359 /*
1360 {
1361 UInt64 v = i + 1;
1362 if (sd.RatingVector_DeletedIndex >= 0 && i >= (unsigned)sd.RatingVector_DeletedIndex)
1363 v += sd.RatingVector_NumDeleted;
1364 char temp[64];
1365 ConvertUInt64ToString(v, temp);
1366 s += " : ";
1367 s += temp;
1368 }
1369 */
1370 }
1371
1372 if (sd.BenchWasFinished)
1373 {
1374 s.Add_LF();
1375 s += "-------------";
1376 s.Add_LF();
1377 {
1378 // average time is not correct because of freq detection in first iteration
1379 AddRatingsLine(s, sd.Enc_BenchRes, sd.Dec_BenchRes
1380 #ifdef PRINT_ITER_TIME
1381 , (DWORD)(sd.TotalTicks / (sd.NumPasses_Finished ? sd.NumPasses_Finished : 1))
1382 #endif
1383 );
1384 }
1385 }
1386 // s.Add_LF(); s += "OnTimer: "; s.Add_UInt32(k_OnTimer_cnt);
1387 // s.Add_LF(); s += "finished Message: "; s.Add_UInt32(k_Message_Finished_cnt);
1388 // static cnt = 0; cnt++; s.Add_LF(); s += "Print: "; s.Add_UInt32(cnt);
1389 // s.Add_LF(); s += "NumEncProgress: "; s.Add_UInt32((UInt32)sd.NumEncProgress);
1390 // s.Add_LF(); s += "NumDecProgress: "; s.Add_UInt32((UInt32)sd.NumDecProgress);
1391 SetItemText(IDT_BENCH_LOG, s);
1392 }
1393 }
1394
1395
1396 bool CBenchmarkDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
1397 {
1398 if (code == CBN_SELCHANGE &&
1399 (itemID == IDC_BENCH_DICTIONARY ||
1400 itemID == IDC_BENCH_NUM_PASSES ||
1401 itemID == IDC_BENCH_NUM_THREADS))
1402 {
1403 RestartBenchmark();
1404 return true;
1405 }
1406 return CModalDialog::OnCommand(code, itemID, lParam);
1407 }
1408
1409
1410 bool CBenchmarkDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
1411 {
1412 switch (buttonID)
1413 {
1414 case IDB_RESTART:
1415 RestartBenchmark();
1416 return true;
1417 case IDB_STOP:
1418 OnStopButton();
1419 return true;
1420 }
1421 return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
1422 }
1423
1424
1425
1426
1427
1428 // ---------- Benchmark Thread ----------
1429
1430 struct CBenchCallback Z7_final: public IBenchCallback
1431 {
1432 UInt64 dictionarySize;
1433 CBenchProgressSync *Sync;
1434 CBenchmarkDialog *BenchmarkDialog;
1435
1436 HRESULT SetEncodeResult(const CBenchInfo &info, bool final) Z7_override;
1437 HRESULT SetDecodeResult(const CBenchInfo &info, bool final) Z7_override;
1438 };
1439
1440 HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
1441 {
1442 bool needPost = false;
1443 {
1444 NSynchronization::CCriticalSectionLock lock(Sync->CS);
1445 if (Sync->Exit)
1446 return E_ABORT;
1447 CSyncData &sd = Sync->sd;
1448 // sd.NumEncProgress++;
1449 CTotalBenchRes2 &br = sd.Enc_BenchRes_1;
1450 {
1451 UInt64 dictSize = Sync->DictSize;
1452 if (final)
1453 {
1454 // sd.EncInfo = info;
1455 }
1456 else
1457 {
1458 /* if (!final), then CBenchInfo::NumIterations means totalNumber of threads.
1459 so we can reduce the dictionary */
1460 if (dictSize > info.UnpackSize)
1461 dictSize = info.UnpackSize;
1462 }
1463 br.Rating = info.GetRating_LzmaEnc(dictSize);
1464 }
1465 br.SetFrom_BenchInfo(info);
1466 sd.NeedPrint_Enc_1 = true;
1467 if (final)
1468 {
1469 sd.Enc_BenchRes.Update_With_Res2(br);
1470 sd.NeedPrint_Enc = true;
1471 needPost = true;
1472 }
1473 }
1474
1475 if (needPost)
1476 BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished);
1477
1478 return S_OK;
1479 }
1480
1481
1482 HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
1483 {
1484 NSynchronization::CCriticalSectionLock lock(Sync->CS);
1485 if (Sync->Exit)
1486 return E_ABORT;
1487 CSyncData &sd = Sync->sd;
1488 // sd.NumDecProgress++;
1489 CTotalBenchRes2 &br = sd.Dec_BenchRes_1;
1490 br.Rating = info.GetRating_LzmaDec();
1491 br.SetFrom_BenchInfo(info);
1492 sd.NeedPrint_Dec_1 = true;
1493 if (final)
1494 sd.Dec_BenchRes.Update_With_Res2(br);
1495 return S_OK;
1496 }
1497
1498
1499 struct CBenchCallback2 Z7_final: public IBenchPrintCallback
1500 {
1501 CBenchProgressSync *Sync;
1502 bool TotalMode;
1503
1504 void Print(const char *s) Z7_override;
1505 void NewLine() Z7_override;
1506 HRESULT CheckBreak() Z7_override;
1507 };
1508
1509 void CBenchCallback2::Print(const char *s)
1510 {
1511 if (TotalMode)
1512 {
1513 NSynchronization::CCriticalSectionLock lock(Sync->CS);
1514 Sync->Text += s;
1515 Sync->TextWasChanged = true;
1516 }
1517 }
1518
1519 void CBenchCallback2::NewLine()
1520 {
1521 Print("\xD\n");
1522 }
1523
1524 HRESULT CBenchCallback2::CheckBreak()
1525 {
1526 if (Sync->Exit)
1527 return E_ABORT;
1528 return S_OK;
1529 }
1530
1531
1532
1533 struct CFreqCallback Z7_final: public IBenchFreqCallback
1534 {
1535 CBenchmarkDialog *BenchmarkDialog;
1536
1537 virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) Z7_override;
1538 virtual HRESULT FreqsFinished(unsigned numThreads) Z7_override;
1539 };
1540
1541 HRESULT CFreqCallback::AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage)
1542 {
1543 HRESULT res;
1544 {
1545 CBenchProgressSync &sync = BenchmarkDialog->Sync;
1546 NSynchronization::CCriticalSectionLock lock(sync.CS);
1547 UString &s = sync.FreqString_Sync;
1548 if (sync.NumFreqThreadsPrev != numThreads)
1549 {
1550 sync.NumFreqThreadsPrev = numThreads;
1551 if (!s.IsEmpty())
1552 s.Add_LF();
1553 s.Add_UInt32(numThreads);
1554 s += "T Frequency (MHz):";
1555 s.Add_LF();
1556 }
1557 s.Add_Space();
1558 if (numThreads != 1)
1559 {
1560 s.Add_UInt64(GetUsagePercents(usage));
1561 s.Add_Char('%');
1562 s.Add_Space();
1563 }
1564 s.Add_UInt64(GetMips(freq));
1565 // BenchmarkDialog->Sync.sd.NeedPrint_Freq = true;
1566 res = sync.Exit ? E_ABORT : S_OK;
1567 }
1568 // BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished);
1569 return res;
1570 }
1571
1572 HRESULT CFreqCallback::FreqsFinished(unsigned /* numThreads */)
1573 {
1574 HRESULT res;
1575 {
1576 CBenchProgressSync &sync = BenchmarkDialog->Sync;
1577 NSynchronization::CCriticalSectionLock lock(sync.CS);
1578 sync.sd.NeedPrint_Freq = true;
1579 BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished);
1580 res = sync.Exit ? E_ABORT : S_OK;
1581 }
1582 BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished);
1583 return res;
1584 }
1585
1586
1587
1588 // define USE_DUMMY only for debug
1589 // #define USE_DUMMY
1590 #ifdef USE_DUMMY
1591 static unsigned dummy = 1;
1592 static unsigned Dummy(unsigned limit)
1593 {
1594 unsigned sum = 0;
1595 for (unsigned k = 0; k < limit; k++)
1596 {
1597 sum += dummy;
1598 if (sum == 0)
1599 break;
1600 }
1601 return sum;
1602 }
1603 #endif
1604
1605
1606 HRESULT CThreadBenchmark::Process()
1607 {
1608 /* the first benchmark pass can be slow,
1609 if we run benchmark while the window is being created,
1610 and (no freq detecion loop) && (dictionary is small) (-mtic is small) */
1611
1612 // Sleep(300); // for debug
1613 #ifdef USE_DUMMY
1614 Dummy(1000 * 1000 * 1000); // for debug
1615 #endif
1616
1617 CBenchProgressSync &sync = BenchmarkDialog->Sync;
1618 HRESULT finishHRESULT = S_OK;
1619
1620 try
1621 {
1622 for (UInt32 passIndex = 0;; passIndex++)
1623 {
1624 // throw 1; // to debug
1625 // throw CSystemException(E_INVALIDARG); // to debug
1626
1627 UInt64 dictionarySize;
1628 UInt32 numThreads;
1629 {
1630 NSynchronization::CCriticalSectionLock lock(sync.CS);
1631 if (sync.Exit)
1632 break;
1633 dictionarySize = sync.DictSize;
1634 numThreads = sync.NumThreads;
1635 }
1636
1637 #ifdef PRINT_ITER_TIME
1638 const DWORD startTick = GetTickCount();
1639 #endif
1640
1641 CBenchCallback callback;
1642
1643 callback.dictionarySize = dictionarySize;
1644 callback.Sync = &sync;
1645 callback.BenchmarkDialog = BenchmarkDialog;
1646
1647 CBenchCallback2 callback2;
1648 callback2.TotalMode = BenchmarkDialog->TotalMode;
1649 callback2.Sync = &sync;
1650
1651 CFreqCallback freqCallback;
1652 freqCallback.BenchmarkDialog = BenchmarkDialog;
1653
1654 HRESULT result;
1655
1656 try
1657 {
1658 CObjectVector<CProperty> props;
1659
1660 props = BenchmarkDialog->Props;
1661
1662 if (BenchmarkDialog->TotalMode)
1663 {
1664 props = BenchmarkDialog->Props;
1665 }
1666 else
1667 {
1668 {
1669 CProperty prop;
1670 prop.Name = "mt";
1671 prop.Value.Add_UInt32(numThreads);
1672 props.Add(prop);
1673 }
1674 {
1675 CProperty prop;
1676 prop.Name = 'd';
1677 prop.Name.Add_UInt32((UInt32)(dictionarySize >> 10));
1678 prop.Name.Add_Char('k');
1679 props.Add(prop);
1680 }
1681 }
1682
1683 result = Bench(EXTERNAL_CODECS_LOC_VARS
1684 BenchmarkDialog->TotalMode ? &callback2 : NULL,
1685 BenchmarkDialog->TotalMode ? NULL : &callback,
1686 props, 1, false,
1687 (!BenchmarkDialog->TotalMode) && passIndex == 0 ? &freqCallback: NULL);
1688
1689 // result = S_FALSE; // for debug;
1690 // throw 1;
1691 }
1692 catch(...)
1693 {
1694 result = E_FAIL;
1695 }
1696
1697 #ifdef PRINT_ITER_TIME
1698 const DWORD numTicks = GetTickCount() - startTick;
1699 #endif
1700
1701 bool finished = true;
1702
1703 NSynchronization::CCriticalSectionLock lock(sync.CS);
1704
1705 if (result != S_OK)
1706 {
1707 sync.BenchFinish_Task_HRESULT = result;
1708 break;
1709 }
1710
1711 {
1712 CSyncData &sd = sync.sd;
1713
1714 sd.NumPasses_Finished++;
1715 #ifdef PRINT_ITER_TIME
1716 sd.TotalTicks += numTicks;
1717 #endif
1718
1719 if (BenchmarkDialog->TotalMode)
1720 break;
1721
1722 {
1723 CTotalBenchRes tot_BenchRes = sd.Enc_BenchRes_1;
1724 tot_BenchRes.Update_With_Res(sd.Dec_BenchRes_1);
1725
1726 sd.NeedPrint_RatingVector = true;
1727 {
1728 CBenchPassResult pair;
1729 // pair.EncInfo = sd.EncInfo; // for debug
1730 pair.Enc = sd.Enc_BenchRes_1;
1731 pair.Dec = sd.Dec_BenchRes_1;
1732 #ifdef PRINT_ITER_TIME
1733 pair.Ticks = numTicks;
1734 #endif
1735 sync.RatingVector.Add(pair);
1736 // pair.Dec_Defined = true;
1737 }
1738 }
1739
1740 sd.NeedPrint_Dec = true;
1741 sd.NeedPrint_Tot = true;
1742
1743 if (sync.RatingVector.Size() > kRatingVector_NumBundlesMax)
1744 {
1745 // sd.RatingVector_NumDeleted++;
1746 sd.RatingVector_DeletedIndex = (int)(kRatingVector_NumBundlesMax / 4);
1747 sync.RatingVector.Delete((unsigned)(sd.RatingVector_DeletedIndex));
1748 }
1749
1750 if (sync.sd.NumPasses_Finished < sync.NumPasses_Limit)
1751 finished = false;
1752 else
1753 {
1754 sync.sd.BenchWasFinished = true;
1755 // BenchmarkDialog->_finishTime = GetTickCount();
1756 // return 0;
1757 }
1758 }
1759
1760 if (BenchmarkDialog->TotalMode)
1761 break;
1762
1763 /*
1764 if (newTick - prevTick < 1000)
1765 numSameTick++;
1766 if (numSameTick > 5 || finished)
1767 {
1768 prevTick = newTick;
1769 numSameTick = 0;
1770 */
1771 // for (unsigned i = 0; i < 1; i++)
1772 {
1773 // we suppose that PostMsg messages will be processed in order.
1774 if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Iter_Finished))
1775 {
1776 finished = true;
1777 finishHRESULT = E_FAIL;
1778 // throw 1234567;
1779 }
1780 }
1781 if (finished)
1782 break;
1783 }
1784 // return S_OK;
1785 }
1786 catch(CSystemException &e)
1787 {
1788 finishHRESULT = e.ErrorCode;
1789 // BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode));
1790 // return E_FAIL;
1791 }
1792 catch(...)
1793 {
1794 finishHRESULT = E_FAIL;
1795 // BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL));
1796 // return E_FAIL;
1797 }
1798
1799 if (finishHRESULT != S_OK)
1800 {
1801 NSynchronization::CCriticalSectionLock lock(sync.CS);
1802 sync.BenchFinish_Thread_HRESULT = finishHRESULT;
1803 }
1804 if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Thread_Finished))
1805 {
1806 // sync.BenchFinish_Thread_HRESULT = E_FAIL;
1807 }
1808 return 0;
1809 }
1810
1811
1812
1813 static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
1814 {
1815 const wchar_t *end;
1816 UInt64 result = ConvertStringToUInt64(s, &end);
1817 if (*end != 0 || s.IsEmpty())
1818 prop = s;
1819 else if (result <= (UInt32)0xFFFFFFFF)
1820 prop = (UInt32)result;
1821 else
1822 prop = result;
1823 }
1824
1825
1826 HRESULT Benchmark(
1827 DECL_EXTERNAL_CODECS_LOC_VARS
1828 const CObjectVector<CProperty> &props, UInt32 numIterations, HWND hwndParent)
1829 {
1830 CBenchmarkDialog bd;
1831
1832 bd.TotalMode = false;
1833 bd.Props = props;
1834 if (numIterations == 0)
1835 numIterations = 1;
1836 bd.Sync.NumPasses_Limit = numIterations;
1837 bd.Sync.DictSize = (UInt64)(Int64)-1;
1838 bd.Sync.NumThreads = (UInt32)(Int32)-1;
1839 bd.Sync.Level = -1;
1840
1841 COneMethodInfo method;
1842
1843 UInt32 numCPUs = 1;
1844 #ifndef Z7_ST
1845 numCPUs = NSystem::GetNumberOfProcessors();
1846 #endif
1847 UInt32 numThreads = numCPUs;
1848
1849 FOR_VECTOR (i, props)
1850 {
1851 const CProperty &prop = props[i];
1852 UString name = prop.Name;
1853 name.MakeLower_Ascii();
1854 if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*")
1855 {
1856 bd.TotalMode = true;
1857 continue;
1858 }
1859
1860 NCOM::CPropVariant propVariant;
1861 if (!prop.Value.IsEmpty())
1862 ParseNumberString(prop.Value, propVariant);
1863 if (name.IsPrefixedBy(L"mt"))
1864 {
1865 #ifndef Z7_ST
1866 RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads))
1867 if (numThreads != numCPUs)
1868 bd.Sync.NumThreads = numThreads;
1869 #endif
1870 continue;
1871 }
1872 /*
1873 if (name.IsEqualTo("time"))
1874 {
1875 // UInt32 testTime = 4;
1876 // RINOK(ParsePropToUInt32(L"", propVariant, testTime));
1877 continue;
1878 }
1879 RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));
1880 */
1881 // here we need to parse DictSize property, and ignore unknown properties
1882 method.ParseMethodFromPROPVARIANT(name, propVariant);
1883 }
1884
1885 if (bd.TotalMode)
1886 {
1887 // bd.Bench2Text.Empty();
1888 bd.Bench2Text = "7-Zip " MY_VERSION_CPU;
1889 // bd.Bench2Text.Add_Char((char)0xD);
1890 bd.Bench2Text.Add_LF();
1891 }
1892
1893 {
1894 UInt64 dict;
1895 if (method.Get_DicSize(dict))
1896 bd.Sync.DictSize = dict;
1897 }
1898 bd.Sync.Level = (int)method.GetLevel();
1899
1900 // Dummy(1000 * 1000 * 1);
1901
1902 {
1903 CThreadBenchmark &benchmarker = bd._threadBenchmark;
1904 #ifdef Z7_EXTERNAL_CODECS
1905 benchmarker._externalCodecs = _externalCodecs;
1906 #endif
1907 benchmarker.BenchmarkDialog = &bd;
1908 }
1909
1910 bd.Create(hwndParent);
1911
1912 return S_OK;
1913 }
1914
1915
1916 CBenchmarkDialog::~CBenchmarkDialog()
1917 {
1918 if (_thread.IsCreated())
1919 {
1920 /* the following code will be not executed in normal code flow.
1921 it can be called, if there is some internal failure in dialog code. */
1922 Attach(NULL);
1923 MessageBoxError(L"The flaw in benchmark thread code");
1924 Sync.SendExit();
1925 _thread.Wait_Close();
1926 }
1927 }
1928