2004-03-23 02:19:54 +01:00
|
|
|
/*
|
|
|
|
* ReactOS Task Manager
|
|
|
|
*
|
|
|
|
* perfdata.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 1999 - 2001 Brian Palmer <brianp@reactos.org>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2006-05-18 14:49:52 +02:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2004-03-23 02:19:54 +01:00
|
|
|
*/
|
2012-01-23 12:04:05 +01:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2004-03-23 02:19:54 +01:00
|
|
|
#include <windows.h>
|
|
|
|
#include <commctrl.h>
|
|
|
|
#include <winnt.h>
|
2012-01-23 12:04:05 +01:00
|
|
|
|
2004-03-23 02:19:54 +01:00
|
|
|
#include "taskmgr.h"
|
|
|
|
#include "perfdata.h"
|
|
|
|
|
2008-02-06 23:38:13 +01:00
|
|
|
static CRITICAL_SECTION PerfDataCriticalSection;
|
|
|
|
static PPERFDATA pPerfDataOld = NULL; /* Older perf data (saved to establish delta values) */
|
|
|
|
static PPERFDATA pPerfData = NULL; /* Most recent copy of perf data */
|
|
|
|
static ULONG ProcessCountOld = 0;
|
|
|
|
static ULONG ProcessCount = 0;
|
|
|
|
static double dbIdleTime;
|
|
|
|
static double dbKernelTime;
|
|
|
|
static double dbSystemTime;
|
|
|
|
static LARGE_INTEGER liOldIdleTime = {{0,0}};
|
|
|
|
static double OldKernelTime = 0;
|
|
|
|
static LARGE_INTEGER liOldSystemTime = {{0,0}};
|
|
|
|
static SYSTEM_PERFORMANCE_INFORMATION SystemPerfInfo;
|
|
|
|
static SYSTEM_BASIC_INFORMATION SystemBasicInfo;
|
|
|
|
static SYSTEM_CACHE_INFORMATION SystemCacheInfo;
|
|
|
|
static SYSTEM_HANDLE_INFORMATION SystemHandleInfo;
|
2013-09-11 18:04:33 +02:00
|
|
|
static PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SystemProcessorTimeInfo = NULL;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
2020-05-27 23:56:02 +02:00
|
|
|
static size_t size_diff(size_t x, size_t y)
|
|
|
|
{
|
|
|
|
return x > y ? x - y : y - x;
|
|
|
|
}
|
|
|
|
|
2004-03-23 02:19:54 +01:00
|
|
|
BOOL PerfDataInitialize(void)
|
|
|
|
{
|
|
|
|
LONG status;
|
|
|
|
|
|
|
|
InitializeCriticalSection(&PerfDataCriticalSection);
|
2013-09-11 18:04:33 +02:00
|
|
|
|
2004-03-23 02:19:54 +01:00
|
|
|
/*
|
|
|
|
* Get number of processors in the system
|
|
|
|
*/
|
2020-10-20 00:31:47 +02:00
|
|
|
status = NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), NULL);
|
2004-03-23 02:19:54 +01:00
|
|
|
if (status != NO_ERROR)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void PerfDataRefresh(void)
|
|
|
|
{
|
|
|
|
ULONG ulSize;
|
|
|
|
LONG status;
|
|
|
|
LPBYTE pBuffer;
|
|
|
|
ULONG BufferSize;
|
|
|
|
PSYSTEM_PROCESS_INFORMATION pSPI;
|
|
|
|
PPERFDATA pPDOld;
|
|
|
|
ULONG Idx, Idx2;
|
|
|
|
HANDLE hProcess;
|
|
|
|
HANDLE hProcessToken;
|
2009-08-24 06:55:22 +02:00
|
|
|
WCHAR wszTemp[MAX_PATH];
|
2004-03-23 02:19:54 +01:00
|
|
|
DWORD dwSize;
|
|
|
|
SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo;
|
2013-09-11 18:04:33 +02:00
|
|
|
SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo;
|
2004-03-23 02:19:54 +01:00
|
|
|
SYSTEM_CACHE_INFORMATION SysCacheInfo;
|
|
|
|
LPBYTE SysHandleInfoData;
|
2013-09-11 18:04:33 +02:00
|
|
|
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *SysProcessorTimeInfo;
|
2004-03-23 02:19:54 +01:00
|
|
|
double CurrentKernelTime;
|
|
|
|
|
|
|
|
|
|
|
|
/* Get new system time */
|
2020-10-20 00:31:47 +02:00
|
|
|
status = NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0);
|
2004-03-23 02:19:54 +01:00
|
|
|
if (status != NO_ERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Get new CPU's idle time */
|
2020-10-20 00:31:47 +02:00
|
|
|
status = NtQuerySystemInformation(SystemPerformanceInformation, &SysPerfInfo, sizeof(SysPerfInfo), NULL);
|
2004-03-23 02:19:54 +01:00
|
|
|
if (status != NO_ERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Get system cache information */
|
2020-10-20 00:31:47 +02:00
|
|
|
status = NtQuerySystemInformation(SystemCacheInformation, &SysCacheInfo, sizeof(SysCacheInfo), NULL);
|
2004-03-23 02:19:54 +01:00
|
|
|
if (status != NO_ERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Get processor time information */
|
2008-12-08 04:07:31 +01:00
|
|
|
SysProcessorTimeInfo = HeapAlloc(GetProcessHeap(), 0,
|
2020-10-20 00:31:47 +02:00
|
|
|
sizeof(*SysProcessorTimeInfo) * SystemBasicInfo.NumberOfProcessors);
|
|
|
|
status = NtQuerySystemInformation(SystemProcessorPerformanceInformation, SysProcessorTimeInfo,
|
|
|
|
sizeof(*SysProcessorTimeInfo) * SystemBasicInfo.NumberOfProcessors, &ulSize);
|
2007-10-20 17:24:56 +02:00
|
|
|
if (status != NO_ERROR) {
|
2008-12-08 04:07:31 +01:00
|
|
|
HeapFree(GetProcessHeap(), 0, SysProcessorTimeInfo);
|
2004-03-23 02:19:54 +01:00
|
|
|
return;
|
2007-10-20 17:24:56 +02:00
|
|
|
}
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
/* Get handle information
|
|
|
|
* We don't know how much data there is so just keep
|
|
|
|
* increasing the buffer size until the call succeeds
|
|
|
|
*/
|
|
|
|
BufferSize = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
BufferSize += 0x10000;
|
2008-12-08 04:07:31 +01:00
|
|
|
SysHandleInfoData = HeapAlloc(GetProcessHeap(), 0, BufferSize);
|
2004-03-23 02:19:54 +01:00
|
|
|
|
2020-10-20 00:31:47 +02:00
|
|
|
status = NtQuerySystemInformation(SystemHandleInformation, SysHandleInfoData, BufferSize, &ulSize);
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
if (status == 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/) {
|
2008-12-08 04:07:31 +01:00
|
|
|
HeapFree(GetProcessHeap(), 0, SysHandleInfoData);
|
2004-03-23 02:19:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} while (status == 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/);
|
|
|
|
|
|
|
|
/* Get process information
|
|
|
|
* We don't know how much data there is so just keep
|
|
|
|
* increasing the buffer size until the call succeeds
|
|
|
|
*/
|
|
|
|
BufferSize = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
BufferSize += 0x10000;
|
2008-12-08 04:07:31 +01:00
|
|
|
pBuffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
|
2004-03-23 02:19:54 +01:00
|
|
|
|
2020-10-20 00:31:47 +02:00
|
|
|
status = NtQuerySystemInformation(SystemProcessInformation, pBuffer, BufferSize, &ulSize);
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
if (status == 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/) {
|
2008-12-08 04:07:31 +01:00
|
|
|
HeapFree(GetProcessHeap(), 0, pBuffer);
|
2004-03-23 02:19:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} while (status == 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/);
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save system performance info
|
|
|
|
*/
|
|
|
|
memcpy(&SystemPerfInfo, &SysPerfInfo, sizeof(SYSTEM_PERFORMANCE_INFORMATION));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save system cache info
|
|
|
|
*/
|
|
|
|
memcpy(&SystemCacheInfo, &SysCacheInfo, sizeof(SYSTEM_CACHE_INFORMATION));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save system processor time info
|
|
|
|
*/
|
2008-12-08 04:07:31 +01:00
|
|
|
HeapFree(GetProcessHeap(), 0, SystemProcessorTimeInfo);
|
2004-03-23 02:19:54 +01:00
|
|
|
SystemProcessorTimeInfo = SysProcessorTimeInfo;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save system handle info
|
|
|
|
*/
|
|
|
|
memcpy(&SystemHandleInfo, SysHandleInfoData, sizeof(SYSTEM_HANDLE_INFORMATION));
|
2008-12-08 04:07:31 +01:00
|
|
|
HeapFree(GetProcessHeap(), 0, SysHandleInfoData);
|
2004-03-23 02:19:54 +01:00
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
for (CurrentKernelTime=0, Idx=0; Idx<SystemBasicInfo.NumberOfProcessors; Idx++) {
|
2004-03-23 02:19:54 +01:00
|
|
|
CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].KernelTime);
|
2013-09-11 18:04:33 +02:00
|
|
|
CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].Reserved1[0]);
|
|
|
|
CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].Reserved1[1]);
|
2004-03-23 02:19:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If it's a first call - skip idle time calcs */
|
|
|
|
if (liOldIdleTime.QuadPart != 0) {
|
|
|
|
/* CurrentValue = NewValue - OldValue */
|
2013-09-11 18:04:33 +02:00
|
|
|
dbIdleTime = Li2Double(SysPerfInfo.IdleTime) - Li2Double(liOldIdleTime);
|
2004-03-23 02:19:54 +01:00
|
|
|
dbKernelTime = CurrentKernelTime - OldKernelTime;
|
2020-06-25 12:30:00 +02:00
|
|
|
dbSystemTime = Li2Double(SysTimeInfo.SystemTime) - Li2Double(liOldSystemTime);
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
/* CurrentCpuIdle = IdleTime / SystemTime */
|
|
|
|
dbIdleTime = dbIdleTime / dbSystemTime;
|
|
|
|
dbKernelTime = dbKernelTime / dbSystemTime;
|
|
|
|
|
|
|
|
/* CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors */
|
2013-09-11 18:04:33 +02:00
|
|
|
dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */
|
|
|
|
dbKernelTime = 100.0 - dbKernelTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */
|
2004-03-23 02:19:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Store new CPU's idle and system time */
|
2013-09-11 18:04:33 +02:00
|
|
|
liOldIdleTime = SysPerfInfo.IdleTime;
|
2020-06-25 12:30:00 +02:00
|
|
|
liOldSystemTime = SysTimeInfo.SystemTime;
|
2004-03-23 02:19:54 +01:00
|
|
|
OldKernelTime = CurrentKernelTime;
|
|
|
|
|
|
|
|
/* Determine the process count
|
|
|
|
* We loop through the data we got from NtQuerySystemInformation
|
|
|
|
* and count how many structures there are (until RelativeOffset is 0)
|
|
|
|
*/
|
|
|
|
ProcessCountOld = ProcessCount;
|
|
|
|
ProcessCount = 0;
|
|
|
|
pSPI = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
|
|
|
|
while (pSPI) {
|
|
|
|
ProcessCount++;
|
2013-09-11 18:04:33 +02:00
|
|
|
if (pSPI->NextEntryOffset == 0)
|
2004-03-23 02:19:54 +01:00
|
|
|
break;
|
2013-09-11 18:04:33 +02:00
|
|
|
pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset);
|
2004-03-23 02:19:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Now alloc a new PERFDATA array and fill in the data */
|
2008-12-08 04:07:31 +01:00
|
|
|
HeapFree(GetProcessHeap(), 0, pPerfDataOld);
|
2004-03-23 02:19:54 +01:00
|
|
|
pPerfDataOld = pPerfData;
|
2008-12-08 04:07:31 +01:00
|
|
|
pPerfData = HeapAlloc(GetProcessHeap(), 0, sizeof(PERFDATA) * ProcessCount);
|
2004-03-23 02:19:54 +01:00
|
|
|
pSPI = (PSYSTEM_PROCESS_INFORMATION)pBuffer;
|
|
|
|
for (Idx=0; Idx<ProcessCount; Idx++) {
|
|
|
|
/* Get the old perf data for this process (if any) */
|
|
|
|
/* so that we can establish delta values */
|
|
|
|
pPDOld = NULL;
|
|
|
|
for (Idx2=0; Idx2<ProcessCountOld; Idx2++) {
|
2013-09-11 18:04:33 +02:00
|
|
|
if (pPerfDataOld[Idx2].ProcessId == (DWORD_PTR)pSPI->UniqueProcessId) {
|
2004-03-23 02:19:54 +01:00
|
|
|
pPDOld = &pPerfDataOld[Idx2];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear out process perf data structure */
|
|
|
|
memset(&pPerfData[Idx], 0, sizeof(PERFDATA));
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
if (pSPI->ProcessName.Buffer)
|
|
|
|
lstrcpyW(pPerfData[Idx].ImageName, pSPI->ProcessName.Buffer);
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
{
|
2009-06-25 21:43:11 +02:00
|
|
|
WCHAR idleW[255];
|
2018-07-24 00:01:16 +02:00
|
|
|
LoadStringW(hInst, IDS_SYSTEM_IDLE_PROCESS, idleW, ARRAY_SIZE(idleW));
|
2004-03-23 02:19:54 +01:00
|
|
|
lstrcpyW(pPerfData[Idx].ImageName, idleW );
|
|
|
|
}
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
pPerfData[Idx].ProcessId = (DWORD_PTR)pSPI->UniqueProcessId;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
if (pPDOld) {
|
|
|
|
double CurTime = Li2Double(pSPI->KernelTime) + Li2Double(pSPI->UserTime);
|
|
|
|
double OldTime = Li2Double(pPDOld->KernelTime) + Li2Double(pPDOld->UserTime);
|
|
|
|
double CpuTime = (CurTime - OldTime) / dbSystemTime;
|
2013-09-11 18:04:33 +02:00
|
|
|
CpuTime = CpuTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */
|
2004-03-23 02:19:54 +01:00
|
|
|
pPerfData[Idx].CPUUsage = (ULONG)CpuTime;
|
|
|
|
}
|
2013-09-11 18:04:33 +02:00
|
|
|
|
2004-03-23 02:19:54 +01:00
|
|
|
pPerfData[Idx].CPUTime.QuadPart = pSPI->UserTime.QuadPart + pSPI->KernelTime.QuadPart;
|
2013-09-11 18:04:33 +02:00
|
|
|
pPerfData[Idx].vmCounters.WorkingSetSize = pSPI->vmCounters.WorkingSetSize;
|
|
|
|
pPerfData[Idx].vmCounters.PeakWorkingSetSize = pSPI->vmCounters.PeakWorkingSetSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
if (pPDOld)
|
2020-05-27 23:56:02 +02:00
|
|
|
pPerfData[Idx].WorkingSetSizeDelta = size_diff(pSPI->vmCounters.WorkingSetSize, pPDOld->vmCounters.WorkingSetSize);
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
pPerfData[Idx].WorkingSetSizeDelta = 0;
|
2013-09-11 18:04:33 +02:00
|
|
|
pPerfData[Idx].vmCounters.PageFaultCount = pSPI->vmCounters.PageFaultCount;
|
2004-03-23 02:19:54 +01:00
|
|
|
if (pPDOld)
|
2020-05-27 23:56:02 +02:00
|
|
|
pPerfData[Idx].PageFaultCountDelta = size_diff(pSPI->vmCounters.PageFaultCount, pPDOld->vmCounters.PageFaultCount);
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
pPerfData[Idx].PageFaultCountDelta = 0;
|
2013-09-11 18:04:33 +02:00
|
|
|
pPerfData[Idx].vmCounters.VirtualSize = pSPI->vmCounters.VirtualSize;
|
|
|
|
pPerfData[Idx].vmCounters.QuotaPagedPoolUsage = pSPI->vmCounters.QuotaPagedPoolUsage;
|
|
|
|
pPerfData[Idx].vmCounters.QuotaNonPagedPoolUsage = pSPI->vmCounters.QuotaNonPagedPoolUsage;
|
|
|
|
pPerfData[Idx].BasePriority = pSPI->dwBasePriority;
|
2004-03-23 02:19:54 +01:00
|
|
|
pPerfData[Idx].HandleCount = pSPI->HandleCount;
|
2013-09-11 18:04:33 +02:00
|
|
|
pPerfData[Idx].ThreadCount = pSPI->dwThreadCount;
|
2004-03-23 02:19:54 +01:00
|
|
|
pPerfData[Idx].SessionId = pSPI->SessionId;
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD_PTR)pSPI->UniqueProcessId);
|
2004-03-23 02:19:54 +01:00
|
|
|
if (hProcess) {
|
|
|
|
if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_IMPERSONATE, &hProcessToken)) {
|
|
|
|
ImpersonateLoggedOnUser(hProcessToken);
|
2009-08-24 06:55:22 +02:00
|
|
|
memset(wszTemp, 0, sizeof(wszTemp));
|
2004-03-23 02:19:54 +01:00
|
|
|
dwSize = MAX_PATH;
|
2009-08-24 06:55:22 +02:00
|
|
|
GetUserNameW(wszTemp, &dwSize);
|
2004-03-23 02:19:54 +01:00
|
|
|
RevertToSelf();
|
|
|
|
CloseHandle(hProcessToken);
|
|
|
|
}
|
2020-10-18 23:33:27 +02:00
|
|
|
pPerfData[Idx].USERObjectCount = GetGuiResources(hProcess, GR_USEROBJECTS);
|
|
|
|
pPerfData[Idx].GDIObjectCount = GetGuiResources(hProcess, GR_GDIOBJECTS);
|
2020-10-20 00:31:48 +02:00
|
|
|
GetProcessIoCounters(hProcess, &pPerfData[Idx].IOCounters);
|
|
|
|
IsWow64Process(hProcess, &pPerfData[Idx].Wow64Process);
|
2004-03-23 02:19:54 +01:00
|
|
|
CloseHandle(hProcess);
|
|
|
|
}
|
|
|
|
pPerfData[Idx].UserTime.QuadPart = pSPI->UserTime.QuadPart;
|
|
|
|
pPerfData[Idx].KernelTime.QuadPart = pSPI->KernelTime.QuadPart;
|
2013-09-11 18:04:33 +02:00
|
|
|
pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset);
|
2004-03-23 02:19:54 +01:00
|
|
|
}
|
2008-12-08 04:07:31 +01:00
|
|
|
HeapFree(GetProcessHeap(), 0, pBuffer);
|
2004-03-23 02:19:54 +01:00
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetProcessCount(void)
|
|
|
|
{
|
|
|
|
return ProcessCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetProcessorUsage(void)
|
|
|
|
{
|
2007-11-15 14:06:59 +01:00
|
|
|
if( dbIdleTime < 0.0 )
|
|
|
|
return 0;
|
|
|
|
if( dbIdleTime > 100.0 )
|
|
|
|
return 100;
|
2004-03-23 02:19:54 +01:00
|
|
|
return (ULONG)dbIdleTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetProcessorSystemUsage(void)
|
|
|
|
{
|
2007-11-15 14:06:59 +01:00
|
|
|
if( dbKernelTime < 0.0 )
|
|
|
|
return 0;
|
|
|
|
if( dbKernelTime > 100.0 )
|
|
|
|
return 100;
|
2004-03-23 02:19:54 +01:00
|
|
|
return (ULONG)dbKernelTime;
|
|
|
|
}
|
|
|
|
|
2009-08-24 06:55:22 +02:00
|
|
|
BOOL PerfDataGetImageName(ULONG Index, LPWSTR lpImageName, int nMaxCount)
|
2004-03-23 02:19:54 +01:00
|
|
|
{
|
2014-05-11 16:54:29 +02:00
|
|
|
static const WCHAR proc32W[] = {' ','*','3','2',0};
|
2004-03-23 02:19:54 +01:00
|
|
|
BOOL bSuccessful;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount) {
|
2009-08-24 06:55:22 +02:00
|
|
|
wcsncpy(lpImageName, pPerfData[Index].ImageName, nMaxCount);
|
2014-05-11 16:54:29 +02:00
|
|
|
if (pPerfData[Index].Wow64Process &&
|
|
|
|
nMaxCount - lstrlenW(lpImageName) > 4 /* =lstrlenW(proc32W) */)
|
|
|
|
lstrcatW(lpImageName, proc32W);
|
2004-03-23 02:19:54 +01:00
|
|
|
bSuccessful = TRUE;
|
|
|
|
} else {
|
|
|
|
bSuccessful = FALSE;
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
return bSuccessful;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetProcessId(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG ProcessId;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
ProcessId = pPerfData[Index].ProcessId;
|
|
|
|
else
|
|
|
|
ProcessId = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return ProcessId;
|
|
|
|
}
|
|
|
|
|
2009-08-24 06:55:22 +02:00
|
|
|
BOOL PerfDataGetUserName(ULONG Index, LPWSTR lpUserName, int nMaxCount)
|
2004-03-23 02:19:54 +01:00
|
|
|
{
|
|
|
|
BOOL bSuccessful;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount) {
|
2009-08-24 06:55:22 +02:00
|
|
|
wcsncpy(lpUserName, pPerfData[Index].UserName, nMaxCount);
|
2004-03-23 02:19:54 +01:00
|
|
|
bSuccessful = TRUE;
|
|
|
|
} else {
|
|
|
|
bSuccessful = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return bSuccessful;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetSessionId(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG SessionId;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
SessionId = pPerfData[Index].SessionId;
|
|
|
|
else
|
|
|
|
SessionId = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return SessionId;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetCPUUsage(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG CpuUsage;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
CpuUsage = pPerfData[Index].CPUUsage;
|
|
|
|
else
|
|
|
|
CpuUsage = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return CpuUsage;
|
|
|
|
}
|
|
|
|
|
|
|
|
TIME PerfDataGetCPUTime(ULONG Index)
|
|
|
|
{
|
|
|
|
TIME CpuTime = {{0,0}};
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
CpuTime = pPerfData[Index].CPUTime;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return CpuTime;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetWorkingSetSizeBytes(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG WorkingSetSizeBytes;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
2013-09-11 18:04:33 +02:00
|
|
|
WorkingSetSizeBytes = pPerfData[Index].vmCounters.WorkingSetSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
WorkingSetSizeBytes = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return WorkingSetSizeBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetPeakWorkingSetSizeBytes(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG PeakWorkingSetSizeBytes;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
2013-09-11 18:04:33 +02:00
|
|
|
PeakWorkingSetSizeBytes = pPerfData[Index].vmCounters.PeakWorkingSetSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
PeakWorkingSetSizeBytes = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return PeakWorkingSetSizeBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetWorkingSetSizeDelta(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG WorkingSetSizeDelta;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
WorkingSetSizeDelta = pPerfData[Index].WorkingSetSizeDelta;
|
|
|
|
else
|
|
|
|
WorkingSetSizeDelta = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return WorkingSetSizeDelta;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetPageFaultCount(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG PageFaultCount;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
2013-09-11 18:04:33 +02:00
|
|
|
PageFaultCount = pPerfData[Index].vmCounters.PageFaultCount;
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
PageFaultCount = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return PageFaultCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetPageFaultCountDelta(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG PageFaultCountDelta;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
PageFaultCountDelta = pPerfData[Index].PageFaultCountDelta;
|
|
|
|
else
|
|
|
|
PageFaultCountDelta = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return PageFaultCountDelta;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetVirtualMemorySizeBytes(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG VirtualMemorySizeBytes;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
2013-09-11 18:04:33 +02:00
|
|
|
VirtualMemorySizeBytes = pPerfData[Index].vmCounters.VirtualSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
VirtualMemorySizeBytes = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return VirtualMemorySizeBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetPagedPoolUsagePages(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG PagedPoolUsagePages;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
2013-09-11 18:04:33 +02:00
|
|
|
PagedPoolUsagePages = pPerfData[Index].vmCounters.QuotaPagedPoolUsage;
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
PagedPoolUsagePages = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return PagedPoolUsagePages;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetNonPagedPoolUsagePages(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG NonPagedPoolUsagePages;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
2013-09-11 18:04:33 +02:00
|
|
|
NonPagedPoolUsagePages = pPerfData[Index].vmCounters.QuotaNonPagedPoolUsage;
|
2004-03-23 02:19:54 +01:00
|
|
|
else
|
|
|
|
NonPagedPoolUsagePages = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return NonPagedPoolUsagePages;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetBasePriority(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG BasePriority;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
BasePriority = pPerfData[Index].BasePriority;
|
|
|
|
else
|
|
|
|
BasePriority = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return BasePriority;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetHandleCount(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG HandleCount;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
HandleCount = pPerfData[Index].HandleCount;
|
|
|
|
else
|
|
|
|
HandleCount = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return HandleCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetThreadCount(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG ThreadCount;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
ThreadCount = pPerfData[Index].ThreadCount;
|
|
|
|
else
|
|
|
|
ThreadCount = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return ThreadCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetUSERObjectCount(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG USERObjectCount;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
USERObjectCount = pPerfData[Index].USERObjectCount;
|
|
|
|
else
|
|
|
|
USERObjectCount = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return USERObjectCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetGDIObjectCount(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG GDIObjectCount;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
GDIObjectCount = pPerfData[Index].GDIObjectCount;
|
|
|
|
else
|
|
|
|
GDIObjectCount = 0;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return GDIObjectCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL PerfDataGetIOCounters(ULONG Index, PIO_COUNTERS pIoCounters)
|
|
|
|
{
|
|
|
|
BOOL bSuccessful;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
if (Index < ProcessCount)
|
|
|
|
{
|
|
|
|
memcpy(pIoCounters, &pPerfData[Index].IOCounters, sizeof(IO_COUNTERS));
|
|
|
|
bSuccessful = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
bSuccessful = FALSE;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return bSuccessful;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetCommitChargeTotalK(void)
|
|
|
|
{
|
|
|
|
ULONG Total;
|
|
|
|
ULONG PageSize;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
Total = SystemPerfInfo.TotalCommittedPages;
|
|
|
|
PageSize = SystemBasicInfo.PageSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
Total = Total * (PageSize / 1024);
|
|
|
|
|
|
|
|
return Total;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetCommitChargeLimitK(void)
|
|
|
|
{
|
|
|
|
ULONG Limit;
|
|
|
|
ULONG PageSize;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
Limit = SystemPerfInfo.TotalCommitLimit;
|
|
|
|
PageSize = SystemBasicInfo.PageSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
Limit = Limit * (PageSize / 1024);
|
|
|
|
|
|
|
|
return Limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetCommitChargePeakK(void)
|
|
|
|
{
|
|
|
|
ULONG Peak;
|
|
|
|
ULONG PageSize;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
Peak = SystemPerfInfo.PeakCommitment;
|
|
|
|
PageSize = SystemBasicInfo.PageSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
Peak = Peak * (PageSize / 1024);
|
|
|
|
|
|
|
|
return Peak;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetKernelMemoryTotalK(void)
|
|
|
|
{
|
|
|
|
ULONG Total;
|
|
|
|
ULONG Paged;
|
|
|
|
ULONG NonPaged;
|
|
|
|
ULONG PageSize;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
Paged = SystemPerfInfo.PagedPoolUsage;
|
|
|
|
NonPaged = SystemPerfInfo.NonPagedPoolUsage;
|
|
|
|
PageSize = SystemBasicInfo.PageSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
Paged = Paged * (PageSize / 1024);
|
|
|
|
NonPaged = NonPaged * (PageSize / 1024);
|
|
|
|
|
|
|
|
Total = Paged + NonPaged;
|
|
|
|
|
|
|
|
return Total;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetKernelMemoryPagedK(void)
|
|
|
|
{
|
|
|
|
ULONG Paged;
|
|
|
|
ULONG PageSize;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
Paged = SystemPerfInfo.PagedPoolUsage;
|
|
|
|
PageSize = SystemBasicInfo.PageSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
Paged = Paged * (PageSize / 1024);
|
|
|
|
|
|
|
|
return Paged;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetKernelMemoryNonPagedK(void)
|
|
|
|
{
|
|
|
|
ULONG NonPaged;
|
|
|
|
ULONG PageSize;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
NonPaged = SystemPerfInfo.NonPagedPoolUsage;
|
|
|
|
PageSize = SystemBasicInfo.PageSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
NonPaged = NonPaged * (PageSize / 1024);
|
|
|
|
|
|
|
|
return NonPaged;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetPhysicalMemoryTotalK(void)
|
|
|
|
{
|
|
|
|
ULONG Total;
|
|
|
|
ULONG PageSize;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
Total = SystemBasicInfo.MmNumberOfPhysicalPages;
|
|
|
|
PageSize = SystemBasicInfo.PageSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
Total = Total * (PageSize / 1024);
|
|
|
|
|
|
|
|
return Total;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetPhysicalMemoryAvailableK(void)
|
|
|
|
{
|
|
|
|
ULONG Available;
|
|
|
|
ULONG PageSize;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
2013-09-11 18:04:33 +02:00
|
|
|
Available = SystemPerfInfo.AvailablePages;
|
|
|
|
PageSize = SystemBasicInfo.PageSize;
|
2004-03-23 02:19:54 +01:00
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
Available = Available * (PageSize / 1024);
|
|
|
|
|
|
|
|
return Available;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetPhysicalMemorySystemCacheK(void)
|
|
|
|
{
|
|
|
|
ULONG SystemCache;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
SystemCache = SystemCacheInfo.CurrentSize;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
SystemCache = SystemCache / 1024;
|
|
|
|
|
|
|
|
return SystemCache;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetSystemHandleCount(void)
|
|
|
|
{
|
|
|
|
ULONG HandleCount;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
HandleCount = SystemHandleInfo.Count;
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return HandleCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG PerfDataGetTotalThreadCount(void)
|
|
|
|
{
|
|
|
|
ULONG ThreadCount = 0;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
EnterCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
for (i=0; i<ProcessCount; i++)
|
|
|
|
{
|
|
|
|
ThreadCount += pPerfData[i].ThreadCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
LeaveCriticalSection(&PerfDataCriticalSection);
|
|
|
|
|
|
|
|
return ThreadCount;
|
|
|
|
}
|