win7之后的系统的CPU占用计算的原理与实现

来源:互联网 发布:red5源码 教程 编辑:程序博客网 时间:2024/06/05 16:30

        经过比对,发现procexp和任务管理器在计算进程cpu占用上面存在很大的差异,经过研究发现,procexp显示的是正确的,而任务管理器显示的是错误的,任务管理器是用以前老的方式计算的。


        新的cpu计算原理应该是:


进程CPU占用率 = 进程消耗CPU时间 / 所有进程消耗CPU总时间 * 100%


CycleTime:周期时间(即从进程启动开始到当前所消耗的CPU时间总和)


所有进程消耗CPU总时间 = 所有进程的周期时间 + 内核时间(DPC以及中断服务)


Idle进程消耗的CPU时间 = 每个核消耗的CPU时间相加


以下是具体实现:



#include <conio.h>#include <atlbase.h>#include <iostream>#include "SysProcess.h"#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)#define NT_INFORMATION(Status) ((((ULONG)(Status)) >> 30) == 1)#define NT_WARNING(Status) ((((ULONG)(Status)) >> 30) == 2)#define NT_ERROR(Status) ((((ULONG)(Status)) >> 30) == 3)#define SYSTEM_IDLE_PROCESS_ID ((HANDLE)0)#define FIND_FIRST_PROCESS(Processes) ((PSYSTEM_PROCESS_INFORMATION)(Processes))#define FIND_NEXT_PROCESS(Process) ( \((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset ? \(PSYSTEM_PROCESS_INFORMATION)((PCHAR)(Process) + \((PSYSTEM_PROCESS_INFORMATION)(Process))->NextEntryOffset) : \NULL \)#define PhUpdateDelta(DltMgr, NewValue) \((DltMgr)->Delta = (NewValue) - (DltMgr)->Value, \(DltMgr)->Value = (NewValue), (DltMgr)->Delta)typedef NTSTATUS (NTAPI *NTQUERYSYSTEMINFORMATION)(IN SYSTEM_INFORMATION_CLASS, IN OUT PVOID, IN ULONG, OUT PULONG OPTIONAL);typedef NTSTATUS (NTAPI *NTQUERYINFORMATIONPROCESS)(IN HANDLE ProcessHandle, IN PROCESSINFOCLASS ProcessInformationClass, OUT PVOID ProcessInformation, IN ULONG ProcessInformationLength, OUT PULONG ReturnLength OPTIONAL);NTQUERYSYSTEMINFORMATION NtQuerySystemInformation = NULL;NTQUERYINFORMATIONPROCESS NtQueryInformationProcess = NULL;ULONG g_ulCpuNumber = 0;std::vector<PROCESS_ITEM_INFORMATION> g_vecSysProInfos;std::map<HANDLE, HANDLE> g_mapProInfos; //key - UniqueProcessIdPH_UINT64_DELTA g_phCpuCycleDelta = {0};//查找进程是否已存在上一次保存的进程列表里面//vecProInfos上一次保存的进程列表//pProcess当前需要查询的进程inline BOOL GetProcessInfo(const std::vector<PROCESS_ITEM_INFORMATION> &vecProInfos, ULONG64 ProcessId, ULONG64 CreateTime, PROCESS_ITEM_INFORMATION &itemProcess){BOOL bRet = FALSE;for (std::vector<PROCESS_ITEM_INFORMATION>::const_iterator iter = vecProInfos.begin(); iter != vecProInfos.end(); ++ iter){PROCESS_ITEM_INFORMATION item = *iter;if (ProcessId == item.ProcessId && CreateTime == item.CreateTime){itemProcess = item;bRet = TRUE;}}return bRet;}inline HANDLE GetProcessHandle(HANDLE hUniqueProcessId){return g_mapProInfos[hUniqueProcessId];}//获取CPU核数inline ULONG GetCpuNumberOfProcessors(){NTSTATUS status;ULONG ulRet = g_ulCpuNumber;PSYSTEM_BASIC_INFORMATION pSysBasicInfo = NULL;do {if (g_ulCpuNumber != 0){break;}if (NULL == NtQuerySystemInformation){NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation");if (NULL == NtQuerySystemInformation){break;}}ULONG ulSize = sizeof(SYSTEM_BASIC_INFORMATION);pSysBasicInfo = (PSYSTEM_BASIC_INFORMATION)malloc(ulSize);if (NULL == pSysBasicInfo){break;}status = NtQuerySystemInformation(SystemBasicInformation, pSysBasicInfo, ulSize, NULL);if (!NT_SUCCESS(status)){break;}ulRet = pSysBasicInfo->NumberOfProcessors;} while (0);if (NULL != pSysBasicInfo){free(pSysBasicInfo);}return ulRet;}//获取Idle进程的CPU使用时间//https://msdn.microsoft.com/en-us/library/windows/desktop/ms684922(v=vs.85).aspx//Retrieves the cycle time for the idle thread of each processor in the system.//On a system with more than 64 processors, this function retrieves the cycle time for the //idle thread of each processor in the processor group to which the calling thread is assigned. //Use the QueryIdleProcessorCycleTimeEx function to retrieve the cycle time for the //idle thread on each logical processor for a specific processor group.inline ULONG64 GetCpuIdleCycleTime(){NTSTATUS status;ULONGLONG ullRet = 0;PLARGE_INTEGER pCpuIdleCycleTime = NULL;do {if (NULL == NtQuerySystemInformation){NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation");if (NULL == NtQuerySystemInformation){break;}}ULONG ulNumberOfProcessors = GetCpuNumberOfProcessors();ULONG ulSize = ulNumberOfProcessors * sizeof(LARGE_INTEGER);pCpuIdleCycleTime = (PLARGE_INTEGER)malloc(ulSize);if (NULL == pCpuIdleCycleTime){break;}status = NtQuerySystemInformation(SystemProcessorIdleCycleTimeInformation, pCpuIdleCycleTime, ulSize, NULL);if (!NT_SUCCESS(status)){break;}for (ULONG i = 0; i < ulNumberOfProcessors; i++){ullRet += pCpuIdleCycleTime[i].QuadPart;}} while (0);if (NULL != pCpuIdleCycleTime){free(pCpuIdleCycleTime);}return ullRet;}//https://msdn.microsoft.com/en-us/library/windows/desktop/dd405497(v=vs.85).aspx//Retrieves the cycle time each processor in the specified processor group spent executing deferred procedure calls (DPCs) and interrupt service routines (ISRs) since the processor became active.//检索指定组中的每个处理器周期推迟执行过程调用(dpc)和中断服务程序inline ULONG64 GetCpuSystemCycleTime(){NTSTATUS status;ULONGLONG ullRet = 0;ULONGLONG ullTotal = 0;PLARGE_INTEGER pSysCycleTime = NULL;do {if (NULL == NtQuerySystemInformation){NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation");if (NULL == NtQuerySystemInformation){break;}}ULONG ulNumberOfProcessors = GetCpuNumberOfProcessors();ULONG ulSize = ulNumberOfProcessors * sizeof(LARGE_INTEGER);pSysCycleTime = (PLARGE_INTEGER)malloc(ulSize);if (NULL == pSysCycleTime){break;}status = NtQuerySystemInformation(SystemProcessorCycleTimeInformation, pSysCycleTime, ulSize, NULL);if (!NT_SUCCESS(status)){break;}for (ULONG i = 0; i < ulNumberOfProcessors; i++){ullTotal += pSysCycleTime[i].QuadPart;}PhUpdateDelta(&g_phCpuCycleDelta, ullTotal);ullRet = g_phCpuCycleDelta.Delta;} while (0);if (NULL != pSysCycleTime){free(pSysCycleTime);}return ullRet;}//获取进程累计时间inline ULONGLONG GetProcessCycleTime(HANDLE hProcessHandle){NTSTATUS status;ULONGLONG ullRet = 0;PPROCESS_CYCLE_TIME_INFORMATION pProcessCycleTime = NULL;do {if (NULL == NtQueryInformationProcess){NtQueryInformationProcess = (NTQUERYINFORMATIONPROCESS)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQueryInformationProcess");if (NULL == NtQueryInformationProcess){break;}}ULONG ulNeedSize = 0;status = NtQueryInformationProcess(hProcessHandle, ProcessCycleTime, NULL, 0, &ulNeedSize);if (!NT_SUCCESS(status)){break;}pProcessCycleTime = (PPROCESS_CYCLE_TIME_INFORMATION)malloc(ulNeedSize);if (NULL == pProcessCycleTime){break;}status = NtQueryInformationProcess(hProcessHandle, ProcessCycleTime, pProcessCycleTime, ulNeedSize, NULL);if (!NT_SUCCESS(status)){break;}ullRet = pProcessCycleTime->AccumulatedCycles;} while (0);if (NULL != pProcessCycleTime){free(pProcessCycleTime);}return ullRet;}//获取已退出进程在该时间段内使用的周期时间inline ULONGLONG GetDeadProcessCycleTime(const std::vector<PROCESS_ITEM_INFORMATION> &oldVecProInfos, const std::vector<PROCESS_ITEM_INFORMATION> &newVecProInfos){ULONGLONG ullRet = 0;for (std::vector<PROCESS_ITEM_INFORMATION>::const_iterator iter = oldVecProInfos.begin(); iter != oldVecProInfos.end(); ++ iter){PROCESS_ITEM_INFORMATION oldProcess = *iter;PROCESS_ITEM_INFORMATION newProcess = {0};if (GetProcessInfo(newVecProInfos, oldProcess.ProcessId, oldProcess.CreateTime, newProcess)){HANDLE hProcess = GetProcessHandle((HANDLE)oldProcess.ProcessId);ULONGLONG ullCycleTime = GetProcessCycleTime(hProcess);ullRet += ullCycleTime;}}return ullRet;}//计算进程的CPU占用率inline void CalProcessCPUUsage(std::map<ULONG, double> &mapPros){PVOID pProcInfo = NULL;PSYSTEM_PROCESS_INFORMATION pProcess =NULL;ULONG ulNeedSize = 0;ULONG64 sysTotalCycleTime = 0;std::map<ULONG, ULONG64> mapCycleTime;std::vector<PROCESS_ITEM_INFORMATION> vecSysProInfos;if (NULL == NtQuerySystemInformation){NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle(L"ntdll.dll"), "NtQuerySystemInformation");if (NULL == NtQuerySystemInformation){return;}}NtQuerySystemInformation(SystemProcessInformation, NULL, 0, &ulNeedSize);pProcInfo = (PVOID)malloc(ulNeedSize);NtQuerySystemInformation(SystemProcessInformation, pProcInfo, ulNeedSize, NULL);pProcess = FIND_FIRST_PROCESS(pProcInfo);while(pProcess){//Idle进程if (pProcess->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID){pProcess->CycleTime = GetCpuIdleCycleTime();}//所以当前进程PROCESS_ITEM_INFORMATION ProcessItem = {0};if (GetProcessInfo(g_vecSysProInfos, (ULONG64)pProcess->UniqueProcessId, pProcess->CreateTime.QuadPart, ProcessItem)){sysTotalCycleTime += pProcess->CycleTime - ProcessItem.CycleTime;for (std::map<ULONG, double>::iterator iter = mapPros.begin(); iter != mapPros.end(); ++ iter){ULONG ulPid = iter->first;if ((ULONGLONG)pProcess->UniqueProcessId == ulPid){ULONG64 cycleTime = pProcess->CycleTime - ProcessItem.CycleTime;mapCycleTime[ulPid] = cycleTime;}}}else{sysTotalCycleTime += pProcess->CycleTime;for (std::map<ULONG, double>::iterator iter = mapPros.begin(); iter != mapPros.end(); ++ iter){ULONG ulPid = iter->first;if ((ULONGLONG)pProcess->UniqueProcessId == ulPid){ULONG64 cycleTime = pProcess->CycleTime;mapCycleTime[ulPid] = cycleTime;}}}//HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)pProcess->UniqueProcessId);//g_mapProInfos[pProcess->UniqueProcessId] = hProcess;PROCESS_ITEM_INFORMATION process = {0};process.CreateTime = pProcess->CreateTime.QuadPart;process.CycleTime = pProcess->CycleTime;process.ProcessId = (ULONG64)pProcess->UniqueProcessId; vecSysProInfos.push_back(process);pProcess = FIND_NEXT_PROCESS(pProcess);}//内核时间(DPC以及中断服务时间)ULONGLONG ullSysCycleTime = GetCpuSystemCycleTime();////已退出进程使用时间//ULONGLONG ullDeadProCycleTime = GetDeadProcessCycleTime(g_vecSysProInfos, vecSysProInfos);sysTotalCycleTime += ullSysCycleTime;//sysTotalCycleTime += ullDeadProCycleTime;g_vecSysProInfos.clear();for (std::vector<PROCESS_ITEM_INFORMATION>::iterator iter = vecSysProInfos.begin(); iter != vecSysProInfos.end(); ++ iter){g_vecSysProInfos.push_back(*iter);}//先清空下mapPros.clear();for (std::map<ULONG, ULONG64>::iterator iter = mapCycleTime.begin(); iter != mapCycleTime.end(); ++ iter){ULONG ulPid = iter->first;ULONG64 ullCycleTime = iter->second;if (ullCycleTime != 0 && sysTotalCycleTime != 0){double dUsage = 100 * (double)ullCycleTime / (double)sysTotalCycleTime;mapPros[ulPid] = dUsage;}}if (NULL != pProcInfo){free(pProcInfo);}}


进程CPU占用率=进程消耗CPU时间/所有进程消耗CPU总时间*100%

CycleTime周期时间(即从进程启动开始到当前所消耗的CPU时间总和)

所有进程消耗CPU总时间=所有进程的周期时间+内核时间(DPC以及中断服务)

Idle进程消耗的CPU时间=每个核消耗的CPU时间相加


0 0