From b8120e5a5a587fe56cf70ea41dbcd218da5391e8 Mon Sep 17 00:00:00 2001 From: Lord Hepipud Date: Mon, 26 Jan 2026 15:21:34 +0100 Subject: [PATCH] Feature: Changes CPU counter being used for measurement to % Processor Time --- doc/100-General/10-Changelog.md | 1 + .../New-IcingaEnvironmentVariable.psm1 | 1 + .../cpu/New-IcingaProviderFilterDataCpu.psm1 | 41 +++++++++++++------ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/doc/100-General/10-Changelog.md b/doc/100-General/10-Changelog.md index 45f8f45..ce36c8c 100644 --- a/doc/100-General/10-Changelog.md +++ b/doc/100-General/10-Changelog.md @@ -29,6 +29,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic * [#11](https://github.com/Icinga/icinga-powershell-framework/pull/11) Adds feature to update the cache for performance counter instances to keep track of system changes * [#838](https://github.com/Icinga/icinga-powershell-framework/pull/838) Enhances Icinga for Windows to never load and user PowerShell profiles * [#841](https://github.com/Icinga/icinga-powershell-framework/pull/841) Adds new [INFO] state for notice and un-checked monitoring objects +* [#849](https://github.com/Icinga/icinga-powershell-framework/pull/849) Changes CPU provider to use the `\Processor(*)\% Processor Time` counter instead of `\Processor Information(*)\% Processor Utility` ## 1.13.3 (2025-05-08) diff --git a/lib/core/framework/New-IcingaEnvironmentVariable.psm1 b/lib/core/framework/New-IcingaEnvironmentVariable.psm1 index b34c216..a8d1a6a 100644 --- a/lib/core/framework/New-IcingaEnvironmentVariable.psm1 +++ b/lib/core/framework/New-IcingaEnvironmentVariable.psm1 @@ -103,5 +103,6 @@ function New-IcingaEnvironmentVariable() 'FetchedServices' = $FALSE; } ); + $Global:Icinga.Protected.Add('CPUSockets', (Get-IcingaWindowsInformation Win32_Processor).Count); } } diff --git a/lib/provider/assets/cpu/New-IcingaProviderFilterDataCpu.psm1 b/lib/provider/assets/cpu/New-IcingaProviderFilterDataCpu.psm1 index b0ea011..67cc0f3 100644 --- a/lib/provider/assets/cpu/New-IcingaProviderFilterDataCpu.psm1 +++ b/lib/provider/assets/cpu/New-IcingaProviderFilterDataCpu.psm1 @@ -10,23 +10,38 @@ function New-IcingaProviderFilterDataCpu() [switch]$IncludeDetails = $FALSE ); - $CpuData = New-IcingaProviderObject -Name 'Cpu'; - $CpuCounter = New-IcingaPerformanceCounterArray '\Processor Information(*)\% Processor Utility'; - $CounterStructure = New-IcingaPerformanceCounterStructure -CounterCategory 'Processor Information' -PerformanceCounterHash $CpuCounter; - [int]$TotalCpuThreads = 0; - [decimal]$TotalCpuLoad = 0; - [int]$SocketCount = 0; - [hashtable]$SocketList = @{ }; + # TODO: Cleanup this mess + $CpuData = New-IcingaProviderObject -Name 'Cpu'; + $CpuCounter = New-IcingaPerformanceCounterArray '\Processor(*)\% Processor Time'; + $CounterStructure = New-IcingaPerformanceCounterStructure -CounterCategory 'Processor' -PerformanceCounterHash $CpuCounter; + [int]$TotalCpuThreads = 0; + [decimal]$TotalCpuLoad = 0; + [int]$SocketCount = 0; + [hashtable]$SocketList = @{ }; + # Store some general data about the CPU sockets and cores. As we moved back to + # \Processor(*)\% Processor Time, we need to manually try to map cores to sockets + # Remove ony entry from the counter list, which is not a core but the total load entry + [int]$NumberOfThreadsPerSocket = ($CpuCounter.Values.Keys.Count - 1) / $Global:Icinga.Protected.CPUSockets; + [int]$CurrentSocket = 0; + [int]$CurrentThread = 0; + [array]$SortedCoreList = $CounterStructure.Keys | Sort-Object { [int]($_ -replace '^\D+', ''); }; - foreach ($currentcore in $CounterStructure.Keys) { - [string]$Socket = $currentcore.Split(',')[0]; - [string]$CoreId = $currentcore.Split(',')[1]; - [string]$SocketName = [string]::Format('Socket #{0}', $Socket); + foreach ($currentcore in $SortedCoreList) { + [string]$CoreId = $currentcore.Trim(); - if ($Socket -eq '_Total' -Or $CoreId -eq '_Total') { + # We will handle the _Total entry ourselves later + if ($CoreId -eq '_Total') { continue; } + [string]$SocketName = [string]::Format('Socket #{0}', $CurrentSocket); + + $CurrentThread += 1; + if ($CurrentThread -ge $NumberOfThreadsPerSocket) { + $CurrentSocket += 1; + $CurrentThread = 0; + } + if ($SocketList.ContainsKey($SocketName) -eq $FALSE) { $SocketList.Add( $SocketName, @@ -41,7 +56,7 @@ function New-IcingaProviderFilterDataCpu() $CpuData.Metrics | Add-Member -MemberType NoteProperty -Name $SocketName -Value (New-Object PSCustomObject); } - [decimal]$CoreLoad = $CounterStructure[$currentcore]['% Processor Utility'].value; + [decimal]$CoreLoad = $CounterStructure[$CoreId]['% Processor Time'].value; if ($Limit100Percent) { if ($CoreLoad -gt 100) {