在取樣間隔內,計算目標進程核心+使用者時間總和佔所有進程總時間的比例。需呼叫未文件化的 NtQuerySystemInformation (SystemInformationClass=5) 取得 SYSTEM_PROCESS_INFORMATION 結構陣列。
typedef struct _THREAD_INFO {
LARGE_INTEGER CreateTime;
DWORD dwUnknown1, dwStartAddress, StartEIP, dwOwnerPID, dwThreadId;
DWORD dwCurrentPriority, dwBasePriority, dwContextSwitches, Unknown;
DWORD WaitReason;
} THREADINFO;
typedef struct _PROCESS_INFO {
DWORD dwOffset, dwThreadsCount, dwUnused1[6];
LARGE_INTEGER CreateTime, UserTime, KernelTime;
UNICODE_STRING ProcessName;
DWORD dwBasePriority, dwProcessID, dwParentProcessId, dwHandleCount;
DWORD dwUnused3[2], dwVirtualBytesPeak, dwVirtualBytes, dwPageFaults;
DWORD dwWorkingSetPeak, dwWorkingSet;
DWORD dwQuotaPeakPagedPoolUsage, dwQuotaPagedPoolUsage;
DWORD dwQuotaPeakNonPagedPoolUsage, dwQuotaNonPagedPoolUsage;
DWORD dwPageFileUsage, dwPageFileUsagePeak, dCommitCharge;
THREADINFO ThreadSysInfo[1];
} PROCESSINFO;
int GetProcessCpuUsage(int pid) {
static __int64 LastTotal = 0, LastCur = 0;
PVOID pBuf = new BYTE[0x20000];
typedef LONG (__stdcall *PFN)(DWORD, PVOID, DWORD, DWORD);
PFN NtQSI = (PFN)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtQuerySystemInformation");
NtQSI(5, pBuf, 0x20000, 0);
PPROCESSINFO p = (PPROCESSINFO)pBuf;
__int64 Total = 0, Cur = 0;
DWORD ws = 0;
do {
Total += p->KernelTime.QuadPart + p->UserTime.QuadPart;
if (p->dwProcessID == (DWORD)pid) {
ws = p->dwWorkingSet;
Cur += p->KernelTime.QuadPart + p->UserTime.QuadPart;
}
if (p->dwOffset == 0) break;
p = (PPROCESSINFO)((BYTE*)p + p->dwOffset);
} while (true);
int totalDelta = (int)(Total - LastTotal);
int curDelta = (int)(Cur - LastCur);
int cpu = (totalDelta != 0) ? (100 * curDelta / totalDelta) : 0;
LastTotal = Total; LastCur = Cur;
delete[] pBuf;
return cpu;
}
int main() {
while (true) {
printf("%d\n", GetProcessCpuUsage(0)); // 0 = System Idle Process
Sleep(1000);
}
return 0;
}
若需監控特定 PID,請替換參數。程式碼於 Win2000/XP 測試通過。