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