windows平台进程CPU占用率的计算
在进程的性能数据采集过程中,经常用到的一个性能指标就是进程的cpu占用率,下面给出它的计算方法及示例代码。
1、CPU占用率的定义
CPU占用率:指进程在一个时间段内消耗的CPU时间与该时间段长度的比值。
2、CPU占用率计算方法
根据上述定义,可以得到进程CPU占用率计算公式如下:
进程消耗的CPU时间 = 进程消耗的内核态时间 + 进程消耗的用户态时间,即 costTime = kernelTime + UserTime
进程的CPU占用率 = 进程消耗的CPU时间 / 刷新周期
3、CPU占用率计算涉及到的API
示例程序用到的主要API
GetSystemInfo 我们主要用它来获取系统中CPU核心个数
OpenProcess 用来打开指定进程的句柄
GetProcessTimes 根据OpenProcess返回的句柄,获取进程的KernelTime和UserTime
其它API(用于线程等其它情况下的计算)
OpenThread 获取指定线程的句柄
GetThreadTimes 根据OpenThread返回的句柄,获取线程的KernelTime和UserTime (可用于线程CPU占用率计算)
GetSystemTimes 获取总的CPU时间IdleTime KernelTime UserTime,可用于系统总的CPU占用率计算(注:多核CPU中返回的是所有CPU核时间的总和)
NtQuerySystemInformation 这是个native api,可以获取到许多信息
4、示例代码
1 #include "stdafx.h" 2 #include <conio.h> 3 #include <windows.h> 4 #include <TlHelp32.h> 5 #include <process.h> 6 7 #define MY_PROCESS_ERROR(Condition) do{ if (!(Condition)) goto Exit0; } while (false) 8 9 static DWORD g_sdwTickCountOld = 0; // 上一次的tick计数 10 static LARGE_INTEGER g_slgProcessTimeOld; // 保存进程上一次的时间占用 11 static DWORD g_sdwProcessorCoreNum = 0; // 处理器核心数 12 static HANDLE g_shExitEvent = NULL; // 线程退出控制 13 14 typedef struct _TARGET_PROCESS 15 { 16 DWORD dwProcessId; // 进程ID 17 }TARGET_PROCESS, *PTARGET_PROCESS; 18 19 20 21 /*@brief 获取找到的与指定进程名相符的第一个进程ID 22 * @param [in] cpszExeFileName 进程可执行文件名(不带路径) 23 * @param [in/out] dwPID 返回找到的名字符合的第一个进程ID 24 * @return 成功 : S_OK 失败 : 错误码 25 */ 26 HRESULT FindFirstProcessIdByName(const TCHAR* cpszExeFileName, DWORD &dwPID) 27 { 28 HRESULT hr = E_FAIL; 29 30 PROCESSENTRY32 pe = { 0 }; 31 HANDLE hSnapshot = NULL; 32 33 if (NULL == cpszExeFileName) 34 { 35 hr = HRESULT_FROM_WIN32(ERROR_BAD_ARGUMENTS); 36 goto Exit0; 37 } 38 39 pe.dwSize = sizeof(PROCESSENTRY32); 40 hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 41 if (INVALID_HANDLE_VALUE == hSnapshot) 42 { 43 hr = HRESULT_FROM_WIN32(GetLastError()); 44 goto Exit0; 45 } 46 47 if (FALSE == Process32First(hSnapshot, &pe)) 48 { 49 hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES); 50 goto Exit0; 51 } 52 53 hr = S_FALSE; 54 do 55 { 56 if (0 == _tcsicmp(cpszExeFileName, pe.szExeFile)) 57 { 58 dwPID = pe.th32ProcessID; 59 hr = S_OK; 60 break; 61 } 62 }while(Process32Next(hSnapshot, &pe)); 63 64 Exit0: 65 if(hSnapshot) 66 { 67 CloseHandle(hSnapshot); 68 hSnapshot = NULL; 69 } 70 71 return hr; 72 } 73 74 /*@brief 获取进程的Cpu占用率 75 * @param [in] hProcess 进程句柄 76 * @param [in] dwElepsedTime 取样间隔时间(毫秒) 77 * @return 成功 : cpu占用率 失败 : -1 78 */ 79 int GetProcessCpuPercent(const HANDLE hProcess, const DWORD dwElepsedTime) 80 { 81 int nProcCpuPercent = 0; 82 BOOL bRetCode = FALSE; 83 84 FILETIME CreateTime, ExitTime, KernelTime,UserTime; 85 LARGE_INTEGER lgKernelTime; 86 LARGE_INTEGER lgUserTime; 87 LARGE_INTEGER lgCurTime; 88 89 bRetCode = GetProcessTimes(hProcess, &CreateTime, &ExitTime, &KernelTime, &UserTime); 90 if (bRetCode) 91 { 92 lgKernelTime.HighPart = KernelTime.dwHighDateTime; 93 lgKernelTime.LowPart = KernelTime.dwLowDateTime; 94 95 lgUserTime.HighPart = UserTime.dwHighDateTime; 96 lgUserTime.LowPart = UserTime.dwLowDateTime; 97 98 lgCurTime.QuadPart = (lgKernelTime.QuadPart + lgUserTime.QuadPart) / 10000; 99 nProcCpuPercent = (int)((lgCurTime.QuadPart - g_slgProcessTimeOld.QuadPart) * 100 / dwElepsedTime); 100 g_slgProcessTimeOld = lgCurTime; 101 nProcCpuPercent = nProcCpuPercent / g_sdwProcessorCoreNum; 102 } 103 else 104 { 105 nProcCpuPercent = -1; 106 } 107 108 return nProcCpuPercent; 109 } 110 111 unsigned __stdcall WorkerThread(void *pArg) 112 { 113 HRESULT hr = E_FAIL; 114 115 HANDLE hProcess = NULL; 116 DWORD dwProcessId = 0; 117 DWORD dwRetVal = 0; 118 DWORD dwCurrentTickCount = 0; 119 DWORD dwElapsedTime = 0; 120 int nProcessCpuPercent = 0; 121 122 TARGET_PROCESS *pTargetProcess = (TARGET_PROCESS *)pArg; 123 124 dwProcessId = pTargetProcess->dwProcessId; 125 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION , FALSE, dwProcessId); 126 MY_PROCESS_ERROR(hProcess); 127 128 do 129 { 130 dwRetVal = WaitForSingleObject(g_shExitEvent, 1000); 131 if (WAIT_OBJECT_0 == dwRetVal || 132 WAIT_FAILED == dwRetVal 133 ) 134 { 135 break; 136 } 137 138 dwCurrentTickCount = GetTickCount(); 139 dwElapsedTime = dwCurrentTickCount - g_sdwTickCountOld; 140 g_sdwTickCountOld = dwCurrentTickCount; 141 nProcessCpuPercent = GetProcessCpuPercent(hProcess, dwElapsedTime); 142 wprintf(L"cpu = %d\n", nProcessCpuPercent); 143 } while (1); 144 Exit0: 145 if (hProcess) 146 { 147 CloseHandle(hProcess); 148 hProcess = NULL; 149 } 150 151 return 0; 152 } 153 154 int _tmain(int argc, _TCHAR* argv[]) 155 { 156 HRESULT hr = E_FAIL; 157 158 HANDLE hThread = NULL; 159 unsigned int uiTid = 0; 160 SYSTEM_INFO sysInfo = { 0 }; 161 TARGET_PROCESS struTargetProcess; 162 163 if (argc > 1) 164 { 165 hr = FindFirstProcessIdByName(argv[1], struTargetProcess.dwProcessId); 166 if (S_OK != hr) 167 { 168 _tprintf(_T("Can't find process \'%s\' ret=0x%X\n"), argv[1], hr); 169 goto Exit0; 170 } 171 172 GetSystemInfo(&sysInfo); 173 g_sdwProcessorCoreNum = sysInfo.dwNumberOfProcessors; 174 175 g_shExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 176 MY_PROCESS_ERROR(g_shExitEvent); 177 178 hThread = (HANDLE)_beginthreadex(NULL, 0, WorkerThread, &struTargetProcess, 0, &uiTid); 179 MY_PROCESS_ERROR(hThread); 180 181 _getch(); 182 SetEvent(g_shExitEvent); 183 WaitForSingleObject(hThread, INFINITE); 184 } 185 else 186 { 187 _tprintf(_T("Please input a process name.\n")); 188 } 189 190 Exit0: 191 if (hThread) 192 { 193 CloseHandle(hThread); 194 hThread = NULL; 195 } 196 197 if (g_shExitEvent) 198 { 199 CloseHandle(g_shExitEvent); 200 g_shExitEvent = NULL; 201 } 202 203 return 0; 204 }