Top: a hyper-thread wears its core's temperature, and the columns line up

The process table carries each logical CPU's core id from sysfs topology; a row with
no reading still has the temperature cells, so the % column is one column.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-22 20:22:54 -07:00
co-authored by Claude Fable 5.1
parent 41e63f74e9
commit 4280b2226a
5 changed files with 41 additions and 8 deletions
+30
View File
@@ -1011,6 +1011,34 @@ func uidName(uid string) string {
return n
}
// coreIDs maps logical CPUs to physical cores from sysfs topology: on a chip with
// hyper-threading, CPUs 8–15 are the second threads of cores 0–7, and coretemp names its
// sensors by core. Read once; the topology does not change while we run.
var (
coreIDsOnce sync.Once
coreIDsVal []int
)
func coreIDs(n int) []int {
coreIDsOnce.Do(func() {
for i := 0; ; i++ {
b, err := os.ReadFile("/sys/devices/system/cpu/cpu" + strconv.Itoa(i) + "/topology/core_id")
if err != nil {
break
}
id, err := strconv.Atoi(strings.TrimSpace(string(b)))
if err != nil {
break
}
coreIDsVal = append(coreIDsVal, id)
}
})
if len(coreIDsVal) < n {
return nil
}
return coreIDsVal[:n]
}
// ProcTable is the Processes tab payload.
type ProcTable struct {
T int64 `json:"t"`
@@ -1021,6 +1049,7 @@ type ProcTable struct {
CPUMHz float64 `json:"cpu_mhz,omitempty"`
CPUMaxMHz float64 `json:"cpu_max_mhz,omitempty"`
CPUTemp float64 `json:"cpu_temp,omitempty"`
CoreIDs []int `json:"core_ids,omitempty"` // for each logical CPU, the physical core it is a thread of (what the temperature sensors are named by)
Load [3]float64 `json:"load"`
Mem Mem `json:"mem"`
Swap Mem `json:"swap"`
@@ -1204,6 +1233,7 @@ func (c *Collector) Processes() ProcTable {
if n := len(c.ring); n > 0 {
last := c.ring[n-1]
t.CPU, t.Cores, t.Net, t.CPUTemp = last.CPU, last.Cores, last.Net, cpuTemp(last.Temps)
t.CoreIDs = coreIDs(len(last.Cores))
from := n - 90
if from < 0 {
from = 0