cpu_openbsd.go 3.3 KB

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