Vendor psutils and remove neko
This commit is contained in:
74
plugins/system/ps/cpu/cpu.go
Normal file
74
plugins/system/ps/cpu/cpu.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CPUTimesStat struct {
|
||||
CPU string `json:"cpu"`
|
||||
User float64 `json:"user"`
|
||||
System float64 `json:"system"`
|
||||
Idle float64 `json:"idle"`
|
||||
Nice float64 `json:"nice"`
|
||||
Iowait float64 `json:"iowait"`
|
||||
Irq float64 `json:"irq"`
|
||||
Softirq float64 `json:"softirq"`
|
||||
Steal float64 `json:"steal"`
|
||||
Guest float64 `json:"guest"`
|
||||
GuestNice float64 `json:"guest_nice"`
|
||||
Stolen float64 `json:"stolen"`
|
||||
}
|
||||
|
||||
type CPUInfoStat struct {
|
||||
CPU int32 `json:"cpu"`
|
||||
VendorID string `json:"vendor_id"`
|
||||
Family string `json:"family"`
|
||||
Model string `json:"model"`
|
||||
Stepping int32 `json:"stepping"`
|
||||
PhysicalID string `json:"physical_id"`
|
||||
CoreID string `json:"core_id"`
|
||||
Cores int32 `json:"cores"`
|
||||
ModelName string `json:"model_name"`
|
||||
Mhz float64 `json:"mhz"`
|
||||
CacheSize int32 `json:"cache_size"`
|
||||
Flags []string `json:"flags"`
|
||||
}
|
||||
|
||||
var lastCPUTimes []CPUTimesStat
|
||||
var lastPerCPUTimes []CPUTimesStat
|
||||
|
||||
func CPUCounts(logical bool) (int, error) {
|
||||
return runtime.NumCPU(), nil
|
||||
}
|
||||
|
||||
func (c CPUTimesStat) String() string {
|
||||
v := []string{
|
||||
`"cpu":"` + c.CPU + `"`,
|
||||
`"user":` + strconv.FormatFloat(c.User, 'f', 1, 64),
|
||||
`"system":` + strconv.FormatFloat(c.System, 'f', 1, 64),
|
||||
`"idle":` + strconv.FormatFloat(c.Idle, 'f', 1, 64),
|
||||
`"nice":` + strconv.FormatFloat(c.Nice, 'f', 1, 64),
|
||||
`"iowait":` + strconv.FormatFloat(c.Iowait, 'f', 1, 64),
|
||||
`"irq":` + strconv.FormatFloat(c.Irq, 'f', 1, 64),
|
||||
`"softirq":` + strconv.FormatFloat(c.Softirq, 'f', 1, 64),
|
||||
`"steal":` + strconv.FormatFloat(c.Steal, 'f', 1, 64),
|
||||
`"guest":` + strconv.FormatFloat(c.Guest, 'f', 1, 64),
|
||||
`"guest_nice":` + strconv.FormatFloat(c.GuestNice, 'f', 1, 64),
|
||||
`"stolen":` + strconv.FormatFloat(c.Stolen, 'f', 1, 64),
|
||||
}
|
||||
|
||||
return `{` + strings.Join(v, ",") + `}`
|
||||
}
|
||||
|
||||
func (c CPUInfoStat) String() string {
|
||||
s, _ := json.Marshal(c)
|
||||
return string(s)
|
||||
}
|
||||
|
||||
func init() {
|
||||
lastCPUTimes, _ = CPUTimes(false)
|
||||
lastPerCPUTimes, _ = CPUTimes(true)
|
||||
}
|
||||
149
plugins/system/ps/cpu/cpu_darwin.go
Normal file
149
plugins/system/ps/cpu/cpu_darwin.go
Normal file
@@ -0,0 +1,149 @@
|
||||
// +build darwin
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
common "github.com/shirou/gopsutil/common"
|
||||
)
|
||||
|
||||
// sys/resource.h
|
||||
const (
|
||||
CPUser = 0
|
||||
CPNice = 1
|
||||
CPSys = 2
|
||||
CPIntr = 3
|
||||
CPIdle = 4
|
||||
CPUStates = 5
|
||||
)
|
||||
|
||||
// time.h
|
||||
const (
|
||||
ClocksPerSec = 128
|
||||
)
|
||||
|
||||
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
|
||||
var ret []CPUTimesStat
|
||||
|
||||
var sysctlCall string
|
||||
var ncpu int
|
||||
if percpu {
|
||||
sysctlCall = "kern.cp_times"
|
||||
ncpu, _ = CPUCounts(true)
|
||||
} else {
|
||||
sysctlCall = "kern.cp_time"
|
||||
ncpu = 1
|
||||
}
|
||||
|
||||
cpuTimes, err := common.DoSysctrl(sysctlCall)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
for i := 0; i < ncpu; i++ {
|
||||
offset := CPUStates * i
|
||||
user, err := strconv.ParseFloat(cpuTimes[CPUser+offset], 64)
|
||||
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 {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
c := CPUTimesStat{
|
||||
User: float64(user / ClocksPerSec),
|
||||
Nice: float64(nice / ClocksPerSec),
|
||||
System: float64(sys / ClocksPerSec),
|
||||
Idle: float64(idle / ClocksPerSec),
|
||||
Irq: float64(intr / ClocksPerSec),
|
||||
}
|
||||
if !percpu {
|
||||
c.CPU = "cpu-total"
|
||||
} else {
|
||||
c.CPU = fmt.Sprintf("cpu%d", i)
|
||||
}
|
||||
|
||||
ret = append(ret, c)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Returns only one CPUInfoStat on FreeBSD
|
||||
func CPUInfo() ([]CPUInfoStat, error) {
|
||||
var ret []CPUInfoStat
|
||||
|
||||
out, err := exec.Command("/usr/sbin/sysctl", "machdep.cpu").Output()
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
c := CPUInfoStat{}
|
||||
for _, line := range strings.Split(string(out), "\n") {
|
||||
values := strings.Fields(line)
|
||||
if len(values) < 1 {
|
||||
continue
|
||||
}
|
||||
|
||||
t, err := strconv.ParseInt(values[1], 10, 64)
|
||||
// err is not checked here because some value is string.
|
||||
if strings.HasPrefix(line, "machdep.cpu.brand_string") {
|
||||
c.ModelName = strings.Join(values[1:], " ")
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.family") {
|
||||
c.Family = values[1]
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.model") {
|
||||
c.Model = values[1]
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.stepping") {
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
c.Stepping = int32(t)
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.features") {
|
||||
for _, v := range values[1:] {
|
||||
c.Flags = append(c.Flags, strings.ToLower(v))
|
||||
}
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.leaf7_features") {
|
||||
for _, v := range values[1:] {
|
||||
c.Flags = append(c.Flags, strings.ToLower(v))
|
||||
}
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.extfeatures") {
|
||||
for _, v := range values[1:] {
|
||||
c.Flags = append(c.Flags, strings.ToLower(v))
|
||||
}
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.core_count") {
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
c.Cores = int32(t)
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.cache.size") {
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
c.CacheSize = int32(t)
|
||||
} else if strings.HasPrefix(line, "machdep.cpu.vendor") {
|
||||
c.VendorID = values[1]
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// c.Mhz = mustParseFloat64(values[1])
|
||||
}
|
||||
|
||||
return append(ret, c), nil
|
||||
}
|
||||
134
plugins/system/ps/cpu/cpu_freebsd.go
Normal file
134
plugins/system/ps/cpu/cpu_freebsd.go
Normal file
@@ -0,0 +1,134 @@
|
||||
// +build freebsd
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
common "github.com/shirou/gopsutil/common"
|
||||
)
|
||||
|
||||
// sys/resource.h
|
||||
const (
|
||||
CPUser = 0
|
||||
CPNice = 1
|
||||
CPSys = 2
|
||||
CPIntr = 3
|
||||
CPIdle = 4
|
||||
CPUStates = 5
|
||||
)
|
||||
|
||||
// time.h
|
||||
const (
|
||||
ClocksPerSec = 128
|
||||
)
|
||||
|
||||
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
|
||||
var ret []CPUTimesStat
|
||||
|
||||
var sysctlCall string
|
||||
var ncpu int
|
||||
if percpu {
|
||||
sysctlCall = "kern.cp_times"
|
||||
ncpu, _ = CPUCounts(true)
|
||||
} else {
|
||||
sysctlCall = "kern.cp_time"
|
||||
ncpu = 1
|
||||
}
|
||||
|
||||
cpuTimes, err := common.DoSysctrl(sysctlCall)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
for i := 0; i < ncpu; i++ {
|
||||
offset := CPUStates * i
|
||||
user, err := strconv.ParseFloat(cpuTimes[CPUser+offset], 64)
|
||||
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 {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
c := CPUTimesStat{
|
||||
User: float64(user / ClocksPerSec),
|
||||
Nice: float64(nice / ClocksPerSec),
|
||||
System: float64(sys / ClocksPerSec),
|
||||
Idle: float64(idle / ClocksPerSec),
|
||||
Irq: float64(intr / ClocksPerSec),
|
||||
}
|
||||
if !percpu {
|
||||
c.CPU = "cpu-total"
|
||||
} else {
|
||||
c.CPU = fmt.Sprintf("cpu%d", i)
|
||||
}
|
||||
|
||||
ret = append(ret, c)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Returns only one CPUInfoStat on FreeBSD
|
||||
func CPUInfo() ([]CPUInfoStat, error) {
|
||||
filename := "/var/run/dmesg.boot"
|
||||
lines, _ := common.ReadLines(filename)
|
||||
|
||||
var ret []CPUInfoStat
|
||||
|
||||
c := CPUInfoStat{}
|
||||
for _, line := range lines {
|
||||
if matches := regexp.MustCompile(`CPU:\s+(.+) \(([\d.]+).+\)`).FindStringSubmatch(line); matches != nil {
|
||||
c.ModelName = matches[1]
|
||||
t, err := strconv.ParseFloat(matches[2], 64)
|
||||
if err != nil {
|
||||
return ret, nil
|
||||
}
|
||||
c.Mhz = t
|
||||
} else if matches := regexp.MustCompile(`Origin = "(.+)" Id = (.+) Family = (.+) Model = (.+) Stepping = (.+)`).FindStringSubmatch(line); matches != nil {
|
||||
c.VendorID = matches[1]
|
||||
c.Family = matches[3]
|
||||
c.Model = matches[4]
|
||||
t, err := strconv.ParseInt(matches[5], 10, 32)
|
||||
if err != nil {
|
||||
return ret, nil
|
||||
}
|
||||
c.Stepping = int32(t)
|
||||
} else if matches := regexp.MustCompile(`Features=.+<(.+)>`).FindStringSubmatch(line); matches != nil {
|
||||
for _, v := range strings.Split(matches[1], ",") {
|
||||
c.Flags = append(c.Flags, strings.ToLower(v))
|
||||
}
|
||||
} else if matches := regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`).FindStringSubmatch(line); matches != nil {
|
||||
for _, v := range strings.Split(matches[1], ",") {
|
||||
c.Flags = append(c.Flags, strings.ToLower(v))
|
||||
}
|
||||
} else if matches := regexp.MustCompile(`Logical CPUs per core: (\d+)`).FindStringSubmatch(line); matches != nil {
|
||||
// FIXME: no this line?
|
||||
t, err := strconv.ParseInt(matches[1], 10, 32)
|
||||
if err != nil {
|
||||
return ret, nil
|
||||
}
|
||||
c.Cores = int32(t)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return append(ret, c), nil
|
||||
}
|
||||
206
plugins/system/ps/cpu/cpu_linux.go
Normal file
206
plugins/system/ps/cpu/cpu_linux.go
Normal file
@@ -0,0 +1,206 @@
|
||||
// +build linux
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
common "github.com/shirou/gopsutil/common"
|
||||
)
|
||||
|
||||
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
|
||||
filename := "/proc/stat"
|
||||
var lines = []string{}
|
||||
if percpu {
|
||||
var startIdx uint = 1
|
||||
for {
|
||||
linen, _ := common.ReadLinesOffsetN(filename, startIdx, 1)
|
||||
line := linen[0]
|
||||
if !strings.HasPrefix(line, "cpu") {
|
||||
break
|
||||
}
|
||||
lines = append(lines, line)
|
||||
startIdx += 1
|
||||
}
|
||||
} else {
|
||||
lines, _ = common.ReadLinesOffsetN(filename, 0, 1)
|
||||
}
|
||||
|
||||
ret := make([]CPUTimesStat, 0, len(lines))
|
||||
|
||||
for _, line := range lines {
|
||||
ct, err := parseStatLine(line)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
ret = append(ret, *ct)
|
||||
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func CPUInfo() ([]CPUInfoStat, error) {
|
||||
filename := "/proc/cpuinfo"
|
||||
lines, _ := common.ReadLines(filename)
|
||||
|
||||
var ret []CPUInfoStat
|
||||
|
||||
var c CPUInfoStat
|
||||
for _, line := range lines {
|
||||
fields := strings.Split(line, ":")
|
||||
if len(fields) < 2 {
|
||||
if c.VendorID != "" {
|
||||
ret = append(ret, c)
|
||||
}
|
||||
continue
|
||||
}
|
||||
key := strings.TrimSpace(fields[0])
|
||||
value := strings.TrimSpace(fields[1])
|
||||
|
||||
switch key {
|
||||
case "processor":
|
||||
c = CPUInfoStat{}
|
||||
t, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
c.CPU = int32(t)
|
||||
case "vendor_id":
|
||||
c.VendorID = value
|
||||
case "cpu family":
|
||||
c.Family = value
|
||||
case "model":
|
||||
c.Model = value
|
||||
case "model name":
|
||||
c.ModelName = value
|
||||
case "stepping":
|
||||
t, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
c.Stepping = int32(t)
|
||||
case "cpu MHz":
|
||||
t, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
c.Mhz = t
|
||||
case "cache size":
|
||||
t, err := strconv.ParseInt(strings.Replace(value, " KB", "", 1), 10, 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
c.CacheSize = int32(t)
|
||||
case "physical id":
|
||||
c.PhysicalID = value
|
||||
case "core id":
|
||||
c.CoreID = value
|
||||
case "cpu cores":
|
||||
t, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
c.Cores = int32(t)
|
||||
case "flags":
|
||||
c.Flags = strings.Split(value, ",")
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
var CLK_TCK = 100
|
||||
|
||||
func init() {
|
||||
out, err := exec.Command("getconf", "CLK_TCK").CombinedOutput()
|
||||
if err == nil {
|
||||
i, err := strconv.Atoi(strings.TrimSpace(string(out)))
|
||||
if err == nil {
|
||||
CLK_TCK = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseStatLine(line string) (*CPUTimesStat, error) {
|
||||
fields := strings.Fields(line)
|
||||
|
||||
if strings.HasPrefix(fields[0], "cpu") == false {
|
||||
// return CPUTimesStat{}, e
|
||||
return nil, errors.New("not contain cpu")
|
||||
}
|
||||
|
||||
cpu := fields[0]
|
||||
if cpu == "cpu" {
|
||||
cpu = "cpu-total"
|
||||
}
|
||||
user, err := strconv.ParseFloat(fields[1], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nice, err := strconv.ParseFloat(fields[2], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
system, err := strconv.ParseFloat(fields[3], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idle, err := strconv.ParseFloat(fields[4], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iowait, err := strconv.ParseFloat(fields[5], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
irq, err := strconv.ParseFloat(fields[6], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
softirq, err := strconv.ParseFloat(fields[7], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stolen, err := strconv.ParseFloat(fields[8], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cpu_tick := float64(CLK_TCK)
|
||||
ct := &CPUTimesStat{
|
||||
CPU: cpu,
|
||||
User: float64(user) / cpu_tick,
|
||||
Nice: float64(nice) / cpu_tick,
|
||||
System: float64(system) / cpu_tick,
|
||||
Idle: float64(idle) / cpu_tick,
|
||||
Iowait: float64(iowait) / cpu_tick,
|
||||
Irq: float64(irq) / cpu_tick,
|
||||
Softirq: float64(softirq) / cpu_tick,
|
||||
Stolen: float64(stolen) / cpu_tick,
|
||||
}
|
||||
if len(fields) > 9 { // Linux >= 2.6.11
|
||||
steal, err := strconv.ParseFloat(fields[9], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ct.Steal = float64(steal)
|
||||
}
|
||||
if len(fields) > 10 { // Linux >= 2.6.24
|
||||
guest, err := strconv.ParseFloat(fields[10], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ct.Guest = float64(guest)
|
||||
}
|
||||
if len(fields) > 11 { // Linux >= 3.2.0
|
||||
guestNice, err := strconv.ParseFloat(fields[11], 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ct.GuestNice = float64(guestNice)
|
||||
}
|
||||
|
||||
return ct, nil
|
||||
}
|
||||
98
plugins/system/ps/cpu/cpu_test.go
Normal file
98
plugins/system/ps/cpu/cpu_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCpu_times(t *testing.T) {
|
||||
v, err := CPUTimes(false)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Error("could not get CPUs ", err)
|
||||
}
|
||||
empty := CPUTimesStat{}
|
||||
for _, vv := range v {
|
||||
if vv == empty {
|
||||
t.Errorf("could not get CPU User: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCpu_counts(t *testing.T) {
|
||||
v, err := CPUCounts(true)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if v == 0 {
|
||||
t.Errorf("could not get CPU counts: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCPUTimeStat_String(t *testing.T) {
|
||||
v := CPUTimesStat{
|
||||
CPU: "cpu0",
|
||||
User: 100.1,
|
||||
System: 200.1,
|
||||
Idle: 300.1,
|
||||
}
|
||||
e := `{"cpu":"cpu0","user":100.1,"system":200.1,"idle":300.1,"nice":0.0,"iowait":0.0,"irq":0.0,"softirq":0.0,"steal":0.0,"guest":0.0,"guest_nice":0.0,"stolen":0.0}`
|
||||
if e != fmt.Sprintf("%v", v) {
|
||||
t.Errorf("CPUTimesStat string is invalid: %v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCpuInfo(t *testing.T) {
|
||||
v, err := CPUInfo()
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if len(v) == 0 {
|
||||
t.Errorf("could not get CPU Info")
|
||||
}
|
||||
for _, vv := range v {
|
||||
if vv.ModelName == "" {
|
||||
t.Errorf("could not get CPU Info: %v", vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testCPUPercent(t *testing.T, percpu bool) {
|
||||
numcpu := runtime.NumCPU()
|
||||
testCount := 3
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
testCount = 100
|
||||
v, err := CPUPercent(time.Millisecond, percpu)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) {
|
||||
t.Fatalf("wrong number of entries from CPUPercent: %v", v)
|
||||
}
|
||||
}
|
||||
for i := 0; i < testCount; i++ {
|
||||
duration := time.Duration(10) * time.Microsecond
|
||||
v, err := CPUPercent(duration, percpu)
|
||||
if err != nil {
|
||||
t.Errorf("error %v", err)
|
||||
}
|
||||
for _, percent := range v {
|
||||
if percent < 0.0 || percent > 100.0*float64(numcpu) {
|
||||
t.Fatalf("CPUPercent value is invalid: %f", percent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCPUPercent(t *testing.T) {
|
||||
testCPUPercent(t, false)
|
||||
}
|
||||
|
||||
func TestCPUPercentPerCpu(t *testing.T) {
|
||||
testCPUPercent(t, true)
|
||||
}
|
||||
61
plugins/system/ps/cpu/cpu_unix.go
Normal file
61
plugins/system/ps/cpu/cpu_unix.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// +build linux freebsd darwin
|
||||
|
||||
package cpu
|
||||
|
||||
import "time"
|
||||
|
||||
func init() {
|
||||
lastCPUTimes, _ = CPUTimes(false)
|
||||
lastPerCPUTimes, _ = CPUTimes(true)
|
||||
}
|
||||
|
||||
func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) {
|
||||
getAllBusy := func(t CPUTimesStat) (float64, float64) {
|
||||
busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
|
||||
t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen
|
||||
return busy + t.Idle, busy
|
||||
}
|
||||
|
||||
calculate := func(t1, t2 CPUTimesStat) float64 {
|
||||
t1All, t1Busy := getAllBusy(t1)
|
||||
t2All, t2Busy := getAllBusy(t2)
|
||||
|
||||
if t2Busy <= t1Busy {
|
||||
return 0
|
||||
}
|
||||
if t2All <= t1All {
|
||||
return 1
|
||||
}
|
||||
return (t2Busy - t1Busy) / (t2All - t1All) * 100
|
||||
}
|
||||
|
||||
cpuTimes, err := CPUTimes(percpu)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if interval > 0 {
|
||||
if !percpu {
|
||||
lastCPUTimes = cpuTimes
|
||||
} else {
|
||||
lastPerCPUTimes = cpuTimes
|
||||
}
|
||||
time.Sleep(interval)
|
||||
cpuTimes, err = CPUTimes(percpu)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ret := make([]float64, len(cpuTimes))
|
||||
if !percpu {
|
||||
ret[0] = calculate(lastCPUTimes[0], cpuTimes[0])
|
||||
lastCPUTimes = cpuTimes
|
||||
} else {
|
||||
for i, t := range cpuTimes {
|
||||
ret[i] = calculate(lastPerCPUTimes[i], t)
|
||||
}
|
||||
lastPerCPUTimes = cpuTimes
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
101
plugins/system/ps/cpu/cpu_windows.go
Normal file
101
plugins/system/ps/cpu/cpu_windows.go
Normal file
@@ -0,0 +1,101 @@
|
||||
// +build windows
|
||||
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
common "github.com/shirou/gopsutil/common"
|
||||
)
|
||||
|
||||
// TODO: Get percpu
|
||||
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
|
||||
var ret []CPUTimesStat
|
||||
|
||||
var lpIdleTime common.FILETIME
|
||||
var lpKernelTime common.FILETIME
|
||||
var lpUserTime common.FILETIME
|
||||
r, _, _ := common.ProcGetSystemTimes.Call(
|
||||
uintptr(unsafe.Pointer(&lpIdleTime)),
|
||||
uintptr(unsafe.Pointer(&lpKernelTime)),
|
||||
uintptr(unsafe.Pointer(&lpUserTime)))
|
||||
if r == 0 {
|
||||
return ret, syscall.GetLastError()
|
||||
}
|
||||
|
||||
LOT := float64(0.0000001)
|
||||
HIT := (LOT * 4294967296.0)
|
||||
idle := ((HIT * float64(lpIdleTime.DwHighDateTime)) + (LOT * float64(lpIdleTime.DwLowDateTime)))
|
||||
user := ((HIT * float64(lpUserTime.DwHighDateTime)) + (LOT * float64(lpUserTime.DwLowDateTime)))
|
||||
kernel := ((HIT * float64(lpKernelTime.DwHighDateTime)) + (LOT * float64(lpKernelTime.DwLowDateTime)))
|
||||
system := (kernel - idle)
|
||||
|
||||
ret = append(ret, CPUTimesStat{
|
||||
Idle: float64(idle),
|
||||
User: float64(user),
|
||||
System: float64(system),
|
||||
})
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func CPUInfo() ([]CPUInfoStat, error) {
|
||||
var ret []CPUInfoStat
|
||||
lines, err := common.GetWmic("cpu", "get", "Family,L2CacheSize,Manufacturer,Name,NumberOfLogicalProcessors,ProcessorId,Stepping")
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
for i, t := range lines {
|
||||
cache, err := strconv.Atoi(t[2])
|
||||
if err != nil {
|
||||
cache = 0
|
||||
}
|
||||
cores, err := strconv.Atoi(t[5])
|
||||
if err != nil {
|
||||
cores = 0
|
||||
}
|
||||
stepping := 0
|
||||
if len(t) > 7 {
|
||||
stepping, err = strconv.Atoi(t[6])
|
||||
if err != nil {
|
||||
stepping = 0
|
||||
}
|
||||
}
|
||||
cpu := CPUInfoStat{
|
||||
CPU: int32(i),
|
||||
Family: t[1],
|
||||
CacheSize: int32(cache),
|
||||
VendorID: t[3],
|
||||
ModelName: t[4],
|
||||
Cores: int32(cores),
|
||||
PhysicalID: t[6],
|
||||
Stepping: int32(stepping),
|
||||
Flags: []string{},
|
||||
}
|
||||
ret = append(ret, cpu)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func CPUPercent(interval time.Duration, percpu bool) ([]float64, error) {
|
||||
ret := []float64{}
|
||||
|
||||
lines, err := common.GetWmic("cpu", "get", "loadpercentage")
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
for _, l := range lines {
|
||||
if len(l) < 2 {
|
||||
continue
|
||||
}
|
||||
p, err := strconv.Atoi(l[1])
|
||||
if err != nil {
|
||||
p = 0
|
||||
}
|
||||
// but windows can only get one percent.
|
||||
ret = append(ret, float64(p)/100.0)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
Reference in New Issue
Block a user