diff --git a/CPUSTRES/CPUStressEx.rc b/CPUSTRES/CPUStressEx.rc index 84555a5..2423a65 100644 --- a/CPUSTRES/CPUStressEx.rc +++ b/CPUSTRES/CPUStressEx.rc @@ -103,6 +103,7 @@ BEGIN END MENUITEM SEPARATOR MENUITEM "A&ffinity...", ID_PROCESS_AFFINITY + MENUITEM "CPU Rate &Limit...", ID_PROCESS_CPURATELIMIT MENUITEM "CPU &Set...", ID_CPUSETS_PROCESSCPUSET MENUITEM SEPARATOR MENUITEM "Create &Thread", ID_PROCESS_CREATETHREAD @@ -150,6 +151,14 @@ BEGIN BEGIN MENUITEM "&Always on Top", ID_OPTIONS_ALWAYSONTOP MENUITEM "Auto Refresh Thread Indices", ID_OPTIONS_AUTOREFRESHTHREADINDICES, CHECKED + POPUP "&CPU Update Interval" + BEGIN + MENUITEM "0.5 Second", ID_CPUUPDATEINTERVAL_0 + MENUITEM "1 Second", ID_CPUUPDATEINTERVAL_1SECOND + MENUITEM "2 Seconds", ID_CPUUPDATEINTERVAL_2SECONDS + MENUITEM "5 Seconds", ID_CPUUPDATEINTERVAL_5SECONDS + MENUITEM "10 Seconds", ID_CPUUPDATEINTERVAL_10SECONDS + END END POPUP "&Help" BEGIN @@ -184,6 +193,7 @@ BEGIN MENUITEM SEPARATOR MENUITEM "A&ffinity...", ID_THREAD_AFFINITY MENUITEM "&Ideal CPU...", ID_THREAD_IDEALCPU + MENUITEM "&Selected CPU Set...", ID_CPUSETS_THREADSELECTEDCPUSET MENUITEM SEPARATOR MENUITEM "&Kill", ID_THREAD_KILL END @@ -550,7 +560,7 @@ END STRINGTABLE BEGIN - IDR_MAINFRAME "CPU Stress (PID: $)" + IDR_MAINFRAME "CPU Stress v2.1 (PID: $)" END STRINGTABLE diff --git a/CPUSTRES/ChildView.cpp b/CPUSTRES/ChildView.cpp index ae01332..764411f 100644 --- a/CPUSTRES/ChildView.cpp +++ b/CPUSTRES/ChildView.cpp @@ -63,6 +63,10 @@ BEGIN_MESSAGE_MAP(CChildView, CWnd) ON_UPDATE_COMMAND_UI(ID_STATUS_THREAD, OnUpdateStatusThreads) ON_UPDATE_COMMAND_UI(ID_STATUS_PROCESSCPU, OnUpdateStatusProcessCpu) + ON_COMMAND(ID_PROCESS_CPURATELIMIT, &CChildView::OnProcessCpuratelimit) + + ON_COMMAND_RANGE(ID_CPUUPDATEINTERVAL_0, ID_CPUUPDATEINTERVAL_10SECONDS, OnCpuUpdateInterval) + ON_UPDATE_COMMAND_UI_RANGE(ID_CPUUPDATEINTERVAL_0, ID_CPUUPDATEINTERVAL_10SECONDS, OnUpdateCpuUpdateInterval) END_MESSAGE_MAP() void CChildView::DoDataExchange(CDataExchange* pDX) { @@ -113,9 +117,9 @@ int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) { m_List.InsertColumn(2, L"Active?", LVCFMT_CENTER, 80); m_List.InsertColumn(3, L"Activity", LVCFMT_LEFT, 80); m_List.InsertColumn(4, L"Priority", LVCFMT_LEFT, 100); - m_List.InsertColumn(5, L"Ideal CPU", LVCFMT_CENTER, 80); + m_List.InsertColumn(5, L"Ideal CPU", LVCFMT_CENTER, 70); m_List.InsertColumn(6, L"Affinity", LVCFMT_RIGHT, 120); - m_List.InsertColumn(7, L"CPU (%)", LVCFMT_RIGHT, 80); + m_List.InsertColumn(7, L"CPU (%)", LVCFMT_CENTER, 80); VERIFY(::QueryPerformanceFrequency(&m_QueryFrequency)); VERIFY(::QueryPerformanceCounter(&m_LastQueryCount)); @@ -123,7 +127,7 @@ int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct) { CreateThreads(); SetTimer(1, 10000, nullptr); - SetTimer(2, 1000, nullptr); + SetTimer(2, m_CpuUpdateInterval, nullptr); return 0; } @@ -468,7 +472,7 @@ void CChildView::UpdateCPUTimes() { for (auto& thread : m_Threads) { if (thread->IsActive()) { auto cpu = thread->GetCPUTime(m_QueryFrequency) / CGlobals::GetProcessorCount(); - text.Format(L"%.2f", cpu / 100000.0); + text.Format(L"%.2lf", cpu / 1000.0); m_List.SetItemText(i, 7, text); } else { @@ -498,3 +502,25 @@ void CChildView::OnUpdateStatusProcessCpu(CCmdUI* pCmdUI) { text.Format(L"Process CPU: %.2f %%", m_ProcessCPU); pCmdUI->SetText(text); } + + +void CChildView::OnProcessCpuratelimit() { + if (m_hJob == nullptr) { + m_hJob = ::CreateJobObject(nullptr, nullptr); + ASSERT(m_hJob); + VERIFY(::AssignProcessToJobObject(m_hJob, ::GetCurrentProcess())); + } +} + +void CChildView::OnCpuUpdateInterval(UINT id) { + static const int intervals[] = { 500, 1000, 2000, 5000, 10000 }; + m_CpuUpdateIndex = id - ID_CPUUPDATEINTERVAL_0; + m_CpuUpdateInterval = intervals[m_CpuUpdateIndex]; + SetTimer(2, m_CpuUpdateInterval, nullptr); +} + +void CChildView::OnUpdateCpuUpdateInterval(CCmdUI* pCmdUI) { + pCmdUI->SetRadio(pCmdUI->m_nID - ID_CPUUPDATEINTERVAL_0 == m_CpuUpdateIndex); +} + + diff --git a/CPUSTRES/ChildView.h b/CPUSTRES/ChildView.h index d08bff5..5818ce8 100644 --- a/CPUSTRES/ChildView.h +++ b/CPUSTRES/ChildView.h @@ -37,6 +37,8 @@ private: LARGE_INTEGER m_LastQueryCount, m_QueryFrequency; long long m_LastProcessTimes = 0; double m_ProcessCPU; + HANDLE m_hJob = nullptr; + int m_CpuUpdateInterval = 1000, m_CpuUpdateIndex = 1; void CreateThreads(); std::unique_ptr CreateThread(); @@ -90,5 +92,8 @@ protected: void OnUpdateStatusThreads(CCmdUI*); void OnUpdateStatusProcessCpu(CCmdUI*); + afx_msg void OnProcessCpuratelimit(); + void OnCpuUpdateInterval(UINT id); + void OnUpdateCpuUpdateInterval(CCmdUI*); }; diff --git a/CPUSTRES/MainFrm.cpp b/CPUSTRES/MainFrm.cpp index 16ea516..161824d 100644 --- a/CPUSTRES/MainFrm.cpp +++ b/CPUSTRES/MainFrm.cpp @@ -35,6 +35,9 @@ CMainFrame::CMainFrame() { CMainFrame::~CMainFrame() {} int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { + // increase chance of UI thread to be responsive + ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); + if(CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; diff --git a/CPUSTRES/Thread.cpp b/CPUSTRES/Thread.cpp index 145b39d..fd2b16d 100644 --- a/CPUSTRES/Thread.cpp +++ b/CPUSTRES/Thread.cpp @@ -77,15 +77,15 @@ int CThread::GetIdealCPU() const { return n.Number; } -ULONG CThread::GetCPUTime(const LARGE_INTEGER& frequency) const { +long long 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; + long long cpu = 0; if (m_LastCpu > 0) { - cpu = static_cast((total - m_LastCpu) * 1000000LL / ((counter.QuadPart - m_LastCounter.QuadPart) * 1000000LL / frequency.QuadPart)); + cpu = (total - m_LastCpu) * 10000 / ((counter.QuadPart - m_LastCounter.QuadPart) * 1000000LL / frequency.QuadPart); } m_LastCounter = counter; diff --git a/CPUSTRES/Thread.h b/CPUSTRES/Thread.h index fa2e7ed..f0b3fbd 100644 --- a/CPUSTRES/Thread.h +++ b/CPUSTRES/Thread.h @@ -50,7 +50,7 @@ public: DWORD SetIdealCPU(int n); int GetIdealCPU() const; - ULONG GetCPUTime(const LARGE_INTEGER& frequency) const; + long long GetCPUTime(const LARGE_INTEGER& frequency) const; void Terminate(); void Suspend(); diff --git a/CPUSTRES/resource.h b/CPUSTRES/resource.h index 60f70fd..3d579c2 100644 --- a/CPUSTRES/resource.h +++ b/CPUSTRES/resource.h @@ -60,13 +60,26 @@ #define ID_CPUSETS_PROCESSCPUSET 32808 #define ID_CPUSETS_THREADSELECTEDCPUSET 32809 #define ID_PROCESS_QUEUETHREADPOOLWORK 32810 +#define ID_PROCESS_CPURATELIMIT 32811 +#define ID_CPURATELIMIT_10 32812 +#define ID_CPURATELIMIT_20 32813 +#define ID_CPURATELIMIT_50 32814 +#define ID_CPURATELIMIT_75 32815 +#define ID_CPURATELIMIT_100 32816 +#define ID_CPURATELIMIT_CUSTOM 32817 +#define ID_OPTIONS_CPUUPDATEINTERVAL 32818 +#define ID_CPUUPDATEINTERVAL_0 32819 +#define ID_CPUUPDATEINTERVAL_1SECOND 32820 +#define ID_CPUUPDATEINTERVAL_2SECONDS 32821 +#define ID_CPUUPDATEINTERVAL_5SECONDS 32822 +#define ID_CPUUPDATEINTERVAL_10SECONDS 32823 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 323 -#define _APS_NEXT_COMMAND_VALUE 32811 +#define _APS_NEXT_COMMAND_VALUE 32824 #define _APS_NEXT_CONTROL_VALUE 1011 #define _APS_NEXT_SYMED_VALUE 312 #endif