[TASKMGR]
[reactos.git] / reactos / base / applications / taskmgr / perfdata.c
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 = cwcUserName;
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
155 /* Allocate a new entry */
156 *pcwcUserName = wcslen(pUserName);
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