From 7b11a5fcdb32d862982960399da1cf07c385d7fa Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Mon, 8 Dec 2008 12:57:53 +0000 Subject: [PATCH] - Implement KeQueryRuntimeProcess for querying total user/kernel times of a process. - Use it for obtaining idle process times, and per-process information in QuerySystemInformation routines. - Fix incorrect multiplier being applied to user/kernel times (should be KeMaximumIncrement instead of 100000). - Slightly rework SystemProcessorPerformanceInformation to provide valid data. - This fixed a bug existing since revision 24148, 2 years ago. See issue #2329 for more details. svn path=/trunk/; revision=37934 --- reactos/ntoskrnl/ex/sysinfo.c | 76 ++++++++++++++------------ reactos/ntoskrnl/include/internal/ke.h | 10 ++++ reactos/ntoskrnl/ke/procobj.c | 48 ++++++++++++++++ 3 files changed, 100 insertions(+), 34 deletions(-) diff --git a/reactos/ntoskrnl/ex/sysinfo.c b/reactos/ntoskrnl/ex/sysinfo.c index 4b990670f65..e229008ccde 100644 --- a/reactos/ntoskrnl/ex/sysinfo.c +++ b/reactos/ntoskrnl/ex/sysinfo.c @@ -538,6 +538,7 @@ QSI_DEF(SystemProcessorInformation) /* Class 2 - Performance Information */ QSI_DEF(SystemPerformanceInformation) { + ULONG IdleUser, IdleKernel; PSYSTEM_PERFORMANCE_INFORMATION Spi = (PSYSTEM_PERFORMANCE_INFORMATION) Buffer; @@ -554,8 +555,8 @@ QSI_DEF(SystemPerformanceInformation) TheIdleProcess = PsIdleProcess; - Spi->IdleProcessTime.QuadPart = TheIdleProcess->Pcb.KernelTime * 100000LL; - + IdleKernel = KeQueryRuntimeProcess(&TheIdleProcess->Pcb, &IdleUser); + Spi->IdleProcessTime.QuadPart = UInt32x32To64(IdleKernel, KeMaximumIncrement); Spi->IoReadTransferCount = IoReadTransferCount; Spi->IoWriteTransferCount = IoWriteTransferCount; Spi->IoOtherTransferCount = IoOtherTransferCount; @@ -699,7 +700,8 @@ QSI_DEF(SystemProcessInformation) { ULONG ovlSize = 0, nThreads; PEPROCESS pr = NULL, syspr; - unsigned char *pCur; + PUCHAR pCur; + ULONG TotalUser, TotalKernel; NTSTATUS Status = STATUS_SUCCESS; _SEH2_TRY @@ -757,8 +759,6 @@ QSI_DEF(SystemProcessInformation) SpiCur->NextEntryOffset = curSize+inLen; // relative offset to the beginnnig of the next structure SpiCur->NumberOfThreads = nThreads; SpiCur->CreateTime = pr->CreateTime; - SpiCur->UserTime.QuadPart = pr->Pcb.UserTime * 100000LL; - SpiCur->KernelTime.QuadPart = pr->Pcb.KernelTime * 100000LL; SpiCur->ImageName.Length = strlen(pr->ImageFileName) * sizeof(WCHAR); SpiCur->ImageName.MaximumLength = (USHORT)inLen; SpiCur->ImageName.Buffer = (void*)(pCur+curSize); @@ -798,8 +798,8 @@ QSI_DEF(SystemProcessInformation) current = CONTAINING_RECORD(current_entry, ETHREAD, ThreadListEntry); - ThreadInfo->KernelTime.QuadPart = current->Tcb.KernelTime * 100000LL; - ThreadInfo->UserTime.QuadPart = current->Tcb.UserTime * 100000LL; + ThreadInfo->KernelTime.QuadPart = UInt32x32To64(current->Tcb.KernelTime, KeMaximumIncrement); + ThreadInfo->UserTime.QuadPart = UInt32x32To64(current->Tcb.UserTime, KeMaximumIncrement); ThreadInfo->CreateTime.QuadPart = current->CreateTime.QuadPart; ThreadInfo->WaitTime = current->Tcb.WaitTime; ThreadInfo->StartAddress = (PVOID) current->StartAddress; @@ -809,10 +809,16 @@ QSI_DEF(SystemProcessInformation) ThreadInfo->ContextSwitches = current->Tcb.ContextSwitches; ThreadInfo->ThreadState = current->Tcb.State; ThreadInfo->WaitReason = current->Tcb.WaitReason; + ThreadInfo++; current_entry = current_entry->Flink; } + /* Query total user/kernel times of a process */ + TotalKernel = KeQueryRuntimeProcess(&pr->Pcb, &TotalUser); + SpiCur->UserTime.QuadPart = UInt32x32To64(TotalUser, KeMaximumIncrement); + SpiCur->KernelTime.QuadPart = UInt32x32To64(TotalKernel, KeMaximumIncrement); + /* Handle idle process entry */ if (pr == PsIdleProcess) pr = NULL; @@ -882,37 +888,39 @@ QSI_DEF(SystemDeviceInformation) /* Class 8 - Processor Performance Information */ QSI_DEF(SystemProcessorPerformanceInformation) { - PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi - = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer; + PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION Spi + = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION) Buffer; - LONG i; - LARGE_INTEGER CurrentTime; - PKPRCB Prcb; + LONG i; + ULONG TotalTime; + LARGE_INTEGER CurrentTime; + PKPRCB Prcb; - *ReqSize = KeNumberProcessors * sizeof (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); - /* - * Check user buffer's size - */ - if (Size < KeNumberProcessors * sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)) - { - return (STATUS_INFO_LENGTH_MISMATCH); - } + *ReqSize = KeNumberProcessors * sizeof (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION); - CurrentTime.QuadPart = KeQueryInterruptTime(); - Prcb = KeGetPcr()->Prcb; - for (i = 0; i < KeNumberProcessors; i++) - { - Spi->IdleTime.QuadPart = (Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime) * 100000LL; - Spi->KernelTime.QuadPart = Prcb->KernelTime * 100000LL; - Spi->UserTime.QuadPart = Prcb->UserTime * 100000LL; - Spi->DpcTime.QuadPart = Prcb->DpcTime * 100000LL; - Spi->InterruptTime.QuadPart = Prcb->InterruptTime * 100000LL; - Spi->InterruptCount = Prcb->InterruptCount; - Spi++; - Prcb = (PKPRCB)((ULONG_PTR)Prcb + PAGE_SIZE); - } + /* Check user buffer's size */ + if (Size < *ReqSize) + { + return STATUS_INFO_LENGTH_MISMATCH; + } - return (STATUS_SUCCESS); + CurrentTime.QuadPart = KeQueryInterruptTime(); + Prcb = KeGetPcr()->Prcb; + for (i = 0; i < KeNumberProcessors; i++) + { + /* Calculate total user and kernel times */ + TotalTime = Prcb->IdleThread->KernelTime + Prcb->IdleThread->UserTime; + Spi->IdleTime.QuadPart = UInt32x32To64(TotalTime, KeMaximumIncrement); + Spi->KernelTime.QuadPart = UInt32x32To64(Prcb->KernelTime, KeMaximumIncrement); + Spi->UserTime.QuadPart = UInt32x32To64(Prcb->UserTime, KeMaximumIncrement); + Spi->DpcTime.QuadPart = UInt32x32To64(Prcb->DpcTime, KeMaximumIncrement); + Spi->InterruptTime.QuadPart = UInt32x32To64(Prcb->InterruptTime, KeMaximumIncrement); + Spi->InterruptCount = Prcb->InterruptCount; + Spi++; + Prcb = (PKPRCB)((ULONG_PTR)Prcb + PAGE_SIZE); + } + + return STATUS_SUCCESS; } /* Class 9 - Flags Information */ diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 633c79a8f03..ac310824d78 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -716,6 +716,16 @@ VOID FASTCALL KiActivateWaiterQueue(IN PKQUEUE Queue); +ULONG +NTAPI +KeQueryRuntimeProcess(IN PKPROCESS Process, + OUT PULONG UserTime); + +ULONG +NTAPI +KeQueryRuntimeThread(IN PKTHREAD Thread, + OUT PULONG UserTime); + /* INITIALIZATION FUNCTIONS *************************************************/ BOOLEAN diff --git a/reactos/ntoskrnl/ke/procobj.c b/reactos/ntoskrnl/ke/procobj.c index fd52948dbae..3ba5769871c 100644 --- a/reactos/ntoskrnl/ke/procobj.c +++ b/reactos/ntoskrnl/ke/procobj.c @@ -719,6 +719,54 @@ KeUnstackDetachProcess(IN PRKAPC_STATE ApcState) } } +/* + * @implemented + */ +ULONG +NTAPI +KeQueryRuntimeProcess(IN PKPROCESS Process, + OUT PULONG UserTime) +{ + ULONG TotalUser, TotalKernel; + KLOCK_QUEUE_HANDLE ProcessLock; + PLIST_ENTRY NextEntry, ListHead; + PKTHREAD Thread; + + ASSERT_PROCESS(Process); + + /* Initialize user and kernel times */ + TotalUser = Process->UserTime; + TotalKernel = Process->KernelTime; + + /* Lock the process */ + KiAcquireProcessLock(Process, &ProcessLock); + + /* Loop all child threads and sum up their times */ + ListHead = &Process->ThreadListHead; + NextEntry = ListHead->Flink; + while (ListHead != NextEntry) + { + /* Get the thread */ + Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); + + /* Sum up times */ + TotalKernel += Thread->KernelTime; + TotalUser += Thread->UserTime; + + /* Go to the next one */ + NextEntry = NextEntry->Flink; + } + + /* Release lock */ + KiReleaseProcessLock(&ProcessLock); + + /* Return the user time */ + *UserTime = TotalUser; + + /* Return the kernel time */ + return TotalKernel; +} + /* * @implemented */