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