獲取電腦實時CPU使用率


要求:實現一個計算電腦實時CPU占有率的測試程序,將多種方法獲取結果顯示在對話框上,動態顯示。

實現:

1、新建基於對話框的MFC應用程序,Dialog上添加控件,為控件添加CSting類型變量m_RateResult1、m_RateResult2、m_RateResult3,

      

2、創建線程類(Thread.h和Thread.cpp),在 ####Dlg.cpp 文件中的初始化函數 OnInitDialog() 中創建計算CPU利用率的線程

    // TODO: 在此添加額外的初始化代碼

    _beginthread(&CThread::InitCalcuPdh, 0, this);
    _beginthread(&CThread::InitCalcuGet, 0, this);
    _beginthread(&CThread::InitCalcuNt,  0, this);

3、線程類中計算CPU利用率

方式一:使用Performance Data Helper(PDH)性能數據助手,獲取CPU利用率

 1 void CThread::InitCalcuPdh(void *pDlg)
 2 {
 3     CCalculateCPURateDlg *pItemDlg = (CCalculateCPURateDlg *)pDlg;
 4     if (pItemDlg == NULL)
 5     {
 6         return;
 7     }
 8 
 9     while(1)
10     {
11         //打開查詢(query)句柄
12         HQUERY query;
13         PDH_STATUS status = PdhOpenQuery(NULL, NULL, &query);
14         if (status != ERROR_SUCCESS)
15         {
16             pItemDlg->MessageBox(L"Open Query Error", NULL, MB_OK);
17             continue;
18         }
19             
20         //在查詢中加入計數器(counter)
21         HCOUNTER counter;
22         //counter = (HCOUNTER *)GlobalAlloc(GPTR, sizeof(HCOUNTER));
23         status = PdhAddCounter(query, LPCWSTR(L"\\Processor Information(_Total)\\% Processor Time"), NULL, &counter);
24         if (status != ERROR_SUCCESS)
25         {
26             pItemDlg->MessageBox(L"Add Counter Error", NULL, MB_OK);
27             continue;
28         }
29 
30         //收集query的數據,在兩條PdhCollectQueryData()語句之間加入一條Sleep(1000)語句
31         PdhCollectQueryData(query);
32         Sleep(1000);
33         PdhCollectQueryData(query);
34 
35         //獲得格式化(可以顯示的)數據
36         PDH_FMT_COUNTERVALUE pdhValue;
37         DWORD dwValue;
38         status = PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, &dwValue, &pdhValue);
39         if (status != ERROR_SUCCESS)
40         {
41             pItemDlg->MessageBox(L"Get Value Error", NULL, MB_OK);
42             continue;
43         }
44         pItemDlg->m_RateResult1.Format(L"%.0lf%%", pdhValue.doubleValue);
45 
46         SendMessage(pItemDlg->m_hWnd, WM_UPDATEDATA, FALSE, FALSE); 
47         PdhCloseQuery(query);
48     }
49 }

方式二:使用windows 自帶的API(GetSystemTimes)獲取CPU利用率

 1 __int64 DiffFileTime(FILETIME time1, FILETIME time2)
 2 {
 3     __int64 a = time1.dwHighDateTime << 32 | time1.dwLowDateTime;
 4     __int64 b = time2.dwHighDateTime << 32 | time2.dwLowDateTime;
 5     return (b - a);
 6 }
 7 void CThread::InitCalcuGet(void *pDlg)
 8 {
 9     CCalculateCPURateDlg *pItemDlg = (CCalculateCPURateDlg *)pDlg;
10     if (pItemDlg == NULL)
11     {
12         return;
13     }
14 
15     while(1)
16     {
17         double cpurate;
18         __int64 idle, kernel, user;
19         FILETIME preidleTime, idleTime;      //空閑時間
20         FILETIME prekernelTime, kernelTime;  //內核態時間
21         FILETIME preuserTime, userTime;      //用戶態時間
22 
23         //計算CPU使用率,需要收集兩份樣本,中間用Sleep()函數間隔1s
24         GetSystemTimes(&preidleTime, &prekernelTime, &preuserTime);
25         Sleep(1000);
26         GetSystemTimes(&idleTime, &kernelTime, &userTime);
27 
28         idle = DiffFileTime(preidleTime, idleTime);
29         kernel = DiffFileTime(prekernelTime, kernelTime);
30         user = DiffFileTime(preuserTime, userTime);
31 
32         if (kernel + user == 0)
33             cpurate = 0.0;
34         else
35             cpurate = abs((kernel + user - idle) * 100 / (kernel + user));//(總的時間-空閑時間)/總的時間=占用cpu的時間就是使用率
36         
37         pItemDlg->m_RateResult2.Format(L"%.0lf%%", cpurate);
38         SendMessage(pItemDlg->m_hWnd, WM_UPDATEDATA, FALSE, FALSE); 
39     }
40 }

方式三:使用windows API(NtQuerySystemInformation)獲取CPU利用率

 1 typedef struct _UINT64_DELTA
 2 {
 3     ULONG64 Value;
 4     ULONG64 Delta;
 5 } UINT64_DELTA, *PUINT64_DELTA;
 6 
 7 #define UpdateDelta(DltMgr, NewValue) \
 8 ((DltMgr)->Delta = (NewValue) - (DltMgr)->Value, \
 9 (DltMgr)->Value = (NewValue), (DltMgr)->Delta)
10 
11 void CThread::InitCalcuNt(void *pDlg)
12 {
13     CCalculateCPURateDlg *pItemDlg = (CCalculateCPURateDlg *)pDlg;
14     if (pItemDlg == NULL)
15     {
16         return;
17     }
18 
19     while(1)
20     {
21         double cpu_rate;
22         ULONG64 total_time = 0;
23         ULONG64 sys_time = 0;
24         static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION CpuInformation[1024];
25         static SYSTEM_INFO sys_info;
26 
27         static UINT64_DELTA cpu_kernel_delta;
28         static UINT64_DELTA cpu_user_delta;
29         static UINT64_DELTA cpu_idle_delta;
30         static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpu_totals;
31         memset(&cpu_totals, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
32 
33         GetSystemInfo(&sys_info);
34 
35         NtQuerySystemInformation(
36             SystemProcessorPerformanceInformation,
37             &CpuInformation,
38             sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * (ULONG)sys_info.dwNumberOfProcessors,
39             NULL
40             );
41 
42         for (int i = 0; i < (int)sys_info.dwNumberOfProcessors; i++)
43         {
44             SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION& cpu_info = CpuInformation[i];
45 
46             // KernelTime includes idle time.
47             LONGLONG dpc_time = cpu_info.Reserved1[0].QuadPart;
48             LONGLONG interrupt_time = cpu_info.Reserved1[i].QuadPart;
49             cpu_info.KernelTime.QuadPart -= cpu_info.IdleTime.QuadPart;
50             cpu_info.KernelTime.QuadPart += dpc_time + interrupt_time;
51 
52             cpu_totals.Reserved1[0].QuadPart += dpc_time;
53             cpu_totals.IdleTime.QuadPart += cpu_info.IdleTime.QuadPart;
54             cpu_totals.Reserved2 += cpu_info.Reserved2;
55             cpu_totals.Reserved1[1].QuadPart += cpu_info.Reserved1[1].QuadPart;
56             cpu_totals.KernelTime.QuadPart += cpu_info.KernelTime.QuadPart;
57             cpu_totals.UserTime.QuadPart += cpu_info.UserTime.QuadPart;
58         }
59 
60         UpdateDelta(&cpu_kernel_delta, cpu_totals.KernelTime.QuadPart);
61         UpdateDelta(&cpu_user_delta, cpu_totals.UserTime.QuadPart);
62         UpdateDelta(&cpu_idle_delta, cpu_totals.IdleTime.QuadPart);
63 
64         total_time = cpu_kernel_delta.Delta + cpu_user_delta.Delta + cpu_idle_delta.Delta;
65         sys_time = cpu_kernel_delta.Delta + cpu_user_delta.Delta;
66 
67         if (total_time)
68             cpu_rate = sys_time * 100.0 / total_time;
69         else
70             cpu_rate = 0.0;
71         pItemDlg->m_RateResult3.Format(L"%.0lf%%", cpu_rate);
72         Sleep(1000);
73 
74         SendMessage(pItemDlg->m_hWnd, WM_UPDATEDATA, FALSE, FALSE); 
75     }
76 }

4、stdafx.h 中添加

#pragma comment(lib,"pdh.lib")
#pragma comment(lib,"ntdll.lib")
#include <Pdh.h>
#include <PdhMsg.h>
#include <Windows.h> 
#include <Winternl.h>

 

 

錯誤:

1、在線程中調用UpdateData函數,在Debug模式下編譯可以通過,但運行時會觸發中斷

原因:MFC對象不支持多線程操作,不能供多個線程進程使用。子線程調用pDlg-> UpdateData(FALSE)時主線程(界面線程)會阻塞,更新必須由它完成,這樣就形成死鎖。更改界面的操作最好用主線程(界面線程),要想在子線程(工作線程)里執行界面的操作,可以通過向主線程發送消息來解決。

解決:

####Dlg.h 中添加

#define WM_UPDATEDATA  10000+1

afx_msg LRESULT OnUpdateData(WPARAM wParam, LPARAM lParam);

####Dlg.cpp 中添加

ON_MESSAGE(WM_UPDATEDATA, OnUpdateData) 

LRESULT CCalculateCPURateDlg::OnUpdateData(WPARAM wParam, LPARAM lParam) 
{ 
    UpdateData(wParam); 
    return 0; 
} 

Thread.cpp 中添加

SendMessage(pItemDlg->m_hWnd, WM_UPDATEDATA, FALSE, FALSE);

2、在某些環境中exe文件運行失敗

解決:Release使用MT選項編譯,Debug使用MTd選項編譯(同時屬性頁中選擇在靜態庫中使用MFC)

 

參考博客:

https://www.cnblogs.com/einyboy/archive/2012/06/13/2548243.html

http://www.cnblogs.com/hbccdf/p/get_sys_cpu_usage_and_mem_usage.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM