added CPU column to Threads tab

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@4470 21ef857c-d57f-4fe0-8362-d861dc6d29cd
This commit is contained in:
wj32
2011-08-19 02:40:51 +00:00
parent e6b6078e15
commit c3f9d377ea
7 changed files with 117 additions and 55 deletions
+1
View File
@@ -3,6 +3,7 @@ Process Hacker
2.20
* NEW/IMPROVED:
* Added column selection for handle list
* Added CPU column to threads list
* Implemented Properties button for Thread handles
* Set descending sort as the default for most numeric columns
* Extended header context menu
+14 -2
View File
@@ -22,6 +22,8 @@ extern BOOLEAN PhEnableProcessQueryStage2;
extern BOOLEAN PhEnablePurgeProcessRecords;
extern BOOLEAN PhEnableCycleCpuUsage;
extern PVOID PhProcessInformation; // only can be used if running on same thread as process provider
extern ULONG PhProcessInformationSequenceNumber;
extern SYSTEM_PERFORMANCE_INFORMATION PhPerfInformation;
extern PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuInformation;
extern SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuTotals;
@@ -29,6 +31,12 @@ extern ULONG PhTotalProcesses;
extern ULONG PhTotalThreads;
extern ULONG PhTotalHandles;
extern ULONG64 PhCpuTotalCycleDelta;
extern PLARGE_INTEGER PhCpuIdleCycleTime; // cycle time for Idle
extern PLARGE_INTEGER PhCpuSystemCycleTime; // cycle time for DPCs and Interrupts
extern PH_UINT64_DELTA PhCpuIdleCycleDelta;
extern PH_UINT64_DELTA PhCpuSystemCycleDelta;
extern FLOAT PhCpuKernelUsage;
extern FLOAT PhCpuUserUsage;
extern PFLOAT PhCpusKernelUsage;
@@ -36,11 +44,11 @@ extern PFLOAT PhCpusUserUsage;
extern PH_UINT64_DELTA PhCpuKernelDelta;
extern PH_UINT64_DELTA PhCpuUserDelta;
extern PH_UINT64_DELTA PhCpuOtherDelta;
extern PH_UINT64_DELTA PhCpuIdleDelta;
extern PPH_UINT64_DELTA PhCpusKernelDelta;
extern PPH_UINT64_DELTA PhCpusUserDelta;
extern PPH_UINT64_DELTA PhCpusOtherDelta;
extern PPH_UINT64_DELTA PhCpusIdleDelta;
extern PH_UINT64_DELTA PhIoReadDelta;
extern PH_UINT64_DELTA PhIoWriteDelta;
@@ -556,6 +564,10 @@ typedef struct _PH_THREAD_ITEM
LARGE_INTEGER KernelTime;
LARGE_INTEGER UserTime;
FLOAT CpuUsage;
PH_UINT64_DELTA CpuKernelDelta;
PH_UINT64_DELTA CpuUserDelta;
PH_UINT32_DELTA ContextSwitchesDelta;
PH_UINT64_DELTA CyclesDelta;
LONG Priority;
+7 -5
View File
@@ -550,12 +550,13 @@ VOID PhWriteNetworkList(
// Columns
#define PHTHTLC_TID 0
#define PHTHTLC_CYCLESDELTA 1
#define PHTHTLC_STARTADDRESS 2
#define PHTHTLC_PRIORITY 3
#define PHTHTLC_SERVICE 4
#define PHTHTLC_CPU 1
#define PHTHTLC_CYCLESDELTA 2
#define PHTHTLC_STARTADDRESS 3
#define PHTHTLC_PRIORITY 4
#define PHTHTLC_SERVICE 5
#define PHTHTLC_MAXIMUM 5
#define PHTHTLC_MAXIMUM 6
typedef struct _PH_THREAD_NODE
{
@@ -570,6 +571,7 @@ typedef struct _PH_THREAD_NODE
ULONG ValidMask;
WCHAR CpuUsageText[PH_INT32_STR_LEN_1];
PPH_STRING CyclesDeltaText; // used for Context Switches Delta as well
PPH_STRING PriorityText;
} PH_THREAD_NODE, *PPH_THREAD_NODE;
+3 -1
View File
@@ -2346,11 +2346,13 @@ INT_PTR CALLBACK PhpProcessThreadsDlgProc(
threadsContext = propPageContext->Context =
PhAllocate(sizeof(PH_THREADS_CONTEXT));
// The thread provider must execute on the primary provider thread because
// it depends on data from the process provider.
threadsContext->Provider = PhCreateThreadProvider(
processItem->ProcessId
);
PhRegisterProvider(
&PhSecondaryProviderThread,
&PhPrimaryProviderThread,
PhThreadProviderUpdate,
threadsContext->Provider,
&threadsContext->ProviderRegistration
+18 -12
View File
@@ -169,6 +169,8 @@ BOOLEAN PhEnableProcessQueryStage2 = FALSE;
BOOLEAN PhEnablePurgeProcessRecords = TRUE;
BOOLEAN PhEnableCycleCpuUsage = TRUE;
PVOID PhProcessInformation; // only can be used if running on same thread as process provider
ULONG PhProcessInformationSequenceNumber = 0;
SYSTEM_PERFORMANCE_INFORMATION PhPerfInformation;
PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuInformation;
SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION PhCpuTotals;
@@ -179,6 +181,7 @@ ULONG PhTotalHandles;
SYSTEM_PROCESS_INFORMATION PhDpcsProcessInformation;
SYSTEM_PROCESS_INFORMATION PhInterruptsProcessInformation;
ULONG64 PhCpuTotalCycleDelta; // real cycle time delta for this period
PLARGE_INTEGER PhCpuIdleCycleTime; // cycle time for Idle
PLARGE_INTEGER PhCpuSystemCycleTime; // cycle time for DPCs and Interrupts
PH_UINT64_DELTA PhCpuIdleCycleDelta;
@@ -276,17 +279,14 @@ BOOLEAN PhProcessProviderInitialization()
(ULONG)PhSystemBasicInformation.NumberOfProcessors
);
if (WindowsVersion >= WINDOWS_7)
{
PhCpuIdleCycleTime = PhAllocate(
sizeof(LARGE_INTEGER) *
(ULONG)PhSystemBasicInformation.NumberOfProcessors
);
PhCpuSystemCycleTime = PhAllocate(
sizeof(LARGE_INTEGER) *
(ULONG)PhSystemBasicInformation.NumberOfProcessors
);
}
PhCpuIdleCycleTime = PhAllocate(
sizeof(LARGE_INTEGER) *
(ULONG)PhSystemBasicInformation.NumberOfProcessors
);
PhCpuSystemCycleTime = PhAllocate(
sizeof(LARGE_INTEGER) *
(ULONG)PhSystemBasicInformation.NumberOfProcessors
);
usageBuffer = PhAllocate(
sizeof(FLOAT) *
@@ -1968,6 +1968,8 @@ VOID PhProcessProviderUpdate(
if (sysTotalCycleTime == 0)
sysTotalCycleTime = -1;
PhCpuTotalCycleDelta = sysTotalCycleTime;
// Look for new processes and update existing ones.
process = PH_FIRST_PROCESS(processes);
@@ -2215,7 +2217,11 @@ VOID PhProcessProviderUpdate(
}
}
PhFree(processes);
if (PhProcessInformation)
PhFree(PhProcessInformation);
PhProcessInformation = processes;
PhProcessInformationSequenceNumber++;
if (PhpTsProcesses)
{
+44 -3
View File
@@ -90,9 +90,10 @@ VOID PhInitializeThreadList(
// Default columns
PhAddTreeNewColumn(hwnd, PHTHTLC_TID, TRUE, L"TID", 50, PH_ALIGN_LEFT, 0, 0);
PhAddTreeNewColumnEx(hwnd, PHTHTLC_CYCLESDELTA, TRUE, L"Cycles Delta", 80, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);
PhAddTreeNewColumn(hwnd, PHTHTLC_STARTADDRESS, TRUE, L"Start Address", 180, PH_ALIGN_LEFT, 2, 0);
PhAddTreeNewColumnEx(hwnd, PHTHTLC_PRIORITY, TRUE, L"Priority", 80, PH_ALIGN_LEFT, 3, 0, TRUE);
PhAddTreeNewColumnEx(hwnd, PHTHTLC_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 1, DT_RIGHT, TRUE);
PhAddTreeNewColumnEx(hwnd, PHTHTLC_CYCLESDELTA, TRUE, L"Cycles Delta", 80, PH_ALIGN_RIGHT, 2, DT_RIGHT, TRUE);
PhAddTreeNewColumn(hwnd, PHTHTLC_STARTADDRESS, TRUE, L"Start Address", 180, PH_ALIGN_LEFT, 3, 0);
PhAddTreeNewColumnEx(hwnd, PHTHTLC_PRIORITY, TRUE, L"Priority", 80, PH_ALIGN_LEFT, 4, 0, TRUE);
PhAddTreeNewColumn(hwnd, PHTHTLC_SERVICE, FALSE, L"Service", 100, PH_ALIGN_LEFT, -1, 0);
TreeNew_SetRedraw(hwnd, TRUE);
@@ -385,6 +386,20 @@ BEGIN_SORT_FUNCTION(Tid)
}
END_SORT_FUNCTION
BEGIN_SORT_FUNCTION(Cpu)
{
sortResult = singlecmp(threadItem1->CpuUsage, threadItem2->CpuUsage);
if (sortResult == 0)
{
if (context->UseCycleTime)
sortResult = uint64cmp(threadItem1->CyclesDelta.Delta, threadItem2->CyclesDelta.Delta);
else
sortResult = uintcmp(threadItem1->ContextSwitchesDelta.Delta, threadItem2->ContextSwitchesDelta.Delta);
}
}
END_SORT_FUNCTION
BEGIN_SORT_FUNCTION(CyclesDelta)
{
if (context->UseCycleTime)
@@ -436,6 +451,7 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback(
static PVOID sortFunctions[] =
{
SORT_FUNCTION(Tid),
SORT_FUNCTION(Cpu),
SORT_FUNCTION(CyclesDelta),
SORT_FUNCTION(StartAddress),
SORT_FUNCTION(Priority),
@@ -491,6 +507,31 @@ BOOLEAN NTAPI PhpThreadTreeNewCallback(
case PHTHTLC_TID:
PhInitializeStringRef(&getCellText->Text, threadItem->ThreadIdString);
break;
case PHTHTLC_CPU:
{
FLOAT cpuUsage;
cpuUsage = threadItem->CpuUsage * 100;
if (cpuUsage >= 0.01)
{
PH_FORMAT format;
SIZE_T returnLength;
PhInitFormatF(&format, cpuUsage, 2);
if (PhFormatToBuffer(&format, 1, node->CpuUsageText, sizeof(node->CpuUsageText), &returnLength))
{
getCellText->Text.Buffer = node->CpuUsageText;
getCellText->Text.Length = (USHORT)(returnLength - sizeof(WCHAR)); // minus null terminator
}
}
else if (cpuUsage != 0 && PhCsShowCpuBelow001)
{
PhInitializeStringRef(&getCellText->Text, L"< 0.01");
}
}
break;
case PHTHTLC_CYCLESDELTA:
if (context->UseCycleTime)
{
+30 -32
View File
@@ -598,7 +598,6 @@ PPH_STRING PhpGetThreadBasicStartAddress(
static NTSTATUS PhpGetThreadCycleTime(
__in PPH_THREAD_PROVIDER ThreadProvider,
__in_opt PULARGE_INTEGER IdleThreadCycleTimes,
__in PPH_THREAD_ITEM ThreadItem,
__out PULONG64 CycleTime
)
@@ -609,12 +608,9 @@ static NTSTATUS PhpGetThreadCycleTime(
}
else
{
if (
IdleThreadCycleTimes &&
(ULONG)ThreadItem->ThreadId < (ULONG)PhSystemBasicInformation.NumberOfProcessors
)
if ((ULONG)ThreadItem->ThreadId < (ULONG)PhSystemBasicInformation.NumberOfProcessors)
{
*CycleTime = IdleThreadCycleTimes[(ULONG)ThreadItem->ThreadId].QuadPart;
*CycleTime = PhCpuIdleCycleTime[(ULONG)ThreadItem->ThreadId].QuadPart;
return STATUS_SUCCESS;
}
}
@@ -653,15 +649,22 @@ VOID PhThreadProviderUpdate(
__in PVOID Object
)
{
static ULONG lastSequenceNumber = -1;
PPH_THREAD_PROVIDER threadProvider = (PPH_THREAD_PROVIDER)Object;
PVOID processes;
PSYSTEM_PROCESS_INFORMATION process;
PSYSTEM_THREAD_INFORMATION threads;
ULONG numberOfThreads;
ULONG i;
PULARGE_INTEGER idleThreadCycleTimes = NULL;
if (!NT_SUCCESS(PhEnumProcesses(&processes)))
if (PhProcessInformationSequenceNumber == lastSequenceNumber)
return; // processes have not be updated, probably because the user has unticked Update Automatically
processes = PhProcessInformation;
lastSequenceNumber = PhProcessInformationSequenceNumber;
if (!processes)
return;
process = PhFindProcessInformation(processes, threadProvider->ProcessId);
@@ -688,25 +691,6 @@ VOID PhThreadProviderUpdate(
{
threads[i].ClientId.UniqueThread = (HANDLE)i;
}
// Get the cycle times if we're on Vista.
if (WINDOWS_HAS_CYCLE_TIME)
{
idleThreadCycleTimes = PhAllocate(
sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors
);
if (!NT_SUCCESS(NtQuerySystemInformation(
SystemProcessorIdleCycleTimeInformation,
idleThreadCycleTimes,
sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors,
NULL
)))
{
PhFree(idleThreadCycleTimes);
idleThreadCycleTimes = NULL;
}
}
}
// Look for dead threads.
@@ -833,7 +817,6 @@ VOID PhThreadProviderUpdate(
if (NT_SUCCESS(PhpGetThreadCycleTime(
threadProvider,
idleThreadCycleTimes,
threadItem,
&cycles
)))
@@ -842,6 +825,10 @@ VOID PhThreadProviderUpdate(
}
}
// Initialize the CPU time deltas.
PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart);
PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart);
// Try to get the start address.
if (threadItem->ThreadHandle)
@@ -998,7 +985,6 @@ VOID PhThreadProviderUpdate(
if (NT_SUCCESS(PhpGetThreadCycleTime(
threadProvider,
idleThreadCycleTimes,
threadItem,
&cycles
)))
@@ -1012,6 +998,21 @@ VOID PhThreadProviderUpdate(
}
}
// Update the CPU time deltas.
PhUpdateDelta(&threadItem->CpuKernelDelta, threadItem->KernelTime.QuadPart);
PhUpdateDelta(&threadItem->CpuUserDelta, threadItem->UserTime.QuadPart);
// Update the CPU usage.
if (WINDOWS_HAS_CYCLE_TIME && PhEnableCycleCpuUsage)
{
threadItem->CpuUsage = (FLOAT)threadItem->CyclesDelta.Delta / PhCpuTotalCycleDelta;
}
else
{
threadItem->CpuUsage = (FLOAT)(threadItem->CpuKernelDelta.Delta + threadItem->CpuUserDelta.Delta) /
(PhCpuKernelDelta.Delta + PhCpuUserDelta.Delta + PhCpuIdleDelta.Delta);
}
// Update the Win32 priority.
{
LONG oldPriorityWin32 = threadItem->PriorityWin32;
@@ -1060,8 +1061,5 @@ VOID PhThreadProviderUpdate(
}
}
PhFree(processes);
if (idleThreadCycleTimes) PhFree(idleThreadCycleTimes);
PhInvokeCallback(&threadProvider->UpdatedEvent, NULL);
}