mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-27 05:57:27 +00:00
4f14ad6ab9
Three rules chose a node's single CPU temperature. Node history took CPUMax first, agent history took cpu_package first, and the node drawer recomputed the maximum of package, CPUMax and every core in the browser. On an agent-fed node CPUMax is built from cores alone and can sit below the package, and elsewhere a core can run above the package, so the drawer's CPU temperature headline could disagree with the line drawn beneath it and with the History tab. Node alerts and the CPU low/record tracking used yet another package-first rule. models.PrimaryCPUTemperatureCelsius is now the one rule: the hottest usable package, CPU-maximum or core reading, with a sensor-map form for agents. Node and agent history, the router's live fallbacks, the unified resource temperature, node temperature alerts and the CPU low/record tracking all call it. The drawer reads the resource value through a new Node.cpuTemperature field instead of recomputing it, and getCpuTemperature is removed. Mock mode wrote a second package reading under a cpu.package key into every agent host, including node-linked ones, from a series unrelated to the node's static reading. A node and its linked agent now carry one reading, sampled from the agent's series under the agent's real keys, and both histories seed from that series, so the current reading continues the line.
72 lines
2.1 KiB
Go
72 lines
2.1 KiB
Go
package models
|
|
|
|
import (
|
|
"math"
|
|
"strings"
|
|
)
|
|
|
|
// PrimaryCPUTemperatureCelsius is Pulse's one rule for a machine's headline
|
|
// CPU temperature: the hottest current CPU reading, taken from the package
|
|
// (Intel Package id, AMD Tctl/Tdie), the producer's CPU maximum, or any core.
|
|
//
|
|
// Every surface that names a single CPU temperature reads this value: node and
|
|
// agent metrics history, the unified resource temperature, node temperature
|
|
// alerts and the CPU low/record tracking. The node drawer shows the resource
|
|
// value instead of recomputing it, so its headline matches the line drawn
|
|
// beneath it. The hottest reading wins because it is the one nearest a thermal
|
|
// limit: AMD Tctl and Tccd, or a core running above the package, can differ by
|
|
// several degrees.
|
|
func PrimaryCPUTemperatureCelsius(temperature *Temperature) *float64 {
|
|
if temperature == nil || !temperature.Available {
|
|
return nil
|
|
}
|
|
var best float64
|
|
found := false
|
|
consider := func(value float64) {
|
|
if !usableCPUTemperature(value) {
|
|
return
|
|
}
|
|
if !found || value > best {
|
|
best = value
|
|
found = true
|
|
}
|
|
}
|
|
consider(temperature.CPUPackage)
|
|
consider(temperature.CPUMax)
|
|
for _, core := range temperature.Cores {
|
|
consider(core.Temp)
|
|
}
|
|
if !found {
|
|
return nil
|
|
}
|
|
return &best
|
|
}
|
|
|
|
// HostSensorPrimaryCPUTemperatureCelsius applies PrimaryCPUTemperatureCelsius
|
|
// to an agent's flat sensor map: the hottest reading whose key names a CPU
|
|
// sensor ("cpu_package", "cpu_core_N"). For the keys the agent reports this
|
|
// equals PrimaryCPUTemperatureCelsius of the node temperature built from the
|
|
// same map, so a linked node and its agent carry one value.
|
|
func HostSensorPrimaryCPUTemperatureCelsius(sensors HostSensorSummary) *float64 {
|
|
var best float64
|
|
found := false
|
|
for key, value := range sensors.TemperatureCelsius {
|
|
if !strings.HasPrefix(strings.ToLower(strings.TrimSpace(key)), "cpu") ||
|
|
!usableCPUTemperature(value) {
|
|
continue
|
|
}
|
|
if !found || value > best {
|
|
best = value
|
|
found = true
|
|
}
|
|
}
|
|
if !found {
|
|
return nil
|
|
}
|
|
return &best
|
|
}
|
|
|
|
func usableCPUTemperature(value float64) bool {
|
|
return value > 0 && !math.IsNaN(value) && !math.IsInf(value, 0)
|
|
}
|