calculate cpu percentage compared to last call if 0 interval is given

pull/205/head
Ben Aldrich 9 years ago
parent bae75faa5a
commit c389989453

@ -5,6 +5,7 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"strings" "strings"
"sync"
) )
type TimesStat struct { type TimesStat struct {
@ -37,8 +38,21 @@ type InfoStat struct {
Flags []string `json:"flags"` Flags []string `json:"flags"`
} }
var lastCPUTimes []TimesStat //CPUPercent
var lastPerCPUTimes []TimesStat type cpuPercent struct {
sync.Mutex
lastCPUTimes []TimesStat
lastPerCPUTimes []TimesStat
}
var lastCPUPercent cpuPercent
func init() {
lastCPUPercent.Lock()
lastCPUPercent.lastCPUTimes, _ = Times(false)
lastCPUPercent.lastPerCPUTimes, _ = Times(true)
lastCPUPercent.Unlock()
}
func Counts(logical bool) (int, error) { func Counts(logical bool) (int, error) {
return runtime.NumCPU(), nil return runtime.NumCPU(), nil

@ -94,6 +94,40 @@ func testCPUPercent(t *testing.T, percpu bool) {
} }
} }
func testCPUPercentLastUsed(t *testing.T, percpu bool) {
numcpu := runtime.NumCPU()
testCount := 10
if runtime.GOOS != "windows" {
testCount = 2
v, err := Percent(time.Millisecond, percpu)
if err != nil {
t.Errorf("error %v", err)
}
// Skip CircleCI which CPU num is different
if os.Getenv("CIRCLECI") != "true" {
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++ {
v, err := Percent(0, percpu)
if err != nil {
t.Errorf("error %v", err)
}
time.Sleep(1 * time.Millisecond)
for _, percent := range v {
// Check for slightly greater then 100% to account for any rounding issues.
if percent < 0.0 || percent > 100.0001*float64(numcpu) {
t.Fatalf("CPUPercent value is invalid: %f", percent)
}
}
}
}
func TestCPUPercent(t *testing.T) { func TestCPUPercent(t *testing.T) {
testCPUPercent(t, false) testCPUPercent(t, false)
} }
@ -101,3 +135,11 @@ func TestCPUPercent(t *testing.T) {
func TestCPUPercentPerCpu(t *testing.T) { func TestCPUPercentPerCpu(t *testing.T) {
testCPUPercent(t, true) testCPUPercent(t, true)
} }
func TestCPUPercentIntervalZero(t *testing.T) {
testCPUPercentLastUsed(t, false)
}
func TestCPUPercentIntervalZeroPerCPU(t *testing.T) {
testCPUPercentLastUsed(t, true)
}

@ -7,24 +7,46 @@ import (
"time" "time"
) )
func Percent(interval time.Duration, percpu bool) ([]float64, error) { func getAllBusy(t TimesStat) (float64, float64) {
getAllBusy := func(t TimesStat) (float64, float64) { busy := t.User + t.System + t.Nice + t.Iowait + t.Irq +
busy := t.User + t.System + t.Nice + t.Iowait + t.Irq + t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen
t.Softirq + t.Steal + t.Guest + t.GuestNice + t.Stolen return busy + t.Idle, busy
return busy + t.Idle, busy }
func calculateBusy(t1, t2 TimesStat) 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
}
func calcualteALLBusy(t1, t2 []TimesStat) ([]float64, error) {
// Make sure the CPU measurements have the same length.
if len(t1) != len(t2) {
return nil, fmt.Errorf(
"received two CPU counts: %d != %d",
len(t1), len(t2),
)
} }
calculate := func(t1, t2 TimesStat) float64 { ret := make([]float64, len(t1))
t1All, t1Busy := getAllBusy(t1) for i, t := range t2 {
t2All, t2Busy := getAllBusy(t2) ret[i] = calculateBusy(t1[i], t)
}
return ret, nil
}
if t2Busy <= t1Busy { //Percent calculates the percentage of cpu used either per CPU or combined.
return 0 //If an interval of 0 is given it will compare the current cpu times against the last call.
} func Percent(interval time.Duration, percpu bool) ([]float64, error) {
if t2All <= t1All { if interval <= 0 {
return 1 return percentUsedFromLastCall(percpu)
}
return (t2Busy - t1Busy) / (t2All - t1All) * 100
} }
// Get CPU usage at the start of the interval. // Get CPU usage at the start of the interval.
@ -33,9 +55,7 @@ func Percent(interval time.Duration, percpu bool) ([]float64, error) {
return nil, err return nil, err
} }
if interval > 0 { time.Sleep(interval)
time.Sleep(interval)
}
// And at the end of the interval. // And at the end of the interval.
cpuTimes2, err := Times(percpu) cpuTimes2, err := Times(percpu)
@ -43,17 +63,28 @@ func Percent(interval time.Duration, percpu bool) ([]float64, error) {
return nil, err return nil, err
} }
// Make sure the CPU measurements have the same length. return calcualteALLBusy(cpuTimes1, cpuTimes2)
if len(cpuTimes1) != len(cpuTimes2) { }
return nil, fmt.Errorf(
"received two CPU counts: %d != %d", func percentUsedFromLastCall(percpu bool) ([]float64, error) {
len(cpuTimes1), len(cpuTimes2), cpuTimes, err := Times(percpu)
) if err != nil {
return nil, err
}
lastCPUPercent.Lock()
defer lastCPUPercent.Unlock()
var lastTimes []TimesStat
if percpu {
lastTimes = lastCPUPercent.lastPerCPUTimes
lastCPUPercent.lastPerCPUTimes = cpuTimes
} else {
lastTimes = lastCPUPercent.lastCPUTimes
lastCPUPercent.lastCPUTimes = cpuTimes
} }
ret := make([]float64, len(cpuTimes1)) if lastTimes == nil {
for i, t := range cpuTimes2 { return nil, fmt.Errorf("Error getting times for cpu percent. LastTimes was nil")
ret[i] = calculate(cpuTimes1[i], t)
} }
return ret, nil return calcualteALLBusy(lastTimes, cpuTimes)
} }

Loading…
Cancel
Save