博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[编程点滴]获取进程的CPU占用率
阅读量:5336 次
发布时间:2019-06-15

本文共 13322 字,大约阅读时间需要 44 分钟。

首先, 感觉是个蛋疼的话题, 不过是做某个软件遇到的.

Windows系统的TaskManager里面其实就有这个功能, 显示一个进程的相关信息, 诸如pid,CPU占用率, 内存, 线程数等.

那么TaskManager是怎么求出某个进程的CPU占用率的呢? 用的NtQuerySystemInformation, NtQueryInformationProcess等吧, 貌似有人Debug过, 看到了这些函数的调用.

不过使用NtQuerySystemInformation这样的函数是有问题的, 1它们不是public的, 2是官方说它们在Vista以后的版本里面可能被修改.

一个可观的替代方案是使用GetSystemTimes和GetProcessTimes:

1 BOOL WINAPI GetSystemTimes( 2   _Out_opt_  LPFILETIME lpIdleTime, 3   _Out_opt_  LPFILETIME lpKernelTime, 4   _Out_opt_  LPFILETIME lpUserTime 5 ); 6  7 BOOL WINAPI GetProcessTimes( 8   _In_   HANDLE hProcess, 9   _Out_  LPFILETIME lpCreationTime,10   _Out_  LPFILETIME lpExitTime,11   _Out_  LPFILETIME lpKernelTime,12   _Out_  LPFILETIME lpUserTime13 );

GetSystemTimes获得系统(自开机以来)处于Kernel状态下面的CPU时间,以及系统处于User状态下的时间,以及Idle的时间.我们只用Kernel时间和User时间, 不用Idle时间.

相应的, GetProcess也能求出一个进程在上面3中状态下的时间.

下面公式可以求出进程的CPU占用率.

                  CpuPercentageEquation

但是事情并没有就此结束, 因为我发现仅仅做上面的工作的话, 在某些系统(当然还是Windows系列...)下面会不奏效, 这就是很多软件开发者考虑的兼容性的问题.

是权限的问题, OpenProcess调用失败是因为你启动的进程没有能够Debug某个进程的权限.

虽然Admin下面有些权限是有的, 但默认的情况下进程的一些访问权限是没有被置为可用状态(即Enabled)的,所以我们要做的首先是使这些权限可用。

下面3个函数基本可以搞定:OpenProcessToken, LookupPrivilegeValue ,AdjustTokenPrivileges(详情见msdn..)

1 HANDLE WINAPI OpenProcess( 2   _In_  DWORD dwDesiredAccess, 3   _In_  BOOL bInheritHandle, 4   _In_  DWORD dwProcessId 5 ); 6  7 BOOL WINAPI OpenProcessToken( 8   _In_   HANDLE ProcessHandle, 9   _In_   DWORD DesiredAccess,10   _Out_  PHANDLE TokenHandle11 );12 13 BOOL WINAPI LookupPrivilegeValue(14   _In_opt_  LPCTSTR lpSystemName,15   _In_      LPCTSTR lpName,16   _Out_     PLUID lpLuid17 );18 19 BOOL WINAPI AdjustTokenPrivileges(20   _In_       HANDLE TokenHandle,21   _In_       BOOL DisableAllPrivileges,22   _In_opt_   PTOKEN_PRIVILEGES NewState,23   _In_       DWORD BufferLength,24   _Out_opt_  PTOKEN_PRIVILEGES PreviousState,25   _Out_opt_  PDWORD ReturnLength26 );

下面是获取进程CPU percent的完整代码:

Source Code
1 //CpuUsage.h  2 #ifndef _CPU_USAGE_H_  3 #define _CPU_USAGE_H_  4   5 #include 
6 7 class CpuUsage 8 { 9 public: 10 CpuUsage(DWORD dwProcessID); 11 ULONGLONG GetUsageEx(); 12 ULONGLONG GetSystemNonIdleTimes(); 13 ULONGLONG GetProcessNonIdleTimes(); 14 private: 15 ULONGLONG SubtractTimes(const FILETIME& ftA, const FILETIME& ftB); 16 ULONGLONG AddTimes(const FILETIME& ftA, const FILETIME& ftB); 17 bool EnoughTimePassed(); 18 inline bool IsFirstRun() const { return (m_dwLastRun == 0); } 19 20 //system total times 21 FILETIME m_ftPrevSysKernel; 22 FILETIME m_ftPrevSysUser; 23 24 //process times 25 FILETIME m_ftPrevProcKernel; 26 FILETIME m_ftPrevProcUser; 27 28 ULONGLONG m_ullPrevSysNonIdleTime;//这个变量和后面的便利记录上次获取的非idle的系统cpu时间和进程cpu时间. 29 ULONGLONG m_ullPrevProcNonIdleTime;//这个类只绑定一个进程, 在构造函数里面初始化进来.. 30 31 ULONGLONG m_nCpuUsage; 32 ULONGLONG m_dwLastRun; 33 DWORD m_dwProcessID; 34 HANDLE m_hProcess; 35 volatile LONG m_lRunCount; 36 }; 37 38 #endif 39 40 41 //CpuUsage.cpp 42 43 #include
44 #include "CPUusage.h" 45 #include
46 //#define USE_DEPRECATED_FUNCS 47 void ErrorMsg(LPTSTR lpszFunction); 48 BOOL SetPrivilege(HANDLE hProcess, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege); 49 50 #ifdef USE_DEPRECATED_FUNCS 51 #define SystemBasicInformation 0 52 #define SystemPerformanceInformation 2 53 #define SystemTimeInformation 3 54 #define SystemProcessorPerformanceInformation 8 55 #define ProcessTimes 4 56 57 #define Li2Double(x) ((double)((x).HighPart) * 4.294967296E9 + (double)((x).LowPart)) 58 59 typedef struct 60 { 61 DWORD dwUnknown1; 62 ULONG uKeMaximumIncrement; 63 ULONG uPageSize; 64 ULONG uMmNumberOfPhysicalPages; 65 ULONG uMmLowestPhysicalPage; 66 ULONG uMmHighestPhysicalPage; 67 ULONG uAllocationGranularity; 68 PVOID pLowestUserAddress; 69 PVOID pMmHighestUserAddress; 70 ULONG uKeActiveProcessors; 71 BYTE bKeNumberProcessors; 72 BYTE bUnknown2; 73 WORD wUnknown3; 74 } SYSTEM_BASIC_INFORMATION; 75 76 typedef struct 77 { 78 LARGE_INTEGER liIdleTime; 79 DWORD dwSpare[312]; 80 } SYSTEM_PERFORMANCE_INFORMATION; 81 82 typedef struct 83 { 84 LARGE_INTEGER liKeBootTime; 85 LARGE_INTEGER liKeSystemTime; 86 LARGE_INTEGER liExpTimeZoneBias; 87 ULONG uCurrentTimeZoneId; 88 DWORD dwReserved; 89 } SYSTEMTEXTIME_INFORMATION; 90 91 typedef struct 92 _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION 93 { 94 LARGE_INTEGER IdleTime; 95 LARGE_INTEGER KernelTime; 96 LARGE_INTEGER UserTime; 97 LARGE_INTEGER Reserved1[2]; 98 ULONG Reserved2; 99 } SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;100 101 typedef struct _KERNEL_USERTEXTIMES102 {103 LARGE_INTEGER CreateTime;104 LARGE_INTEGER ExitTime;105 LARGE_INTEGER KernelTime;106 LARGE_INTEGER UserTime;107 } KERNEL_USERTEXTIMES, *PKERNEL_USERTEXTIMES;108 109 typedef LONG (WINAPI *PROCNTQSI)(UINT, PVOID, ULONG, PULONG);110 PROCNTQSI NtQuerySystemInformation;111 112 typedef LONG (WINAPI *PROCNTQIP)(HANDLE, UINT, PVOID, ULONG, PULONG);113 PROCNTQIP NtQueryInformationProcess;114 115 ULONGLONG CpuUsage::GetSystemNonIdleTimes()116 {117 SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;118 SYSTEMTEXTIME_INFORMATION SysTimeInfo;119 SYSTEM_BASIC_INFORMATION SysBaseInfo;120 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcPerfInfo[32];121 LONG status;122 NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "NtQuerySystemInformation");123 if (!NtQuerySystemInformation)124 return 0;125 status = NtQuerySystemInformation(SystemBasicInformation, &SysBaseInfo, sizeof(SysBaseInfo), NULL);126 if (status != NO_ERROR)127 {128 MessageBox(TEXT("FailSystemInfo"));129 return 0;130 }131 status = NtQuerySystemInformation(SystemProcessorPerformanceInformation, SysProcPerfInfo, sizeof(SysProcPerfInfo), NULL);132 if(status != NO_ERROR) return 0;133 int nProcessors = SysBaseInfo.bKeNumberProcessors; //机器内部CPU的个数134 ULONGLONG ullSysTotal = 0;135 for(int i = 0; i < nProcessors; i++)136 {137 ullSysTotal += SysProcPerfInfo[i].KernelTime.QuadPart + SysProcPerfInfo[i].UserTime.QuadPart;138 }139 return ullSysTotal;140 }141 142 ULONGLONG CpuUsage::GetProcessNonIdleTimes()143 {144 KERNEL_USERTEXTIMES KernelUserTimes;145 ::ZeroMemory(&KernelUserTimes, sizeof(KernelUserTimes));146 NtQueryInformationProcess = (PROCNTQIP)GetProcAddress(GetModuleHandle(TEXT("ntdll")), "NtQueryInformationProcess");147 LONG status = NtQueryInformationProcess(m_hProcess, ProcessTimes, &KernelUserTimes, sizeof(KernelUserTimes), NULL);148 if(status == 0)149 {150 ErrorExit(TEXT("GetProcessNonIdleTimes"));151 return 0;152 }153 return KernelUserTimes.KernelTime.QuadPart + KernelUserTimes.UserTime.QuadPart;154 155 }156 157 #endif158 159 CpuUsage::CpuUsage(DWORD dwProcessID)160 : m_nCpuUsage(0),161 m_dwLastRun(0),162 m_lRunCount(0),163 m_dwProcessID(dwProcessID),164 m_ullPrevProcNonIdleTime(0),165 m_ullPrevSysNonIdleTime(0)166 {167 HANDLE hProcess = GetCurrentProcess();168 SetPrivilege(hProcess, SE_DEBUG_NAME, TRUE);169 170 m_hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION , TRUE, m_dwProcessID);171 if(m_hProcess == 0)172 {173 ErrorMsg(TEXT("OpenProcess"));174 }175 ZeroMemory(&m_ftPrevSysKernel, sizeof(FILETIME));176 ZeroMemory(&m_ftPrevSysUser, sizeof(FILETIME));177 178 ZeroMemory(&m_ftPrevProcKernel, sizeof(FILETIME));179 ZeroMemory(&m_ftPrevProcUser, sizeof(FILETIME));180 }181 182 183 ULONGLONG CpuUsage::SubtractTimes(const FILETIME &ftA, const FILETIME &ftB)184 {185 LARGE_INTEGER a, b;186 a.LowPart = ftA.dwLowDateTime;187 a.HighPart = ftA.dwHighDateTime;188 189 b.LowPart = ftB.dwLowDateTime;190 b.HighPart = ftB.dwHighDateTime;191 192 return a.QuadPart - b.QuadPart;193 }194 195 ULONGLONG CpuUsage::AddTimes(const FILETIME &ftA, const FILETIME &ftB)196 {197 LARGE_INTEGER a, b;198 a.LowPart = ftA.dwLowDateTime;199 a.HighPart = ftA.dwHighDateTime;200 201 b.LowPart = ftB.dwLowDateTime;202 b.HighPart = ftB.dwHighDateTime;203 204 return a.QuadPart + b.QuadPart;205 }206 207 bool CpuUsage::EnoughTimePassed()208 {209 const int minElapsedMS = 250;//milliseconds210 211 ULONGLONG dwCurrentTickCount = GetTickCount();212 return (dwCurrentTickCount - m_dwLastRun) > minElapsedMS;213 }214 #ifndef USE_DEPRECATED_FUNCS215 216 ULONGLONG CpuUsage::GetSystemNonIdleTimes()217 {218 FILETIME ftSysIdle, ftSysKernel, ftSysUser;219 if(!GetSystemTimes(&ftSysIdle, &ftSysKernel, &ftSysUser))220 {221 ErrorMsg(TEXT("GetSystemTimes"));222 return 0;223 }224 return AddTimes(ftSysKernel, ftSysUser);225 }226 227 228 ULONGLONG CpuUsage::GetProcessNonIdleTimes()229 {230 FILETIME ftProcCreation, ftProcExit, ftProcKernel, ftProcUser;231 if(!GetProcessTimes(m_hProcess, &ftProcCreation, &ftProcExit, &ftProcKernel, &ftProcUser) && false)232 {233 ErrorMsg(TEXT("GetProcessNonIdleTimes"));234 return 0;235 }236 return AddTimes(ftProcKernel, ftProcUser);237 }238 #endif239 240 ULONGLONG CpuUsage::GetUsageEx()241 {242 ULONGLONG nCpuCopy = m_nCpuUsage;243 if (::InterlockedIncrement(&m_lRunCount) == 1)244 {245 if (!EnoughTimePassed())246 {247 ::InterlockedDecrement(&m_lRunCount);248 return nCpuCopy;249 }250 ULONGLONG ullSysNonIdleTime = GetSystemNonIdleTimes();251 ULONGLONG ullProcNonIdleTime = GetProcessNonIdleTimes();252 if (!IsFirstRun())253 {254 ULONGLONG ullTotalSys = ullSysNonIdleTime - m_ullPrevSysNonIdleTime;255 if(ullTotalSys == 0)256 {257 ::InterlockedDecrement(&m_lRunCount);258 return nCpuCopy;259 }260 m_nCpuUsage = ULONGLONG((ullProcNonIdleTime - m_ullPrevProcNonIdleTime) * 100.0 / (ullTotalSys));261 m_ullPrevSysNonIdleTime = ullSysNonIdleTime;262 m_ullPrevProcNonIdleTime = ullProcNonIdleTime;263 }264 m_dwLastRun = (ULONGLONG)GetTickCount();265 nCpuCopy = m_nCpuUsage;266 }267 ::InterlockedDecrement(&m_lRunCount);268 return nCpuCopy;269 }270 271 BOOL SetPrivilege(HANDLE hProcess, LPCTSTR lpszPrivilege, BOOL bEnablePrivilege)272 {273 HANDLE hToken;274 if(!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken))275 {276 ErrorMsg(TEXT("OpenProcessToken"));277 return FALSE;278 }279 LUID luid;280 if(!LookupPrivilegeValue(NULL, lpszPrivilege, &luid))281 {282 ErrorMsg(TEXT("LookupPrivilegeValue"));283 return FALSE;284 }285 TOKEN_PRIVILEGES tkp;286 tkp.PrivilegeCount = 1;287 tkp.Privileges[0].Luid = luid;288 tkp.Privileges[0].Attributes = (bEnablePrivilege) ? SE_PRIVILEGE_ENABLED : FALSE;289 if(!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL))290 {291 ErrorMsg(TEXT("AdjustTokenPrivileges"));292 return FALSE;293 }294 return TRUE;295 }296 297 void ErrorMsg(LPTSTR lpszFunction)298 {299 // Retrieve the system error message for the last-error code300 301 LPVOID lpMsgBuf;302 LPVOID lpDisplayBuf;303 DWORD dw = GetLastError();304 305 FormatMessage(306 FORMAT_MESSAGE_ALLOCATE_BUFFER |307 FORMAT_MESSAGE_FROM_SYSTEM |308 FORMAT_MESSAGE_IGNORE_INSERTS,309 NULL,310 dw,311 LANG_USER_DEFAULT,312 (LPTSTR) &lpMsgBuf,313 0, NULL );314 315 // Display the error message316 317 lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,318 (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));319 StringCchPrintf((LPTSTR)lpDisplayBuf,320 LocalSize(lpDisplayBuf) / sizeof(TCHAR),321 TEXT("%s failed with error %d: %s"),322 lpszFunction, dw, lpMsgBuf);323 MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);324 325 LocalFree(lpMsgBuf);326 LocalFree(lpDisplayBuf);327 ExitProcess(dw);328 }329 330 //main.cpp331 332 #include "cpuusage.h"333 #include
334 #include
335 #include
336 using namespace std;337 338 const int second = 1000;339 340 int main(int argc, char* argv[])341 {342 if(argc != 2)343 {344 printf("Use the toolkit like:
\n");345 return 0;346 }347 DWORD dwProcId = atoi(argv[1]);348 CpuUsage cu(dwProcId);349 SYSTEMTIME st;350 while(true)351 {352 GetLocalTime(&st);353 printf("Process(pid:%d) uses %I64d%% cpu at %02d:%02d.%02d\n", dwProcId, cu.GetUsageEx(), st.wHour, st.wMinute, st.wSecond);354 ::Sleep(second);355 }356 }

搞上面那坨代码的时候我发现了ProcessHacker, 它是个开源版本的Process Explorer, 如果你对Windows里面那些乌七八糟的东西感兴趣的话, 可以看看.

ProcessHacker:

posted on
2012-11-02 00:12  阅读(
...) 评论(
...) 收藏

转载于:https://www.cnblogs.com/jackiesteed/articles/2750540.html

你可能感兴趣的文章
直播技术细节3
查看>>
《分布式服务架构:原理、设计于实战》总结
查看>>
java中new一个对象和对象=null有什么区别
查看>>
字母和数字键的键码值(keyCode)
查看>>
协议和代理
查看>>
IE8调用window.open导出EXCEL文件题目
查看>>
sql server 2008 不允许保存更改,您所做的更改要求删除并重新创建以下表 的解决办法(转)...
查看>>
[转]iOS学习笔记(2)--Xcode6.1创建仅xib文件无storyboard的hello world应用
查看>>
Spring mvc初学
查看>>
python标准库学习7
查看>>
有意思的代码片段
查看>>
C8051开发环境
查看>>
VTKMY 3.3 VS 2010 Configuration 配置
查看>>
255. Verify Preorder Sequence in Binary Search Tree
查看>>
01_1_准备ibatis环境
查看>>
windows中修改catalina.sh上传到linux执行报错This file is needed to run this program解决
查看>>
[fowarding]Ubuntu jsp平台使用JDBC来连接MySQL数据库
查看>>
JavaScript中的BOM和DOM
查看>>
注册表操作
查看>>
360浏览器兼容模式 不能$.post (不是a 连接 onclick的问题!!)
查看>>