Merge pull request #25 from KenjiTakahashi/cpu_percent

CPUTimes per cpu and CPUPercent
pull/26/head
shirou 10 years ago
commit f4c7973669

@ -17,8 +17,18 @@ import (
var NotImplementedError = errors.New("not implemented yet")
// readLines read contents from file and split by new line.
// readLines reads contents from file and splits them by new line.
// A convenience wrapper to readLinesOffsetN(filename, 0, -1).
func readLines(filename string) ([]string, error) {
return readLinesOffsetN(filename, 0, -1)
}
// readLines reads contents from file and splits them by new line.
// The offset tells at which line number to start.
// The count determines the number of lines to read (starting from offset):
// n >= 0: at most n lines
// n < 0: whole file
func readLinesOffsetN(filename string, offset uint, n int) ([]string, error) {
f, err := os.Open(filename)
if err != nil {
return []string{""}, err
@ -28,10 +38,15 @@ func readLines(filename string) ([]string, error) {
var ret []string
r := bufio.NewReader(f)
for i := 0; i < n+int(offset) || n < 0; i++ {
line, err := r.ReadString('\n')
for err == nil {
if err != nil {
break
}
if i < int(offset) {
continue
}
ret = append(ret, strings.Trim(line, "\n"))
line, err = r.ReadString('\n')
}
return ret, nil

@ -3,6 +3,7 @@ package gopsutil
import (
"encoding/json"
"runtime"
"time"
)
type CPUTimesStat struct {
@ -39,6 +40,57 @@ func CPUCounts(logical bool) (int, error) {
return runtime.NumCPU(), nil
}
var lastCPUTimes []CPUTimesStat
var lastPerCPUTimes []CPUTimesStat
func CPUPercent(interval time.Duration, percpu bool) ([]float32, error) {
getAllBusy := func(t CPUTimesStat) (float32, float32) {
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) float32 {
t1All, t1Busy := getAllBusy(t1)
t2All, t2Busy := getAllBusy(t2)
if t2Busy <= t1Busy {
return 0
}
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([]float32, 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
}
func (c CPUTimesStat) String() string {
s, _ := json.Marshal(c)
return string(s)
@ -48,3 +100,8 @@ func (c CPUInfoStat) String() string {
s, _ := json.Marshal(c)
return string(s)
}
func init() {
lastCPUTimes, _ = CPUTimes(false)
lastPerCPUTimes, _ = CPUTimes(true)
}

@ -23,32 +23,43 @@ const (
ClocksPerSec = 128
)
// TODO: get per cpus
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
var ret []CPUTimesStat
cpuTime, err := doSysctrl("kern.cp_time")
var sysctlCall string
var ncpu int
if percpu {
sysctlCall = "kern.cp_times"
ncpu, _ = CPUCounts(true)
} else {
sysctlCall = "kern.cp_time"
ncpu = 1
}
cpuTimes, err := doSysctrl(sysctlCall)
if err != nil {
return ret, err
}
user, err := strconv.ParseFloat(cpuTime[CPUser], 32)
for i := 0; i < ncpu; i++ {
offset := CPUStates * i
user, err := strconv.ParseFloat(cpuTimes[CPUser+offset], 32)
if err != nil {
return ret, err
}
nice, err := strconv.ParseFloat(cpuTime[CPNice], 32)
nice, err := strconv.ParseFloat(cpuTimes[CPNice+offset], 32)
if err != nil {
return ret, err
}
sys, err := strconv.ParseFloat(cpuTime[CPSys], 32)
sys, err := strconv.ParseFloat(cpuTimes[CPSys+offset], 32)
if err != nil {
return ret, err
}
idle, err := strconv.ParseFloat(cpuTime[CPIdle], 32)
idle, err := strconv.ParseFloat(cpuTimes[CPIdle+offset], 32)
if err != nil {
return ret, err
}
intr, err := strconv.ParseFloat(cpuTime[CPIntr], 32)
intr, err := strconv.ParseFloat(cpuTimes[CPIntr+offset], 32)
if err != nil {
return ret, err
}
@ -60,8 +71,14 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
Idle: float32(idle / ClocksPerSec),
Irq: float32(intr / ClocksPerSec),
}
if !percpu {
c.CPU = "cpu-total"
} else {
c.CPU = fmt.Sprintf("cpu%d", i)
}
ret = append(ret, c)
}
return ret, nil
}

@ -3,6 +3,7 @@
package gopsutil
import (
"fmt"
"regexp"
"strconv"
"strings"
@ -23,32 +24,43 @@ const (
ClocksPerSec = 128
)
// TODO: get per cpus
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
var ret []CPUTimesStat
cpuTime, err := doSysctrl("kern.cp_time")
var sysctlCall string
var ncpu int
if percpu {
sysctlCall = "kern.cp_times"
ncpu, _ = CPUCounts(true)
} else {
sysctlCall = "kern.cp_time"
ncpu = 1
}
cpuTimes, err := doSysctrl(sysctlCall)
if err != nil {
return ret, err
}
user, err := strconv.ParseFloat(cpuTime[CPUser], 32)
for i := 0; i < ncpu; i++ {
offset := CPUStates * i
user, err := strconv.ParseFloat(cpuTimes[CPUser+offset], 32)
if err != nil {
return ret, err
}
nice, err := strconv.ParseFloat(cpuTime[CPNice], 32)
nice, err := strconv.ParseFloat(cpuTimes[CPNice+offset], 32)
if err != nil {
return ret, err
}
sys, err := strconv.ParseFloat(cpuTime[CPSys], 32)
sys, err := strconv.ParseFloat(cpuTimes[CPSys+offset], 32)
if err != nil {
return ret, err
}
idle, err := strconv.ParseFloat(cpuTime[CPIdle], 32)
idle, err := strconv.ParseFloat(cpuTimes[CPIdle+offset], 32)
if err != nil {
return ret, err
}
intr, err := strconv.ParseFloat(cpuTime[CPIntr], 32)
intr, err := strconv.ParseFloat(cpuTimes[CPIntr+offset], 32)
if err != nil {
return ret, err
}
@ -60,8 +72,14 @@ func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
Idle: float32(idle / ClocksPerSec),
Irq: float32(intr / ClocksPerSec),
}
if !percpu {
c.CPU = "cpu-total"
} else {
c.CPU = fmt.Sprintf("cpu%d", i)
}
ret = append(ret, c)
}
return ret, nil
}

@ -10,7 +10,13 @@ import (
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
filename := "/proc/stat"
lines, _ := readLines(filename)
var lines []string
if percpu {
ncpu, _ := CPUCounts(true)
lines, _ = readLinesOffsetN(filename, 1, ncpu)
} else {
lines, _ = readLinesOffsetN(filename, 0, 1)
}
ret := make([]CPUTimesStat, 0, len(lines))

@ -2,7 +2,9 @@ package gopsutil
import (
"fmt"
"runtime"
"testing"
"time"
)
func TestCpu_times(t *testing.T) {
@ -55,3 +57,33 @@ func TestCpuInfo(t *testing.T) {
}
}
}
func testCPUPercent(t *testing.T, percpu bool) {
v, err := CPUPercent(time.Millisecond, percpu)
if err != nil {
t.Errorf("error %v", err)
}
numcpu := runtime.NumCPU()
if (percpu && len(v) != numcpu) || (!percpu && len(v) != 1) {
t.Fatalf("wrong number of entries from CPUPercent: %v", v)
}
for i := 0; i < 1000; i++ {
v, err := CPUPercent(0, percpu)
if err != nil {
t.Errorf("error %v", err)
}
for _, percent := range v {
if percent < 0.0 || percent > 100.0*float32(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)
}

@ -7,6 +7,7 @@ import (
"unsafe"
)
// TODO: Get percpu
func CPUTimes(percpu bool) ([]CPUTimesStat, error) {
var ret []CPUTimesStat

Loading…
Cancel
Save