Skip to content

Commit

Permalink
added thread and CPU percentage columns
Browse files Browse the repository at this point in the history
  • Loading branch information
zodiacon committed Jan 21, 2018
1 parent 44a9217 commit 6a57932
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 13 deletions.
Binary file added CPUSTRES/CPUSTRES.rc
Binary file not shown.
13 changes: 10 additions & 3 deletions CPUSTRES/CPUStressEx.rc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
/////////////////////////////////////////////////////////////////////////////

Expand Down
4 changes: 4 additions & 0 deletions CPUSTRES/CPUStressEx.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
<Midl>
<MkTypLibCompatible>false</MkTypLibCompatible>
Expand All @@ -173,6 +174,7 @@
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>false</GenerateDebugInformation>
</Link>
<Midl>
<MkTypLibCompatible>false</MkTypLibCompatible>
Expand All @@ -192,6 +194,7 @@
<ClInclude Include="Globals.h" />
<ClInclude Include="MainFrm.h" />
<ClInclude Include="Resource.h" />
<ClInclude Include="resource1.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="SystemCpuSet.h" />
<ClInclude Include="SystemCPUSetDlg.h" />
Expand All @@ -217,6 +220,7 @@
<ClCompile Include="ThreadsListCtrl.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="CPUSTRES.rc" />
<ResourceCompile Include="CPUStressEx.rc" />
</ItemGroup>
<ItemGroup>
Expand Down
6 changes: 6 additions & 0 deletions CPUSTRES/CPUStressEx.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@
<ClInclude Include="SystemCpuSet.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource1.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CPUStressEx.cpp">
Expand Down Expand Up @@ -88,6 +91,9 @@
<ResourceCompile Include="CPUStressEx.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
<ResourceCompile Include="CPUSTRES.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="res\CPUStressEx.rc2">
Expand Down
86 changes: 85 additions & 1 deletion CPUSTRES/ChildView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -170,6 +179,7 @@ PCWSTR CChildView::ThreadPriorityToString(int priority) {

void CChildView::UpdateThreadProcessIndices() {
auto threads = CGlobals::EnumerateThreads(::GetCurrentProcessId());
m_TotalThreads = static_cast<int>(threads.size());
if (m_CurrentThreadIds == threads)
return;

Expand All @@ -192,6 +202,21 @@ void CChildView::UpdateThreadProcessIndices() {
}
}

BOOL CChildView::QueueItemForThreadPool(int busyPercent) {
return ::QueueUserWorkItem([](auto param) {
return BurnSomeCycles(static_cast<int>(reinterpret_cast<INT_PTR>(param)));
}, reinterpret_cast<PVOID>(static_cast<INT_PTR>(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<CThread> CChildView::CreateThread() {
auto thread = make_unique<CThread>();
return thread;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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<ULONG>((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);
}
12 changes: 11 additions & 1 deletion CPUSTRES/ChildView.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,20 @@ class CChildView : public CWnd {
std::vector < std::unique_ptr<CThread>> m_Threads;
std::vector<DWORD> 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<CThread> CreateThread();
void AddThread(std::unique_ptr<CThread>& thread);
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:
Expand Down Expand Up @@ -76,9 +83,12 @@ class CChildView : public CWnd {
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*);
};

7 changes: 6 additions & 1 deletion CPUSTRES/MainFrm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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();

Expand Down
1 change: 1 addition & 0 deletions CPUSTRES/MainFrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class CMainFrame : public CFrameWnd {
protected: // control bar embedded members
CDialogBar m_wndDlgBar;
CChildView m_wndView;
CStatusBar m_StatusBar;

// Generated message map functions
protected:
Expand Down
Binary file added CPUSTRES/RCa25180
Binary file not shown.
25 changes: 21 additions & 4 deletions CPUSTRES/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -21,7 +21,7 @@ CThread::CThread() {
CThread::~CThread() {
::CloseHandle(m_hThread);
::CloseHandle(m_hTerminate);
}
}

void CThread::Suspend() {
if (!IsActive()) return;
Expand All @@ -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();
Expand Down Expand Up @@ -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<ULONG>((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);
}

Expand Down
4 changes: 4 additions & 0 deletions CPUSTRES/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class CThread {
DWORD SetIdealCPU(int n);
int GetIdealCPU() const;

ULONG GetCPUTime(const LARGE_INTEGER& frequency) const;

void Terminate();
void Suspend();
void Resume();
Expand All @@ -67,6 +69,8 @@ class CThread {
ActivityLevel m_ActivityLevel = ActivityLevel::Low;
bool m_Active = false;
DWORD_PTR m_Affinity;
mutable long long m_LastCpu = 0;
mutable LARGE_INTEGER m_LastCounter;
};


8 changes: 5 additions & 3 deletions CPUSTRES/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Loading

0 comments on commit 6a57932

Please sign in to comment.