/* * 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 */ #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */ #include #include #include #include #include #include #include #include #include "taskmgr.h" #include "perfdata.h" PROCNTQSI NtQuerySystemInformation = NULL; PROCGGR pGetGuiResources = NULL; PROCGPIC pGetProcessIoCounters = NULL; CRITICAL_SECTION PerfDataCriticalSection; PPERFDATA pPerfDataOld = NULL; /* Older perf data (saved to establish delta values) */ PPERFDATA pPerfData = NULL; /* Most recent copy of perf data */ ULONG ProcessCountOld = 0; ULONG ProcessCount = 0; double dbIdleTime; double dbKernelTime; double dbSystemTime; LARGE_INTEGER liOldIdleTime = {{0,0}}; double OldKernelTime = 0; LARGE_INTEGER liOldSystemTime = {{0,0}}; SYSTEM_PERFORMANCE_INFORMATION SystemPerfInfo; SYSTEM_BASIC_INFORMATION SystemBasicInfo; SYSTEM_CACHE_INFORMATION SystemCacheInfo; SYSTEM_HANDLE_INFORMATION SystemHandleInfo; PSYSTEM_PROCESSORTIME_INFO SystemProcessorTimeInfo = NULL; BOOL PerfDataInitialize(void) { LONG status; NtQuerySystemInformation = (PROCNTQSI)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQuerySystemInformation"); pGetGuiResources = (PROCGGR)GetProcAddress(GetModuleHandle(_T("user32.dll")), "GetGuiResources"); pGetProcessIoCounters = (PROCGPIC)GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "GetProcessIoCounters"); InitializeCriticalSection(&PerfDataCriticalSection); if (!NtQuerySystemInformation) return FALSE; /* * Get number of processors in the system */ status = NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), NULL); if (status != NO_ERROR) return FALSE; return TRUE; } void PerfDataUninitialize(void) { NtQuerySystemInformation = NULL; DeleteCriticalSection(&PerfDataCriticalSection); } void PerfDataRefresh(void) { ULONG ulSize; LONG status; LPBYTE pBuffer; ULONG BufferSize; PSYSTEM_PROCESS_INFORMATION pSPI; PPERFDATA pPDOld; ULONG Idx, Idx2; HANDLE hProcess; HANDLE hProcessToken; TCHAR szTemp[MAX_PATH]; DWORD dwSize; SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo; SYSTEM_TIME_INFORMATION SysTimeInfo; SYSTEM_CACHE_INFORMATION SysCacheInfo; LPBYTE SysHandleInfoData; PSYSTEM_PROCESSORTIME_INFO SysProcessorTimeInfo; double CurrentKernelTime; if (!NtQuerySystemInformation) return; /* Get new system time */ status = NtQuerySystemInformation(SystemTimeInformation, &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(SystemCacheInformation, &SysCacheInfo, sizeof(SysCacheInfo), NULL); if (status != NO_ERROR) return; /* Get processor time information */ SysProcessorTimeInfo = (PSYSTEM_PROCESSORTIME_INFO)malloc(sizeof(SYSTEM_PROCESSORTIME_INFO) * SystemBasicInfo.bKeNumberProcessors); status = NtQuerySystemInformation(SystemProcessorTimeInformation, SysProcessorTimeInfo, sizeof(SYSTEM_PROCESSORTIME_INFO) * SystemBasicInfo.bKeNumberProcessors, &ulSize); if (status != NO_ERROR) { free(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 = (LPBYTE)malloc(BufferSize); status = NtQuerySystemInformation(SystemHandleInformation, SysHandleInfoData, BufferSize, &ulSize); if (status == 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/) { free(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 = (LPBYTE)malloc(BufferSize); status = NtQuerySystemInformation(SystemProcessInformation, pBuffer, BufferSize, &ulSize); if (status == 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/) { free(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 */ free(SystemProcessorTimeInfo); SystemProcessorTimeInfo = SysProcessorTimeInfo; /* * Save system handle info */ memcpy(&SystemHandleInfo, SysHandleInfoData, sizeof(SYSTEM_HANDLE_INFORMATION)); free(SysHandleInfoData); for (CurrentKernelTime=0, Idx=0; IdxRelativeOffset == 0) break; pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->RelativeOffset); } /* Now alloc a new PERFDATA array and fill in the data */ free(pPerfDataOld); pPerfDataOld = pPerfData; pPerfData = (PPERFDATA)malloc(sizeof(PERFDATA) * ProcessCount); pSPI = (PSYSTEM_PROCESS_INFORMATION)pBuffer; for (Idx=0; IdxProcessId) { pPDOld = &pPerfDataOld[Idx2]; break; } } /* Clear out process perf data structure */ memset(&pPerfData[Idx], 0, sizeof(PERFDATA)); if (pSPI->Name.Buffer) lstrcpyW(pPerfData[Idx].ImageName, pSPI->Name.Buffer); else { static const WCHAR idleW[] = {'S','y','s','t','e','m',' ','I','d','l','e',' ','P','r','o','c','e','s','s',0}; lstrcpyW(pPerfData[Idx].ImageName, idleW ); } pPerfData[Idx].ProcessId = pSPI->ProcessId; 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.bKeNumberProcessors; /* + 0.5; */ pPerfData[Idx].CPUUsage = (ULONG)CpuTime; } pPerfData[Idx].CPUTime.QuadPart = pSPI->UserTime.QuadPart + pSPI->KernelTime.QuadPart; pPerfData[Idx].WorkingSetSizeBytes = pSPI->TotalWorkingSetSizeBytes; pPerfData[Idx].PeakWorkingSetSizeBytes = pSPI->PeakWorkingSetSizeBytes; if (pPDOld) pPerfData[Idx].WorkingSetSizeDelta = labs((LONG)pSPI->TotalWorkingSetSizeBytes - (LONG)pPDOld->WorkingSetSizeBytes); else pPerfData[Idx].WorkingSetSizeDelta = 0; pPerfData[Idx].PageFaultCount = pSPI->PageFaultCount; if (pPDOld) pPerfData[Idx].PageFaultCountDelta = labs((LONG)pSPI->PageFaultCount - (LONG)pPDOld->PageFaultCount); else pPerfData[Idx].PageFaultCountDelta = 0; pPerfData[Idx].VirtualMemorySizeBytes = pSPI->TotalVirtualSizeBytes; pPerfData[Idx].PagedPoolUsagePages = pSPI->TotalPagedPoolUsagePages; pPerfData[Idx].NonPagedPoolUsagePages = pSPI->TotalNonPagedPoolUsagePages; pPerfData[Idx].BasePriority = pSPI->BasePriority; pPerfData[Idx].HandleCount = pSPI->HandleCount; pPerfData[Idx].ThreadCount = pSPI->ThreadCount; pPerfData[Idx].SessionId = pSPI->SessionId; hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pSPI->ProcessId); if (hProcess) { if (OpenProcessToken(hProcess, TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_IMPERSONATE, &hProcessToken)) { ImpersonateLoggedOnUser(hProcessToken); memset(szTemp, 0, sizeof(TCHAR[MAX_PATH])); dwSize = MAX_PATH; GetUserName(szTemp, &dwSize); #ifndef UNICODE MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szTemp, -1, pPerfData[Idx].UserName, MAX_PATH); /* int MultiByteToWideChar( UINT CodePage, // code page DWORD dwFlags, // character-type options LPCSTR lpMultiByteStr, // string to map int cbMultiByte, // number of bytes in string LPWSTR lpWideCharStr, // wide-character buffer int cchWideChar // size of buffer ); */ #endif RevertToSelf(); CloseHandle(hProcessToken); } if (pGetGuiResources) { pPerfData[Idx].USERObjectCount = pGetGuiResources(hProcess, GR_USEROBJECTS); pPerfData[Idx].GDIObjectCount = pGetGuiResources(hProcess, GR_GDIOBJECTS); } if (pGetProcessIoCounters) pGetProcessIoCounters(hProcess, &pPerfData[Idx].IOCounters); CloseHandle(hProcess); } pPerfData[Idx].UserTime.QuadPart = pSPI->UserTime.QuadPart; pPerfData[Idx].KernelTime.QuadPart = pSPI->KernelTime.QuadPart; pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->RelativeOffset); } free(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, LPTSTR lpImageName, int nMaxCount) { BOOL bSuccessful; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) { #ifdef _UNICODE wcsncpy(lpImageName, pPerfData[Index].ImageName, nMaxCount); #else WideCharToMultiByte(CP_ACP, 0, pPerfData[Index].ImageName, -1, lpImageName, nMaxCount, NULL, NULL); #endif 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, LPTSTR lpUserName, int nMaxCount) { BOOL bSuccessful; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) { #ifdef _UNICODE wcsncpy(lpUserName, pPerfData[Index].UserName, nMaxCount); #else WideCharToMultiByte(CP_ACP, 0, pPerfData[Index].UserName, -1, lpUserName, nMaxCount, NULL, NULL); #endif 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].WorkingSetSizeBytes; else WorkingSetSizeBytes = 0; LeaveCriticalSection(&PerfDataCriticalSection); return WorkingSetSizeBytes; } ULONG PerfDataGetPeakWorkingSetSizeBytes(ULONG Index) { ULONG PeakWorkingSetSizeBytes; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) PeakWorkingSetSizeBytes = pPerfData[Index].PeakWorkingSetSizeBytes; 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].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].VirtualMemorySizeBytes; else VirtualMemorySizeBytes = 0; LeaveCriticalSection(&PerfDataCriticalSection); return VirtualMemorySizeBytes; } ULONG PerfDataGetPagedPoolUsagePages(ULONG Index) { ULONG PagedPoolUsagePages; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) PagedPoolUsagePages = pPerfData[Index].PagedPoolUsagePages; else PagedPoolUsagePages = 0; LeaveCriticalSection(&PerfDataCriticalSection); return PagedPoolUsagePages; } ULONG PerfDataGetNonPagedPoolUsagePages(ULONG Index) { ULONG NonPagedPoolUsagePages; EnterCriticalSection(&PerfDataCriticalSection); if (Index < ProcessCount) NonPagedPoolUsagePages = pPerfData[Index].NonPagedPoolUsagePages; 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.MmTotalCommittedPages; PageSize = SystemBasicInfo.uPageSize; LeaveCriticalSection(&PerfDataCriticalSection); Total = Total * (PageSize / 1024); return Total; } ULONG PerfDataGetCommitChargeLimitK(void) { ULONG Limit; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Limit = SystemPerfInfo.MmTotalCommitLimit; PageSize = SystemBasicInfo.uPageSize; LeaveCriticalSection(&PerfDataCriticalSection); Limit = Limit * (PageSize / 1024); return Limit; } ULONG PerfDataGetCommitChargePeakK(void) { ULONG Peak; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Peak = SystemPerfInfo.MmPeakLimit; PageSize = SystemBasicInfo.uPageSize; LeaveCriticalSection(&PerfDataCriticalSection); Peak = Peak * (PageSize / 1024); return Peak; } ULONG PerfDataGetKernelMemoryTotalK(void) { ULONG Total; ULONG Paged; ULONG NonPaged; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Paged = SystemPerfInfo.PoolPagedBytes; NonPaged = SystemPerfInfo.PoolNonPagedBytes; PageSize = SystemBasicInfo.uPageSize; 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.PoolPagedBytes; PageSize = SystemBasicInfo.uPageSize; LeaveCriticalSection(&PerfDataCriticalSection); Paged = Paged * (PageSize / 1024); return Paged; } ULONG PerfDataGetKernelMemoryNonPagedK(void) { ULONG NonPaged; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); NonPaged = SystemPerfInfo.PoolNonPagedBytes; PageSize = SystemBasicInfo.uPageSize; LeaveCriticalSection(&PerfDataCriticalSection); NonPaged = NonPaged * (PageSize / 1024); return NonPaged; } ULONG PerfDataGetPhysicalMemoryTotalK(void) { ULONG Total; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Total = SystemBasicInfo.uMmNumberOfPhysicalPages; PageSize = SystemBasicInfo.uPageSize; LeaveCriticalSection(&PerfDataCriticalSection); Total = Total * (PageSize / 1024); return Total; } ULONG PerfDataGetPhysicalMemoryAvailableK(void) { ULONG Available; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); Available = SystemPerfInfo.MmAvailablePages; PageSize = SystemBasicInfo.uPageSize; LeaveCriticalSection(&PerfDataCriticalSection); Available = Available * (PageSize / 1024); return Available; } ULONG PerfDataGetPhysicalMemorySystemCacheK(void) { ULONG SystemCache; ULONG PageSize; EnterCriticalSection(&PerfDataCriticalSection); SystemCache = SystemCacheInfo.CurrentSize; PageSize = SystemBasicInfo.uPageSize; LeaveCriticalSection(&PerfDataCriticalSection); /* SystemCache = SystemCache * (PageSize / 1024); */ 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