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