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