Merge pull request #432 from stevenh/raw-sysctl

Eliminate use of sysctl command on FreeBSD
pull/438/head
shirou 8 years ago committed by GitHub
commit 8f7dc4e5a1

@ -3,21 +3,14 @@ package cpu
import ( import (
"fmt" "fmt"
"os/exec" "os/exec"
"reflect"
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"unsafe"
"github.com/shirou/gopsutil/internal/common" "github.com/shirou/gopsutil/internal/common"
) "golang.org/x/sys/unix"
// sys/resource.h
const (
CPUser = 0
CPNice = 1
CPSys = 2
CPIntr = 3
CPIdle = 4
CPUStates = 5
) )
var ClocksPerSec = float64(128) var ClocksPerSec = float64(128)
@ -27,6 +20,8 @@ var featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`)
var featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`) var featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`)
var cpuEnd = regexp.MustCompile(`^Trying to mount root`) var cpuEnd = regexp.MustCompile(`^Trying to mount root`)
var cpuCores = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`) var cpuCores = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`)
var cpuTimesSize int
var emptyTimes cpuTimes
func init() { func init() {
getconf, err := exec.LookPath("/usr/bin/getconf") getconf, err := exec.LookPath("/usr/bin/getconf")
@ -43,64 +38,49 @@ func init() {
} }
} }
func Times(percpu bool) ([]TimesStat, error) { func timeStat(name string, t *cpuTimes) *TimesStat {
var ret []TimesStat return &TimesStat{
User: float64(t.User) / ClocksPerSec,
var sysctlCall string Nice: float64(t.Nice) / ClocksPerSec,
var ncpu int System: float64(t.Sys) / ClocksPerSec,
if percpu { Idle: float64(t.Idle) / ClocksPerSec,
sysctlCall = "kern.cp_times" Irq: float64(t.Intr) / ClocksPerSec,
ncpu, _ = Counts(true) CPU: name,
} else {
sysctlCall = "kern.cp_time"
ncpu = 1
}
cpuTimes, err := common.DoSysctrl(sysctlCall)
if err != nil {
return ret, err
} }
}
for i := 0; i < ncpu; i++ { func Times(percpu bool) ([]TimesStat, error) {
offset := CPUStates * i if percpu {
user, err := strconv.ParseFloat(cpuTimes[CPUser+offset], 64) buf, err := unix.SysctlRaw("kern.cp_times")
if err != nil {
return ret, err
}
nice, err := strconv.ParseFloat(cpuTimes[CPNice+offset], 64)
if err != nil {
return ret, err
}
sys, err := strconv.ParseFloat(cpuTimes[CPSys+offset], 64)
if err != nil {
return ret, err
}
idle, err := strconv.ParseFloat(cpuTimes[CPIdle+offset], 64)
if err != nil {
return ret, err
}
intr, err := strconv.ParseFloat(cpuTimes[CPIntr+offset], 64)
if err != nil { if err != nil {
return ret, err return nil, err
} }
c := TimesStat{ // We can't do this in init due to the conflict with cpu.init()
User: float64(user / ClocksPerSec), if cpuTimesSize == 0 {
Nice: float64(nice / ClocksPerSec), cpuTimesSize = int(reflect.TypeOf(cpuTimes{}).Size())
System: float64(sys / ClocksPerSec),
Idle: float64(idle / ClocksPerSec),
Irq: float64(intr / ClocksPerSec),
} }
if !percpu {
c.CPU = "cpu-total" ncpus := len(buf) / cpuTimesSize
} else { ret := make([]TimesStat, 0, ncpus)
c.CPU = fmt.Sprintf("cpu%d", i) for i := 0; i < ncpus; i++ {
times := (*cpuTimes)(unsafe.Pointer(&buf[i*cpuTimesSize]))
if *times == emptyTimes {
// CPU not present
continue
}
ret = append(ret, *timeStat(fmt.Sprintf("cpu%d", len(ret)), times))
} }
return ret, nil
}
ret = append(ret, c) buf, err := unix.SysctlRaw("kern.cp_time")
if err != nil {
return nil, err
} }
return ret, nil times := (*cpuTimes)(unsafe.Pointer(&buf[0]))
return []TimesStat{*timeStat("cpu-total", times)}, nil
} }
// Returns only one InfoStat on FreeBSD. The information regarding core // Returns only one InfoStat on FreeBSD. The information regarding core
@ -113,27 +93,21 @@ func Info() ([]InfoStat, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var vals []string
if vals, err = common.DoSysctrl("hw.clockrate"); err != nil { var u32 uint32
if u32, err = unix.SysctlUint32("hw.clockrate"); err != nil {
return nil, err return nil, err
} }
if c.Mhz, err = strconv.ParseFloat(vals[0], 64); err != nil { c.Mhz = float64(u32)
return nil, fmt.Errorf("unable to parse FreeBSD CPU clock rate: %v", err)
}
if vals, err = common.DoSysctrl("hw.ncpu"); err != nil { if u32, err = unix.SysctlUint32("hw.ncpu"); err != nil {
return nil, err return nil, err
} }
var i64 int64 c.Cores = int32(u32)
if i64, err = strconv.ParseInt(vals[0], 10, 32); err != nil {
return nil, fmt.Errorf("unable to parse FreeBSD cores: %v", err)
}
c.Cores = int32(i64)
if vals, err = common.DoSysctrl("hw.model"); err != nil { if c.ModelName, err = unix.Sysctl("hw.model"); err != nil {
return nil, err return nil, err
} }
c.ModelName = strings.Join(vals, " ")
ret := make([]InfoStat, num) ret := make([]InfoStat, num)
for i := 0; i < num; i++ { for i := 0; i < num; i++ {

@ -0,0 +1,9 @@
package cpu
type cpuTimes struct {
User uint32
Nice uint32
Sys uint32
Intr uint32
Idle uint32
}

@ -0,0 +1,9 @@
package cpu
type cpuTimes struct {
User uint64
Nice uint64
Sys uint64
Intr uint64
Idle uint64
}

@ -9,14 +9,15 @@ import (
"os" "os"
"os/exec" "os/exec"
"runtime" "runtime"
"strconv"
"strings" "strings"
"sync/atomic" "sync/atomic"
"syscall"
"time" "time"
"unsafe" "unsafe"
"github.com/shirou/gopsutil/internal/common" "github.com/shirou/gopsutil/internal/common"
"github.com/shirou/gopsutil/process" "github.com/shirou/gopsutil/process"
"golang.org/x/sys/unix"
) )
const ( const (
@ -61,9 +62,9 @@ func Info() (*InfoStat, error) {
ret.Procs = uint64(len(procs)) ret.Procs = uint64(len(procs))
} }
values, err := common.DoSysctrl("kern.hostuuid") hostid, err := unix.Sysctl("kern.hostuuid")
if err == nil && len(values) == 1 && values[0] != "" { if err == nil && hostid != "" {
ret.HostID = strings.ToLower(values[0]) ret.HostID = strings.ToLower(hostid)
} }
return ret, nil return ret, nil
@ -77,19 +78,13 @@ func BootTime() (uint64, error) {
if t != 0 { if t != 0 {
return t, nil return t, nil
} }
values, err := common.DoSysctrl("kern.boottime") buf, err := unix.SysctlRaw("kern.boottime")
if err != nil { if err != nil {
return 0, err return 0, err
} }
// ex: { sec = 1392261637, usec = 627534 } Thu Feb 13 12:20:37 2014
v := strings.Replace(values[2], ",", "", 1)
boottime, err := strconv.ParseUint(v, 10, 64) tv := *(*syscall.Timeval)(unsafe.Pointer((&buf[0])))
if err != nil { atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec))
return 0, err
}
t = uint64(boottime)
atomic.StoreUint64(&cachedBootTime, t)
return t, nil return t, nil
} }

@ -1,4 +1,4 @@
// +build freebsd // +build freebsd openbsd
package load package load
@ -32,7 +32,7 @@ func Avg() (*AvgStat, error) {
return ret, nil return ret, nil
} }
// Misc returnes miscellaneous host-wide statistics. // Misc returns miscellaneous host-wide statistics.
// darwin use ps command to get process running/blocked count. // darwin use ps command to get process running/blocked count.
// Almost same as Darwin implementation, but state is different. // Almost same as Darwin implementation, but state is different.
func Misc() (*MiscStat, error) { func Misc() (*MiscStat, error) {

@ -1,65 +0,0 @@
// +build openbsd
package load
import (
"os/exec"
"strconv"
"strings"
"github.com/shirou/gopsutil/internal/common"
)
func Avg() (*AvgStat, error) {
values, err := common.DoSysctrl("vm.loadavg")
if err != nil {
return nil, err
}
load1, err := strconv.ParseFloat(values[0], 64)
if err != nil {
return nil, err
}
load5, err := strconv.ParseFloat(values[1], 64)
if err != nil {
return nil, err
}
load15, err := strconv.ParseFloat(values[2], 64)
if err != nil {
return nil, err
}
ret := &AvgStat{
Load1: float64(load1),
Load5: float64(load5),
Load15: float64(load15),
}
return ret, nil
}
// Misc returnes miscellaneous host-wide statistics.
// darwin use ps command to get process running/blocked count.
// Almost same as Darwin implementation, but state is different.
func Misc() (*MiscStat, error) {
bin, err := exec.LookPath("ps")
if err != nil {
return nil, err
}
out, err := invoke.Command(bin, "axo", "state")
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
ret := MiscStat{}
for _, l := range lines {
if strings.Contains(l, "R") {
ret.ProcsRunning++
} else if strings.Contains(l, "D") {
ret.ProcsBlocked++
}
}
return &ret, nil
}

@ -8,74 +8,52 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/shirou/gopsutil/internal/common" "golang.org/x/sys/unix"
) )
func VirtualMemory() (*VirtualMemoryStat, error) { func VirtualMemory() (*VirtualMemoryStat, error) {
pageSize, err := common.DoSysctrl("vm.stats.vm.v_page_size") pageSize, err := unix.SysctlUint32("vm.stats.vm.v_page_size")
if err != nil { if err != nil {
return nil, err return nil, err
} }
p, err := strconv.ParseUint(pageSize[0], 10, 64) pageCount, err := unix.SysctlUint32("vm.stats.vm.v_page_count")
if err != nil { if err != nil {
return nil, err return nil, err
} }
free, err := unix.SysctlUint32("vm.stats.vm.v_free_count")
pageCount, err := common.DoSysctrl("vm.stats.vm.v_page_count")
if err != nil { if err != nil {
return nil, err return nil, err
} }
free, err := common.DoSysctrl("vm.stats.vm.v_free_count") active, err := unix.SysctlUint32("vm.stats.vm.v_active_count")
if err != nil { if err != nil {
return nil, err return nil, err
} }
active, err := common.DoSysctrl("vm.stats.vm.v_active_count") inactive, err := unix.SysctlUint32("vm.stats.vm.v_inactive_count")
if err != nil { if err != nil {
return nil, err return nil, err
} }
inactive, err := common.DoSysctrl("vm.stats.vm.v_inactive_count") cached, err := unix.SysctlUint32("vm.stats.vm.v_cache_count")
if err != nil { if err != nil {
return nil, err return nil, err
} }
cache, err := common.DoSysctrl("vm.stats.vm.v_cache_count") buffers, err := unix.SysctlUint32("vfs.bufspace")
if err != nil { if err != nil {
return nil, err return nil, err
} }
buffer, err := common.DoSysctrl("vfs.bufspace") wired, err := unix.SysctlUint32("vm.stats.vm.v_wire_count")
if err != nil { if err != nil {
return nil, err return nil, err
} }
wired, err := common.DoSysctrl("vm.stats.vm.v_wire_count")
if err != nil {
return nil, err
}
parsed := make([]uint64, 0, 7)
vv := []string{
pageCount[0],
free[0],
active[0],
inactive[0],
cache[0],
buffer[0],
wired[0],
}
for _, target := range vv {
t, err := strconv.ParseUint(target, 10, 64)
if err != nil {
return nil, err
}
parsed = append(parsed, t)
}
p := uint64(pageSize)
ret := &VirtualMemoryStat{ ret := &VirtualMemoryStat{
Total: parsed[0] * p, Total: uint64(pageCount) * p,
Free: parsed[1] * p, Free: uint64(free) * p,
Active: parsed[2] * p, Active: uint64(active) * p,
Inactive: parsed[3] * p, Inactive: uint64(inactive) * p,
Cached: parsed[4] * p, Cached: uint64(cached) * p,
Buffers: parsed[5], Buffers: uint64(buffers),
Wired: parsed[6] * p, Wired: uint64(wired) * p,
} }
ret.Available = ret.Inactive + ret.Cached + ret.Free ret.Available = ret.Inactive + ret.Cached + ret.Free

Loading…
Cancel
Save