From 57d5711d44975a0928fa81b0018d6c7c8a8002f7 Mon Sep 17 00:00:00 2001 From: Omar Polo Date: Sun, 6 Feb 2022 23:47:17 +0000 Subject: [PATCH] refactor TimesWithContext don't make assumptions on which CPUs are online and wich aren't based on hw.smt and hw.ncpuonline. Rather, use KERN_CPUSTATS to get the CPU statistics, which includes a flag field that can tell us if that CPU is online or not. --- cpu/cpu_openbsd.go | 119 ++++++++++++++++++++++------------------------------- 1 file changed, 49 insertions(+), 70 deletions(-) diff --git a/cpu/cpu_openbsd.go b/cpu/cpu_openbsd.go index 4acc7d0..2339ed7 100644 --- a/cpu/cpu_openbsd.go +++ b/cpu/cpu_openbsd.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "runtime" - "syscall" "unsafe" "github.com/shirou/gopsutil/v3/internal/common" @@ -26,13 +25,14 @@ const ( cpIntr = 4 cpIdle = 5 cpuStates = 6 + cpuOnline = 0x0001 // CPUSTATS_ONLINE // sys/sysctl.h - ctlKern = 1 // "high kernel": proc, limits - ctlHw = 6 // CTL_HW - smt = 24 // HW_SMT - kernCptime = 40 // KERN_CPTIME - kernCptime2 = 71 // KERN_CPTIME2 + ctlKern = 1 // "high kernel": proc, limits + ctlHw = 6 // CTL_HW + smt = 24 // HW_SMT + kernCpTime = 40 // KERN_CPTIME + kernCPUStats = 85 // KERN_CPUSTATS ) var ClocksPerSec = float64(128) @@ -45,87 +45,66 @@ func init() { } } -func smtEnabled() (bool, error) { - mib := []int32{ctlHw, smt} - buf, _, err := common.CallSyscall(mib) - if err != nil { - return false, err - } - - smt := *(*uint32)(unsafe.Pointer(&buf[0])) - return smt == 1, nil -} - func Times(percpu bool) ([]TimesStat, error) { return TimesWithContext(context.Background(), percpu) } -func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { - var ret []TimesStat - - var ncpu int - if percpu { - ncpu, _ = Counts(true) - } else { - ncpu = 1 +func cpsToTS(cpuTimes [cpuStates]uint64, name string) TimesStat { + return TimesStat{ + CPU: name, + User: float64(cpuTimes[cpUser]) / ClocksPerSec, + Nice: float64(cpuTimes[cpNice]) / ClocksPerSec, + System: float64(cpuTimes[cpSys]) / ClocksPerSec, + Idle: float64(cpuTimes[cpIdle]) / ClocksPerSec, + Irq: float64(cpuTimes[cpIntr]) / ClocksPerSec, } +} - smt, err := smtEnabled() - if err == syscall.EOPNOTSUPP { - // if hw.smt is not applicable for this platform (e.g. i386), - // pretend it's enabled - smt = true - } else if err != nil { - return nil, err - } +func TimesWithContext(ctx context.Context, percpu bool) (ret []TimesStat, err error) { + cpuTimes := [cpuStates]uint64{} - for i := 0; i < ncpu; i++ { - j := i - if !smt { - j *= 2 + if !percpu { + mib := []int32{ctlKern, kernCpTime} + buf, _, err := common.CallSyscall(mib) + if err != nil { + return ret, err } - - var mib []int32 - if percpu { - mib = []int32{ctlKern, kernCptime2, int32(j)} - } else { - mib = []int32{ctlKern, kernCptime} + var x []C.long + // could use unsafe.Slice but it's only for go1.17+ + x = (*[cpuStates]C.long)(unsafe.Pointer(&buf[0]))[:] + for i := range x { + cpuTimes[i] = uint64(x[i]) } + c := cpsToTS(cpuTimes, "cpu-total") + return []TimesStat{c}, nil + } + + ncpu, err := unix.SysctlUint32("hw.ncpu") + if err != nil { + return + } + + var i uint32 + for i = 0; i < ncpu; i++ { + mib := []int32{ctlKern, kernCPUStats, int32(i)} buf, _, err := common.CallSyscall(mib) if err != nil { return ret, err } - var cpuTimes [cpuStates]uint64 - if percpu { - // could use unsafe.Slice but it's only for go1.17+ - var x []uint64 - x = (*[cpuStates]uint64)(unsafe.Pointer(&buf[0]))[:] - for i := range x { - cpuTimes[i] = x[i] - } - } else { - // KERN_CPTIME yields long[CPUSTATES] and `long' is - // platform dependent - var x []C.long - x = (*[cpuStates]C.long)(unsafe.Pointer(&buf[0]))[:] - for i := range x { - cpuTimes[i] = uint64(x[i]) - } + data := unsafe.Pointer(&buf[0]) + fptr := unsafe.Pointer(uintptr(data) + uintptr(8*cpuStates)) + flags := *(*uint64)(fptr) + if (flags & cpuOnline) == 0 { + continue } - c := TimesStat{ - User: float64(cpuTimes[cpUser]) / ClocksPerSec, - Nice: float64(cpuTimes[cpNice]) / ClocksPerSec, - System: float64(cpuTimes[cpSys]) / ClocksPerSec, - Idle: float64(cpuTimes[cpIdle]) / ClocksPerSec, - Irq: float64(cpuTimes[cpIntr]) / ClocksPerSec, - } - if percpu { - c.CPU = fmt.Sprintf("cpu%d", j) - } else { - c.CPU = "cpu-total" + var x []uint64 + x = (*[cpuStates]uint64)(data)[:] + for i := range x { + cpuTimes[i] = x[i] } + c := cpsToTS(cpuTimes, fmt.Sprintf("cpu%d", i)) ret = append(ret, c) }