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