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/System.h"
14 #include "../../../Windows/Thread.h"
15 
16 #include "../../Common/MethodProps.h"
17 
18 #include "../FileManager/HelpUtils.h"
19 
20 #include "../../MyVersion.h"
21 
22 #include "BenchmarkDialog.h"
23 
24 using namespace NWindows;
25 
26 #define kHelpTopic "fm/benchmark.htm"
27 
28 static const UINT_PTR kTimerID = 4;
29 static const UINT kTimerElapse = 1000;
30 
31 #ifdef LANG
32 #include "../FileManager/LangUtils.h"
33 #endif
34 
35 using namespace NWindows;
36 
37 UString HResultToMessage(HRESULT errorCode);
38 
39 #ifdef LANG
40 static const UInt32 kLangIDs[] =
41 {
42   IDT_BENCH_DICTIONARY,
43   IDT_BENCH_MEMORY,
44   IDT_BENCH_NUM_THREADS,
45   IDT_BENCH_SPEED,
46   IDT_BENCH_RATING_LABEL,
47   IDT_BENCH_USAGE_LABEL,
48   IDT_BENCH_RPU_LABEL,
49   IDG_BENCH_COMPRESSING,
50   IDG_BENCH_DECOMPRESSING,
51   IDG_BENCH_TOTAL_RATING,
52   IDT_BENCH_CURRENT,
53   IDT_BENCH_RESULTING,
54   IDT_BENCH_ELAPSED,
55   IDT_BENCH_PASSES,
56   IDB_STOP,
57   IDB_RESTART
58 };
59 
60 static const UInt32 kLangIDs_Colon[] =
61 {
62   IDT_BENCH_SIZE
63 };
64 
65 #endif
66 
67 static LPCTSTR const kProcessingString = TEXT("...");
68 static LPCTSTR const kMB = TEXT(" MB");
69 static LPCTSTR const kMIPS = TEXT(" MIPS");
70 static LPCTSTR const kKBs = TEXT(" KB/s");
71 
72 static const unsigned kMinDicLogSize =
73   #ifdef UNDER_CE
74     20;
75   #else
76     21;
77   #endif
78 
79 static const UInt32 kMinDicSize = (1 << kMinDicLogSize);
80 static const UInt32 kMaxDicSize =
81     #ifdef MY_CPU_64BIT
82     (1 << 30);
83     #else
84     (1 << 27);
85     #endif
86 
OnInit()87 bool CBenchmarkDialog::OnInit()
88 {
89   #ifdef LANG
90   LangSetWindowText(*this, IDD_BENCH);
91   LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));
92   LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon));
93   LangSetDlgItemText(*this, IDT_BENCH_CURRENT2, IDT_BENCH_CURRENT);
94   LangSetDlgItemText(*this, IDT_BENCH_RESULTING2, IDT_BENCH_RESULTING);
95   #endif
96 
97   Sync.Init();
98 
99   if (TotalMode)
100   {
101     _consoleEdit.Attach(GetItem(IDE_BENCH2_EDIT));
102     LOGFONT f;
103     memset(&f, 0, sizeof(f));
104     f.lfHeight = 14;
105     f.lfWidth = 0;
106     f.lfWeight = FW_DONTCARE;
107     f.lfCharSet = DEFAULT_CHARSET;
108     f.lfOutPrecision = OUT_DEFAULT_PRECIS;
109     f.lfClipPrecision = CLIP_DEFAULT_PRECIS;
110     f.lfQuality = DEFAULT_QUALITY;
111 
112     f.lfPitchAndFamily = FIXED_PITCH;
113     // MyStringCopy(f.lfFaceName, TEXT(""));
114     // f.lfFaceName[0] = 0;
115     _font.Create(&f);
116     if (_font._font)
117       _consoleEdit.SendMsg(WM_SETFONT, (WPARAM)_font._font, TRUE);
118   }
119 
120   UInt32 numCPUs = 1;
121 
122   {
123     UString s ("/ ");
124 
125     NSystem::CProcessAffinity threadsInfo;
126     threadsInfo.InitST();
127 
128     #ifndef _7ZIP_ST
129 
130     if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0)
131       numCPUs = threadsInfo.GetNumProcessThreads();
132     else
133       numCPUs = NSystem::GetNumberOfProcessors();
134 
135     #endif
136 
137     s.Add_UInt32(numCPUs);
138     s += GetProcessThreadsInfo(threadsInfo);
139     SetItemText(IDT_BENCH_HARDWARE_THREADS, s);
140   }
141 
142   {
143     UString s;
144     {
145       AString s1, s2;
146       GetSysInfo(s1, s2);
147       s = s1;
148       SetItemText(IDT_BENCH_SYS1, s);
149       if (s1 != s2 && !s2.IsEmpty())
150       {
151         s = s2;
152         SetItemText(IDT_BENCH_SYS2, s);
153       }
154     }
155     /*
156     {
157       GetVersionString(s);
158       SetItemText(IDT_BENCH_SYSTEM, s);
159     }
160     */
161     {
162       AString s2;
163       GetCpuName(s2);
164       s = s2;
165       SetItemText(IDT_BENCH_CPU, s);
166     }
167     /*
168     {
169       AString s2;
170       GetCpuFeatures(s2);
171       s = s2;
172       SetItemText(IDT_BENCH_CPU_FEATURE, s);
173     }
174     */
175 
176     s = "7-Zip " MY_VERSION_CPU;
177     SetItemText(IDT_BENCH_VER, s);
178   }
179 
180 
181   if (numCPUs < 1)
182     numCPUs = 1;
183   numCPUs = MyMin(numCPUs, (UInt32)(1 << 8));
184 
185   if (Sync.NumThreads == (UInt32)(Int32)-1)
186   {
187     Sync.NumThreads = numCPUs;
188     if (Sync.NumThreads > 1)
189       Sync.NumThreads &= ~1;
190   }
191   m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS));
192   int cur = 0;
193   for (UInt32 num = 1; num <= numCPUs * 2;)
194   {
195     TCHAR s[16];
196     ConvertUInt32ToString(num, s);
197     int index = (int)m_NumThreads.AddString(s);
198     m_NumThreads.SetItemData(index, num);
199     if (num <= Sync.NumThreads)
200       cur = index;
201     if (num > 1)
202       num++;
203     num++;
204   }
205   m_NumThreads.SetCurSel(cur);
206   Sync.NumThreads = GetNumberOfThreads();
207 
208   m_Dictionary.Attach(GetItem(IDC_BENCH_DICTIONARY));
209   cur = 0;
210 
211   ramSize = (UInt64)(sizeof(size_t)) << 29;
212   ramSize_Defined = NSystem::GetRamSize(ramSize);
213 
214   #ifdef UNDER_CE
215   const UInt32 kNormalizedCeSize = (16 << 20);
216   if (ramSize > kNormalizedCeSize && ramSize < (33 << 20))
217     ramSize = kNormalizedCeSize;
218   #endif
219 
220   if (Sync.DictionarySize == (UInt32)(Int32)-1)
221   {
222     unsigned dicSizeLog = 25;
223 
224     #ifdef UNDER_CE
225     dicSizeLog = 20;
226     #endif
227 
228     if (ramSize_Defined)
229     for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
230       if (GetBenchMemoryUsage(Sync.NumThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize)
231         break;
232     Sync.DictionarySize = (1 << dicSizeLog);
233   }
234 
235   if (Sync.DictionarySize < kMinDicSize) Sync.DictionarySize = kMinDicSize;
236   if (Sync.DictionarySize > kMaxDicSize) Sync.DictionarySize = kMaxDicSize;
237 
238   for (unsigned i = kMinDicLogSize; i <= 30; i++)
239     for (unsigned j = 0; j < 2; j++)
240     {
241       UInt32 dict = ((UInt32)1 << i) + ((UInt32)j << (i - 1));
242       if (dict > kMaxDicSize)
243         continue;
244       TCHAR s[32];
245       ConvertUInt32ToString((dict >> 20), s);
246       lstrcat(s, kMB);
247       int index = (int)m_Dictionary.AddString(s);
248       m_Dictionary.SetItemData(index, dict);
249       if (dict <= Sync.DictionarySize)
250         cur = index;
251     }
252   m_Dictionary.SetCurSel(cur);
253 
254   OnChangeSettings();
255 
256   Sync._startEvent.Set();
257   _timer = SetTimer(kTimerID, kTimerElapse);
258 
259   if (TotalMode)
260     NormalizeSize(true);
261   else
262     NormalizePosition();
263   return CModalDialog::OnInit();
264 }
265 
OnSize(WPARAM,int xSize,int ySize)266 bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
267 {
268   if (!TotalMode)
269     return false;
270   int mx, my;
271   GetMargins(8, mx, my);
272   int bx1, bx2, by;
273   GetItemSizes(IDCANCEL, bx1, by);
274   GetItemSizes(IDHELP, bx2, by);
275 
276   {
277     int y = ySize - my - by;
278     int x = xSize - mx - bx1;
279 
280     InvalidateRect(NULL);
281 
282     MoveItem(IDCANCEL, x, y, bx1, by);
283     MoveItem(IDHELP, x - mx - bx2, y, bx2, by);
284   }
285 
286   if (_consoleEdit)
287   {
288     int yPos = ySize - my - by;
289     RECT rect;
290     GetClientRectOfItem(IDE_BENCH2_EDIT, rect);
291     int y = rect.top;
292     int ySize2 = yPos - my - y;
293     const int kMinYSize = 20;
294     int xx = xSize - mx * 2;
295     if (ySize2 < kMinYSize)
296     {
297       ySize2 = kMinYSize;
298     }
299     _consoleEdit.Move(mx, y, xx, ySize2);
300   }
301   return false;
302 }
303 
GetNumberOfThreads()304 UInt32 CBenchmarkDialog::GetNumberOfThreads()
305 {
306   return (UInt32)m_NumThreads.GetItemData_of_CurSel();
307 }
308 
309 
SetItemText_Number(int itemID,UInt64 val,LPCTSTR post)310 void CBenchmarkDialog::SetItemText_Number(int itemID, UInt64 val, LPCTSTR post)
311 {
312   TCHAR s[64];
313   ConvertUInt64ToString(val, s);
314   if (post)
315     lstrcat(s, post);
316   SetItemText(itemID, s);
317 }
318 
PrintSize_MB(UString & s,UInt64 size)319 static void PrintSize_MB(UString &s, UInt64 size)
320 {
321   char temp[32];
322   ConvertUInt64ToString((size + (1 << 20) - 1) >> 20, temp);
323   s += temp;
324   s += kMB;
325 }
326 
327 extern bool g_LargePagesMode;
328 
OnChangeDictionary()329 UInt32 CBenchmarkDialog::OnChangeDictionary()
330 {
331   const UInt32 dict = (UInt32)m_Dictionary.GetItemData_of_CurSel();
332   const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(), dict);
333 
334   UString s;
335   PrintSize_MB(s, memUsage);
336   if (ramSize_Defined)
337   {
338     s += " / ";
339     PrintSize_MB(s, ramSize);
340   }
341   if (g_LargePagesMode)
342     s += " LP";
343 
344   SetItemText(IDT_BENCH_MEMORY_VAL, s);
345 
346   return dict;
347 }
348 
349 static const UInt32 g_IDs[] =
350 {
351   IDT_BENCH_COMPRESS_USAGE1,
352   IDT_BENCH_COMPRESS_USAGE2,
353   IDT_BENCH_COMPRESS_SPEED1,
354   IDT_BENCH_COMPRESS_SPEED2,
355   IDT_BENCH_COMPRESS_RATING1,
356   IDT_BENCH_COMPRESS_RATING2,
357   IDT_BENCH_COMPRESS_RPU1,
358   IDT_BENCH_COMPRESS_RPU2,
359 
360   IDT_BENCH_DECOMPR_SPEED1,
361   IDT_BENCH_DECOMPR_SPEED2,
362   IDT_BENCH_DECOMPR_RATING1,
363   IDT_BENCH_DECOMPR_RATING2,
364   IDT_BENCH_DECOMPR_USAGE1,
365   IDT_BENCH_DECOMPR_USAGE2,
366   IDT_BENCH_DECOMPR_RPU1,
367   IDT_BENCH_DECOMPR_RPU2,
368 
369   IDT_BENCH_TOTAL_USAGE_VAL,
370   IDT_BENCH_TOTAL_RATING_VAL,
371   IDT_BENCH_TOTAL_RPU_VAL
372 
373   // IDT_BENCH_FREQ_CUR,
374   // IDT_BENCH_FREQ_RES
375 };
376 
OnChangeSettings()377 void CBenchmarkDialog::OnChangeSettings()
378 {
379   EnableItem(IDB_STOP, true);
380   UInt32 dict = OnChangeDictionary();
381 
382   for (int i = 0; i < ARRAY_SIZE(g_IDs); i++)
383     SetItemText(g_IDs[i], kProcessingString);
384   _startTime = GetTickCount();
385   PrintTime();
386   NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
387   Sync.Init();
388   Sync.DictionarySize = dict;
389   Sync.Changed = true;
390   Sync.NumThreads = GetNumberOfThreads();
391 }
392 
OnRestartButton()393 void CBenchmarkDialog::OnRestartButton()
394 {
395   OnChangeSettings();
396 }
397 
OnStopButton()398 void CBenchmarkDialog::OnStopButton()
399 {
400   EnableItem(IDB_STOP, false);
401   Sync.Pause();
402 }
403 
OnHelp()404 void CBenchmarkDialog::OnHelp()
405 {
406   ShowHelpWindow(kHelpTopic);
407 }
408 
OnCancel()409 void CBenchmarkDialog::OnCancel()
410 {
411   Sync.Stop();
412   KillTimer(_timer);
413   CModalDialog::OnCancel();
414 }
415 
416 void GetTimeString(UInt64 timeValue, wchar_t *s);
417 
PrintTime()418 void CBenchmarkDialog::PrintTime()
419 {
420   UInt32 curTime = ::GetTickCount();
421   UInt32 elapsedTime = (curTime - _startTime);
422   UInt32 elapsedSec = elapsedTime / 1000;
423   if (elapsedSec != 0 && Sync.WasPaused())
424     return;
425   WCHAR s[40];
426   GetTimeString(elapsedSec, s);
427   SetItemText(IDT_BENCH_ELAPSED_VAL, s);
428 }
429 
PrintRating(UInt64 rating,UINT controlID)430 void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID)
431 {
432   SetItemText_Number(controlID, rating / 1000000, kMIPS);
433 }
434 
PrintUsage(UInt64 usage,UINT controlID)435 void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID)
436 {
437   SetItemText_Number(controlID, (usage + 5000) / 10000, TEXT("%"));
438 }
439 
PrintResults(UInt32 dictionarySize,const CBenchInfo2 & info,UINT usageID,UINT speedID,UINT rpuID,UINT ratingID,bool decompressMode)440 void CBenchmarkDialog::PrintResults(
441     UInt32 dictionarySize,
442     const CBenchInfo2 &info,
443     UINT usageID, UINT speedID, UINT rpuID, UINT ratingID,
444     bool decompressMode)
445 {
446   if (info.GlobalTime == 0)
447     return;
448 
449   {
450     const UInt64 speed = info.UnpackSize * info.NumIterations * info.GlobalFreq / info.GlobalTime;
451     SetItemText_Number(speedID, speed >> 10, kKBs);
452   }
453   UInt64 rating;
454   if (decompressMode)
455     rating = info.GetDecompressRating();
456   else
457     rating = info.GetCompressRating(dictionarySize);
458 
459   PrintRating(rating, ratingID);
460   PrintRating(info.GetRatingPerUsage(rating), rpuID);
461   PrintUsage(info.GetUsage(), usageID);
462 }
463 
OnTimer(WPARAM,LPARAM)464 bool CBenchmarkDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
465 {
466   bool printTime = true;
467   if (TotalMode)
468   {
469     if (Sync.WasStopped())
470       printTime = false;
471   }
472   if (printTime)
473     PrintTime();
474 
475   if (TotalMode)
476   {
477     bool wasChanged = false;
478     {
479       NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
480 
481       if (Sync.TextWasChanged)
482       {
483         wasChanged = true;
484         Bench2Text += Sync.Text;
485         Sync.Text.Empty();
486         Sync.TextWasChanged = false;
487       }
488     }
489     if (wasChanged)
490       _consoleEdit.SetText(Bench2Text);
491     return true;
492   }
493 
494   SetItemText_Number(IDT_BENCH_SIZE_VAL, (Sync.ProcessedSize >> 20), kMB);
495 
496   SetItemText_Number(IDT_BENCH_PASSES_VAL, Sync.NumPasses);
497 
498   /*
499   if (Sync.FirstPath)
500     SetItemText_Number(IDT_BENCH_FREQ_CUR, Sync.Freq, TEXT(" MHz"));
501   else
502     SetItemText_Number(IDT_BENCH_FREQ_RES, Sync.Freq, TEXT(" MHz"));
503   */
504 
505   /*
506   if (Sync.FreqWasChanged)
507   {
508     SetItemText(IDT_BENCH_FREQ, Sync.Freq);
509     Sync.FreqWasChanged  = false;
510   }
511   */
512 
513   {
514     UInt32 dicSizeTemp = (UInt32)MyMax(Sync.ProcessedSize, UInt64(1) << 20);
515     dicSizeTemp = MyMin(dicSizeTemp, Sync.DictionarySize),
516     PrintResults(dicSizeTemp,
517       Sync.CompressingInfoTemp,
518       IDT_BENCH_COMPRESS_USAGE1,
519       IDT_BENCH_COMPRESS_SPEED1,
520       IDT_BENCH_COMPRESS_RPU1,
521       IDT_BENCH_COMPRESS_RATING1);
522   }
523 
524   {
525     PrintResults(
526       Sync.DictionarySize,
527       Sync.CompressingInfo,
528       IDT_BENCH_COMPRESS_USAGE2,
529       IDT_BENCH_COMPRESS_SPEED2,
530       IDT_BENCH_COMPRESS_RPU2,
531       IDT_BENCH_COMPRESS_RATING2);
532   }
533 
534   {
535     PrintResults(
536       Sync.DictionarySize,
537       Sync.DecompressingInfoTemp,
538       IDT_BENCH_DECOMPR_USAGE1,
539       IDT_BENCH_DECOMPR_SPEED1,
540       IDT_BENCH_DECOMPR_RPU1,
541       IDT_BENCH_DECOMPR_RATING1,
542       true);
543   }
544   {
545     PrintResults(
546       Sync.DictionarySize,
547       Sync.DecompressingInfo,
548       IDT_BENCH_DECOMPR_USAGE2,
549       IDT_BENCH_DECOMPR_SPEED2,
550       IDT_BENCH_DECOMPR_RPU2,
551       IDT_BENCH_DECOMPR_RATING2,
552       true);
553     if (Sync.DecompressingInfo.GlobalTime > 0 &&
554         Sync.CompressingInfo.GlobalTime > 0)
555     {
556       UInt64 comprRating = Sync.CompressingInfo.GetCompressRating(Sync.DictionarySize);
557       UInt64 decomprRating = Sync.DecompressingInfo.GetDecompressRating();
558       PrintRating((comprRating + decomprRating) / 2, IDT_BENCH_TOTAL_RATING_VAL);
559       PrintRating((
560           Sync.CompressingInfo.GetRatingPerUsage(comprRating) +
561           Sync.DecompressingInfo.GetRatingPerUsage(decomprRating)) / 2, IDT_BENCH_TOTAL_RPU_VAL);
562       PrintUsage(
563         (Sync.CompressingInfo.GetUsage() +
564          Sync.DecompressingInfo.GetUsage()) / 2, IDT_BENCH_TOTAL_USAGE_VAL);
565     }
566   }
567   return true;
568 }
569 
OnCommand(int code,int itemID,LPARAM lParam)570 bool CBenchmarkDialog::OnCommand(int code, int itemID, LPARAM lParam)
571 {
572   if (code == CBN_SELCHANGE &&
573       (itemID == IDC_BENCH_DICTIONARY ||
574        itemID == IDC_BENCH_NUM_THREADS))
575   {
576     OnChangeSettings();
577     return true;
578   }
579   return CModalDialog::OnCommand(code, itemID, lParam);
580 }
581 
OnButtonClicked(int buttonID,HWND buttonHWND)582 bool CBenchmarkDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
583 {
584   switch (buttonID)
585   {
586     case IDB_RESTART:
587       OnRestartButton();
588       return true;
589     case IDB_STOP:
590       OnStopButton();
591       return true;
592   }
593   return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
594 }
595 
596 struct CThreadBenchmark
597 {
598   CBenchmarkDialog *BenchmarkDialog;
599   DECL_EXTERNAL_CODECS_LOC_VARS2;
600   // UInt32 dictionarySize;
601   // UInt32 numThreads;
602 
603   HRESULT Process();
604   HRESULT Result;
MyThreadFunctionCThreadBenchmark605   static THREAD_FUNC_DECL MyThreadFunction(void *param)
606   {
607     ((CThreadBenchmark *)param)->Result = ((CThreadBenchmark *)param)->Process();
608     return 0;
609   }
610 };
611 
612 struct CBenchCallback: public IBenchCallback
613 {
614   UInt32 dictionarySize;
615   CBenchProgressSync *Sync;
616 
617   // void AddCpuFreq(UInt64 cpuFreq);
618   HRESULT SetFreq(bool showFreq, UInt64 cpuFreq);
619   HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
620   HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
621 };
622 
623 /*
624 void CBenchCallback::AddCpuFreq(UInt64 cpuFreq)
625 {
626   NSynchronization::CCriticalSectionLock lock(Sync->CS);
627   {
628     wchar_t s[32];
629     ConvertUInt64ToString(cpuFreq, s);
630     Sync->Freq.Add_Space_if_NotEmpty();
631     Sync->Freq += s;
632     Sync->FreqWasChanged = true;
633   }
634 }
635 */
636 
SetFreq(bool,UInt64)637 HRESULT CBenchCallback::SetFreq(bool /* showFreq */, UInt64 /* cpuFreq */)
638 {
639   return S_OK;
640 }
641 
SetEncodeResult(const CBenchInfo & info,bool final)642 HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
643 {
644   NSynchronization::CCriticalSectionLock lock(Sync->CS);
645   if (Sync->Changed || Sync->Paused || Sync->Stopped)
646     return E_ABORT;
647   Sync->ProcessedSize = info.UnpackSize * info.NumIterations;
648   if (final && Sync->CompressingInfo.GlobalTime == 0)
649   {
650     (CBenchInfo&)Sync->CompressingInfo = info;
651     if (Sync->CompressingInfo.GlobalTime == 0)
652       Sync->CompressingInfo.GlobalTime = 1;
653   }
654   else
655     (CBenchInfo&)Sync->CompressingInfoTemp = info;
656 
657   return S_OK;
658 }
659 
SetDecodeResult(const CBenchInfo & info,bool final)660 HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
661 {
662   NSynchronization::CCriticalSectionLock lock(Sync->CS);
663   if (Sync->Changed || Sync->Paused || Sync->Stopped)
664     return E_ABORT;
665   CBenchInfo info2 = info;
666   if (final && Sync->DecompressingInfo.GlobalTime == 0)
667   {
668     (CBenchInfo&)Sync->DecompressingInfo = info2;
669     if (Sync->DecompressingInfo.GlobalTime == 0)
670       Sync->DecompressingInfo.GlobalTime = 1;
671   }
672   else
673     (CBenchInfo&)Sync->DecompressingInfoTemp = info2;
674   return S_OK;
675 }
676 
677 struct CBenchCallback2: public IBenchPrintCallback
678 {
679   CBenchProgressSync *Sync;
680   bool TotalMode;
681 
682   void Print(const char *s);
683   void NewLine();
684   HRESULT CheckBreak();
685 };
686 
Print(const char * s)687 void CBenchCallback2::Print(const char *s)
688 {
689   if (TotalMode)
690   {
691     NSynchronization::CCriticalSectionLock lock(Sync->CS);
692     Sync->Text += s;
693     Sync->TextWasChanged = true;
694   }
695 }
696 
NewLine()697 void CBenchCallback2::NewLine()
698 {
699   Print("\xD\n");
700 }
701 
CheckBreak()702 HRESULT CBenchCallback2::CheckBreak()
703 {
704   if (Sync->Changed || Sync->Paused || Sync->Stopped)
705     return E_ABORT;
706   return S_OK;
707 }
708 
709 
710 
711 /*
712 struct CFreqCallback: public IBenchFreqCallback
713 {
714   CBenchProgressSync *Sync;
715 
716   virtual void AddCpuFreq(UInt64 freq);
717 };
718 
719 void CFreqCallback::AddCpuFreq(UInt64 freq)
720 {
721   NSynchronization::CCriticalSectionLock lock(Sync->CS);
722   Sync->Freq = freq;
723 }
724 */
725 
726 
727 
Process()728 HRESULT CThreadBenchmark::Process()
729 {
730   CBenchProgressSync &sync = BenchmarkDialog->Sync;
731   sync.WaitCreating();
732   try
733   {
734     for (;;)
735     {
736       if (sync.WasStopped())
737         return 0;
738       if (sync.WasPaused())
739       {
740         Sleep(200);
741         continue;
742       }
743       UInt32 dictionarySize;
744       UInt32 numThreads;
745       {
746         NSynchronization::CCriticalSectionLock lock(sync.CS);
747         if (sync.Stopped || sync.Paused)
748           continue;
749         if (sync.Changed)
750           sync.Init();
751         dictionarySize = sync.DictionarySize;
752         numThreads = sync.NumThreads;
753         /*
754         if (sync.CompressingInfo.GlobalTime != 0)
755           sync.FirstPath = false;
756         */
757       }
758 
759       CBenchCallback callback;
760       callback.dictionarySize = dictionarySize;
761       callback.Sync = &sync;
762       CBenchCallback2 callback2;
763       callback2.TotalMode = BenchmarkDialog->TotalMode;
764       callback2.Sync = &sync;
765       // CFreqCallback freqCallback;
766       // freqCallback.Sync = &sync;
767       HRESULT result;
768 
769       try
770       {
771         CObjectVector<CProperty> props;
772         if (BenchmarkDialog->TotalMode)
773         {
774           props = BenchmarkDialog->Props;
775         }
776         else
777         {
778           {
779             CProperty prop;
780             prop.Name = "mt";
781             prop.Value.Add_UInt32(numThreads);
782             props.Add(prop);
783           }
784           {
785             CProperty prop;
786             prop.Name = 'd';
787             prop.Name.Add_UInt32(dictionarySize);
788             prop.Name += 'b';
789             props.Add(prop);
790           }
791         }
792 
793         result = Bench(EXTERNAL_CODECS_LOC_VARS
794             BenchmarkDialog->TotalMode ? &callback2 : NULL,
795             BenchmarkDialog->TotalMode ? NULL : &callback,
796             // &freqCallback,
797             props, 1, false);
798 
799         if (BenchmarkDialog->TotalMode)
800         {
801           sync.Stop();
802         }
803       }
804       catch(...)
805       {
806         result = E_FAIL;
807       }
808 
809       if (result != S_OK)
810       {
811         if (result != E_ABORT)
812         {
813           {
814             NSynchronization::CCriticalSectionLock lock(sync.CS);
815             sync.Pause();
816           }
817           UString message;
818           if (result == S_FALSE)
819             message = "Decoding error";
820           else if (result == CLASS_E_CLASSNOTAVAILABLE)
821             message = "Can't find 7z.dll";
822           else
823             message = HResultToMessage(result);
824           BenchmarkDialog->MessageBoxError(message);
825         }
826       }
827       else
828       {
829         NSynchronization::CCriticalSectionLock lock(sync.CS);
830         sync.NumPasses++;
831       }
832     }
833     // return S_OK;
834   }
835   catch(CSystemException &e)
836   {
837     BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode));
838     return E_FAIL;
839   }
840   catch(...)
841   {
842     BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL));
843     return E_FAIL;
844   }
845 }
846 
ParseNumberString(const UString & s,NCOM::CPropVariant & prop)847 static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
848 {
849   const wchar_t *end;
850   UInt64 result = ConvertStringToUInt64(s, &end);
851   if (*end != 0 || s.IsEmpty())
852     prop = s;
853   else if (result <= (UInt32)0xFFFFFFFF)
854     prop = (UInt32)result;
855   else
856     prop = result;
857 }
858 
Benchmark(DECL_EXTERNAL_CODECS_LOC_VARS const CObjectVector<CProperty> & props,HWND hwndParent)859 HRESULT Benchmark(
860     DECL_EXTERNAL_CODECS_LOC_VARS
861     const CObjectVector<CProperty> &props, HWND hwndParent)
862 {
863   CThreadBenchmark benchmarker;
864   #ifdef EXTERNAL_CODECS
865   benchmarker.__externalCodecs = __externalCodecs;
866   #endif
867 
868   CBenchmarkDialog bd;
869   bd.Props = props;
870   bd.TotalMode = false;
871   bd.Sync.DictionarySize = (UInt32)(Int32)-1;
872   bd.Sync.NumThreads = (UInt32)(Int32)-1;
873 
874   COneMethodInfo method;
875 
876   UInt32 numCPUs = 1;
877   #ifndef _7ZIP_ST
878   numCPUs = NSystem::GetNumberOfProcessors();
879   #endif
880   UInt32 numThreads = numCPUs;
881 
882   FOR_VECTOR (i, props)
883   {
884     const CProperty &prop = props[i];
885     UString name = prop.Name;
886     name.MakeLower_Ascii();
887     if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*")
888     {
889       bd.TotalMode = true;
890       continue;
891     }
892 
893     NCOM::CPropVariant propVariant;
894     if (!prop.Value.IsEmpty())
895       ParseNumberString(prop.Value, propVariant);
896     if (name.IsPrefixedBy(L"mt"))
897     {
898       #ifndef _7ZIP_ST
899       RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads));
900       if (numThreads != numCPUs)
901         bd.Sync.NumThreads = numThreads;
902       #endif
903       continue;
904     }
905     if (name.IsEqualTo("testtime"))
906     {
907       // UInt32 testTime = 4;
908       // RINOK(ParsePropToUInt32(L"", propVariant, testTime));
909       continue;
910     }
911     RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));
912   }
913 
914   if (bd.TotalMode)
915   {
916     // bd.Bench2Text.Empty();
917     bd.Bench2Text = "7-Zip " MY_VERSION_CPU;
918     bd.Bench2Text += (char)0xD;
919     bd.Bench2Text.Add_LF();
920   }
921 
922   {
923     UInt32 dict;
924     if (method.Get_DicSize(dict))
925       bd.Sync.DictionarySize = dict;
926   }
927 
928   benchmarker.BenchmarkDialog = &bd;
929 
930   NWindows::CThread thread;
931   RINOK(thread.Create(CThreadBenchmark::MyThreadFunction, &benchmarker));
932   bd.Create(hwndParent);
933   return thread.Wait();
934 }
935