github.com/boomhut/fiber/v2@v2.0.0-20230603160335-b65c856e57d3/internal/gopsutil/cpu/cpu_openbsd.go (about)

     1  //go:build openbsd
     2  // +build openbsd
     3  
     4  package cpu
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"encoding/binary"
    10  	"fmt"
    11  	"os/exec"
    12  	"runtime"
    13  	"strconv"
    14  	"strings"
    15  	"syscall"
    16  
    17  	"github.com/boomhut/fiber/v2/internal/gopsutil/common"
    18  	"golang.org/x/sys/unix"
    19  )
    20  
    21  // sys/sched.h
    22  var (
    23  	CPUser    = 0
    24  	CPNice    = 1
    25  	CPSys     = 2
    26  	CPIntr    = 3
    27  	CPIdle    = 4
    28  	CPUStates = 5
    29  )
    30  
    31  // sys/sysctl.h
    32  const (
    33  	CTLKern     = 1  // "high kernel": proc, limits
    34  	CTLHw       = 6  // CTL_HW
    35  	SMT         = 24 // HW_SMT
    36  	KernCptime  = 40 // KERN_CPTIME
    37  	KernCptime2 = 71 // KERN_CPTIME2
    38  )
    39  
    40  var ClocksPerSec = float64(128)
    41  
    42  func init() {
    43  	func() {
    44  		getconf, err := exec.LookPath("getconf")
    45  		if err != nil {
    46  			return
    47  		}
    48  		out, err := invoke.Command(getconf, "CLK_TCK")
    49  		// ignore errors
    50  		if err == nil {
    51  			i, err := strconv.ParseFloat(strings.TrimSpace(string(out)), 64)
    52  			if err == nil {
    53  				ClocksPerSec = float64(i)
    54  			}
    55  		}
    56  	}()
    57  	func() {
    58  		v, err := unix.Sysctl("kern.osrelease") // can't reuse host.PlatformInformation because of circular import
    59  		if err != nil {
    60  			return
    61  		}
    62  		v = strings.ToLower(v)
    63  		version, err := strconv.ParseFloat(v, 64)
    64  		if err != nil {
    65  			return
    66  		}
    67  		if version >= 6.4 {
    68  			CPIntr = 4
    69  			CPIdle = 5
    70  			CPUStates = 6
    71  		}
    72  	}()
    73  }
    74  
    75  func smt() (bool, error) {
    76  	mib := []int32{CTLHw, SMT}
    77  	buf, _, err := common.CallSyscall(mib)
    78  	if err != nil {
    79  		return false, err
    80  	}
    81  
    82  	var ret bool
    83  	br := bytes.NewReader(buf)
    84  	if err := binary.Read(br, binary.LittleEndian, &ret); err != nil {
    85  		return false, err
    86  	}
    87  
    88  	return ret, nil
    89  }
    90  
    91  func Times(percpu bool) ([]TimesStat, error) {
    92  	return TimesWithContext(context.Background(), percpu)
    93  }
    94  
    95  func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) {
    96  	var ret []TimesStat
    97  
    98  	var ncpu int
    99  	if percpu {
   100  		ncpu, _ = Counts(true)
   101  	} else {
   102  		ncpu = 1
   103  	}
   104  
   105  	smt, err := smt()
   106  	if err == syscall.EOPNOTSUPP {
   107  		// if hw.smt is not applicable for this platform (e.g. i386),
   108  		// pretend it's enabled
   109  		smt = true
   110  	} else if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	for i := 0; i < ncpu; i++ {
   115  		j := i
   116  		if !smt {
   117  			j *= 2
   118  		}
   119  
   120  		var cpuTimes = make([]int32, CPUStates)
   121  		var mib []int32
   122  		if percpu {
   123  			mib = []int32{CTLKern, KernCptime2, int32(j)}
   124  		} else {
   125  			mib = []int32{CTLKern, KernCptime}
   126  		}
   127  		buf, _, err := common.CallSyscall(mib)
   128  		if err != nil {
   129  			return ret, err
   130  		}
   131  
   132  		br := bytes.NewReader(buf)
   133  		err = binary.Read(br, binary.LittleEndian, &cpuTimes)
   134  		if err != nil {
   135  			return ret, err
   136  		}
   137  		c := TimesStat{
   138  			User:   float64(cpuTimes[CPUser]) / ClocksPerSec,
   139  			Nice:   float64(cpuTimes[CPNice]) / ClocksPerSec,
   140  			System: float64(cpuTimes[CPSys]) / ClocksPerSec,
   141  			Idle:   float64(cpuTimes[CPIdle]) / ClocksPerSec,
   142  			Irq:    float64(cpuTimes[CPIntr]) / ClocksPerSec,
   143  		}
   144  		if percpu {
   145  			c.CPU = fmt.Sprintf("cpu%d", j)
   146  		} else {
   147  			c.CPU = "cpu-total"
   148  		}
   149  		ret = append(ret, c)
   150  	}
   151  
   152  	return ret, nil
   153  }
   154  
   155  // Returns only one (minimal) CPUInfoStat on OpenBSD
   156  func Info() ([]InfoStat, error) {
   157  	return InfoWithContext(context.Background())
   158  }
   159  
   160  func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
   161  	var ret []InfoStat
   162  	var err error
   163  
   164  	c := InfoStat{}
   165  
   166  	mhz, err := unix.SysctlUint32("hw.cpuspeed")
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  	c.Mhz = float64(mhz)
   171  
   172  	ncpu, err := unix.SysctlUint32("hw.ncpuonline")
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	c.Cores = int32(ncpu)
   177  
   178  	if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
   179  		return nil, err
   180  	}
   181  
   182  	return append(ret, c), nil
   183  }
   184  
   185  func CountsWithContext(ctx context.Context, logical bool) (int, error) {
   186  	return runtime.NumCPU(), nil
   187  }