Note, dependency has to be pinned to a specific release version commit hashes since it doesn't follow Go module v2+ guidelines. see: https://github.com/shirou/gopsutil/issues/663 https://github.com/golang/go/issues/34402
		
			
				
	
	
		
			196 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// +build openbsd
 | 
						|
 | 
						|
package cpu
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"context"
 | 
						|
	"encoding/binary"
 | 
						|
	"fmt"
 | 
						|
	"os/exec"
 | 
						|
	"runtime"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"syscall"
 | 
						|
 | 
						|
	"github.com/shirou/gopsutil/internal/common"
 | 
						|
	"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
 | 
						|
	NCpuOnline  = 25 // HW_NCPUONLINE
 | 
						|
	KernCptime  = 40 // KERN_CPTIME
 | 
						|
	KernCptime2 = 71 // KERN_CPTIME2
 | 
						|
)
 | 
						|
 | 
						|
var ClocksPerSec = float64(128)
 | 
						|
 | 
						|
func init() {
 | 
						|
	func() {
 | 
						|
		getconf, err := exec.LookPath("getconf")
 | 
						|
		if err != nil {
 | 
						|
			return
 | 
						|
		}
 | 
						|
		out, err := invoke.Command(getconf, "CLK_TCK")
 | 
						|
		// ignore errors
 | 
						|
		if err == nil {
 | 
						|
			i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
 | 
						|
			if err == nil {
 | 
						|
				ClocksPerSec = float64(i)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}()
 | 
						|
	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{}
 | 
						|
 | 
						|
	var u32 uint32
 | 
						|
	if u32, err = unix.SysctlUint32("hw.cpuspeed"); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	c.Mhz = float64(u32)
 | 
						|
 | 
						|
	mib := []int32{CTLHw, NCpuOnline}
 | 
						|
	buf, _, err := common.CallSyscall(mib)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	var ncpu int32
 | 
						|
	br := bytes.NewReader(buf)
 | 
						|
	err = binary.Read(br, binary.LittleEndian, &ncpu)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	c.Cores = 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
 | 
						|
}
 |