disk.IOCounters() is always an empty map on Darwin
Describe the bug
disk.IOCounters() does not return any information for any disks on Darwin.
To Reproduce
package main
import (
"fmt"
"github.com/shirou/gopsutil/disk"
)
func main() {
ps, err := disk.Partitions(false)
if err != nil {
panic(err)
}
for _, p := range ps {
iocs, err := disk.IOCounters(p.Device)
if err != nil {
panic(err)
}
fmt.Printf("Dev %s, MP %s, counters = %v\n", p.Device, p.Mountpoint, iocs)
for k, ioc := range iocs {
fmt.Printf("\tcounters[%s] = %v\n", k, ioc)
}
}
}
Observed:
MacBook-Air-2:tmp$ go run .
Dev /dev/disk1s1, MP /, counters = map[]
Dev /dev/disk1s4, MP /private/var/vm, counters = map[]
Expected behavior IO counters from the API to not be the empty set.
Environment (please complete the following information):
- [x] Mac OS: [paste the result of
sw_versanduname -a]
MacBook-Air-2:tmp$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.13.6
BuildVersion: 17G10021
MacBook-Air-2:tmp$ uname -a
Darwin MacBook-Air-2.local 17.7.0 Darwin Kernel Version 17.7.0: Sun Dec 1 19:19:56 PST 2019; root:xnu-4570.71.63~1/RELEASE_X86_64 x86_64
Additional context Not cross-compiling.
MacBook-Air-2:tmp Monika$ go version
go version go1.14.1 darwin/amd64
So, on OSX there isn't a relationship between partitions and the names under which IOCounters are stored. For example, on this laptop there are two partitions, devices /dev/disk1s1 and ...s4. There is one IOCounter with the name disk0, and no label. So maybe there's an issue with how the devices are mapped? On a system with exactly one hard drive, IOCounter thinks it's called disk0 and the device list has it as /devdisk1....
I haven't dug into the code any further, but I'm going to plug in some USB drives and see if I can identify the naming pattern.
Edit
Interesting.
- The internal hard drive is reported as
disk0byIOCounters()and/dev/disk1s1byPartitions() - A USB-C memory stick is reported as
disk2byIOCounters()and/dev/disk2s1byPartitions()This is going to make guessing at the mapping between the output of these two functions difficult.
The result of IOCounters() on Darwin comes from a C call. @Lomanic, were you the original contributor of this piece of code, and are you able to shed any light on this? I'm quickly getting out of my depth.
Edit 2
IOCounters() names come from the C call; Partitions() comes from a Go library; this probably accounts for the discrepency in naming.
Edit 3
I now believe that this behavior is a consequence of how Apple is handling logical volumes. Using the ghw libray, I see on this machine (only the internal HD, no USB stick):
disk disk0, 2 partitions
/dev/disk0s1 (300MB) [EFI]
/dev/disk0s2 (234GB) [Apple_APFS]
disk disk1, 4 partitions
/dev/disk1s1 (234GB) [APFS Volume] mounted@/
/dev/disk1s2 (234GB) [APFS Volume]
/dev/disk1s3 (234GB) [APFS Volume]
/dev/disk1s4 (234GB) [APFS Volume] mounted@/private/var/vm
disk0 is consistent with IOCounters() naming. However, the second partition is broken up into 4 logical volumes which all show up as disk1. IOCounters() doesn't see disk1 at all, and Partitions() sees only disk1. Partitions() does not, however, see all of the partitions; it only sees the first and last.
Incidentally, this could explain a second issue that's been reported (against gotop) by someone on Linux who's using LVM; if the disk package is having trouble with logical volumes under Darwin, perhaps it's also having difficulty with them under Linux. The bug reports have the same root cause in gotop -- that IOCounters is not matching device names and is returning empty maps.
Thanks for the repro case, I see indeed the behavior you describe on my VM. Interesting problem, I don't see an easy solution for the moment, would need more digging.
Regarding Linux, maybe this is the same thing as here https://github.com/shirou/gopsutil/issues/813#issuecomment-572307603