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