/* * ReactOS Task Manager * * perfdata.c * * Copyright (C) 1999 - 2001 Brian Palmer * * 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 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #include #include "taskmgr.h" #include "perfdata.h" 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; static PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SystemProcessorTimeInfo = NULL; static size_t size_diff(size_t x, size_t y) { return x > y ? x - y : y - x; } BOOL PerfDataInitialize(void) { LONG status; InitializeCriticalSection(&PerfDataCriticalSection); /* * Get number of processors in the system */ status = NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), NULL); 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; WCHAR wszTemp[MAX_PATH]; DWORD dwSize; SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo; SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo; SYSTEM_CACHE_INFORMATION SysCacheInfo; LPBYTE SysHandleInfoData; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *SysProcessorTimeInfo; double CurrentKernelTime; /* Get new system time */ status = NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), 0); if (status != NO_ERROR) return; /* Get new CPU's idle time */ status = NtQuerySystemInformation(SystemPerformanceInformation, &SysPerfInfo, sizeof(SysPerfInfo), NULL); if (status != NO_ERROR) return; /* Get system cache information */ status = NtQuerySystemInformation(SystemFileCacheInformation, &SysCacheInfo, sizeof(SysCacheInfo), NULL); if (status != NO_ERROR) return; /* Get processor time information */ SysProcessorTimeInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*SysProcessorTimeInfo) * SystemBasicInfo.NumberOfProcessors); status = NtQuerySystemInformation(SystemProcessorPerformanceInformation, SysProcessorTimeInfo, sizeof(*SysProcessorTimeInfo) * SystemBasicInfo.NumberOfProcessors, &ulSize); if (status != NO_ERROR) { HeapFree(GetProcessHeap(), 0, SysProcessorTimeInfo); return; } /* 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; SysHandleInfoData = HeapAlloc(GetProcessHeap(), 0, BufferSize); status = NtQuerySystemInformation(SystemHandleInformation, SysHandleInfoData, BufferSize, &ulSize); if (status == 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/) { HeapFree(GetProcessHeap(), 0, SysHandleInfoData); } } 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; pBuffer = HeapAlloc(GetProcessHeap(), 0, BufferSize); status = NtQuerySystemInformation(SystemProcessInformation, pBuffer, BufferSize, &ulSize); if (status == 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/) { HeapFree(GetProcessHeap(), 0, pBuffer); } } 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 */ HeapFree(GetProcessHeap(), 0, SystemProcessorTimeInfo); SystemProcessorTimeInfo = SysProcessorTimeInfo; /* * Save system handle info */ memcpy(&SystemHandleInfo, SysHandleInfoData, sizeof(SYSTEM_HANDLE_INFORMATION)); HeapFree(GetProcessHeap(), 0, SysHandleInfoData); for (CurrentKernelTime=0, Idx=0; IdxNextEntryOffset == 0) break; pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset); } /* Now alloc a new PERFDATA array and fill in the data */ HeapFree(GetProcessHeap(), 0, pPerfDataOld); pPerfDataOld = pPerfData; pPerfData = HeapAlloc(GetProcessHeap(), 0, sizeof(PERFDATA) * ProcessCount); pSPI = (PSYSTEM_PROCESS_INFORMATION)pBuffer; for (Idx=0; IdxUniqueProcessId) { pPDOld = &pPerfDataOld[Idx2]; break; } } /* Clear out process perf data structure */ memset(&pPerfData[Idx], 0, sizeof(PERFDATA)); if (pSPI->ProcessName.Buffer) lstrcpyW(pPerfData[Idx].ImageName, pSPI->ProcessName.Buffer); else { WCHAR idleW[255]; LoadStringW(hInst, IDS_SYSTEM_IDLE_PROCESS, idleW, ARRAY_SIZE(idleW)); lstrcpyW(pPerfData[Idx].ImageName, idleW ); } pPerfData[Idx].ProcessId = (DWORD_PTR)pSPI->UniqueProcessId; if (pPDOld) { double CurTime = Li2Double(pSPI->KernelTime) + Li2Double(pSPI->UserTime); double OldTime = Li2Double(pPDOld->KernelTime) + Li2Double(pPDOld->UserTime); double CpuTime = (CurTime - OldTime) / dbSystemTime; CpuTime = CpuTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */ pPerfData[Idx].CPUUsage = (ULONG)CpuTime; } pPerfData[Idx].CPUTime.QuadPart = pSPI->UserTime.QuadPart + pSPI->KernelTime.QuadPart; pPerfData[Idx].vmCounters.WorkingSetSize = pSPI->vmCounters.WorkingSetSize; pPerfData[Idx].vmCounters.PeakWorkingSetSize = pSPI->vmCounters.PeakWorkingSetSize; if (pPDOld) pPerfData[Idx].WorkingSetSizeDelta = size_diff(pSPI->vmCounters.WorkingSetSize, pPDOld->vmCounters.WorkingSetSize); else pPerfData[Idx].WorkingSetSizeDelta = 0; pPerfData[Idx].vmCounters.PageFaultCount = pSPI->vmCounters.PageFaultCount; if (pPDOld) pPerfData[Idx].PageFaultCountDelta = size_diff(pSPI->vmCounters.PageFaultCount, pPDOld->vmCounters.PageFaultCount); else pPerfData[Idx].PageFaultCountDelta = 0; 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; pPerfData[Idx].HandleCount = pSPI->HandleCount; pPerfData[Idx].ThreadCount = pSPI->dwThreadCount; pPerfData[Idx].SessionId = pSPI->SessionId; hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD_PTR)pSPI->UniqueProcessId); if (hProcess) { if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_IMPERSONATE, &hProcessToken)) { ImpersonateLoggedOnUser(hProcessToken); memset(wszTemp, 0, sizeof(wszTemp)); dwSize = MAX_PATH; GetUserNameW(wszTemp, &dwSize); RevertToSelf(); CloseHandle(hProcessToken); } pPerfData[Idx].USERObjectCount = GetGuiResources(hProcess, GR_USEROBJECTS); pPerfData[Idx].GDIObjectCount = GetGuiResources(hProcess, GR_GDIOBJECTS); GetProcessIoCounters(hProcess, &pPerfData[Idx].IOCounters); IsWow64Process(hProcess, &pPerfData[Idx].Wow64Process); CloseHandle(hProcess); } pPerfData[Idx].UserTime.QuadPart = pSPI->UserTime.QuadPart; pPerfData[Idx].KernelTime.QuadPart = pSPI->KernelTime.QuadPart; pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset); } HeapFree(GetProcessHeap(), 0, pBuffer); LeaveCriticalSection(&PerfDataCriticalSection); } ULONG PerfDataGetProcessCount(void) { return ProcessCount; } ULONG PerfDataGetProcessorUsage(void) { if( dbIdleTime < 0.0 ) return 0; if( dbIdleTime > 100.0 ) return 100; return (ULONG)dbIdleTime; } ULONG PerfDataGetProcessorSystemUsage(void) { if( dbKernelTime < 0.0 ) return 0; if( dbKernelTime > 100.0 ) return 100; return (ULONG)dbKernelTime; } BOOL PerfDataGetImageName(ULONG Index, LPWSTR lpImageName, int nMaxCount) { static const WCHAR proc32W[] = {' ','*','3','2',0}; BOOL bSuccessful; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) { wcsncpy(lpImageName, pPerfData[Index].ImageName, nMaxCount); if (pPerfData[Index].Wow64Process && nMaxCount - lstrlenW(lpImageName) > 4 /* =lstrlenW(proc32W) */) lstrcatW(lpImageName, proc32W); 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; } BOOL PerfDataGetUserName(ULONG Index, LPWSTR lpUserName, int nMaxCount) { BOOL bSuccessful; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) { wcsncpy(lpUserName, pPerfData[Index].UserName, nMaxCount); 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) WorkingSetSizeBytes = pPerfData[Index].vmCounters.WorkingSetSize; else WorkingSetSizeBytes = 0; LeaveCriticalSection(&PerfDataCriticalSection); return WorkingSetSizeBytes; } ULONG PerfDataGetPeakWorkingSetSizeBytes(ULONG Index) { ULONG PeakWorkingSetSizeBytes; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) PeakWorkingSetSizeBytes = pPerfData[Index].vmCounters.PeakWorkingSetSize; 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) PageFaultCount = pPerfData[Index].vmCounters.PageFaultCount; 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) VirtualMemorySizeBytes = pPerfData[Index].vmCounters.VirtualSize; else VirtualMemorySizeBytes = 0; LeaveCriticalSection(&PerfDataCriticalSection); return VirtualMemorySizeBytes; } ULONG PerfDataGetPagedPoolUsagePages(ULONG Index) { ULONG PagedPoolUsagePages; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) PagedPoolUsagePages = pPerfData[Index].vmCounters.QuotaPagedPoolUsage; else PagedPoolUsagePages = 0; LeaveCriticalSection(&PerfDataCriticalSection); return PagedPoolUsagePages; } ULONG PerfDataGetNonPagedPoolUsagePages(ULONG Index) { ULONG NonPagedPoolUsagePages; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) NonPagedPoolUsagePages = pPerfData[Index].vmCounters.QuotaNonPagedPoolUsage; 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); Total = SystemPerfInfo.TotalCommittedPages; PageSize = SystemBasicInfo.PageSize; LeaveCriticalSection(&PerfDataCriticalSection); Total = Total * (PageSize / 1024); return Total; } ULONG PerfDataGetCommitChargeLimitK(void) { ULONG Limit; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Limit = SystemPerfInfo.TotalCommitLimit; PageSize = SystemBasicInfo.PageSize; LeaveCriticalSection(&PerfDataCriticalSection); Limit = Limit * (PageSize / 1024); return Limit; } ULONG PerfDataGetCommitChargePeakK(void) { ULONG Peak; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Peak = SystemPerfInfo.PeakCommitment; PageSize = SystemBasicInfo.PageSize; LeaveCriticalSection(&PerfDataCriticalSection); Peak = Peak * (PageSize / 1024); return Peak; } ULONG PerfDataGetKernelMemoryTotalK(void) { ULONG Total; ULONG Paged; ULONG NonPaged; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Paged = SystemPerfInfo.PagedPoolUsage; NonPaged = SystemPerfInfo.NonPagedPoolUsage; PageSize = SystemBasicInfo.PageSize; LeaveCriticalSection(&PerfDataCriticalSection); Paged = Paged * (PageSize / 1024); NonPaged = NonPaged * (PageSize / 1024); Total = Paged + NonPaged; return Total; } ULONG PerfDataGetKernelMemoryPagedK(void) { ULONG Paged; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Paged = SystemPerfInfo.PagedPoolUsage; PageSize = SystemBasicInfo.PageSize; LeaveCriticalSection(&PerfDataCriticalSection); Paged = Paged * (PageSize / 1024); return Paged; } ULONG PerfDataGetKernelMemoryNonPagedK(void) { ULONG NonPaged; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); NonPaged = SystemPerfInfo.NonPagedPoolUsage; PageSize = SystemBasicInfo.PageSize; LeaveCriticalSection(&PerfDataCriticalSection); NonPaged = NonPaged * (PageSize / 1024); return NonPaged; } ULONG PerfDataGetPhysicalMemoryTotalK(void) { ULONG Total; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Total = SystemBasicInfo.MmNumberOfPhysicalPages; PageSize = SystemBasicInfo.PageSize; LeaveCriticalSection(&PerfDataCriticalSection); Total = Total * (PageSize / 1024); return Total; } ULONG PerfDataGetPhysicalMemoryAvailableK(void) { ULONG Available; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Available = SystemPerfInfo.AvailablePages; PageSize = SystemBasicInfo.PageSize; 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