Reactos
at master 1134 lines 33 kB view raw
1/* 2 * PROJECT: ReactOS Task Manager 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Performance Counters 5 * COPYRIGHT: Copyright 1999-2001 Brian Palmer <brianp@reactos.org> 6 * Copyright 2014 Ismael Ferreras Morezuelas <swyterzone+ros@gmail.com> 7 */ 8 9#include "precomp.h" 10 11#define WIN32_LEAN_AND_MEAN 12#include <aclapi.h> 13 14#define NTOS_MODE_USER 15#include <ndk/psfuncs.h> 16#include <ndk/exfuncs.h> 17 18CRITICAL_SECTION PerfDataCriticalSection; 19PPERFDATA pPerfDataOld = NULL; /* Older perf data (saved to establish delta values) */ 20PPERFDATA pPerfData = NULL; /* Most recent copy of perf data */ 21ULONG ProcessCountOld = 0; 22ULONG ProcessCount = 0; 23double dbIdleTime; 24double dbKernelTime; 25double dbSystemTime; 26LARGE_INTEGER liOldIdleTime = {{0,0}}; 27double OldKernelTime = 0; 28LARGE_INTEGER liOldSystemTime = {{0,0}}; 29SYSTEM_PERFORMANCE_INFORMATION SystemPerfInfo; 30SYSTEM_BASIC_INFORMATION SystemBasicInfo; 31SYSTEM_FILECACHE_INFORMATION SystemCacheInfo; 32ULONG SystemNumberOfHandles; 33PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SystemProcessorTimeInfo = NULL; 34PSID SystemUserSid = NULL; 35 36PCMD_LINE_CACHE global_cache = NULL; 37 38#define CMD_LINE_MIN(a, b) (a < b ? a - sizeof(WCHAR) : b) 39 40typedef struct _SIDTOUSERNAME 41{ 42 LIST_ENTRY List; 43 LPWSTR pszName; 44 BYTE Data[0]; 45} SIDTOUSERNAME, *PSIDTOUSERNAME; 46 47static LIST_ENTRY SidToUserNameHead = {&SidToUserNameHead, &SidToUserNameHead}; 48 49BOOL PerfDataInitialize(void) 50{ 51 SID_IDENTIFIER_AUTHORITY NtSidAuthority = {SECURITY_NT_AUTHORITY}; 52 NTSTATUS status; 53 54 InitializeCriticalSection(&PerfDataCriticalSection); 55 56 /* 57 * Get number of processors in the system 58 */ 59 status = NtQuerySystemInformation(SystemBasicInformation, &SystemBasicInfo, sizeof(SystemBasicInfo), NULL); 60 if (!NT_SUCCESS(status)) 61 return FALSE; 62 63 /* 64 * Create the SYSTEM Sid 65 */ 66 AllocateAndInitializeSid(&NtSidAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &SystemUserSid); 67 68 /* 69 * Set up global info storage 70 */ 71 SystemProcessorTimeInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)HeapAlloc(GetProcessHeap(), 72 0, sizeof(*SystemProcessorTimeInfo) * SystemBasicInfo.NumberOfProcessors); 73 74 return SystemProcessorTimeInfo != NULL; 75} 76 77void PerfDataUninitialize(void) 78{ 79 PLIST_ENTRY pCur; 80 PSIDTOUSERNAME pEntry; 81 82 if (pPerfData != NULL) 83 HeapFree(GetProcessHeap(), 0, pPerfData); 84 85 DeleteCriticalSection(&PerfDataCriticalSection); 86 87 if (SystemUserSid != NULL) 88 { 89 FreeSid(SystemUserSid); 90 SystemUserSid = NULL; 91 } 92 93 /* Free user names cache list */ 94 pCur = SidToUserNameHead.Flink; 95 while (pCur != &SidToUserNameHead) 96 { 97 pEntry = CONTAINING_RECORD(pCur, SIDTOUSERNAME, List); 98 pCur = pCur->Flink; 99 HeapFree(GetProcessHeap(), 0, pEntry); 100 } 101 102 if (SystemProcessorTimeInfo) { 103 HeapFree(GetProcessHeap(), 0, SystemProcessorTimeInfo); 104 } 105} 106 107static void SidToUserName(PSID Sid, LPWSTR szBuffer, DWORD BufferSize) 108{ 109 static WCHAR szDomainNameUnused[255]; 110 DWORD DomainNameLen = _countof(szDomainNameUnused); 111 SID_NAME_USE Use; 112 113 if (Sid != NULL) 114 LookupAccountSidW(NULL, Sid, szBuffer, &BufferSize, szDomainNameUnused, &DomainNameLen, &Use); 115} 116 117VOID 118WINAPI 119CachedGetUserFromSid( 120 PSID pSid, 121 LPWSTR pUserName, 122 PULONG pcwcUserName) 123{ 124 PLIST_ENTRY pCur; 125 PSIDTOUSERNAME pEntry; 126 ULONG cbSid, cwcUserName; 127 128 cwcUserName = *pcwcUserName; 129 130 /* Walk through the list */ 131 for(pCur = SidToUserNameHead.Flink; 132 pCur != &SidToUserNameHead; 133 pCur = pCur->Flink) 134 { 135 pEntry = CONTAINING_RECORD(pCur, SIDTOUSERNAME, List); 136 if (EqualSid((PSID)&pEntry->Data, pSid)) 137 { 138 wcsncpy(pUserName, pEntry->pszName, cwcUserName); 139 *pcwcUserName = wcslen(pUserName); 140 return; 141 } 142 } 143 144 /* We didn't find the SID in the list, get the name conventional */ 145 SidToUserName(pSid, pUserName, cwcUserName); 146 *pcwcUserName = wcslen(pUserName); 147 148 /* Allocate a new entry */ 149 cwcUserName = *pcwcUserName + 1; 150 cbSid = GetLengthSid(pSid); 151 pEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(SIDTOUSERNAME) + cbSid + cwcUserName * sizeof(WCHAR)); 152 153 /* Copy the Sid and name to our entry */ 154 CopySid(cbSid, (PSID)&pEntry->Data, pSid); 155 pEntry->pszName = (LPWSTR)(pEntry->Data + cbSid); 156 wcsncpy(pEntry->pszName, pUserName, cwcUserName); 157 158 /* Insert the new entry */ 159 pEntry->List.Flink = &SidToUserNameHead; 160 pEntry->List.Blink = SidToUserNameHead.Blink; 161 SidToUserNameHead.Blink->Flink = &pEntry->List; 162 SidToUserNameHead.Blink = &pEntry->List; 163} 164 165void PerfDataRefresh(void) 166{ 167 ULONG ulSize; 168 NTSTATUS status; 169 LPBYTE pBuffer; 170 ULONG BufferSize; 171 PSYSTEM_PROCESS_INFORMATION pSPI; 172 PPERFDATA pPDOld; 173 ULONG Idx, Idx2; 174 HANDLE hProcess; 175 HANDLE hProcessToken; 176 SYSTEM_PERFORMANCE_INFORMATION SysPerfInfo; 177 SYSTEM_TIMEOFDAY_INFORMATION SysTimeInfo; 178 SYSTEM_FILECACHE_INFORMATION SysCacheInfo; 179 SYSTEM_HANDLE_INFORMATION SysHandleInfoData; 180 PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION SysProcessorTimeInfo; 181 double CurrentKernelTime; 182 PSECURITY_DESCRIPTOR ProcessSD; 183 PSID ProcessUser; 184 ULONG Buffer[64]; /* must be 4 bytes aligned! */ 185 ULONG cwcUserName; 186 BOOL bIsWow64; 187 188 /* Get new system time */ 189 status = NtQuerySystemInformation(SystemTimeOfDayInformation, &SysTimeInfo, sizeof(SysTimeInfo), NULL); 190 if (!NT_SUCCESS(status)) 191 return; 192 193 /* Get new CPU's idle time */ 194 status = NtQuerySystemInformation(SystemPerformanceInformation, &SysPerfInfo, sizeof(SysPerfInfo), NULL); 195 if (!NT_SUCCESS(status)) 196 return; 197 198 /* Get system cache information */ 199 status = NtQuerySystemInformation(SystemFileCacheInformation, &SysCacheInfo, sizeof(SysCacheInfo), NULL); 200 if (!NT_SUCCESS(status)) 201 return; 202 203 /* Get processor time information */ 204 SysProcessorTimeInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)HeapAlloc(GetProcessHeap(), 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors); 205 status = NtQuerySystemInformation(SystemProcessorPerformanceInformation, SysProcessorTimeInfo, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) * SystemBasicInfo.NumberOfProcessors, &ulSize); 206 207 if (!NT_SUCCESS(status)) 208 { 209 if (SysProcessorTimeInfo != NULL) 210 HeapFree(GetProcessHeap(), 0, SysProcessorTimeInfo); 211 return; 212 } 213 214 /* Get handle information 215 * Number of handles is enough, no need for data array. 216 */ 217 status = NtQuerySystemInformation(SystemHandleInformation, &SysHandleInfoData, sizeof(SysHandleInfoData), NULL); 218 /* On unexpected error, reuse previous value. 219 * STATUS_SUCCESS (0-1 handle) should never happen. 220 */ 221 if (status != STATUS_INFO_LENGTH_MISMATCH) 222 SysHandleInfoData.NumberOfHandles = SystemNumberOfHandles; 223 224 /* Get process information 225 * We don't know how much data there is so just keep 226 * increasing the buffer size until the call succeeds 227 */ 228 BufferSize = 0; 229 do 230 { 231 BufferSize += 0x10000; 232 pBuffer = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, BufferSize); 233 234 status = NtQuerySystemInformation(SystemProcessInformation, pBuffer, BufferSize, &ulSize); 235 236 if (status == STATUS_INFO_LENGTH_MISMATCH) { 237 HeapFree(GetProcessHeap(), 0, pBuffer); 238 } 239 240 } while (status == STATUS_INFO_LENGTH_MISMATCH); 241 242 EnterCriticalSection(&PerfDataCriticalSection); 243 244 /* 245 * Save system performance info 246 */ 247 memcpy(&SystemPerfInfo, &SysPerfInfo, sizeof(SYSTEM_PERFORMANCE_INFORMATION)); 248 249 /* 250 * Save system cache info 251 */ 252 memcpy(&SystemCacheInfo, &SysCacheInfo, sizeof(SYSTEM_FILECACHE_INFORMATION)); 253 254 /* 255 * Save system processor time info 256 */ 257 memcpy(SystemProcessorTimeInfo, SysProcessorTimeInfo, 258 sizeof(*SystemProcessorTimeInfo) * SystemBasicInfo.NumberOfProcessors); 259 260 if (SysProcessorTimeInfo) { 261 HeapFree(GetProcessHeap(), 0, SysProcessorTimeInfo); 262 } 263 264 /* 265 * Save system handle info 266 */ 267 SystemNumberOfHandles = SysHandleInfoData.NumberOfHandles; 268 269 for (CurrentKernelTime=0, Idx=0; Idx<(ULONG)SystemBasicInfo.NumberOfProcessors; Idx++) { 270 CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].KernelTime); 271 CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].DpcTime); 272 CurrentKernelTime += Li2Double(SystemProcessorTimeInfo[Idx].InterruptTime); 273 } 274 275 /* If it's a first call - skip idle time calcs */ 276 if (liOldIdleTime.QuadPart != 0) { 277 /* CurrentValue = NewValue - OldValue */ 278 dbIdleTime = Li2Double(SysPerfInfo.IdleProcessTime) - Li2Double(liOldIdleTime); 279 dbKernelTime = CurrentKernelTime - OldKernelTime; 280 dbSystemTime = Li2Double(SysTimeInfo.CurrentTime) - Li2Double(liOldSystemTime); 281 282 /* CurrentCpuIdle = IdleTime / SystemTime */ 283 dbIdleTime = dbIdleTime / dbSystemTime; 284 dbKernelTime = dbKernelTime / dbSystemTime; 285 286 /* CurrentCpuUsage% = 100 - (CurrentCpuIdle * 100) / NumberOfProcessors */ 287 dbIdleTime = 100.0 - dbIdleTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */ 288 dbKernelTime = 100.0 - dbKernelTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */ 289 } 290 291 /* Store new CPU's idle and system time */ 292 liOldIdleTime = SysPerfInfo.IdleProcessTime; 293 liOldSystemTime = SysTimeInfo.CurrentTime; 294 OldKernelTime = CurrentKernelTime; 295 296 /* Determine the process count 297 * We loop through the data we got from NtQuerySystemInformation 298 * and count how many structures there are (until RelativeOffset is 0) 299 */ 300 ProcessCountOld = ProcessCount; 301 ProcessCount = 0; 302 pSPI = (PSYSTEM_PROCESS_INFORMATION)pBuffer; 303 while (pSPI) { 304 ProcessCount++; 305 if (pSPI->NextEntryOffset == 0) 306 break; 307 pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset); 308 } 309 310 /* Now alloc a new PERFDATA array and fill in the data */ 311 pPerfData = (PPERFDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PERFDATA) * ProcessCount); 312 313 pSPI = (PSYSTEM_PROCESS_INFORMATION)pBuffer; 314 for (Idx=0; Idx<ProcessCount; Idx++) { 315 /* Get the old perf data for this process (if any) */ 316 /* so that we can establish delta values */ 317 pPDOld = NULL; 318 if (pPerfDataOld) { 319 for (Idx2=0; Idx2<ProcessCountOld; Idx2++) { 320 if (pPerfDataOld[Idx2].ProcessId == pSPI->UniqueProcessId) { 321 pPDOld = &pPerfDataOld[Idx2]; 322 break; 323 } 324 } 325 } 326 327 if (pSPI->ImageName.Buffer) { 328 /* Don't assume a UNICODE_STRING Buffer is zero terminated: */ 329 int len = pSPI->ImageName.Length / 2; 330 /* Check against max size and allow for terminating zero (already zeroed): */ 331 if(len >= MAX_PATH)len=MAX_PATH - 1; 332 wcsncpy(pPerfData[Idx].ImageName, pSPI->ImageName.Buffer, len); 333 } else { 334 LoadStringW(hInst, IDS_IDLE_PROCESS, pPerfData[Idx].ImageName, 335 _countof(pPerfData[Idx].ImageName)); 336 } 337 338 pPerfData[Idx].ProcessId = pSPI->UniqueProcessId; 339 340 if (pPDOld) { 341 double CurTime = Li2Double(pSPI->KernelTime) + Li2Double(pSPI->UserTime); 342 double OldTime = Li2Double(pPDOld->KernelTime) + Li2Double(pPDOld->UserTime); 343 double CpuTime = (CurTime - OldTime) / dbSystemTime; 344 CpuTime = CpuTime * 100.0 / (double)SystemBasicInfo.NumberOfProcessors; /* + 0.5; */ 345 pPerfData[Idx].CPUUsage = (ULONG)CpuTime; 346 } 347 pPerfData[Idx].CPUTime.QuadPart = pSPI->UserTime.QuadPart + pSPI->KernelTime.QuadPart; 348 pPerfData[Idx].WorkingSetSizeBytes = pSPI->WorkingSetSize; 349 pPerfData[Idx].PeakWorkingSetSizeBytes = pSPI->PeakWorkingSetSize; 350 if (pPDOld) 351 pPerfData[Idx].WorkingSetSizeDelta = labs((LONG)pSPI->WorkingSetSize - (LONG)pPDOld->WorkingSetSizeBytes); 352 else 353 pPerfData[Idx].WorkingSetSizeDelta = 0; 354 pPerfData[Idx].PageFaultCount = pSPI->PageFaultCount; 355 if (pPDOld) 356 pPerfData[Idx].PageFaultCountDelta = labs((LONG)pSPI->PageFaultCount - (LONG)pPDOld->PageFaultCount); 357 else 358 pPerfData[Idx].PageFaultCountDelta = 0; 359 pPerfData[Idx].VirtualMemorySizeBytes = pSPI->VirtualSize; 360 pPerfData[Idx].PagedPoolUsagePages = pSPI->QuotaPeakPagedPoolUsage; 361 pPerfData[Idx].NonPagedPoolUsagePages = pSPI->QuotaPeakNonPagedPoolUsage; 362 pPerfData[Idx].BasePriority = pSPI->BasePriority; 363 pPerfData[Idx].HandleCount = pSPI->HandleCount; 364 pPerfData[Idx].ThreadCount = pSPI->NumberOfThreads; 365 pPerfData[Idx].SessionId = pSPI->SessionId; 366 pPerfData[Idx].UserName[0] = UNICODE_NULL; 367 pPerfData[Idx].USERObjectCount = 0; 368 pPerfData[Idx].GDIObjectCount = 0; 369 ProcessUser = SystemUserSid; 370 ProcessSD = NULL; 371 372 if (pSPI->UniqueProcessId != NULL) { 373 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | READ_CONTROL, FALSE, PtrToUlong(pSPI->UniqueProcessId)); 374 if (hProcess) { 375 /* don't query the information of the system process. It's possible but 376 returns Administrators as the owner of the process instead of SYSTEM */ 377 if (pSPI->UniqueProcessId != (HANDLE)0x4) 378 { 379 if (OpenProcessToken(hProcess, TOKEN_QUERY, &hProcessToken)) 380 { 381 DWORD RetLen = 0; 382 BOOL Ret; 383 384 Ret = GetTokenInformation(hProcessToken, TokenUser, (LPVOID)Buffer, sizeof(Buffer), &RetLen); 385 CloseHandle(hProcessToken); 386 387 if (Ret) 388 ProcessUser = ((PTOKEN_USER)Buffer)->User.Sid; 389 else 390 goto ReadProcOwner; 391 } 392 else 393 { 394ReadProcOwner: 395 GetSecurityInfo(hProcess, SE_KERNEL_OBJECT, OWNER_SECURITY_INFORMATION, &ProcessUser, NULL, NULL, NULL, &ProcessSD); 396 } 397 398 pPerfData[Idx].USERObjectCount = GetGuiResources(hProcess, GR_USEROBJECTS); 399 pPerfData[Idx].GDIObjectCount = GetGuiResources(hProcess, GR_GDIOBJECTS); 400 } 401 402 if (IsWow64Process(hProcess, &bIsWow64) && bIsWow64) 403 { 404 wcscat(pPerfData[Idx].ImageName, L" *32"); 405 } 406 407 GetProcessIoCounters(hProcess, &pPerfData[Idx].IOCounters); 408 CloseHandle(hProcess); 409 } else { 410 goto ClearInfo; 411 } 412 } else { 413ClearInfo: 414 /* clear information we were unable to fetch */ 415 ZeroMemory(&pPerfData[Idx].IOCounters, sizeof(IO_COUNTERS)); 416 } 417 418 cwcUserName = _countof(pPerfData[0].UserName); 419 CachedGetUserFromSid(ProcessUser, pPerfData[Idx].UserName, &cwcUserName); 420 421 if (ProcessSD != NULL) 422 { 423 LocalFree((HLOCAL)ProcessSD); 424 } 425 426 pPerfData[Idx].UserTime.QuadPart = pSPI->UserTime.QuadPart; 427 pPerfData[Idx].KernelTime.QuadPart = pSPI->KernelTime.QuadPart; 428 pSPI = (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)pSPI + pSPI->NextEntryOffset); 429 } 430 HeapFree(GetProcessHeap(), 0, pBuffer); 431 if (pPerfDataOld) { 432 HeapFree(GetProcessHeap(), 0, pPerfDataOld); 433 } 434 pPerfDataOld = pPerfData; 435 LeaveCriticalSection(&PerfDataCriticalSection); 436} 437 438ULONG PerfDataGetProcessIndex(ULONG pid) 439{ 440 ULONG idx; 441 442 EnterCriticalSection(&PerfDataCriticalSection); 443 444 for (idx = 0; idx < ProcessCount; idx++) 445 { 446 if (PtrToUlong(pPerfData[idx].ProcessId) == pid) 447 { 448 break; 449 } 450 } 451 452 LeaveCriticalSection(&PerfDataCriticalSection); 453 454 if (idx == ProcessCount) 455 { 456 return -1; 457 } 458 return idx; 459} 460 461ULONG PerfDataGetProcessCount(void) 462{ 463 ULONG Result; 464 EnterCriticalSection(&PerfDataCriticalSection); 465 Result = ProcessCount; 466 LeaveCriticalSection(&PerfDataCriticalSection); 467 return Result; 468} 469 470ULONG PerfDataGetProcessorUsage(void) 471{ 472 ULONG Result; 473 EnterCriticalSection(&PerfDataCriticalSection); 474 Result = (ULONG)min(max(dbIdleTime, 0.), 100.); 475 LeaveCriticalSection(&PerfDataCriticalSection); 476 return Result; 477} 478 479ULONG PerfDataGetProcessorSystemUsage(void) 480{ 481 ULONG Result; 482 EnterCriticalSection(&PerfDataCriticalSection); 483 Result = (ULONG)min(max(dbKernelTime, 0.), 100.); 484 LeaveCriticalSection(&PerfDataCriticalSection); 485 return Result; 486} 487 488BOOL PerfDataGetImageName(ULONG Index, LPWSTR lpImageName, ULONG nMaxCount) 489{ 490 BOOL bSuccessful; 491 492 EnterCriticalSection(&PerfDataCriticalSection); 493 494 if (Index < ProcessCount) { 495 wcsncpy(lpImageName, pPerfData[Index].ImageName, nMaxCount); 496 bSuccessful = TRUE; 497 } else { 498 bSuccessful = FALSE; 499 } 500 LeaveCriticalSection(&PerfDataCriticalSection); 501 return bSuccessful; 502} 503 504ULONG PerfDataGetProcessId(ULONG Index) 505{ 506 ULONG ProcessId; 507 508 EnterCriticalSection(&PerfDataCriticalSection); 509 510 if (Index < ProcessCount) 511 ProcessId = PtrToUlong(pPerfData[Index].ProcessId); 512 else 513 ProcessId = 0; 514 515 LeaveCriticalSection(&PerfDataCriticalSection); 516 517 return ProcessId; 518} 519 520BOOL PerfDataGetUserName(ULONG Index, LPWSTR lpUserName, ULONG nMaxCount) 521{ 522 BOOL bSuccessful; 523 524 EnterCriticalSection(&PerfDataCriticalSection); 525 526 if (Index < ProcessCount) { 527 wcsncpy(lpUserName, pPerfData[Index].UserName, nMaxCount); 528 bSuccessful = TRUE; 529 } else { 530 bSuccessful = FALSE; 531 } 532 533 LeaveCriticalSection(&PerfDataCriticalSection); 534 535 return bSuccessful; 536} 537 538BOOL PerfDataGetCommandLine(ULONG Index, LPWSTR lpCommandLine, ULONG nMaxCount) 539{ 540 static const LPWSTR ellipsis = L"..."; 541 542 PROCESS_BASIC_INFORMATION pbi = {0}; 543 UNICODE_STRING CommandLineStr = {0}; 544 545 PVOID ProcessParams = NULL; 546 HANDLE hProcess; 547 ULONG ProcessId; 548 549 NTSTATUS Status; 550 BOOL result; 551 552 PCMD_LINE_CACHE new_entry; 553 LPWSTR new_string; 554 555 PCMD_LINE_CACHE cache = global_cache; 556 557 /* [A] Search for a string already in cache? If so, use it */ 558 while (cache && cache->pnext != NULL) 559 { 560 if (cache->idx == Index && cache->str != NULL) 561 { 562 /* Found it. Use it, and add some ellipsis at the very end to make it cute */ 563 wcsncpy(lpCommandLine, cache->str, CMD_LINE_MIN(nMaxCount, cache->len)); 564 wcscpy(lpCommandLine + CMD_LINE_MIN(nMaxCount, cache->len) - wcslen(ellipsis), ellipsis); 565 return TRUE; 566 } 567 568 cache = cache->pnext; 569 } 570 571 /* [B] We don't; let's allocate and load a value from the process mem... and cache it */ 572 ProcessId = PerfDataGetProcessId(Index); 573 574 /* Default blank command line in case things don't work out */ 575 wcsncpy(lpCommandLine, L"", nMaxCount); 576 577 /* Ask for a handle to the target process so that we can read its memory and query stuff */ 578 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ProcessId); 579 if (!hProcess) 580 goto cleanup; 581 582 /* First off, get the ProcessEnvironmentBlock location in that process' address space */ 583 Status = NtQueryInformationProcess(hProcess, 0, &pbi, sizeof(pbi), NULL); 584 if (!NT_SUCCESS(Status)) 585 goto cleanup; 586 587 /* Then get the PEB.ProcessParameters member pointer */ 588 result = ReadProcessMemory(hProcess, 589 (PVOID)((ULONG_PTR)pbi.PebBaseAddress + FIELD_OFFSET(PEB, ProcessParameters)), 590 &ProcessParams, 591 sizeof(ProcessParams), 592 NULL); 593 if (!result) 594 goto cleanup; 595 596 /* Then copy the PEB->ProcessParameters.CommandLine member 597 to get the pointer to the string buffer and its size */ 598 result = ReadProcessMemory(hProcess, 599 (PVOID)((ULONG_PTR)ProcessParams + FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, CommandLine)), 600 &CommandLineStr, 601 sizeof(CommandLineStr), 602 NULL); 603 if (!result) 604 goto cleanup; 605 606 /* Allocate the next cache entry and its accompanying string in one go */ 607 new_entry = HeapAlloc(GetProcessHeap(), 608 HEAP_ZERO_MEMORY, 609 sizeof(CMD_LINE_CACHE) + CommandLineStr.Length + sizeof(UNICODE_NULL)); 610 if (!new_entry) 611 goto cleanup; 612 613 new_string = (LPWSTR)((ULONG_PTR)new_entry + sizeof(CMD_LINE_CACHE)); 614 615 /* Bingo, the command line should be stored there, 616 copy the string from the other process */ 617 result = ReadProcessMemory(hProcess, 618 CommandLineStr.Buffer, 619 new_string, 620 CommandLineStr.Length, 621 NULL); 622 if (!result) 623 { 624 /* Weird, after successfully reading the mem of that process 625 various times it fails now, forget it and bail out */ 626 HeapFree(GetProcessHeap(), 0, new_entry); 627 goto cleanup; 628 } 629 630 /* Add our pointer to the cache... */ 631 new_entry->idx = Index; 632 new_entry->str = new_string; 633 new_entry->len = CommandLineStr.Length; 634 635 if (!global_cache) 636 global_cache = new_entry; 637 else 638 cache->pnext = new_entry; 639 640 /* ... and print the buffer for the first time */ 641 wcsncpy(lpCommandLine, new_string, CMD_LINE_MIN(nMaxCount, CommandLineStr.Length)); 642 643cleanup: 644 if (hProcess) CloseHandle(hProcess); 645 return TRUE; 646} 647 648void PerfDataDeallocCommandLineCache() 649{ 650 PCMD_LINE_CACHE cache, pnext; 651 652 for (cache = global_cache; cache; cache = pnext) 653 { 654 pnext = cache->pnext; 655 HeapFree(GetProcessHeap(), 0, cache); 656 } 657 658 global_cache = NULL; 659} 660 661ULONG PerfDataGetSessionId(ULONG Index) 662{ 663 ULONG SessionId; 664 665 EnterCriticalSection(&PerfDataCriticalSection); 666 667 if (Index < ProcessCount) 668 SessionId = pPerfData[Index].SessionId; 669 else 670 SessionId = 0; 671 672 LeaveCriticalSection(&PerfDataCriticalSection); 673 674 return SessionId; 675} 676 677ULONG PerfDataGetCPUUsage(ULONG Index) 678{ 679 ULONG CpuUsage; 680 681 EnterCriticalSection(&PerfDataCriticalSection); 682 683 if (Index < ProcessCount) 684 CpuUsage = pPerfData[Index].CPUUsage; 685 else 686 CpuUsage = 0; 687 688 LeaveCriticalSection(&PerfDataCriticalSection); 689 690 return CpuUsage; 691} 692 693LARGE_INTEGER PerfDataGetCPUTime(ULONG Index) 694{ 695 LARGE_INTEGER CpuTime = {{0,0}}; 696 697 EnterCriticalSection(&PerfDataCriticalSection); 698 699 if (Index < ProcessCount) 700 CpuTime = pPerfData[Index].CPUTime; 701 702 LeaveCriticalSection(&PerfDataCriticalSection); 703 704 return CpuTime; 705} 706 707ULONG PerfDataGetWorkingSetSizeBytes(ULONG Index) 708{ 709 ULONG WorkingSetSizeBytes; 710 711 EnterCriticalSection(&PerfDataCriticalSection); 712 713 if (Index < ProcessCount) 714 WorkingSetSizeBytes = pPerfData[Index].WorkingSetSizeBytes; 715 else 716 WorkingSetSizeBytes = 0; 717 718 LeaveCriticalSection(&PerfDataCriticalSection); 719 720 return WorkingSetSizeBytes; 721} 722 723ULONG PerfDataGetPeakWorkingSetSizeBytes(ULONG Index) 724{ 725 ULONG PeakWorkingSetSizeBytes; 726 727 EnterCriticalSection(&PerfDataCriticalSection); 728 729 if (Index < ProcessCount) 730 PeakWorkingSetSizeBytes = pPerfData[Index].PeakWorkingSetSizeBytes; 731 else 732 PeakWorkingSetSizeBytes = 0; 733 734 LeaveCriticalSection(&PerfDataCriticalSection); 735 736 return PeakWorkingSetSizeBytes; 737} 738 739ULONG PerfDataGetWorkingSetSizeDelta(ULONG Index) 740{ 741 ULONG WorkingSetSizeDelta; 742 743 EnterCriticalSection(&PerfDataCriticalSection); 744 745 if (Index < ProcessCount) 746 WorkingSetSizeDelta = pPerfData[Index].WorkingSetSizeDelta; 747 else 748 WorkingSetSizeDelta = 0; 749 750 LeaveCriticalSection(&PerfDataCriticalSection); 751 752 return WorkingSetSizeDelta; 753} 754 755ULONG PerfDataGetPageFaultCount(ULONG Index) 756{ 757 ULONG PageFaultCount; 758 759 EnterCriticalSection(&PerfDataCriticalSection); 760 761 if (Index < ProcessCount) 762 PageFaultCount = pPerfData[Index].PageFaultCount; 763 else 764 PageFaultCount = 0; 765 766 LeaveCriticalSection(&PerfDataCriticalSection); 767 768 return PageFaultCount; 769} 770 771ULONG PerfDataGetPageFaultCountDelta(ULONG Index) 772{ 773 ULONG PageFaultCountDelta; 774 775 EnterCriticalSection(&PerfDataCriticalSection); 776 777 if (Index < ProcessCount) 778 PageFaultCountDelta = pPerfData[Index].PageFaultCountDelta; 779 else 780 PageFaultCountDelta = 0; 781 782 LeaveCriticalSection(&PerfDataCriticalSection); 783 784 return PageFaultCountDelta; 785} 786 787ULONG PerfDataGetVirtualMemorySizeBytes(ULONG Index) 788{ 789 ULONG VirtualMemorySizeBytes; 790 791 EnterCriticalSection(&PerfDataCriticalSection); 792 793 if (Index < ProcessCount) 794 VirtualMemorySizeBytes = pPerfData[Index].VirtualMemorySizeBytes; 795 else 796 VirtualMemorySizeBytes = 0; 797 798 LeaveCriticalSection(&PerfDataCriticalSection); 799 800 return VirtualMemorySizeBytes; 801} 802 803ULONG PerfDataGetPagedPoolUsagePages(ULONG Index) 804{ 805 ULONG PagedPoolUsage; 806 807 EnterCriticalSection(&PerfDataCriticalSection); 808 809 if (Index < ProcessCount) 810 PagedPoolUsage = pPerfData[Index].PagedPoolUsagePages; 811 else 812 PagedPoolUsage = 0; 813 814 LeaveCriticalSection(&PerfDataCriticalSection); 815 816 return PagedPoolUsage; 817} 818 819ULONG PerfDataGetNonPagedPoolUsagePages(ULONG Index) 820{ 821 ULONG NonPagedPoolUsage; 822 823 EnterCriticalSection(&PerfDataCriticalSection); 824 825 if (Index < ProcessCount) 826 NonPagedPoolUsage = pPerfData[Index].NonPagedPoolUsagePages; 827 else 828 NonPagedPoolUsage = 0; 829 830 LeaveCriticalSection(&PerfDataCriticalSection); 831 832 return NonPagedPoolUsage; 833} 834 835ULONG PerfDataGetBasePriority(ULONG Index) 836{ 837 ULONG BasePriority; 838 839 EnterCriticalSection(&PerfDataCriticalSection); 840 841 if (Index < ProcessCount) 842 BasePriority = pPerfData[Index].BasePriority; 843 else 844 BasePriority = 0; 845 846 LeaveCriticalSection(&PerfDataCriticalSection); 847 848 return BasePriority; 849} 850 851ULONG PerfDataGetHandleCount(ULONG Index) 852{ 853 ULONG HandleCount; 854 855 EnterCriticalSection(&PerfDataCriticalSection); 856 857 if (Index < ProcessCount) 858 HandleCount = pPerfData[Index].HandleCount; 859 else 860 HandleCount = 0; 861 862 LeaveCriticalSection(&PerfDataCriticalSection); 863 864 return HandleCount; 865} 866 867ULONG PerfDataGetThreadCount(ULONG Index) 868{ 869 ULONG ThreadCount; 870 871 EnterCriticalSection(&PerfDataCriticalSection); 872 873 if (Index < ProcessCount) 874 ThreadCount = pPerfData[Index].ThreadCount; 875 else 876 ThreadCount = 0; 877 878 LeaveCriticalSection(&PerfDataCriticalSection); 879 880 return ThreadCount; 881} 882 883ULONG PerfDataGetUSERObjectCount(ULONG Index) 884{ 885 ULONG USERObjectCount; 886 887 EnterCriticalSection(&PerfDataCriticalSection); 888 889 if (Index < ProcessCount) 890 USERObjectCount = pPerfData[Index].USERObjectCount; 891 else 892 USERObjectCount = 0; 893 894 LeaveCriticalSection(&PerfDataCriticalSection); 895 896 return USERObjectCount; 897} 898 899ULONG PerfDataGetGDIObjectCount(ULONG Index) 900{ 901 ULONG GDIObjectCount; 902 903 EnterCriticalSection(&PerfDataCriticalSection); 904 905 if (Index < ProcessCount) 906 GDIObjectCount = pPerfData[Index].GDIObjectCount; 907 else 908 GDIObjectCount = 0; 909 910 LeaveCriticalSection(&PerfDataCriticalSection); 911 912 return GDIObjectCount; 913} 914 915BOOL PerfDataGetIOCounters(ULONG Index, PIO_COUNTERS pIoCounters) 916{ 917 BOOL bSuccessful; 918 919 EnterCriticalSection(&PerfDataCriticalSection); 920 921 if (Index < ProcessCount) 922 { 923 memcpy(pIoCounters, &pPerfData[Index].IOCounters, sizeof(IO_COUNTERS)); 924 bSuccessful = TRUE; 925 } 926 else 927 bSuccessful = FALSE; 928 929 LeaveCriticalSection(&PerfDataCriticalSection); 930 931 return bSuccessful; 932} 933 934ULONG PerfDataGetCommitChargeTotalK(void) 935{ 936 ULONG Total; 937 ULONG PageSize; 938 939 EnterCriticalSection(&PerfDataCriticalSection); 940 941 Total = SystemPerfInfo.CommittedPages; 942 PageSize = SystemBasicInfo.PageSize; 943 944 LeaveCriticalSection(&PerfDataCriticalSection); 945 946 Total = Total * (PageSize / 1024); 947 948 return Total; 949} 950 951ULONG PerfDataGetCommitChargeLimitK(void) 952{ 953 ULONG Limit; 954 ULONG PageSize; 955 956 EnterCriticalSection(&PerfDataCriticalSection); 957 958 Limit = SystemPerfInfo.CommitLimit; 959 PageSize = SystemBasicInfo.PageSize; 960 961 LeaveCriticalSection(&PerfDataCriticalSection); 962 963 Limit = Limit * (PageSize / 1024); 964 965 return Limit; 966} 967 968ULONG PerfDataGetCommitChargePeakK(void) 969{ 970 ULONG Peak; 971 ULONG PageSize; 972 973 EnterCriticalSection(&PerfDataCriticalSection); 974 975 Peak = SystemPerfInfo.PeakCommitment; 976 PageSize = SystemBasicInfo.PageSize; 977 978 LeaveCriticalSection(&PerfDataCriticalSection); 979 980 Peak = Peak * (PageSize / 1024); 981 982 return Peak; 983} 984 985ULONG PerfDataGetKernelMemoryTotalK(void) 986{ 987 ULONG Total; 988 ULONG Paged; 989 ULONG NonPaged; 990 ULONG PageSize; 991 992 EnterCriticalSection(&PerfDataCriticalSection); 993 994 Paged = SystemPerfInfo.PagedPoolPages; 995 NonPaged = SystemPerfInfo.NonPagedPoolPages; 996 PageSize = SystemBasicInfo.PageSize; 997 998 LeaveCriticalSection(&PerfDataCriticalSection); 999 1000 Paged = Paged * (PageSize / 1024); 1001 NonPaged = NonPaged * (PageSize / 1024); 1002 1003 Total = Paged + NonPaged; 1004 1005 return Total; 1006} 1007 1008ULONG PerfDataGetKernelMemoryPagedK(void) 1009{ 1010 ULONG Paged; 1011 ULONG PageSize; 1012 1013 EnterCriticalSection(&PerfDataCriticalSection); 1014 1015 Paged = SystemPerfInfo.PagedPoolPages; 1016 PageSize = SystemBasicInfo.PageSize; 1017 1018 LeaveCriticalSection(&PerfDataCriticalSection); 1019 1020 Paged = Paged * (PageSize / 1024); 1021 1022 return Paged; 1023} 1024 1025ULONG PerfDataGetKernelMemoryNonPagedK(void) 1026{ 1027 ULONG NonPaged; 1028 ULONG PageSize; 1029 1030 EnterCriticalSection(&PerfDataCriticalSection); 1031 1032 NonPaged = SystemPerfInfo.NonPagedPoolPages; 1033 PageSize = SystemBasicInfo.PageSize; 1034 1035 LeaveCriticalSection(&PerfDataCriticalSection); 1036 1037 NonPaged = NonPaged * (PageSize / 1024); 1038 1039 return NonPaged; 1040} 1041 1042ULONG PerfDataGetPhysicalMemoryTotalK(void) 1043{ 1044 ULONG Total; 1045 ULONG PageSize; 1046 1047 EnterCriticalSection(&PerfDataCriticalSection); 1048 1049 Total = SystemBasicInfo.NumberOfPhysicalPages; 1050 PageSize = SystemBasicInfo.PageSize; 1051 1052 LeaveCriticalSection(&PerfDataCriticalSection); 1053 1054 Total = Total * (PageSize / 1024); 1055 1056 return Total; 1057} 1058 1059ULONG PerfDataGetPhysicalMemoryAvailableK(void) 1060{ 1061 ULONG Available; 1062 ULONG PageSize; 1063 1064 EnterCriticalSection(&PerfDataCriticalSection); 1065 1066 Available = SystemPerfInfo.AvailablePages; 1067 PageSize = SystemBasicInfo.PageSize; 1068 1069 LeaveCriticalSection(&PerfDataCriticalSection); 1070 1071 Available = Available * (PageSize / 1024); 1072 1073 return Available; 1074} 1075 1076ULONG PerfDataGetPhysicalMemorySystemCacheK(void) 1077{ 1078 ULONG SystemCache; 1079 ULONG PageSize; 1080 1081 EnterCriticalSection(&PerfDataCriticalSection); 1082 1083 PageSize = SystemBasicInfo.PageSize; 1084 SystemCache = SystemCacheInfo.CurrentSizeIncludingTransitionInPages * PageSize; 1085 1086 LeaveCriticalSection(&PerfDataCriticalSection); 1087 1088 return SystemCache / 1024; 1089} 1090 1091ULONG PerfDataGetSystemHandleCount(void) 1092{ 1093 ULONG HandleCount; 1094 1095 EnterCriticalSection(&PerfDataCriticalSection); 1096 1097 HandleCount = SystemNumberOfHandles; 1098 1099 LeaveCriticalSection(&PerfDataCriticalSection); 1100 1101 return HandleCount; 1102} 1103 1104ULONG PerfDataGetTotalThreadCount(void) 1105{ 1106 ULONG ThreadCount = 0; 1107 ULONG i; 1108 1109 EnterCriticalSection(&PerfDataCriticalSection); 1110 1111 for (i=0; i<ProcessCount; i++) 1112 { 1113 ThreadCount += pPerfData[i].ThreadCount; 1114 } 1115 1116 LeaveCriticalSection(&PerfDataCriticalSection); 1117 1118 return ThreadCount; 1119} 1120 1121BOOL PerfDataGet(ULONG Index, PPERFDATA *lppData) 1122{ 1123 BOOL bSuccessful = FALSE; 1124 1125 EnterCriticalSection(&PerfDataCriticalSection); 1126 if (Index < ProcessCount) 1127 { 1128 *lppData = pPerfData + Index; 1129 bSuccessful = TRUE; 1130 } 1131 LeaveCriticalSection(&PerfDataCriticalSection); 1132 return bSuccessful; 1133} 1134