Skip to content

Commit 797e67f

Browse files
authored
Merge pull request #43 from DataDog/kserrania/fix-cpu-m1
[macOS M1] Backports from upstream to fix cpu.Info() crashes Since #40, we can build projects containing this gopsutil fork on macOS M1. However, using cpu.Info() causes a crash: sysctl hw.cpufrequency doesn't return anything on M1, which makes the following snippet crash: out, err = invoke.Command(sysctl, "hw.cpufrequency") if err != nil { return ret, err } values := strings.Fields(string(out)) hz, err := strconv.ParseFloat(values[1], 64) with an index out-of-range error. This PR: - backports Lomanic/gopsutil@2ec3560, which uses golang.org/x/sys/unix.Sysctl instead of manual calls to the sysctl binary, preventing the crash - backports shirou#1192 to not make cpu.Info() return an error when the CPU frequency cannot be found, to prevent the method from erroring on M1.
2 parents 404e39a + 08bb266 commit 797e67f

File tree

1 file changed

+32
-61
lines changed

1 file changed

+32
-61
lines changed

cpu/cpu_darwin.go

+32-61
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
package cpu
44

55
import (
6-
"os/exec"
76
"strconv"
87
"strings"
8+
9+
"golang.org/x/sys/unix"
910
)
1011

1112
// sys/resource.h
@@ -32,75 +33,45 @@ func Times(percpu bool) ([]TimesStat, error) {
3233
// Returns only one CPUInfoStat on FreeBSD
3334
func Info() ([]InfoStat, error) {
3435
var ret []InfoStat
35-
sysctl, err := exec.LookPath("/usr/sbin/sysctl")
36-
if err != nil {
37-
return ret, err
38-
}
39-
out, err := invoke.Command(sysctl, "machdep.cpu")
40-
if err != nil {
41-
return ret, err
42-
}
4336

4437
c := InfoStat{}
45-
for _, line := range strings.Split(string(out), "\n") {
46-
values := strings.Fields(line)
47-
if len(values) < 1 {
48-
continue
38+
c.ModelName, _ = unix.Sysctl("machdep.cpu.brand_string")
39+
family, _ := unix.SysctlUint32("machdep.cpu.family")
40+
c.Family = strconv.FormatUint(uint64(family), 10)
41+
model, _ := unix.SysctlUint32("machdep.cpu.model")
42+
c.Model = strconv.FormatUint(uint64(model), 10)
43+
stepping, _ := unix.SysctlUint32("machdep.cpu.stepping")
44+
c.Stepping = int32(stepping)
45+
features, err := unix.Sysctl("machdep.cpu.features")
46+
if err == nil {
47+
for _, v := range strings.Fields(features) {
48+
c.Flags = append(c.Flags, strings.ToLower(v))
4949
}
50-
51-
t, err := strconv.ParseInt(values[1], 10, 64)
52-
// err is not checked here because some value is string.
53-
if strings.HasPrefix(line, "machdep.cpu.brand_string") {
54-
c.ModelName = strings.Join(values[1:], " ")
55-
} else if strings.HasPrefix(line, "machdep.cpu.family") {
56-
c.Family = values[1]
57-
} else if strings.HasPrefix(line, "machdep.cpu.model") {
58-
c.Model = values[1]
59-
} else if strings.HasPrefix(line, "machdep.cpu.stepping") {
60-
if err != nil {
61-
return ret, err
62-
}
63-
c.Stepping = int32(t)
64-
} else if strings.HasPrefix(line, "machdep.cpu.features") {
65-
for _, v := range values[1:] {
66-
c.Flags = append(c.Flags, strings.ToLower(v))
67-
}
68-
} else if strings.HasPrefix(line, "machdep.cpu.leaf7_features") {
69-
for _, v := range values[1:] {
70-
c.Flags = append(c.Flags, strings.ToLower(v))
71-
}
72-
} else if strings.HasPrefix(line, "machdep.cpu.extfeatures") {
73-
for _, v := range values[1:] {
74-
c.Flags = append(c.Flags, strings.ToLower(v))
75-
}
76-
} else if strings.HasPrefix(line, "machdep.cpu.core_count") {
77-
if err != nil {
78-
return ret, err
79-
}
80-
c.Cores = int32(t)
81-
} else if strings.HasPrefix(line, "machdep.cpu.cache.size") {
82-
if err != nil {
83-
return ret, err
84-
}
85-
c.CacheSize = int32(t)
86-
} else if strings.HasPrefix(line, "machdep.cpu.vendor") {
87-
c.VendorID = values[1]
50+
}
51+
leaf7Features, err := unix.Sysctl("machdep.cpu.leaf7_features")
52+
if err == nil {
53+
for _, v := range strings.Fields(leaf7Features) {
54+
c.Flags = append(c.Flags, strings.ToLower(v))
8855
}
8956
}
57+
extfeatures, err := unix.Sysctl("machdep.cpu.extfeatures")
58+
if err == nil {
59+
for _, v := range strings.Fields(extfeatures) {
60+
c.Flags = append(c.Flags, strings.ToLower(v))
61+
}
62+
}
63+
cores, _ := unix.SysctlUint32("machdep.cpu.core_count")
64+
c.Cores = int32(cores)
65+
cacheSize, _ := unix.SysctlUint32("machdep.cpu.cache.size")
66+
c.CacheSize = int32(cacheSize)
67+
c.VendorID, _ = unix.Sysctl("machdep.cpu.vendor")
9068

9169
// Use the rated frequency of the CPU. This is a static value and does not
9270
// account for low power or Turbo Boost modes.
93-
out, err = invoke.Command(sysctl, "hw.cpufrequency")
94-
if err != nil {
95-
return ret, err
96-
}
97-
98-
values := strings.Fields(string(out))
99-
hz, err := strconv.ParseFloat(values[1], 64)
100-
if err != nil {
101-
return ret, err
71+
cpuFrequency, err := unix.SysctlUint64("hw.cpufrequency")
72+
if err == nil {
73+
c.Mhz = float64(cpuFrequency) / 1000000.0
10274
}
103-
c.Mhz = hz / 1000000.0
10475

10576
return append(ret, c), nil
10677
}

0 commit comments

Comments
 (0)