diff options
Diffstat (limited to 'CPP/7zip/UI/GUI/BenchmarkDialog.cpp')
-rw-r--r-- | CPP/7zip/UI/GUI/BenchmarkDialog.cpp | 1688 |
1 files changed, 1337 insertions, 351 deletions
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp index 94dfab4c..44d25035 100644 --- a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp +++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp @@ -10,15 +10,27 @@ #include "../../../Common/StringConvert.h" #include "../../../Common/StringToInt.h" +#include "../../../Windows/Synchronization.h" #include "../../../Windows/System.h" #include "../../../Windows/Thread.h" +#include "../../../Windows/SystemInfo.h" + +#include "../../../Windows/Control/ComboBox.h" +#include "../../../Windows/Control/Edit.h" #include "../../Common/MethodProps.h" +#include "../FileManager/DialogSize.h" #include "../FileManager/HelpUtils.h" +#ifdef LANG +#include "../FileManager/LangUtils.h" +#endif #include "../../MyVersion.h" +#include "../Common/Bench.h" + +#include "BenchmarkDialogRes.h" #include "BenchmarkDialog.h" using namespace NWindows; @@ -26,13 +38,350 @@ using namespace NWindows; #define kHelpTopic "fm/benchmark.htm" static const UINT_PTR kTimerID = 4; -static const UINT kTimerElapse = 1000; +static const UINT kTimerElapse = 1000; // 1000 + +// use PRINT_ITER_TIME to show time of each iteration in log box +// #define PRINT_ITER_TIME + +static const unsigned kRatingVector_NumBundlesMax = 20; + +enum MyBenchMessages +{ + k_Message_Finished = WM_APP + 1 +}; + +enum My_Message_WPARAM +{ + k_Msg_WPARM_Thread_Finished = 0, + k_Msg_WPARM_Iter_Finished, + k_Msg_WPARM_Enc1_Finished +}; + + +struct CBenchPassResult +{ + CTotalBenchRes Enc; + CTotalBenchRes Dec; + #ifdef PRINT_ITER_TIME + DWORD Ticks; + #endif + // CBenchInfo EncInfo; // for debug + // CBenchPassResult() {}; +}; + + +struct CTotalBenchRes2: public CTotalBenchRes +{ + UInt64 UnpackSize; + + void Init() + { + CTotalBenchRes::Init(); + UnpackSize = 0; + } + + void SetFrom_BenchInfo(const CBenchInfo &info) + { + NumIterations2 = 1; + Generate_From_BenchInfo(info); + UnpackSize = info.Get_UnpackSize_Full(); + } + + void Update_With_Res2(const CTotalBenchRes2 &r) + { + Update_With_Res(r); + UnpackSize += r.UnpackSize; + } +}; + + +struct CSyncData +{ + UInt32 NumPasses_Finished; + + // UInt64 NumEncProgress; // for debug + // UInt64 NumDecProgress; // for debug + // CBenchInfo EncInfo; // for debug + + CTotalBenchRes2 Enc_BenchRes_1; + CTotalBenchRes2 Enc_BenchRes; + + CTotalBenchRes2 Dec_BenchRes_1; + CTotalBenchRes2 Dec_BenchRes; + + #ifdef PRINT_ITER_TIME + DWORD TotalTicks; + #endif + + int RatingVector_DeletedIndex; + // UInt64 RatingVector_NumDeleted; + + bool BenchWasFinished; // all passes were finished + bool NeedPrint_Freq; + bool NeedPrint_RatingVector; + bool NeedPrint_Enc_1; + bool NeedPrint_Enc; + bool NeedPrint_Dec_1; + bool NeedPrint_Dec; + bool NeedPrint_Tot; // intermediate Total was updated after current pass + + void Init(); +}; + + +void CSyncData::Init() +{ + NumPasses_Finished = 0; + + // NumEncProgress = 0; + // NumDecProgress = 0; + + Enc_BenchRes.Init(); + Enc_BenchRes_1.Init(); + Dec_BenchRes.Init(); + Dec_BenchRes_1.Init(); + + #ifdef PRINT_ITER_TIME + TotalTicks = 0; + #endif + + RatingVector_DeletedIndex = -1; + // RatingVector_NumDeleted = 0; + + BenchWasFinished = + NeedPrint_Freq = + NeedPrint_RatingVector = + NeedPrint_Enc_1 = + NeedPrint_Enc = + NeedPrint_Dec_1 = + NeedPrint_Dec = + NeedPrint_Tot = false; +}; + + +struct CBenchProgressSync +{ + bool Exit; // GUI asks BenchThread to Exit, and BenchThread reads that variable + UInt32 NumThreads; + UInt64 DictSize; + UInt32 NumPasses_Limit; + int Level; + + // must be written by benchmark thread, read by GUI thread */ + CSyncData sd; + CRecordVector<CBenchPassResult> RatingVector; + + NWindows::NSynchronization::CCriticalSection CS; + + AString Text; + bool TextWasChanged; + + /* BenchFinish_Task_HRESULT - for result from benchmark code + BenchFinish_Thread_HRESULT - for Exceptions and service errors + these arreos must be shown even if user escapes benchmark */ + + HRESULT BenchFinish_Task_HRESULT; + HRESULT BenchFinish_Thread_HRESULT; + + UInt32 NumFreqThreadsPrev; + UString FreqString_Sync; + UString FreqString_GUI; + + CBenchProgressSync() + { + NumPasses_Limit = 1; + } + + void Init(); + + void SendExit() + { + NWindows::NSynchronization::CCriticalSectionLock lock(CS); + Exit = true; + } +}; + + +void CBenchProgressSync::Init() +{ + Exit = false; + + BenchFinish_Task_HRESULT = S_OK; + BenchFinish_Thread_HRESULT = S_OK; + + sd.Init(); + RatingVector.Clear(); + + NumFreqThreadsPrev = 0; + FreqString_Sync.Empty(); + FreqString_GUI.Empty(); + + Text.Empty(); + TextWasChanged = true; +} + + + +struct CMyFont +{ + HFONT _font; + CMyFont(): _font(NULL) {} + ~CMyFont() + { + if (_font) + DeleteObject(_font); + } + void Create(const LOGFONT *lplf) + { + _font = CreateFontIndirect(lplf); + } +}; + + +class CBenchmarkDialog; + +struct CThreadBenchmark +{ + CBenchmarkDialog *BenchmarkDialog; + DECL_EXTERNAL_CODECS_LOC_VARS2; + // HRESULT Result; + + HRESULT Process(); + static THREAD_FUNC_DECL MyThreadFunction(void *param) + { + /* ((CThreadBenchmark *)param)->Result = */ + ((CThreadBenchmark *)param)->Process(); + return 0; + } +}; + + +class CBenchmarkDialog: + public NWindows::NControl::CModalDialog +{ + NWindows::NControl::CComboBox m_Dictionary; + NWindows::NControl::CComboBox m_NumThreads; + NWindows::NControl::CComboBox m_NumPasses; + NWindows::NControl::CEdit _consoleEdit; + UINT_PTR _timer; + + UInt32 _startTime; + UInt32 _finishTime; + bool _finishTime_WasSet; + + bool WasStopped_in_GUI; + bool ExitWasAsked_in_GUI; + bool NeedRestart; + + CMyFont _font; + + UInt64 RamSize; + UInt64 RamSize_Limit; + bool RamSize_Defined; + + UInt32 NumPasses_Finished_Prev; + + UString ElapsedSec_Prev; + + void InitSyncNew() + { + NumPasses_Finished_Prev = (UInt32)(Int32)-1; + ElapsedSec_Prev.Empty(); + Sync.Init(); + } + + virtual bool OnInit(); + virtual bool OnDestroy(); + virtual bool OnSize(WPARAM /* wParam */, int xSize, int ySize); + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam); + virtual bool OnCommand(int code, int itemID, LPARAM lParam); + virtual void OnHelp(); + virtual void OnCancel(); + virtual bool OnTimer(WPARAM timerID, LPARAM callback); + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + + void Disable_Stop_Button(); + void OnStopButton(); + void RestartBenchmark(); + void StartBenchmark(); + + void UpdateGui(); + + void PrintTime(); + void PrintRating(UInt64 rating, UINT controlID); + void PrintUsage(UInt64 usage, UINT controlID); + void PrintBenchRes(const CTotalBenchRes2 &info, const UINT ids[]); + + UInt32 GetNumberOfThreads(); + size_t OnChangeDictionary(); + + void SetItemText_Number(int itemID, UInt64 val, LPCTSTR post = NULL); + void Print_MemUsage(UString &s, UInt64 memUsage) const; + bool IsMemoryUsageOK(UInt64 memUsage) const + { return memUsage + (1 << 20) <= RamSize_Limit; } + + void MyKillTimer(); + + void SendExit_Status(const wchar_t *message) + { + SetItemText(IDT_BENCH_ERROR_MESSAGE, message); + Sync.SendExit(); + } + +public: + CBenchProgressSync Sync; + + bool TotalMode; + CObjectVector<CProperty> Props; + + CSysString Bench2Text; + + NWindows::CThread _thread; + CThreadBenchmark _threadBenchmark; + + CBenchmarkDialog(): + _timer(0), + TotalMode(false), + WasStopped_in_GUI(false), + ExitWasAsked_in_GUI(false), + NeedRestart(false) + {} + + ~CBenchmarkDialog(); + + bool PostMsg_Finish(LPARAM param) + { + if ((HWND)*this) + return PostMsg(k_Message_Finished, param); + // the (HWND)*this is NULL only for some internal code failure + return true; + } + + INT_PTR Create(HWND wndParent = 0) + { + BIG_DIALOG_SIZE(332, 228); + return CModalDialog::Create(TotalMode ? IDD_BENCH_TOTAL : SIZED_DIALOG(IDD_BENCH), wndParent); + } + void MessageBoxError(LPCWSTR message) + { + MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR); + } + void MessageBoxError_Status(LPCWSTR message) + { + UString s ("ERROR: "); + s += message; + MessageBoxError(s); + SetItemText(IDT_BENCH_ERROR_MESSAGE, s); + } +}; + + + + + + -#ifdef LANG -#include "../FileManager/LangUtils.h" -#endif -using namespace NWindows; UString HResultToMessage(HRESULT errorCode); @@ -65,36 +414,48 @@ static const UInt32 kLangIDs_Colon[] = #endif static LPCTSTR const kProcessingString = TEXT("..."); +static LPCTSTR const kGB = TEXT(" GB"); static LPCTSTR const kMB = TEXT(" MB"); -static LPCTSTR const kMIPS = TEXT(" MIPS"); +static LPCTSTR const kKB = TEXT(" KB"); +// static LPCTSTR const kMIPS = TEXT(" MIPS"); static LPCTSTR const kKBs = TEXT(" KB/s"); -static const unsigned kMinDicLogSize = - #ifdef UNDER_CE - 20; - #else - 21; - #endif +static const unsigned kMinDicLogSize = 18; -static const UInt32 kMinDicSize = (1 << kMinDicLogSize); -static const UInt32 kMaxDicSize = +static const UInt32 kMinDicSize = (UInt32)1 << kMinDicLogSize; +static const size_t kMaxDicSize = (size_t)1 << (22 + sizeof(size_t) / 4 * 5); +// static const size_t kMaxDicSize = (size_t)1 << 16; + /* #ifdef MY_CPU_64BIT - (1 << 30); + (UInt32)(Int32)-1; // we can use it, if we want 4 GB buffer + // (UInt32)15 << 28; #else - (1 << 27); + (UInt32)1 << 27; #endif + */ + + +static int ComboBox_Add_UInt32(NWindows::NControl::CComboBox &cb, UInt32 v) +{ + TCHAR s[16]; + ConvertUInt32ToString(v, s); + int index = (int)cb.AddString(s); + cb.SetItemData(index, v); + return index; +} + bool CBenchmarkDialog::OnInit() { #ifdef LANG LangSetWindowText(*this, IDD_BENCH); LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs)); - LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon)); + // LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon)); LangSetDlgItemText(*this, IDT_BENCH_CURRENT2, IDT_BENCH_CURRENT); LangSetDlgItemText(*this, IDT_BENCH_RESULTING2, IDT_BENCH_RESULTING); #endif - Sync.Init(); + InitSyncNew(); if (TotalMode) { @@ -120,154 +481,194 @@ bool CBenchmarkDialog::OnInit() UInt32 numCPUs = 1; { - UString s ("/ "); + AString s ("/ "); NSystem::CProcessAffinity threadsInfo; threadsInfo.InitST(); #ifndef _7ZIP_ST - if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0) numCPUs = threadsInfo.GetNumProcessThreads(); else numCPUs = NSystem::GetNumberOfProcessors(); - #endif s.Add_UInt32(numCPUs); s += GetProcessThreadsInfo(threadsInfo); - SetItemText(IDT_BENCH_HARDWARE_THREADS, s); - } - - { - UString s; - { - AString s1, s2; - GetSysInfo(s1, s2); - s = s1; - SetItemText(IDT_BENCH_SYS1, s); - if (s1 != s2 && !s2.IsEmpty()) - { - s = s2; - SetItemText(IDT_BENCH_SYS2, s); - } - } - /* + SetItemTextA(IDT_BENCH_HARDWARE_THREADS, s); + { - GetVersionString(s); - SetItemText(IDT_BENCH_SYSTEM, s); + AString s2; + GetSysInfo(s, s2); + SetItemTextA(IDT_BENCH_SYS1, s); + if (s != s2 && !s2.IsEmpty()) + SetItemTextA(IDT_BENCH_SYS2, s2); } - */ { - AString s2; - GetCpuName(s2); - s = s2; - SetItemText(IDT_BENCH_CPU, s); + GetCpuName_MultiLine(s); + SetItemTextA(IDT_BENCH_CPU, s); } { - AString s2; - AddCpuFeatures(s2); - s = s2; - SetItemText(IDT_BENCH_CPU_FEATURE, s); + GetOsInfoText(s); + s += " : "; + AddCpuFeatures(s); + SetItemTextA(IDT_BENCH_CPU_FEATURE, s); } s = "7-Zip " MY_VERSION_CPU; - SetItemText(IDT_BENCH_VER, s); + SetItemTextA(IDT_BENCH_VER, s); } + // ----- Num Threads ---------- + if (numCPUs < 1) numCPUs = 1; - numCPUs = MyMin(numCPUs, (UInt32)(1 << 8)); + numCPUs = MyMin(numCPUs, (UInt32)(1 << 6)); // it's WIN32 limit + + UInt32 numThreads = Sync.NumThreads; + + if (numThreads == (UInt32)(Int32)-1) + numThreads = numCPUs; + if (numThreads > 1) + numThreads &= ~1; + const UInt32 kNumThreadsMax = (1 << 12); + if (numThreads > kNumThreadsMax) + numThreads = kNumThreadsMax; - if (Sync.NumThreads == (UInt32)(Int32)-1) - { - Sync.NumThreads = numCPUs; - if (Sync.NumThreads > 1) - Sync.NumThreads &= ~1; - } m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS)); + const UInt32 numTheads_Combo = numCPUs * 2; + UInt32 v = 1; int cur = 0; - for (UInt32 num = 1; num <= numCPUs * 2;) + for (; v <= numTheads_Combo;) { - TCHAR s[16]; - ConvertUInt32ToString(num, s); - int index = (int)m_NumThreads.AddString(s); - m_NumThreads.SetItemData(index, num); - if (num <= Sync.NumThreads) + int index = ComboBox_Add_UInt32(m_NumThreads, v); + const UInt32 vNext = v + (v < 2 ? 1 : 2); + if (v <= numThreads) + if (numThreads < vNext || vNext > numTheads_Combo) + { + if (v != numThreads) + index = ComboBox_Add_UInt32(m_NumThreads, numThreads); cur = index; - if (num > 1) - num++; - num++; + } + v = vNext; } m_NumThreads.SetCurSel(cur); Sync.NumThreads = GetNumberOfThreads(); + + // ----- Dictionary ---------- + m_Dictionary.Attach(GetItem(IDC_BENCH_DICTIONARY)); - cur = 0; - ramSize = (UInt64)(sizeof(size_t)) << 29; - ramSize_Defined = NSystem::GetRamSize(ramSize); + RamSize = (UInt64)(sizeof(size_t)) << 29; + RamSize_Defined = NSystem::GetRamSize(RamSize); + #ifdef UNDER_CE const UInt32 kNormalizedCeSize = (16 << 20); - if (ramSize > kNormalizedCeSize && ramSize < (33 << 20)) - ramSize = kNormalizedCeSize; + if (RamSize > kNormalizedCeSize && RamSize < (33 << 20)) + RamSize = kNormalizedCeSize; #endif + RamSize_Limit = RamSize / 16 * 15; - if (Sync.DictionarySize == (UInt32)(Int32)-1) + if (Sync.DictSize == (UInt64)(Int64)-1) { unsigned dicSizeLog = 25; - #ifdef UNDER_CE dicSizeLog = 20; #endif - - if (ramSize_Defined) + if (RamSize_Defined) for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--) - if (GetBenchMemoryUsage(Sync.NumThreads, ((UInt32)1 << dicSizeLog)) + (8 << 20) <= ramSize) + if (IsMemoryUsageOK(GetBenchMemoryUsage( + Sync.NumThreads, Sync.Level, (UInt64)1 << dicSizeLog, TotalMode))) break; - Sync.DictionarySize = (1 << dicSizeLog); + Sync.DictSize = (UInt64)1 << dicSizeLog; } - if (Sync.DictionarySize < kMinDicSize) Sync.DictionarySize = kMinDicSize; - if (Sync.DictionarySize > kMaxDicSize) Sync.DictionarySize = kMaxDicSize; + if (Sync.DictSize < kMinDicSize) Sync.DictSize = kMinDicSize; + if (Sync.DictSize > kMaxDicSize) Sync.DictSize = kMaxDicSize; - for (unsigned i = kMinDicLogSize; i <= 30; i++) - for (unsigned j = 0; j < 2; j++) - { - UInt32 dict = ((UInt32)1 << i) + ((UInt32)j << (i - 1)); - if (dict > kMaxDicSize) - continue; + cur = 0; + for (unsigned i = (kMinDicLogSize - 1) * 2; i <= (32 - 1) * 2; i++) + { + const size_t dict = (size_t)(2 + (i & 1)) << (i / 2); + // if (i == (32 - 1) * 2) dict = kMaxDicSize; TCHAR s[32]; - ConvertUInt32ToString((dict >> 20), s); - lstrcat(s, kMB); - int index = (int)m_Dictionary.AddString(s); + const TCHAR *post; + UInt32 d; + if (dict >= ((UInt32)1 << 31)) { d = (UInt32)(dict >> 30); post = kGB; } + else if (dict >= ((UInt32)1 << 21)) { d = (UInt32)(dict >> 20); post = kMB; } + else { d = (UInt32)(dict >> 10); post = kKB; } + ConvertUInt32ToString(d, s); + lstrcat(s, post); + const int index = (int)m_Dictionary.AddString(s); m_Dictionary.SetItemData(index, dict); - if (dict <= Sync.DictionarySize) + if (dict <= Sync.DictSize) cur = index; + if (dict >= kMaxDicSize) + break; } m_Dictionary.SetCurSel(cur); - OnChangeSettings(); - Sync._startEvent.Set(); - _timer = SetTimer(kTimerID, kTimerElapse); + // ----- Num Passes ---------- + + m_NumPasses.Attach(GetItem(IDC_BENCH_NUM_PASSES)); + cur = 0; + v = 1; + for (;;) + { + int index = ComboBox_Add_UInt32(m_NumPasses, v); + const bool isLast = (v >= 10000000); + UInt32 vNext = v * 10; + if (v < 2) vNext = 2; + else if (v < 5) vNext = 5; + else if (v < 10) vNext = 10; + + if (v <= Sync.NumPasses_Limit) + if (isLast || Sync.NumPasses_Limit < vNext) + { + if (v != Sync.NumPasses_Limit) + index = ComboBox_Add_UInt32(m_NumPasses, Sync.NumPasses_Limit); + cur = index; + } + v = vNext; + if (isLast) + break; + } + m_NumPasses.SetCurSel(cur); if (TotalMode) NormalizeSize(true); else NormalizePosition(); + + RestartBenchmark(); + return CModalDialog::OnInit(); } + bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) { - if (!TotalMode) - return false; int mx, my; GetMargins(8, mx, my); + + if (!TotalMode) + { + RECT rect; + GetClientRectOfItem(IDT_BENCH_LOG, rect); + int x = xSize - rect.left - mx; + int y = ySize - rect.top - my; + if (x < 0) x = 0; + if (y < 0) y = 0; + MoveItem(IDT_BENCH_LOG, rect.left, rect.top, x, y, true); + return false; + } + int bx1, bx2, by; + GetItemSizes(IDCANCEL, bx1, by); GetItemSizes(IDHELP, bx2, by); @@ -299,12 +700,28 @@ bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize) return false; } + UInt32 CBenchmarkDialog::GetNumberOfThreads() { return (UInt32)m_NumThreads.GetItemData_of_CurSel(); } +#define UINT_TO_STR_3(s, val) { \ + s[0] = (wchar_t)('0' + (val) / 100); \ + s[1] = (wchar_t)('0' + (val) % 100 / 10); \ + s[2] = (wchar_t)('0' + (val) % 10); \ + s[3] = 0; } + +static void NumberToDot3(UInt64 val, WCHAR *s) +{ + ConvertUInt64ToString(val / 1000, s); + const UInt32 rem = (UInt32)(val % 1000); + s += MyStringLen(s); + *s++ = '.'; + UINT_TO_STR_3(s, rem); +} + void CBenchmarkDialog::SetItemText_Number(int itemID, UInt64 val, LPCTSTR post) { TCHAR s[64]; @@ -314,33 +731,42 @@ void CBenchmarkDialog::SetItemText_Number(int itemID, UInt64 val, LPCTSTR post) SetItemText(itemID, s); } -static void PrintSize_MB(UString &s, UInt64 size) +static void AddSize_MB(UString &s, UInt64 size) { - char temp[32]; - ConvertUInt64ToString((size + (1 << 20) - 1) >> 20, temp); - s += temp; + s.Add_UInt64((size + (1 << 20) - 1) >> 20); s += kMB; } - -UInt32 CBenchmarkDialog::OnChangeDictionary() +void CBenchmarkDialog::Print_MemUsage(UString &s, UInt64 memUsage) const { - const UInt32 dict = (UInt32)m_Dictionary.GetItemData_of_CurSel(); - const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(), dict); - - UString s; - PrintSize_MB(s, memUsage); - if (ramSize_Defined) + AddSize_MB(s, memUsage); + if (RamSize_Defined) { s += " / "; - PrintSize_MB(s, ramSize); + AddSize_MB(s, RamSize); } +} + +size_t CBenchmarkDialog::OnChangeDictionary() +{ + const size_t dict = (size_t)m_Dictionary.GetItemData_of_CurSel(); + const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(), + Sync.Level, + dict, + false); // totalBench mode + + UString s; + Print_MemUsage(s, memUsage); #ifdef _7ZIP_LARGE_PAGES { AString s2; Add_LargePages_String(s2); - s += s2; + if (!s2.IsEmpty()) + { + s.Add_Space(); + s += s2; + } } #endif @@ -349,8 +775,11 @@ UInt32 CBenchmarkDialog::OnChangeDictionary() return dict; } + static const UInt32 g_IDs[] = { + IDT_BENCH_COMPRESS_SIZE1, + IDT_BENCH_COMPRESS_SIZE2, IDT_BENCH_COMPRESS_USAGE1, IDT_BENCH_COMPRESS_USAGE2, IDT_BENCH_COMPRESS_SPEED1, @@ -360,6 +789,8 @@ static const UInt32 g_IDs[] = IDT_BENCH_COMPRESS_RPU1, IDT_BENCH_COMPRESS_RPU2, + IDT_BENCH_DECOMPR_SIZE1, + IDT_BENCH_DECOMPR_SIZE2, IDT_BENCH_DECOMPR_SPEED1, IDT_BENCH_DECOMPR_SPEED2, IDT_BENCH_DECOMPR_RATING1, @@ -372,108 +803,456 @@ static const UInt32 g_IDs[] = IDT_BENCH_TOTAL_USAGE_VAL, IDT_BENCH_TOTAL_RATING_VAL, IDT_BENCH_TOTAL_RPU_VAL - - // IDT_BENCH_FREQ_CUR, - // IDT_BENCH_FREQ_RES }; -void CBenchmarkDialog::OnChangeSettings() + +static const unsigned k_Ids_Enc_1[] = { + IDT_BENCH_COMPRESS_USAGE1, + IDT_BENCH_COMPRESS_SPEED1, + IDT_BENCH_COMPRESS_RPU1, + IDT_BENCH_COMPRESS_RATING1, + IDT_BENCH_COMPRESS_SIZE1 }; + +static const unsigned k_Ids_Enc[] = { + IDT_BENCH_COMPRESS_USAGE2, + IDT_BENCH_COMPRESS_SPEED2, + IDT_BENCH_COMPRESS_RPU2, + IDT_BENCH_COMPRESS_RATING2, + IDT_BENCH_COMPRESS_SIZE2 }; + +static const unsigned k_Ids_Dec_1[] = { + IDT_BENCH_DECOMPR_USAGE1, + IDT_BENCH_DECOMPR_SPEED1, + IDT_BENCH_DECOMPR_RPU1, + IDT_BENCH_DECOMPR_RATING1, + IDT_BENCH_DECOMPR_SIZE1 }; + +static const unsigned k_Ids_Dec[] = { + IDT_BENCH_DECOMPR_USAGE2, + IDT_BENCH_DECOMPR_SPEED2, + IDT_BENCH_DECOMPR_RPU2, + IDT_BENCH_DECOMPR_RATING2, + IDT_BENCH_DECOMPR_SIZE2 }; + +static const unsigned k_Ids_Tot[] = { + IDT_BENCH_TOTAL_USAGE_VAL, + 0, + IDT_BENCH_TOTAL_RPU_VAL, + IDT_BENCH_TOTAL_RATING_VAL, + 0 }; + + +void CBenchmarkDialog::MyKillTimer() { - EnableItem(IDB_STOP, true); - UInt32 dict = OnChangeDictionary(); + if (_timer != 0) + { + KillTimer(kTimerID); + _timer = 0; + } +} + + +bool CBenchmarkDialog::OnDestroy() +{ + /* actually timer was removed before. + also the timer must be removed by Windows, when window will be removed. */ + MyKillTimer(); // it's optional code + return false; // we return (false) to perform default dialog operation +} + +void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString); + +void CBenchmarkDialog::StartBenchmark() +{ + NeedRestart = false; + WasStopped_in_GUI = false; + + SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); + MyKillTimer(); // optional code. timer was killed before + + const size_t dict = OnChangeDictionary(); + const UInt32 numThreads = GetNumberOfThreads(); + const UInt32 numPasses = (UInt32)m_NumPasses.GetItemData_of_CurSel(); + for (unsigned i = 0; i < ARRAY_SIZE(g_IDs); i++) SetItemText(g_IDs[i], kProcessingString); + + SetItemText_Empty(IDT_BENCH_LOG); + SetItemText_Empty(IDT_BENCH_ELAPSED_VAL); + SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); + + const UInt64 memUsage = GetBenchMemoryUsage(numThreads, Sync.Level, dict, + false); // totalBench + if (!IsMemoryUsageOK(memUsage)) + { + UString s2 = LangString(IDT_BENCH_MEMORY); + if (s2.IsEmpty()) + GetItemText(IDT_BENCH_MEMORY, s2); + UString s; + SetErrorMessage_MemUsage(s, memUsage, RamSize, RamSize_Limit, s2); + MessageBoxError_Status(s); + return; + } + + EnableItem(IDB_STOP, true); + _startTime = GetTickCount(); + _finishTime = _startTime; + _finishTime_WasSet = false; + + { + NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); + InitSyncNew(); + Sync.DictSize = dict; + Sync.NumThreads = numThreads; + Sync.NumPasses_Limit = numPasses; + } + PrintTime(); - NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); - Sync.Init(); - Sync.DictionarySize = dict; - Sync.Changed = true; - Sync.NumThreads = GetNumberOfThreads(); + + _timer = SetTimer(kTimerID, kTimerElapse); + if (_thread.Create(CThreadBenchmark::MyThreadFunction, &_threadBenchmark) != 0) + { + MyKillTimer(); + MessageBoxError_Status(L"Can't create thread"); + }; + return; } -void CBenchmarkDialog::OnRestartButton() + +void CBenchmarkDialog::RestartBenchmark() { - OnChangeSettings(); + if (ExitWasAsked_in_GUI) + return; + + if (_thread.IsCreated()) + { + NeedRestart = true; + SendExit_Status(L"Stop for restart ..."); + } + else + StartBenchmark(); } -void CBenchmarkDialog::OnStopButton() + +void CBenchmarkDialog::Disable_Stop_Button() { + // if we disable focused button, then focus will be lost + if (GetFocus() == GetItem(IDB_STOP)) + { + // SendMsg_NextDlgCtl_Prev(); + SendMsg_NextDlgCtl_CtlId(IDB_RESTART); + } EnableItem(IDB_STOP, false); - Sync.Pause(); } -void CBenchmarkDialog::OnHelp() + +void CBenchmarkDialog::OnStopButton() { - ShowHelpWindow(kHelpTopic); + if (ExitWasAsked_in_GUI) + return; + + Disable_Stop_Button(); + + WasStopped_in_GUI = true; + if (_thread.IsCreated()) + { + SendExit_Status(L"Stop ..."); + } } + + void CBenchmarkDialog::OnCancel() { - Sync.Stop(); - KillTimer(_timer); - CModalDialog::OnCancel(); + ExitWasAsked_in_GUI = true; + + /* + SendMsg_NextDlgCtl_Prev(); + EnableItem(IDCANCEL, false); + */ + + if (_thread.IsCreated()) + SendExit_Status(L"Cancel ..."); + else + CModalDialog::OnCancel(); } -void GetTimeString(UInt64 timeValue, wchar_t *s); + +void CBenchmarkDialog::OnHelp() +{ + ShowHelpWindow(kHelpTopic); +} + + + +// void GetTimeString(UInt64 timeValue, wchar_t *s); void CBenchmarkDialog::PrintTime() { - UInt32 curTime = ::GetTickCount(); - UInt32 elapsedTime = (curTime - _startTime); - UInt32 elapsedSec = elapsedTime / 1000; - if (elapsedSec != 0 && Sync.WasPaused()) + const UInt32 curTime = + _finishTime_WasSet ? + _finishTime : + ::GetTickCount(); + + const UInt32 elapsedTime = (curTime - _startTime); + + WCHAR s[64]; + + // GetTimeString(elapsedTime / 1000, s); + ConvertUInt32ToString(elapsedTime / 1000, s); + + if (_finishTime_WasSet) + { + WCHAR *p = s + MyStringLen(s); + *p++ = '.'; + UINT_TO_STR_3(p, elapsedTime % 1000); + } + + // NumberToDot3((UInt64)elapsedTime, s); + + wcscat(s, L" s"); + + // if (WasStopped_in_GUI) wcscat(s, L" X"); // for debug + + if (s == ElapsedSec_Prev) return; - WCHAR s[40]; - GetTimeString(elapsedSec, s); + + ElapsedSec_Prev = s; + + // static cnt = 0; cnt++; wcscat(s, L" "); + // UString s2; s2.Add_UInt32(cnt); wcscat(s, s2.Ptr()); + SetItemText(IDT_BENCH_ELAPSED_VAL, s); } + +static UInt64 GetMips(UInt64 ips) +{ + return (ips + 500000) / 1000000; +} + + +static UInt64 GetUsagePercents(UInt64 usage) +{ + return Benchmark_GetUsage_Percents(usage); +} + + +static UInt32 GetRating(const CTotalBenchRes &info) +{ + UInt64 numIter = info.NumIterations2; + if (numIter == 0) + numIter = 1000000; + const UInt64 rating64 = GetMips(info.Rating / numIter); + // return rating64; + UInt32 rating32 = (UInt32)rating64; + if (rating32 != rating64) + rating32 = (UInt32)(Int32)-1; + return rating32; +}; + + +static void AddUsageString(UString &s, const CTotalBenchRes &info) +{ + UInt64 numIter = info.NumIterations2; + if (numIter == 0) + numIter = 1000000; + UInt64 usage = GetUsagePercents(info.Usage / numIter); + + wchar_t w[64]; + ConvertUInt64ToString(usage, w); + unsigned len = MyStringLen(w); + while (len < 5) + { + s.Add_Space(); + len++; + } + s += w; + s += "%"; +} + + +static void Add_Dot3String(UString &s, UInt64 val) +{ + WCHAR temp[32]; + NumberToDot3(val, temp); + s += temp; +} + + +static void AddRatingString(UString &s, const CTotalBenchRes &info) +{ + // AddUsageString(s, info); + // s += " "; + // s.Add_UInt32(GetRating(info)); + Add_Dot3String(s, GetRating(info)); +}; + + +static void AddRatingsLine(UString &s, const CTotalBenchRes &enc, const CTotalBenchRes &dec + #ifdef PRINT_ITER_TIME + , DWORD ticks + #endif + ) +{ + // AddUsageString(s, enc); s += " "; + + AddRatingString(s, enc); + s += " "; + AddRatingString(s, dec); + + CTotalBenchRes tot_BenchRes; + tot_BenchRes.SetSum(enc, dec); + + s += " "; + AddRatingString(s, tot_BenchRes); + + s += " "; AddUsageString(s, tot_BenchRes); + + + #ifdef PRINT_ITER_TIME + s += " "; + { + Add_Dot3String(s, ticks; + s += " s"; + // s.Add_UInt32(ticks); s += " ms"; + } + #endif +} + + void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID) { - SetItemText_Number(controlID, rating / 1000000, kMIPS); + // SetItemText_Number(controlID, GetMips(rating), kMIPS); + WCHAR s[64]; + NumberToDot3(GetMips(rating), s); + MyStringCat(s, L" GIPS"); + SetItemText(controlID, s); } void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID) { - SetItemText_Number(controlID, (usage + 5000) / 10000, TEXT("%")); + SetItemText_Number(controlID, GetUsagePercents(usage), TEXT("%")); } -void CBenchmarkDialog::PrintResults( - UInt32 dictionarySize, - const CBenchInfo2 &info, - UINT usageID, UINT speedID, UINT rpuID, UINT ratingID, - bool decompressMode) + +// void SetItemText_Number + +void CBenchmarkDialog::PrintBenchRes( + const CTotalBenchRes2 &info, + const UINT ids[]) { - if (info.GlobalTime == 0) + if (info.NumIterations2 == 0) return; - + if (ids[1] != 0) + SetItemText_Number(ids[1], (info.Speed >> 10) / info.NumIterations2, kKBs); + PrintRating(info.Rating / info.NumIterations2, ids[3]); + PrintRating(info.RPU / info.NumIterations2, ids[2]); + PrintUsage(info.Usage / info.NumIterations2, ids[0]); + if (ids[4] != 0) { - const UInt64 speed = info.UnpackSize * info.NumIterations * info.GlobalFreq / info.GlobalTime; - SetItemText_Number(speedID, speed >> 10, kKBs); + UInt64 val = info.UnpackSize; + LPCTSTR kPostfix; + if (val >= ((UInt64)1 << 40)) + { + kPostfix = kGB; + val >>= 30; + } + else + { + kPostfix = kMB; + val >>= 20; + } + SetItemText_Number(ids[4], val, kPostfix); } - UInt64 rating; - if (decompressMode) - rating = info.GetDecompressRating(); - else - rating = info.GetCompressRating(dictionarySize); - - PrintRating(rating, ratingID); - PrintRating(info.GetRatingPerUsage(rating), rpuID); - PrintUsage(info.GetUsage(), usageID); } -bool CBenchmarkDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */) + +// static UInt32 k_Message_Finished_cnt = 0; +// static UInt32 k_OnTimer_cnt = 0; + +bool CBenchmarkDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) { - bool printTime = true; - if (TotalMode) + if (message != k_Message_Finished) + return CModalDialog::OnMessage(message, wParam, lParam); + { - if (Sync.WasStopped()) - printTime = false; + if (wParam == k_Msg_WPARM_Thread_Finished) + { + _finishTime = GetTickCount(); + _finishTime_WasSet = true; + MyKillTimer(); + + if (_thread.Wait_Close() != 0) + { + MessageBoxError_Status(L"Thread Wait Error"); + } + + if (!WasStopped_in_GUI) + { + WasStopped_in_GUI = true; + Disable_Stop_Button(); + } + + HRESULT res = Sync.BenchFinish_Thread_HRESULT; + if (res != S_OK) + // if (!ExitWasAsked_in_GUI || res != E_ABORT) + MessageBoxError_Status(HResultToMessage(res)); + + if (ExitWasAsked_in_GUI) + { + // SetItemText(IDT_BENCH_ERROR_MESSAGE, "before CModalDialog::OnCancel()"); + // Sleep (2000); + // MessageBoxError(L"test"); + CModalDialog::OnCancel(); + return true; + } + + SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE); + + res = Sync.BenchFinish_Task_HRESULT; + if (res != S_OK) + { + if (!WasStopped_in_GUI || res != E_ABORT) + { + UString m; + if (res == S_FALSE) + m = "Decoding error"; + else if (res == CLASS_E_CLASSNOTAVAILABLE) + m = "Can't find 7z.dll"; + else + m = HResultToMessage(res); + MessageBoxError_Status(m); + } + } + + if (NeedRestart) + { + StartBenchmark(); + return true; + } + } + // k_Message_Finished_cnt++; + UpdateGui(); + return true; } - if (printTime) - PrintTime(); +} + + +bool CBenchmarkDialog::OnTimer(WPARAM timerID, LPARAM /* callback */) +{ + // k_OnTimer_cnt++; + if (timerID == kTimerID) + UpdateGui(); + return true; +} + + +void CBenchmarkDialog::UpdateGui() +{ + PrintTime(); if (TotalMode) { @@ -491,103 +1270,147 @@ bool CBenchmarkDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */) } if (wasChanged) _consoleEdit.SetText(Bench2Text); - return true; + return; } - SetItemText_Number(IDT_BENCH_SIZE_VAL, (Sync.ProcessedSize >> 20), kMB); + CSyncData sd; + CRecordVector<CBenchPassResult> RatingVector; - SetItemText_Number(IDT_BENCH_PASSES_VAL, Sync.NumPasses); + { + NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS); + sd = Sync.sd; - /* - if (Sync.FirstPath) - SetItemText_Number(IDT_BENCH_FREQ_CUR, Sync.Freq, TEXT(" MHz")); - else - SetItemText_Number(IDT_BENCH_FREQ_RES, Sync.Freq, TEXT(" MHz")); - */ + if (sd.NeedPrint_RatingVector) + RatingVector = Sync.RatingVector; + + if (sd.NeedPrint_Freq) + { + Sync.FreqString_GUI = Sync.FreqString_Sync; + sd.NeedPrint_RatingVector = true; + } - /* - if (Sync.FreqWasChanged) - { - SetItemText(IDT_BENCH_FREQ, Sync.Freq); - Sync.FreqWasChanged = false; + Sync.sd.NeedPrint_RatingVector = false; + Sync.sd.NeedPrint_Enc_1 = false; + Sync.sd.NeedPrint_Enc = false; + Sync.sd.NeedPrint_Dec_1 = false; + Sync.sd.NeedPrint_Dec = false; + Sync.sd.NeedPrint_Tot = false; + Sync.sd.NeedPrint_Freq = false; } - */ + if (sd.NumPasses_Finished != NumPasses_Finished_Prev) { - UInt32 dicSizeTemp = (UInt32)MyMax(Sync.ProcessedSize, UInt64(1) << 20); - dicSizeTemp = MyMin(dicSizeTemp, Sync.DictionarySize); - PrintResults(dicSizeTemp, - Sync.CompressingInfoTemp, - IDT_BENCH_COMPRESS_USAGE1, - IDT_BENCH_COMPRESS_SPEED1, - IDT_BENCH_COMPRESS_RPU1, - IDT_BENCH_COMPRESS_RATING1); + SetItemText_Number(IDT_BENCH_PASSES_VAL, sd.NumPasses_Finished, TEXT(" /")); + NumPasses_Finished_Prev = sd.NumPasses_Finished; } + if (sd.NeedPrint_Enc_1) PrintBenchRes(sd.Enc_BenchRes_1, k_Ids_Enc_1); + if (sd.NeedPrint_Enc) PrintBenchRes(sd.Enc_BenchRes, k_Ids_Enc); + if (sd.NeedPrint_Dec_1) PrintBenchRes(sd.Dec_BenchRes_1, k_Ids_Dec_1); + if (sd.NeedPrint_Dec) PrintBenchRes(sd.Dec_BenchRes, k_Ids_Dec); + + if (sd.BenchWasFinished && sd.NeedPrint_Tot) { - PrintResults( - Sync.DictionarySize, - Sync.CompressingInfo, - IDT_BENCH_COMPRESS_USAGE2, - IDT_BENCH_COMPRESS_SPEED2, - IDT_BENCH_COMPRESS_RPU2, - IDT_BENCH_COMPRESS_RATING2); + CTotalBenchRes2 tot_BenchRes = sd.Enc_BenchRes; + tot_BenchRes.Update_With_Res2(sd.Dec_BenchRes); + PrintBenchRes(tot_BenchRes, k_Ids_Tot); } + + if (sd.NeedPrint_RatingVector) + // for (unsigned k = 0; k < 1; k++) { - PrintResults( - Sync.DictionarySize, - Sync.DecompressingInfoTemp, - IDT_BENCH_DECOMPR_USAGE1, - IDT_BENCH_DECOMPR_SPEED1, - IDT_BENCH_DECOMPR_RPU1, - IDT_BENCH_DECOMPR_RATING1, - true); - } - { - PrintResults( - Sync.DictionarySize, - Sync.DecompressingInfo, - IDT_BENCH_DECOMPR_USAGE2, - IDT_BENCH_DECOMPR_SPEED2, - IDT_BENCH_DECOMPR_RPU2, - IDT_BENCH_DECOMPR_RATING2, - true); - if (Sync.DecompressingInfo.GlobalTime > 0 && - Sync.CompressingInfo.GlobalTime > 0) + UString s; + s += Sync.FreqString_GUI; + if (!RatingVector.IsEmpty()) { - UInt64 comprRating = Sync.CompressingInfo.GetCompressRating(Sync.DictionarySize); - UInt64 decomprRating = Sync.DecompressingInfo.GetDecompressRating(); - PrintRating((comprRating + decomprRating) / 2, IDT_BENCH_TOTAL_RATING_VAL); - PrintRating(( - Sync.CompressingInfo.GetRatingPerUsage(comprRating) + - Sync.DecompressingInfo.GetRatingPerUsage(decomprRating)) / 2, IDT_BENCH_TOTAL_RPU_VAL); - PrintUsage( - (Sync.CompressingInfo.GetUsage() + - Sync.DecompressingInfo.GetUsage()) / 2, IDT_BENCH_TOTAL_USAGE_VAL); + if (!s.IsEmpty()) + s.Add_LF(); + s += "Compr Decompr Total CPU" + #ifdef PRINT_ITER_TIME + " Time" + #endif + ; + s.Add_LF(); } + // s += "GIPS GIPS GIPS % s"; s.Add_LF(); + for (unsigned i = 0; i < RatingVector.Size(); i++) + { + if (i != 0) + s.Add_LF(); + if ((int)i == sd.RatingVector_DeletedIndex) + { + s += "..."; + s.Add_LF(); + } + const CBenchPassResult &pair = RatingVector[i]; + /* + s += "g:"; s.Add_UInt32((UInt32)pair.EncInfo.GlobalTime); + s += " u:"; s.Add_UInt32((UInt32)pair.EncInfo.UserTime); + s += " "; + */ + AddRatingsLine(s, pair.Enc, pair.Dec + #ifdef PRINT_ITER_TIME + , pair.Ticks + #endif + ); + /* + { + UInt64 v = i + 1; + if (sd.RatingVector_DeletedIndex >= 0 && i >= (unsigned)sd.RatingVector_DeletedIndex) + v += sd.RatingVector_NumDeleted; + char temp[64]; + ConvertUInt64ToString(v, temp); + s += " : "; + s += temp; + } + */ + } + + if (sd.BenchWasFinished) + { + s.Add_LF(); + s += "-------------"; + s.Add_LF(); + { + // average time is not correct because of freq detection in first iteration + AddRatingsLine(s, sd.Enc_BenchRes, sd.Dec_BenchRes + #ifdef PRINT_ITER_TIME + , (DWORD)(sd.TotalTicks / (sd.NumPasses_Finished ? sd.NumPasses_Finished : 1)) + #endif + ); + } + } + // s.Add_LF(); s += "OnTimer: "; s.Add_UInt32(k_OnTimer_cnt); + // s.Add_LF(); s += "finished Message: "; s.Add_UInt32(k_Message_Finished_cnt); + // static cnt = 0; cnt++; s.Add_LF(); s += "Print: "; s.Add_UInt32(cnt); + // s.Add_LF(); s += "NumEncProgress: "; s.Add_UInt32((UInt32)sd.NumEncProgress); + // s.Add_LF(); s += "NumDecProgress: "; s.Add_UInt32((UInt32)sd.NumDecProgress); + SetItemText(IDT_BENCH_LOG, s); } - return true; } + bool CBenchmarkDialog::OnCommand(int code, int itemID, LPARAM lParam) { if (code == CBN_SELCHANGE && (itemID == IDC_BENCH_DICTIONARY || + itemID == IDC_BENCH_NUM_PASSES || itemID == IDC_BENCH_NUM_THREADS)) { - OnChangeSettings(); + RestartBenchmark(); return true; } return CModalDialog::OnCommand(code, itemID, lParam); } + bool CBenchmarkDialog::OnButtonClicked(int buttonID, HWND buttonHWND) { switch (buttonID) { case IDB_RESTART: - OnRestartButton(); + RestartBenchmark(); return true; case IDB_STOP: OnStopButton(); @@ -596,87 +1419,81 @@ bool CBenchmarkDialog::OnButtonClicked(int buttonID, HWND buttonHWND) return CModalDialog::OnButtonClicked(buttonID, buttonHWND); } -struct CThreadBenchmark -{ - CBenchmarkDialog *BenchmarkDialog; - DECL_EXTERNAL_CODECS_LOC_VARS2; - // UInt32 dictionarySize; - // UInt32 numThreads; - HRESULT Process(); - HRESULT Result; - static THREAD_FUNC_DECL MyThreadFunction(void *param) - { - ((CThreadBenchmark *)param)->Result = ((CThreadBenchmark *)param)->Process(); - return 0; - } -}; + + + +// ---------- Benchmark Thread ---------- struct CBenchCallback: public IBenchCallback { - UInt32 dictionarySize; + UInt64 dictionarySize; CBenchProgressSync *Sync; + CBenchmarkDialog *BenchmarkDialog; - // void AddCpuFreq(UInt64 cpuFreq); - HRESULT SetFreq(bool showFreq, UInt64 cpuFreq); HRESULT SetEncodeResult(const CBenchInfo &info, bool final); HRESULT SetDecodeResult(const CBenchInfo &info, bool final); }; -/* -void CBenchCallback::AddCpuFreq(UInt64 cpuFreq) -{ - NSynchronization::CCriticalSectionLock lock(Sync->CS); - { - wchar_t s[32]; - ConvertUInt64ToString(cpuFreq, s); - Sync->Freq.Add_Space_if_NotEmpty(); - Sync->Freq += s; - Sync->FreqWasChanged = true; - } -} -*/ - -HRESULT CBenchCallback::SetFreq(bool /* showFreq */, UInt64 /* cpuFreq */) -{ - return S_OK; -} - HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final) { - NSynchronization::CCriticalSectionLock lock(Sync->CS); - if (Sync->Changed || Sync->Paused || Sync->Stopped) - return E_ABORT; - Sync->ProcessedSize = info.UnpackSize * info.NumIterations; - if (final && Sync->CompressingInfo.GlobalTime == 0) + bool needPost = false; { - (CBenchInfo&)Sync->CompressingInfo = info; - if (Sync->CompressingInfo.GlobalTime == 0) - Sync->CompressingInfo.GlobalTime = 1; + NSynchronization::CCriticalSectionLock lock(Sync->CS); + if (Sync->Exit) + return E_ABORT; + CSyncData &sd = Sync->sd; + // sd.NumEncProgress++; + CTotalBenchRes2 &br = sd.Enc_BenchRes_1; + { + UInt64 dictSize = Sync->DictSize; + if (final) + { + // sd.EncInfo = info; + } + else + { + /* if (!final), then CBenchInfo::NumIterations means totalNumber of threads. + so we can reduce the dictionary */ + if (dictSize > info.UnpackSize) + dictSize = info.UnpackSize; + } + br.Rating = info.GetRating_LzmaEnc(dictSize); + } + br.SetFrom_BenchInfo(info); + sd.NeedPrint_Enc_1 = true; + if (final) + { + sd.Enc_BenchRes.Update_With_Res2(br); + sd.NeedPrint_Enc = true; + needPost = true; + } } - else - (CBenchInfo&)Sync->CompressingInfoTemp = info; + + if (needPost) + BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); return S_OK; } + HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final) { NSynchronization::CCriticalSectionLock lock(Sync->CS); - if (Sync->Changed || Sync->Paused || Sync->Stopped) + if (Sync->Exit) return E_ABORT; - CBenchInfo info2 = info; - if (final && Sync->DecompressingInfo.GlobalTime == 0) - { - (CBenchInfo&)Sync->DecompressingInfo = info2; - if (Sync->DecompressingInfo.GlobalTime == 0) - Sync->DecompressingInfo.GlobalTime = 1; - } - else - (CBenchInfo&)Sync->DecompressingInfoTemp = info2; + CSyncData &sd = Sync->sd; + // sd.NumDecProgress++; + CTotalBenchRes2 &br = sd.Dec_BenchRes_1; + br.Rating = info.GetRating_LzmaDec(); + br.SetFrom_BenchInfo(info); + sd.NeedPrint_Dec_1 = true; + if (final) + sd.Dec_BenchRes.Update_With_Res2(br); return S_OK; } + struct CBenchCallback2: public IBenchPrintCallback { CBenchProgressSync *Sync; @@ -704,74 +1521,142 @@ void CBenchCallback2::NewLine() HRESULT CBenchCallback2::CheckBreak() { - if (Sync->Changed || Sync->Paused || Sync->Stopped) + if (Sync->Exit) return E_ABORT; return S_OK; } -/* struct CFreqCallback: public IBenchFreqCallback { - CBenchProgressSync *Sync; + CBenchmarkDialog *BenchmarkDialog; - virtual void AddCpuFreq(UInt64 freq); + virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage); + virtual HRESULT FreqsFinished(unsigned numThreads); }; -void CFreqCallback::AddCpuFreq(UInt64 freq) +HRESULT CFreqCallback::AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) { - NSynchronization::CCriticalSectionLock lock(Sync->CS); - Sync->Freq = freq; + HRESULT res; + { + CBenchProgressSync &sync = BenchmarkDialog->Sync; + NSynchronization::CCriticalSectionLock lock(sync.CS); + UString &s = sync.FreqString_Sync; + if (sync.NumFreqThreadsPrev != numThreads) + { + sync.NumFreqThreadsPrev = numThreads; + if (!s.IsEmpty()) + s.Add_LF(); + s.Add_UInt32(numThreads); + s += "T Frequency (MHz):"; + s.Add_LF(); + } + s += " "; + if (numThreads != 1) + { + s.Add_UInt64(GetUsagePercents(usage)); + s += '%'; + s.Add_Space(); + } + s.Add_UInt64(GetMips(freq)); + // BenchmarkDialog->Sync.sd.NeedPrint_Freq = true; + res = sync.Exit ? E_ABORT : S_OK; + } + // BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); + return res; +} + +HRESULT CFreqCallback::FreqsFinished(unsigned /* numThreads */) +{ + HRESULT res; + { + CBenchProgressSync &sync = BenchmarkDialog->Sync; + NSynchronization::CCriticalSectionLock lock(sync.CS); + sync.sd.NeedPrint_Freq = true; + BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); + res = sync.Exit ? E_ABORT : S_OK; + } + BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished); + return res; } -*/ +// define USE_DUMMY only for debug +// #define USE_DUMMY +#ifdef USE_DUMMY +static unsigned dummy = 1; +static unsigned Dummy(unsigned limit) +{ + unsigned sum = 0; + for (unsigned k = 0; k < limit; k++) + { + sum += dummy; + if (sum == 0) + break; + } + return sum; +} +#endif + + HRESULT CThreadBenchmark::Process() { + /* the first benchmark pass can be slow, + if we run benchmark while the window is being created, + and (no freq detecion loop) && (dictionary is small) (-mtic is small) */ + + // Sleep(300); // for debug + #ifdef USE_DUMMY + Dummy(1000 * 1000 * 1000); // for debug + #endif + CBenchProgressSync &sync = BenchmarkDialog->Sync; - sync.WaitCreating(); + HRESULT finishHRESULT = S_OK; + try { - for (;;) + for (UInt32 passIndex = 0;; passIndex++) { - if (sync.WasStopped()) - return 0; - if (sync.WasPaused()) - { - Sleep(200); - continue; - } - UInt32 dictionarySize; + // throw 1; // to debug + // throw CSystemException(E_INVALIDARG); // to debug + + UInt64 dictionarySize; UInt32 numThreads; { NSynchronization::CCriticalSectionLock lock(sync.CS); - if (sync.Stopped || sync.Paused) - continue; - if (sync.Changed) - sync.Init(); - dictionarySize = sync.DictionarySize; + if (sync.Exit) + break; + dictionarySize = sync.DictSize; numThreads = sync.NumThreads; - /* - if (sync.CompressingInfo.GlobalTime != 0) - sync.FirstPath = false; - */ } + + #ifdef PRINT_ITER_TIME + const DWORD startTick = GetTickCount(); + #endif CBenchCallback callback; + callback.dictionarySize = dictionarySize; callback.Sync = &sync; + callback.BenchmarkDialog = BenchmarkDialog; + CBenchCallback2 callback2; callback2.TotalMode = BenchmarkDialog->TotalMode; callback2.Sync = &sync; - // CFreqCallback freqCallback; - // freqCallback.Sync = &sync; + + CFreqCallback freqCallback; + freqCallback.BenchmarkDialog = BenchmarkDialog; + HRESULT result; try { CObjectVector<CProperty> props; + + props = BenchmarkDialog->Props; + if (BenchmarkDialog->TotalMode) { props = BenchmarkDialog->Props; @@ -787,8 +1672,8 @@ HRESULT CThreadBenchmark::Process() { CProperty prop; prop.Name = 'd'; - prop.Name.Add_UInt32(dictionarySize); - prop.Name += 'b'; + prop.Name.Add_UInt32((UInt32)(dictionarySize >> 10)); + prop.Name += 'k'; props.Add(prop); } } @@ -796,57 +1681,133 @@ HRESULT CThreadBenchmark::Process() result = Bench(EXTERNAL_CODECS_LOC_VARS BenchmarkDialog->TotalMode ? &callback2 : NULL, BenchmarkDialog->TotalMode ? NULL : &callback, - // &freqCallback, - props, 1, false); + props, 1, false, + (!BenchmarkDialog->TotalMode) && passIndex == 0 ? &freqCallback: NULL); - if (BenchmarkDialog->TotalMode) - { - sync.Stop(); - } + // result = S_FALSE; // for debug; + // throw 1; } catch(...) { result = E_FAIL; } + #ifdef PRINT_ITER_TIME + const DWORD numTicks = GetTickCount() - startTick; + #endif + + bool finished = true; + + NSynchronization::CCriticalSectionLock lock(sync.CS); + if (result != S_OK) { - if (result != E_ABORT) + sync.BenchFinish_Task_HRESULT = result; + break; + } + + { + CSyncData &sd = sync.sd; + + sd.NumPasses_Finished++; + #ifdef PRINT_ITER_TIME + sd.TotalTicks += numTicks; + #endif + + if (BenchmarkDialog->TotalMode) + break; + { + CTotalBenchRes tot_BenchRes = sd.Enc_BenchRes_1; + tot_BenchRes.Update_With_Res(sd.Dec_BenchRes_1); + + sd.NeedPrint_RatingVector = true; { - NSynchronization::CCriticalSectionLock lock(sync.CS); - sync.Pause(); + CBenchPassResult pair; + // pair.EncInfo = sd.EncInfo; // for debug + pair.Enc = sd.Enc_BenchRes_1; + pair.Dec = sd.Dec_BenchRes_1; + #ifdef PRINT_ITER_TIME + pair.Ticks = numTicks; + #endif + sync.RatingVector.Add(pair); + // pair.Dec_Defined = true; } - UString message; - if (result == S_FALSE) - message = "Decoding error"; - else if (result == CLASS_E_CLASSNOTAVAILABLE) - message = "Can't find 7z.dll"; - else - message = HResultToMessage(result); - BenchmarkDialog->MessageBoxError(message); + } + + sd.NeedPrint_Dec = true; + sd.NeedPrint_Tot = true; + + if (sync.RatingVector.Size() > kRatingVector_NumBundlesMax) + { + // sd.RatingVector_NumDeleted++; + sd.RatingVector_DeletedIndex = (int)(kRatingVector_NumBundlesMax / 4); + sync.RatingVector.Delete((unsigned)(sd.RatingVector_DeletedIndex)); + } + + if (sync.sd.NumPasses_Finished < sync.NumPasses_Limit) + finished = false; + else + { + sync.sd.BenchWasFinished = true; + // BenchmarkDialog->_finishTime = GetTickCount(); + // return 0; } } - else + + if (BenchmarkDialog->TotalMode) + break; + + /* + if (newTick - prevTick < 1000) + numSameTick++; + if (numSameTick > 5 || finished) { - NSynchronization::CCriticalSectionLock lock(sync.CS); - sync.NumPasses++; + prevTick = newTick; + numSameTick = 0; + */ + // for (unsigned i = 0; i < 1; i++) + { + // we suppose that PostMsg messages will be processed in order. + if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Iter_Finished)) + { + finished = true; + finishHRESULT = E_FAIL; + // throw 1234567; + } } + if (finished) + break; } // return S_OK; } catch(CSystemException &e) { - BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode)); - return E_FAIL; + finishHRESULT = e.ErrorCode; + // BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode)); + // return E_FAIL; } catch(...) { - BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL)); - return E_FAIL; + finishHRESULT = E_FAIL; + // BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL)); + // return E_FAIL; + } + + if (finishHRESULT != S_OK) + { + NSynchronization::CCriticalSectionLock lock(sync.CS); + sync.BenchFinish_Thread_HRESULT = finishHRESULT; } + if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Thread_Finished)) + { + // sync.BenchFinish_Thread_HRESULT = E_FAIL; + } + return 0; } + + static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) { const wchar_t *end; @@ -859,20 +1820,21 @@ static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop) prop = result; } + HRESULT Benchmark( DECL_EXTERNAL_CODECS_LOC_VARS - const CObjectVector<CProperty> &props, HWND hwndParent) + const CObjectVector<CProperty> &props, UInt32 numIterations, HWND hwndParent) { - CThreadBenchmark benchmarker; - #ifdef EXTERNAL_CODECS - benchmarker.__externalCodecs = __externalCodecs; - #endif - CBenchmarkDialog bd; - bd.Props = props; + bd.TotalMode = false; - bd.Sync.DictionarySize = (UInt32)(Int32)-1; + bd.Props = props; + if (numIterations == 0) + numIterations = 1; + bd.Sync.NumPasses_Limit = numIterations; + bd.Sync.DictSize = (UInt64)(Int64)-1; bd.Sync.NumThreads = (UInt32)(Int32)-1; + bd.Sync.Level = -1; COneMethodInfo method; @@ -905,13 +1867,17 @@ HRESULT Benchmark( #endif continue; } - if (name.IsEqualTo("testtime")) + /* + if (name.IsEqualTo("time")) { // UInt32 testTime = 4; // RINOK(ParsePropToUInt32(L"", propVariant, testTime)); continue; } RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant)); + */ + // here we need to parse DictSize property, and ignore unknown properties + method.ParseMethodFromPROPVARIANT(name, propVariant); } if (bd.TotalMode) @@ -923,17 +1889,37 @@ HRESULT Benchmark( } { - UInt32 dict; + UInt64 dict; if (method.Get_DicSize(dict)) - bd.Sync.DictionarySize = dict; + bd.Sync.DictSize = dict; + } + bd.Sync.Level = method.GetLevel(); + + // Dummy(1000 * 1000 * 1); + + { + CThreadBenchmark &benchmarker = bd._threadBenchmark; + #ifdef EXTERNAL_CODECS + benchmarker.__externalCodecs = __externalCodecs; + #endif + benchmarker.BenchmarkDialog = &bd; } - benchmarker.BenchmarkDialog = &bd; + bd.Create(hwndParent); + return S_OK; +} + + +CBenchmarkDialog::~CBenchmarkDialog() +{ + if (_thread.IsCreated()) { - NWindows::CThread thread; - RINOK(thread.Create(CThreadBenchmark::MyThreadFunction, &benchmarker)); - bd.Create(hwndParent); - return thread.Wait_Close(); + /* the following code will be not executed in normal code flow. + it can be called, if there is some internal failure in dialog code. */ + Attach(NULL); + MessageBoxError(L"The flaw in benchmark thread code"); + Sync.SendExit(); + _thread.Wait_Close(); } } |