shirou_gopsutil/v3/cpu/cpu_openbsd.go

179 lines
3.3 KiB
Go
Raw Normal View History

// +build openbsd
package cpu
import (
"bytes"
"context"
"encoding/binary"
"fmt"
"runtime"
"strconv"
"strings"
"syscall"
"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
)
// 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
)
var ClocksPerSec = float64(128)
func init() {
clkTck, err := sysconf.Sysconf(sysconf.SC_CLK_TCK)
// ignore errors
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
}
for i := 0; i < ncpu; i++ {
j := i
if !smt {
j *= 2
}
var cpuTimes = make([]int32, cpUStates)
var mib []int32
if percpu {
mib = []int32{ctlKern, kernCptime2, int32(j)}
} else {
mib = []int32{ctlKern, kernCptime}
}
buf, _, err := common.CallSyscall(mib)
if err != nil {
return ret, err
}
br := bytes.NewReader(buf)
err = binary.Read(br, binary.LittleEndian, &cpuTimes)
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"
}
ret = append(ret, c)
}
return ret, nil
}
// Returns only one (minimal) CPUInfoStat on OpenBSD
func Info() ([]InfoStat, error) {
return InfoWithContext(context.Background())
}
func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
var ret []InfoStat
var err error
c := InfoStat{}
mhz, err := unix.SysctlUint32("hw.cpuspeed")
if err != nil {
return nil, err
}
c.Mhz = float64(mhz)
ncpu, err := unix.SysctlUint32("hw.ncpuonline")
if err != nil {
return nil, err
}
c.Cores = int32(ncpu)
if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
return nil, err
}
return append(ret, c), nil
}
func CountsWithContext(ctx context.Context, logical bool) (int, error) {
return runtime.NumCPU(), nil
}