A drive is a drive: NVMe namespaces fold into their controller
An Apple SSD presents three namespaces and the kernel lists each as a whole disk, so the dashboard was showing one drive as three. The Disks page has always folded them; now the dashboard, the Top tab and the disk.* sensors do too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
5761ee09db
commit
4b255fe63f
@@ -715,10 +715,53 @@ func (c *Collector) disks(dt float64) []Disk {
|
||||
c.prevDisk[name] = [3]uint64{rd, wr, ticks}
|
||||
out = append(out, d)
|
||||
}
|
||||
out = foldNVMe(out)
|
||||
sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
|
||||
return out
|
||||
}
|
||||
|
||||
var nsRe = regexp.MustCompile(`^(nvme\d+)n\d+$`)
|
||||
|
||||
// foldNVMe merges nvme0n1, nvme0n2, … into the drive they are: one controller presenting
|
||||
// several namespaces, which the kernel lists as whole disks apiece. An Apple SSD shows three —
|
||||
// the 466 GiB of storage and two of firmware, a few MiB each — and a page that lists disks was
|
||||
// listing all three as separate drives. The Disks page has always folded them (internal/storage
|
||||
// does the same); this is what the dashboard, the Top tab and the disk.* sensors read.
|
||||
//
|
||||
// Rates add up across namespaces. Busy does not: they share one controller, so the time it
|
||||
// spent working is the longest of them, never the sum.
|
||||
func foldNVMe(devs []Disk) []Disk {
|
||||
byCtrl := map[string]int{}
|
||||
out := devs[:0]
|
||||
for _, d := range devs {
|
||||
m := nsRe.FindStringSubmatch(d.Name)
|
||||
if m == nil {
|
||||
out = append(out, d)
|
||||
continue
|
||||
}
|
||||
ctrl := m[1]
|
||||
if i, ok := byCtrl[ctrl]; ok {
|
||||
out[i].Size += d.Size
|
||||
out[i].ReadBps = round1(out[i].ReadBps + d.ReadBps)
|
||||
out[i].WriteBps = round1(out[i].WriteBps + d.WriteBps)
|
||||
if d.UtilPct > out[i].UtilPct {
|
||||
out[i].UtilPct = d.UtilPct
|
||||
}
|
||||
if out[i].Temp == 0 {
|
||||
out[i].Temp = d.Temp
|
||||
}
|
||||
continue
|
||||
}
|
||||
d.Name = ctrl
|
||||
if mdl := strings.TrimSpace(readStr("/sys/class/nvme/" + ctrl + "/model")); mdl != "" {
|
||||
d.Model = mdl
|
||||
}
|
||||
byCtrl[ctrl] = len(out)
|
||||
out = append(out, d)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// ---- filesystems ----
|
||||
|
||||
// Kernel/virtual filesystems that aren't storage. Anything else that's mounted is
|
||||
|
||||
Reference in New Issue
Block a user