Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix cpu_openbsd.go once and for all #1244

Merged
merged 6 commits into from Feb 25, 2022
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
155 changes: 59 additions & 96 deletions cpu/cpu_openbsd.go
Expand Up @@ -4,37 +4,35 @@
package cpu

import (
"bytes"
"context"
"encoding/binary"
"fmt"
"runtime"
"strconv"
"strings"
"syscall"
"unsafe"

"github.com/shirou/gopsutil/v3/internal/common"
"github.com/tklauser/go-sysconf"
"golang.org/x/sys/unix"
)

// sys/sched.h
var (
CPUser = 0
cpNice = 1
cpSys = 2
cpIntr = 3
cpIdle = 4
cpUStates = 5
)
import "C"

// sys/sysctl.h
const (
ctlKern = 1 // "high kernel": proc, limits
ctlHw = 6 // CTL_HW
sMT = 24 // HW_sMT
kernCptime = 40 // KERN_CPTIME
kernCptime2 = 71 // KERN_CPTIME2
// sys/sched.h
cpUser = 0
cpNice = 1
cpSys = 2
cpSpin = 3
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
kernCPUStats = 85 // KERN_CPUSTATS
)

var ClocksPerSec = float64(128)
Expand All @@ -45,99 +43,64 @@ func init() {
if err == nil {
ClocksPerSec = float64(clkTck)
}

func() {
v, err := unix.Sysctl("kern.osrelease") // can't reuse host.PlatformInformation because of circular import
if err != nil {
return
}
v = strings.ToLower(v)
version, err := strconv.ParseFloat(v, 64)
if err != nil {
return
}
if version >= 6.4 {
cpIntr = 4
cpIdle = 5
cpUStates = 6
}
}()
}

func smt() (bool, error) {
mib := []int32{ctlHw, sMT}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return false, err
}

var ret bool
br := bytes.NewReader(buf)
if err := binary.Read(br, binary.LittleEndian, &ret); err != nil {
return false, err
}

return ret, 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
}

smt, err := smt()
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 cpsToTS(cpuTimes []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,
}
}

for i := 0; i < ncpu; i++ {
j := i
if !smt {
j *= 2
}

cpuTimes := make([]int32, cpUStates)
var mib []int32
if percpu {
mib = []int32{ctlKern, kernCptime2, int32(j)}
} else {
mib = []int32{ctlKern, kernCptime}
}
func TimesWithContext(ctx context.Context, percpu bool) (ret []TimesStat, err error) {
if !percpu {
mib := []int32{ctlKern, kernCpTime}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return ret, err
}
var x []C.long
// could use unsafe.Slice but it's only for go1.17+
x = (*[cpuStates]C.long)(unsafe.Pointer(&buf[0]))[:]
shirou marked this conversation as resolved.
Show resolved Hide resolved
cpuTimes := [cpuStates]uint64{}
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
}

br := bytes.NewReader(buf)
err = binary.Read(br, binary.LittleEndian, &cpuTimes)
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
}
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"

data := unsafe.Pointer(&buf[0])
fptr := unsafe.Pointer(uintptr(data) + uintptr(8*cpuStates))
flags := *(*uint64)(fptr)
if (flags & cpuOnline) == 0 {
continue
}

var x []uint64
x = (*[cpuStates]uint64)(data)[:]
c := cpsToTS(x, fmt.Sprintf("cpu%d", i))
ret = append(ret, c)
}

Expand Down