diff --git a/2.x/trunk/CHANGELOG.txt b/2.x/trunk/CHANGELOG.txt index 780de2ed4..4ec2fbbf2 100644 --- a/2.x/trunk/CHANGELOG.txt +++ b/2.x/trunk/CHANGELOG.txt @@ -3,6 +3,7 @@ Process Hacker 2.37 * HIGHLIGHTS: * Updated for Windows 10 + * The "Include CPU (and other) usage of children in collapsed processes" option now aggregates memory and I/O statistics * Added regex search to "Find Handles or DLLs" * Added process exit codes to log * Fixed crash that occurred under some conditions when processes terminated diff --git a/2.x/trunk/ProcessHacker/ProcessHacker.rc b/2.x/trunk/ProcessHacker/ProcessHacker.rc index 68d0516b5..52a43a8c2 100644 --- a/2.x/trunk/ProcessHacker/ProcessHacker.rc +++ b/2.x/trunk/ProcessHacker/ProcessHacker.rc @@ -1321,8 +1321,8 @@ BEGIN "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,43,167,10 CONTROL "Resolve addresses for network connections",IDC_ENABLENETWORKRESOLVE, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,155,10 - CONTROL "Include CPU usage of children in collapsed processes",IDC_PROPAGATECPUUSAGE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,184,10 + CONTROL "Include CPU (and other) usage of children in collapsed processes",IDC_PROPAGATECPUUSAGE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,223,10 CONTROL "Show tooltips instantly",IDC_ENABLEINSTANTTOOLTIPS, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,79,88,10 CONTROL "Enable cycle-based CPU usage",IDC_ENABLECYCLECPUUSAGE, @@ -2484,6 +2484,11 @@ BEGIN 0 END +IDD_OPTADVANCED AFX_DIALOG_LAYOUT +BEGIN + 0 +END + #endif // English (Australia) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/2.x/trunk/ProcessHacker/appsup.c b/2.x/trunk/ProcessHacker/appsup.c index 30339d4a5..24bb98082 100644 --- a/2.x/trunk/ProcessHacker/appsup.c +++ b/2.x/trunk/ProcessHacker/appsup.c @@ -1578,7 +1578,7 @@ VOID PhInitializeTreeNewColumnMenuEx( TreeNew_GetSort(Data->TreeNewHandle, &sortColumn, &sortOrder); - if (sortColumn != Data->DefaultSortColumn || sortOrder != Data->DefaultSortOrder) + if (sortOrder != Data->DefaultSortOrder || (Data->DefaultSortOrder != NoSortOrder && sortColumn != Data->DefaultSortColumn)) resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L"Reset Sort", NULL, NULL); } diff --git a/2.x/trunk/ProcessHacker/proctree.c b/2.x/trunk/ProcessHacker/proctree.c index a71927deb..bd6cd58ae 100644 --- a/2.x/trunk/ProcessHacker/proctree.c +++ b/2.x/trunk/ProcessHacker/proctree.c @@ -36,6 +36,20 @@ #include #include +typedef enum _PHP_AGGREGATE_TYPE +{ + AggregateTypeFloat, + AggregateTypeInt32, + AggregateTypeInt64, + AggregateTypeIntPtr +} PHP_AGGREGATE_TYPE; + +typedef enum _PHP_AGGREGATE_LOCATION +{ + AggregateLocationProcessNode, + AggregateLocationProcessItem +} PHP_AGGREGATE_LOCATION; + VOID PhpRemoveProcessNode( _In_ PPH_PROCESS_NODE ProcessNode ); @@ -692,21 +706,86 @@ static BOOLEAN PhpFormatInt32GroupDigits( } } -static FLOAT PhpCalculateInclusiveCpuUsage( - _In_ PPH_PROCESS_NODE ProcessNode +FORCEINLINE PVOID PhpFieldForAggregate( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset + ) +{ + PVOID object; + + switch (Location) + { + case AggregateLocationProcessNode: + object = ProcessNode; + break; + case AggregateLocationProcessItem: + object = ProcessNode->ProcessItem; + break; + default: + PhRaiseStatus(STATUS_INVALID_PARAMETER); + } + + return PTR_ADD_OFFSET(object, FieldOffset); +} + +FORCEINLINE VOID PhpAccumulateField( + _Inout_ PVOID Accumulator, + _In_ PVOID Value, + _In_ PHP_AGGREGATE_TYPE Type + ) +{ + switch (Type) + { + case AggregateTypeFloat: + *(PFLOAT)Accumulator += *(PFLOAT)Value; + break; + case AggregateTypeInt32: + *(PULONG)Accumulator += *(PULONG)Value; + break; + case AggregateTypeInt64: + *(PULONG64)Accumulator += *(PULONG64)Value; + break; + case AggregateTypeIntPtr: + *(PULONG_PTR)Accumulator += *(PULONG_PTR)Value; + break; + } +} + +static VOID PhpAggregateField( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_TYPE Type, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset, + _Inout_ PVOID AggregatedValue ) { - FLOAT cpuUsage; ULONG i; - cpuUsage = ProcessNode->ProcessItem->CpuUsage; + PhpAccumulateField(AggregatedValue, PhpFieldForAggregate(ProcessNode, Location, FieldOffset), Type); for (i = 0; i < ProcessNode->Children->Count; i++) { - cpuUsage += PhpCalculateInclusiveCpuUsage(ProcessNode->Children->Items[i]); + PhpAggregateField(ProcessNode->Children->Items[i], Type, Location, FieldOffset, AggregatedValue); } +} - return cpuUsage; +static VOID PhpAggregateFieldIfNeeded( + _In_ PPH_PROCESS_NODE ProcessNode, + _In_ PHP_AGGREGATE_TYPE Type, + _In_ PHP_AGGREGATE_LOCATION Location, + _In_ SIZE_T FieldOffset, + _Inout_ PVOID AggregatedValue + ) +{ + if (!PhCsPropagateCpuUsage || ProcessNode->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder) + { + PhpAccumulateField(AggregatedValue, PhpFieldForAggregate(ProcessNode, Location, FieldOffset), Type); + } + else + { + PhpAggregateField(ProcessNode, Type, Location, FieldOffset, AggregatedValue); + } } static VOID PhpUpdateProcessNodeWsCounters( @@ -1943,16 +2022,10 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_CPU: { - FLOAT cpuUsage; + FLOAT cpuUsage = 0; - if (!PhCsPropagateCpuUsage || node->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder) - { - cpuUsage = processItem->CpuUsage * 100; - } - else - { - cpuUsage = PhpCalculateInclusiveCpuUsage(node) * 100; - } + PhpAggregateFieldIfNeeded(node, AggregateTypeFloat, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CpuUsage), &cpuUsage); + cpuUsage *= 100; if (cpuUsage >= 0.01) { @@ -1985,18 +2058,16 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_IOTOTALRATE: { - ULONG64 number; + ULONG64 number = 0; if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) // delta is wrong on first run of process provider { - number = processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number); + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number); + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number); number *= 1000; number /= PhCsUpdateInterval; } - else - { - number = 0; - } if (number != 0) { @@ -2010,8 +2081,12 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( } break; case PHPRTLC_PRIVATEBYTES: - PhMoveReference(&node->PrivateBytesText, PhFormatSize(processItem->VmCounters.PagefileUsage, -1)); - getCellText->Text = node->PrivateBytesText->sr; + { + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.PagefileUsage), &value); + PhMoveReference(&node->PrivateBytesText, PhFormatSize(value, -1)); + getCellText->Text = node->PrivateBytesText->sr; + } break; case PHPRTLC_USERNAME: getCellText->Text = PhGetStringRef(processItem->UserName); @@ -2039,8 +2114,12 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( getCellText->Text = node->PeakPrivateBytesText->sr; break; case PHPRTLC_WORKINGSET: - PhMoveReference(&node->WorkingSetText, PhFormatSize(processItem->VmCounters.WorkingSetSize, -1)); - getCellText->Text = node->WorkingSetText->sr; + { + SIZE_T value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeIntPtr, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, VmCounters.WorkingSetSize), &value); + PhMoveReference(&node->WorkingSetText, PhFormatSize(value, -1)); + getCellText->Text = node->WorkingSetText->sr; + } break; case PHPRTLC_PEAKWORKINGSET: PhMoveReference(&node->PeakWorkingSetText, PhFormatSize(processItem->VmCounters.PeakWorkingSetSize, -1)); @@ -2091,10 +2170,18 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( PhInitializeStringRefLongHint(&getCellText->Text, node->BasePriorityText); break; case PHPRTLC_THREADS: - PhpFormatInt32GroupDigits(processItem->NumberOfThreads, node->ThreadsText, sizeof(node->ThreadsText), &getCellText->Text); + { + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfThreads), &value); + PhpFormatInt32GroupDigits(value, node->ThreadsText, sizeof(node->ThreadsText), &getCellText->Text); + } break; case PHPRTLC_HANDLES: - PhpFormatInt32GroupDigits(processItem->NumberOfHandles, node->HandlesText, sizeof(node->HandlesText), &getCellText->Text); + { + ULONG value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt32, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, NumberOfHandles), &value); + PhpFormatInt32GroupDigits(value, node->HandlesText, sizeof(node->HandlesText), &getCellText->Text); + } break; case PHPRTLC_GDIHANDLES: PhpUpdateProcessNodeGdiUserHandles(node); @@ -2106,18 +2193,15 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_IORORATE: { - ULONG64 number; + ULONG64 number = 0; if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) { - number = processItem->IoReadDelta.Delta + processItem->IoOtherDelta.Delta; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoReadDelta.Delta), &number); + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoOtherDelta.Delta), &number); number *= 1000; number /= PhCsUpdateInterval; } - else - { - number = 0; - } if (number != 0) { @@ -2132,18 +2216,14 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( break; case PHPRTLC_IOWRATE: { - ULONG64 number; + ULONG64 number = 0; if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) { - number = processItem->IoWriteDelta.Delta; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, IoWriteDelta.Delta), &number); number *= 1000; number /= PhCsUpdateInterval; } - else - { - number = 0; - } if (number != 0) { @@ -2294,9 +2374,12 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( case PHPRTLC_CYCLES: if (WindowsVersion >= WINDOWS_7) { - if (processItem->CycleTimeDelta.Value != 0) + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Value), &value); + + if (value != 0) { - PhMoveReference(&node->CyclesText, PhFormatUInt64(processItem->CycleTimeDelta.Value, TRUE)); + PhMoveReference(&node->CyclesText, PhFormatUInt64(value, TRUE)); getCellText->Text = node->CyclesText->sr; } } @@ -2308,9 +2391,12 @@ BOOLEAN NTAPI PhpProcessTreeNewCallback( case PHPRTLC_CYCLESDELTA: if (WindowsVersion >= WINDOWS_7) { - if (processItem->CycleTimeDelta.Delta != 0) + ULONG64 value = 0; + PhpAggregateFieldIfNeeded(node, AggregateTypeInt64, AggregateLocationProcessItem, FIELD_OFFSET(PH_PROCESS_ITEM, CycleTimeDelta.Delta), &value); + + if (value != 0) { - PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(processItem->CycleTimeDelta.Delta, TRUE)); + PhMoveReference(&node->CyclesDeltaText, PhFormatUInt64(value, TRUE)); getCellText->Text = node->CyclesDeltaText->sr; } } diff --git a/2.x/trunk/phlib/format_i.h b/2.x/trunk/phlib/format_i.h index 0a443fc3f..5158e6a38 100644 --- a/2.x/trunk/phlib/format_i.h +++ b/2.x/trunk/phlib/format_i.h @@ -494,7 +494,7 @@ CommonInt64Format: maxSizeUnit = PhMaxSizeUnit; while ( - s >= 1024 && + s >= 1000 && i < sizeof(PhpSizeUnitNamesCounted) / sizeof(PH_STRINGREF) && i < maxSizeUnit )