mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user