• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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