From 6a57932aa0e4171ccccef67cf902f370ead7bba9 Mon Sep 17 00:00:00 2001 From: Pavel Yosifovich Date: Sun, 21 Jan 2018 10:40:34 +0200 Subject: [PATCH] added thread and CPU percentage columns --- CPUSTRES/CPUSTRES.rc | Bin 0 -> 2668 bytes CPUSTRES/CPUStressEx.rc | 13 +++- CPUSTRES/CPUStressEx.vcxproj | 4 ++ CPUSTRES/CPUStressEx.vcxproj.filters | 6 ++ CPUSTRES/ChildView.cpp | 86 ++++++++++++++++++++++++++- CPUSTRES/ChildView.h | 12 +++- CPUSTRES/MainFrm.cpp | 7 ++- CPUSTRES/MainFrm.h | 1 + CPUSTRES/RCa25180 | Bin 0 -> 2940 bytes CPUSTRES/Thread.cpp | 25 ++++++-- CPUSTRES/Thread.h | 4 ++ CPUSTRES/resource.h | 8 ++- CPUSTRES/resource1.h | 14 +++++ MemLimit/MemLimit.cpp | Bin 12308 -> 12276 bytes 14 files changed, 167 insertions(+), 13 deletions(-) create mode 100644 CPUSTRES/CPUSTRES.rc create mode 100644 CPUSTRES/RCa25180 create mode 100644 CPUSTRES/resource1.h diff --git a/CPUSTRES/CPUSTRES.rc b/CPUSTRES/CPUSTRES.rc new file mode 100644 index 0000000000000000000000000000000000000000..d3073e2568d2f7af869072deb64b4b10e8a26de4 GIT binary patch literal 2668 zcmdUxOK;jh5Xb-LO8E{hT!LDalALnnk)WtRA|6p9A)zSL4H9)K4C1%3(w$;{TKCuG*(04`b75p`H z4sQiDy$z=u&H+zmZJ}Ste9@jha7*3MD%^;Fmq^c@Y$c=LK<8E!CvUn{CmA|Tv)VnKJ${{%2=_m28LC0_y z6ZIv(r$pT*PQ&9E{sDV8Cr@YLx5GEldx(Ge5c3`-)v*C9tEG^*Usf9)d2hE|)O#0@ z-G~lclBt*)2((YmBc6OGjyNTK8LO641#zmU77nkE4|;2k#imZEs-&kz^v{IuYIF09 z>gut~?jKfAs5!>QkQ$z$H9)`SZtcMxz@0$5u1=5i87qw)pNcbSb$)?I-_Y*7yPnSP zR-ap=wi_T)EZHLRuIqP`4YsRjf==~yJ4G!I31X&a^CABZvuF}U_vB6Qin5cVqA3$- zN^K@n{NB?dpAKK_({pdCy4gCXYiwR5%lbWUc4RBg&?&a?HvL(y>67-xqEBzDhw#zq un?*2fuUuz~%sle+weMl8>Bry09?Np!koLwrEUx#6FB1D!%)WKAdH)a3`Z$OH literal 0 HcmV?d00001 diff --git a/CPUSTRES/CPUStressEx.rc b/CPUSTRES/CPUStressEx.rc index 9f8af89..84555a5 100644 --- a/CPUSTRES/CPUStressEx.rc +++ b/CPUSTRES/CPUStressEx.rc @@ -107,6 +107,7 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Create &Thread", ID_PROCESS_CREATETHREAD MENUITEM "Create &4 Threads", ID_PROCESS_CREATE4THREADS + MENUITEM "&Queue Thread Pool Work", ID_PROCESS_QUEUETHREADPOOLWORK MENUITEM SEPARATOR MENUITEM "&Refresh\tF5", ID_PROCESS_REFRESH END @@ -251,12 +252,12 @@ END IDD_ABOUTBOX DIALOGEX 0, 0, 263, 84 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "About CPUStressEx" +CAPTION "About CPUSTRES" FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN ICON IDR_MAINFRAME,IDC_STATIC,14,14,20,20 - LTEXT "CPUSTRES v2.0",IDC_STATIC,42,14,114,8,SS_NOPREFIX - LTEXT "Copyright (C) 2016 Pavel Yosifovich",IDC_STATIC,42,26,170,8 + LTEXT "CPUSTRES v2.1",IDC_STATIC,42,14,114,8,SS_NOPREFIX + LTEXT "Copyright (C) 2016-2018 Pavel Yosifovich",IDC_STATIC,42,26,170,8 DEFPUSHBUTTON "OK",IDOK,106,63,50,14,WS_GROUP CONTROL "Sysinternals - www.sysinternals.com",IDC_LINK,"MfcLink",WS_TABSTOP,39,38,182,14 END @@ -596,6 +597,12 @@ BEGIN AFX_IDS_SCTASKLIST "Activate Task List" END +STRINGTABLE +BEGIN + ID_STATUS_THREAD "Total Threads: 000" + ID_STATUS_PROCESSCPU "Process CPU: 100.10%" +END + #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/CPUSTRES/CPUStressEx.vcxproj b/CPUSTRES/CPUStressEx.vcxproj index e5f1607..d2a3f46 100644 --- a/CPUSTRES/CPUStressEx.vcxproj +++ b/CPUSTRES/CPUStressEx.vcxproj @@ -147,6 +147,7 @@ Windows true true + false false @@ -173,6 +174,7 @@ Windows true true + false false @@ -192,6 +194,7 @@ + @@ -217,6 +220,7 @@ + diff --git a/CPUSTRES/CPUStressEx.vcxproj.filters b/CPUSTRES/CPUStressEx.vcxproj.filters index 369628a..aeb71bb 100644 --- a/CPUSTRES/CPUStressEx.vcxproj.filters +++ b/CPUSTRES/CPUStressEx.vcxproj.filters @@ -51,6 +51,9 @@ Header Files + + Header Files + @@ -88,6 +91,9 @@ Resource Files + + Resource Files + diff --git a/CPUSTRES/ChildView.cpp b/CPUSTRES/ChildView.cpp index cc63db2..ae01332 100644 --- a/CPUSTRES/ChildView.cpp +++ b/CPUSTRES/ChildView.cpp @@ -59,6 +59,10 @@ BEGIN_MESSAGE_MAP(CChildView, CWnd) ON_COMMAND(ID_CPUSETS_PROCESSCPUSET, &CChildView::OnCpusetsProcesscpuset) ON_COMMAND(ID_CPUSETS_THREADSELECTEDCPUSET, &CChildView::OnCpusetsThreadselectedcpuset) ON_UPDATE_COMMAND_UI(ID_CPUSETS_THREADSELECTEDCPUSET, &CChildView::OnUpdateCpusetsThreadselectedcpuset) + ON_COMMAND(ID_PROCESS_QUEUETHREADPOOLWORK, &CChildView::OnProcessQueuethreadpoolwork) + + ON_UPDATE_COMMAND_UI(ID_STATUS_THREAD, OnUpdateStatusThreads) + ON_UPDATE_COMMAND_UI(ID_STATUS_PROCESSCPU, OnUpdateStatusProcessCpu) END_MESSAGE_MAP() void CChildView::DoDataExchange(CDataExchange* pDX) { @@ -111,10 +115,15 @@ int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) { m_List.InsertColumn(4, L"Priority", LVCFMT_LEFT, 100); m_List.InsertColumn(5, L"Ideal CPU", LVCFMT_CENTER, 80); m_List.InsertColumn(6, L"Affinity", LVCFMT_RIGHT, 120); + m_List.InsertColumn(7, L"CPU (%)", LVCFMT_RIGHT, 80); + + VERIFY(::QueryPerformanceFrequency(&m_QueryFrequency)); + VERIFY(::QueryPerformanceCounter(&m_LastQueryCount)); CreateThreads(); SetTimer(1, 10000, nullptr); + SetTimer(2, 1000, nullptr); return 0; } @@ -170,6 +179,7 @@ PCWSTR CChildView::ThreadPriorityToString(int priority) { void CChildView::UpdateThreadProcessIndices() { auto threads = CGlobals::EnumerateThreads(::GetCurrentProcessId()); + m_TotalThreads = static_cast(threads.size()); if (m_CurrentThreadIds == threads) return; @@ -192,6 +202,21 @@ void CChildView::UpdateThreadProcessIndices() { } } +BOOL CChildView::QueueItemForThreadPool(int busyPercent) { + return ::QueueUserWorkItem([](auto param) { + return BurnSomeCycles(static_cast(reinterpret_cast(param))); + }, reinterpret_cast(static_cast(busyPercent)), WT_EXECUTEDEFAULT); +} + +DWORD CChildView::BurnSomeCycles(int percent) { + int time = (int)::GetTickCount(); + while ((int)::GetTickCount() - time < percent * 10) + ; // burn CPU cycles + + ::Sleep(1000 - percent * 10); + return percent; +} + unique_ptr CChildView::CreateThread() { auto thread = make_unique(); return thread; @@ -342,7 +367,15 @@ void CChildView::OnThreadKill() { } void CChildView::OnTimer(UINT_PTR nIDEvent) { - UpdateThreadProcessIndices(); + switch (nIDEvent) { + case 1: + UpdateThreadProcessIndices(); + break; + + case 2: + UpdateCPUTimes(); + break; + } } void CChildView::OnProcessRefresh() { @@ -414,3 +447,54 @@ void CChildView::OnCpusetsThreadselectedcpuset() { void CChildView::OnUpdateCpusetsThreadselectedcpuset(CCmdUI *pCmdUI) { pCmdUI->Enable(m_List.GetSelectedCount() == 1); } + + +void CChildView::OnProcessQueuethreadpoolwork() { + if (!QueueItemForThreadPool(50)) { + AfxMessageBox(L"Failed to queue work item to thread pool"); + return; + } +} + +void CChildView::OnUpdateStatusThreads(CCmdUI* pCmdUI) { + CString text; + text.Format(L"Total threads: %d", m_TotalThreads); + pCmdUI->SetText(text); +} + +void CChildView::UpdateCPUTimes() { + int i = 0; + CString text; + for (auto& thread : m_Threads) { + if (thread->IsActive()) { + auto cpu = thread->GetCPUTime(m_QueryFrequency) / CGlobals::GetProcessorCount(); + text.Format(L"%.2f", cpu / 100000.0); + m_List.SetItemText(i, 7, text); + } + else { + m_List.SetItemText(i, 7, L""); + } + i++; + } + + FILETIME dummy, kernel, user; + VERIFY(::GetProcessTimes(::GetCurrentProcess(), &dummy, &dummy, &kernel, &user)); + + LARGE_INTEGER counter; + VERIFY(::QueryPerformanceCounter(&counter)); + auto total = *(long long*)&kernel + *(long long*)&user; + ULONG cpu = 0; + if (m_LastProcessTimes > 0) { + cpu = static_cast((total - m_LastProcessTimes) * 1000000LL / ((counter.QuadPart - m_LastQueryCount.QuadPart) * 1000000LL / m_QueryFrequency.QuadPart)); + m_ProcessCPU = cpu / CGlobals::GetProcessorCount() / 100000.0; + } + + m_LastQueryCount = counter; + m_LastProcessTimes = total; +} + +void CChildView::OnUpdateStatusProcessCpu(CCmdUI* pCmdUI) { + CString text; + text.Format(L"Process CPU: %.2f %%", m_ProcessCPU); + pCmdUI->SetText(text); +} diff --git a/CPUSTRES/ChildView.h b/CPUSTRES/ChildView.h index 74bdada..d08bff5 100644 --- a/CPUSTRES/ChildView.h +++ b/CPUSTRES/ChildView.h @@ -33,6 +33,10 @@ private: std::vector < std::unique_ptr> m_Threads; std::vector m_CurrentThreadIds; bool m_AutoRefreshThreadIndices = true; + int m_TotalThreads; + LARGE_INTEGER m_LastQueryCount, m_QueryFrequency; + long long m_LastProcessTimes = 0; + double m_ProcessCPU; void CreateThreads(); std::unique_ptr CreateThread(); @@ -40,6 +44,9 @@ private: static PCWSTR ActivityLevelToString(ActivityLevel level); static PCWSTR ThreadPriorityToString(int priority); void UpdateThreadProcessIndices(); + BOOL QueueItemForThreadPool(int busyPercent); + static DWORD CALLBACK BurnSomeCycles(int percent); + void UpdateCPUTimes(); // Generated message map functions protected: @@ -76,9 +83,12 @@ protected: afx_msg void OnOptionsAutorefreshthreadindices(); afx_msg void OnUpdateOptionsAutorefreshthreadindices(CCmdUI *pCmdUI); afx_msg void OnCpusetsSystemcpuset(); -public: afx_msg void OnCpusetsProcesscpuset(); afx_msg void OnCpusetsThreadselectedcpuset(); afx_msg void OnUpdateCpusetsThreadselectedcpuset(CCmdUI *pCmdUI); + afx_msg void OnProcessQueuethreadpoolwork(); + + void OnUpdateStatusThreads(CCmdUI*); + void OnUpdateStatusProcessCpu(CCmdUI*); }; diff --git a/CPUSTRES/MainFrm.cpp b/CPUSTRES/MainFrm.cpp index a55b6f9..16ea516 100644 --- a/CPUSTRES/MainFrm.cpp +++ b/CPUSTRES/MainFrm.cpp @@ -39,7 +39,7 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { return -1; // create a view to occupy the client area of the frame - if(!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW, CRect(), this, AFX_IDW_PANE_FIRST)) { + if(!m_wndView.Create(nullptr, nullptr, AFX_WS_DEFAULT_VIEW, CRect(), this, AFX_IDW_PANE_FIRST)) { TRACE0("Failed to create view window\n"); return -1; } @@ -49,6 +49,11 @@ int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { return -1; } + m_StatusBar.Create(this); + UINT indicators[] = { ID_STATUS_THREAD, ID_STATUS_PROCESSCPU }; + + m_StatusBar.SetIndicators(indicators, _countof(indicators)); + SetProcessAffinityText(); SetProcessPriorityClassText(); diff --git a/CPUSTRES/MainFrm.h b/CPUSTRES/MainFrm.h index 1cae3d1..4c50b3b 100644 --- a/CPUSTRES/MainFrm.h +++ b/CPUSTRES/MainFrm.h @@ -37,6 +37,7 @@ public: protected: // control bar embedded members CDialogBar m_wndDlgBar; CChildView m_wndView; + CStatusBar m_StatusBar; // Generated message map functions protected: diff --git a/CPUSTRES/RCa25180 b/CPUSTRES/RCa25180 new file mode 100644 index 0000000000000000000000000000000000000000..563649c8c707125d70f2c6d46bb028fec2eadc0d GIT binary patch literal 2940 zcmd6p-ER^>6vfZ8iT}e0FKsl{rQp{arIipVZ3;&Nid0ccuXV*Z#`42oz4Ol}n(Ic1I;_3s*@F2azKLJc z(z%A}YoH6AFk6I8+W|gfGCb4+RoAkbOQ45!c3 zU{x=$TRjtO3ug0M`b@T?#7CRyJ8KSnX3G;Quw9R-V~MY=t>pY8e7+P^+(;vs-}Dx} zCKwn3L$K@UOe2p)le;tZ)YS(peg02%gr&=Mwr{Jcd?Twao1NP1cN6m|sLk~a{I0>u za2&vZ_xyL*b&Gu(9w*pq{5DT$_nF*ye1l){X+%WMYAhd$R*_X#g=ev6+7ulAjw|b` z2`nt^S`xy;`41;E2;6oQS#0blc}Ds5sGn0ZWn;!PQRnGPTW6pwpui+0e-* zWN7LQEDRd#qqiYyY*EPwHg*}7=O@E$^&Al60?v={>fyidGj_4|unw8qp4YGRgeXz2 z#@emTY7D)i=;Tc&msI$cXvaQE`Oh@d+cvdl&ja)C&aI{weuoi=7554AI0A{b?;m!z ztuJ5cS=yWJd;)T-3OP*sg7ux^T#hG2`KrF>tiKy7y#0(_tDUIATW-NGPV2DyT{Q*X z9^SjA`(~=Eo-)#U_JrC^Ct(Ct=6g_{iK}?l^?XOf|D*GAvwszl#+t%^*WL5TmV1|0 oohc(Q<=@`>#`RtA{ksm)P*6y@@u~VRp(0hqd=1%G>z}CW7fpy|C;$Ke literal 0 HcmV?d00001 diff --git a/CPUSTRES/Thread.cpp b/CPUSTRES/Thread.cpp index 64a87be..145b39d 100644 --- a/CPUSTRES/Thread.cpp +++ b/CPUSTRES/Thread.cpp @@ -10,7 +10,7 @@ CThread::CThread() { int cpus = CGlobals::GetProcessorCount(); - if(cpus == sizeof(DWORD_PTR) * 8) + if (cpus == sizeof(DWORD_PTR) * 8) m_Affinity = (DWORD_PTR)-1; else m_Affinity = (((DWORD_PTR)1) << cpus) - 1; @@ -21,7 +21,7 @@ CThread::CThread() { CThread::~CThread() { ::CloseHandle(m_hThread); ::CloseHandle(m_hTerminate); -} +} void CThread::Suspend() { if (!IsActive()) return; @@ -46,7 +46,7 @@ DWORD CThread::ThreadFunction() { for (;;) { if (::WaitForSingleObject(hTerminate, 0) == WAIT_OBJECT_0) break; - + auto level = m_ActivityLevel; if (level != ActivityLevel::Maximum) { auto time = ::GetTickCount(); @@ -77,11 +77,28 @@ int CThread::GetIdealCPU() const { return n.Number; } +ULONG CThread::GetCPUTime(const LARGE_INTEGER& frequency) const { + FILETIME kernel, user, dummy; + VERIFY(::GetThreadTimes(m_hThread, &dummy, &dummy, &kernel, &user)); + LARGE_INTEGER counter; + VERIFY(::QueryPerformanceCounter(&counter)); + auto total = *(long long*)&kernel + *(long long*)&user; + ULONG cpu = 0; + if (m_LastCpu > 0) { + cpu = static_cast((total - m_LastCpu) * 1000000LL / ((counter.QuadPart - m_LastCounter.QuadPart) * 1000000LL / frequency.QuadPart)); + } + + m_LastCounter = counter; + m_LastCpu = total; + + return cpu; +} + void CThread::Terminate() { m_ActivityLevel = ActivityLevel::None; ::SetEvent(m_hTerminate); Resume(); - if(::WaitForSingleObject(m_hThread, 500) == WAIT_TIMEOUT) + if (::WaitForSingleObject(m_hThread, 500) == WAIT_TIMEOUT) ::TerminateThread(m_hThread, 1); } diff --git a/CPUSTRES/Thread.h b/CPUSTRES/Thread.h index 02785d7..fa2e7ed 100644 --- a/CPUSTRES/Thread.h +++ b/CPUSTRES/Thread.h @@ -50,6 +50,8 @@ public: DWORD SetIdealCPU(int n); int GetIdealCPU() const; + ULONG GetCPUTime(const LARGE_INTEGER& frequency) const; + void Terminate(); void Suspend(); void Resume(); @@ -67,6 +69,8 @@ private: ActivityLevel m_ActivityLevel = ActivityLevel::Low; bool m_Active = false; DWORD_PTR m_Affinity; + mutable long long m_LastCpu = 0; + mutable LARGE_INTEGER m_LastCounter; }; diff --git a/CPUSTRES/resource.h b/CPUSTRES/resource.h index ee7571e..60f70fd 100644 --- a/CPUSTRES/resource.h +++ b/CPUSTRES/resource.h @@ -5,6 +5,8 @@ #define IDD_ABOUTBOX 100 #define IDR_MAINFRAME 128 #define IDR_CPUStressExTYPE 130 +#define ID_STATUS_THREAD 310 +#define ID_STATUS_PROCESSCPU 311 #define IDI_PLAY 312 #define IDI_KILL 313 #define IDI_PAUSE 314 @@ -21,7 +23,6 @@ #define IDC_MFCLINK1 1008 #define IDC_LINK 1008 #define IDC_CPUSETS 1009 -#define IDC_BUTTON1 1010 #define ID_THREAD_ACTIVE 32771 #define ID_THREAD_ACTIVITYLEVEL 32772 #define ID_ACTIVITYLEVEL_LOW 32773 @@ -58,14 +59,15 @@ #define ID_CPUSETS_SYSTEMCPUSET 32807 #define ID_CPUSETS_PROCESSCPUSET 32808 #define ID_CPUSETS_THREADSELECTEDCPUSET 32809 +#define ID_PROCESS_QUEUETHREADPOOLWORK 32810 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 323 -#define _APS_NEXT_COMMAND_VALUE 32810 +#define _APS_NEXT_COMMAND_VALUE 32811 #define _APS_NEXT_CONTROL_VALUE 1011 -#define _APS_NEXT_SYMED_VALUE 310 +#define _APS_NEXT_SYMED_VALUE 312 #endif #endif diff --git a/CPUSTRES/resource1.h b/CPUSTRES/resource1.h new file mode 100644 index 0000000..9f31b16 --- /dev/null +++ b/CPUSTRES/resource1.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by CPUSTRES.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/MemLimit/MemLimit.cpp b/MemLimit/MemLimit.cpp index 0f2f8c5845de07f9e470c7160f6d94f6c008f05d..aa7322d24508d4171bb8524d8b64ff9250d88d8c 100644 GIT binary patch delta 15 WcmbP|@FjkO1otEbq0L_0r&Itm5(U)& delta 38 scmewoKP6#<1h=FMLncEpLjgk$Ln1>ZLnx4)$dJyE%3!rwko&O;0Mup*4*&oF