From 832dcb96c85ba64247441aee448e06ebe2a07a8e Mon Sep 17 00:00:00 2001 From: Hilko Bengen Date: Tue, 27 Sep 2016 00:34:37 +0200 Subject: [PATCH] cpu.Percent (Windows): Use the same implementation as on Unix WMI is way too slow. --- cpu/cpu.go | 83 ++++++++++++++++++++++++++++++++++++++++++ cpu/cpu_unix.go | 90 ---------------------------------------------- cpu/cpu_windows.go | 19 ---------- 3 files changed, 83 insertions(+), 109 deletions(-) delete mode 100644 cpu/cpu_unix.go diff --git a/cpu/cpu.go b/cpu/cpu.go index 6f76b764c..b51e27ff6 100644 --- a/cpu/cpu.go +++ b/cpu/cpu.go @@ -2,10 +2,12 @@ package cpu import ( "encoding/json" + "fmt" "runtime" "strconv" "strings" "sync" + "time" "github.com/shirou/gopsutil/internal/common" ) @@ -91,3 +93,84 @@ func (c InfoStat) String() string { s, _ := json.Marshal(c) return string(s) } + +func getAllBusy(t TimesStat) (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 +} + +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 calculateAllBusy(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), + ) + } + + ret := make([]float64, len(t1)) + for i, t := range t2 { + ret[i] = calculateBusy(t1[i], t) + } + return ret, nil +} + +//Percent calculates the percentage of cpu used either per CPU or combined. +//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 interval <= 0 { + return percentUsedFromLastCall(percpu) + } + + // Get CPU usage at the start of the interval. + cpuTimes1, err := Times(percpu) + if err != nil { + return nil, err + } + + time.Sleep(interval) + + // And at the end of the interval. + cpuTimes2, err := Times(percpu) + if err != nil { + return nil, err + } + + return calculateAllBusy(cpuTimes1, cpuTimes2) +} + +func percentUsedFromLastCall(percpu bool) ([]float64, error) { + 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 + } + + if lastTimes == nil { + return nil, fmt.Errorf("Error getting times for cpu percent. LastTimes was nil") + } + return calculateAllBusy(lastTimes, cpuTimes) +} diff --git a/cpu/cpu_unix.go b/cpu/cpu_unix.go deleted file mode 100644 index 0ed7d62ad..000000000 --- a/cpu/cpu_unix.go +++ /dev/null @@ -1,90 +0,0 @@ -// +build linux freebsd darwin - -package cpu - -import ( - "fmt" - "time" -) - -func getAllBusy(t TimesStat) (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 -} - -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 calculateAllBusy(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), - ) - } - - ret := make([]float64, len(t1)) - for i, t := range t2 { - ret[i] = calculateBusy(t1[i], t) - } - return ret, nil -} - -//Percent calculates the percentage of cpu used either per CPU or combined. -//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 interval <= 0 { - return percentUsedFromLastCall(percpu) - } - - // Get CPU usage at the start of the interval. - cpuTimes1, err := Times(percpu) - if err != nil { - return nil, err - } - - time.Sleep(interval) - - // And at the end of the interval. - cpuTimes2, err := Times(percpu) - if err != nil { - return nil, err - } - - return calculateAllBusy(cpuTimes1, cpuTimes2) -} - -func percentUsedFromLastCall(percpu bool) ([]float64, error) { - 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 - } - - if lastTimes == nil { - return nil, fmt.Errorf("Error getting times for cpu percent. LastTimes was nil") - } - return calculateAllBusy(lastTimes, cpuTimes) - -} diff --git a/cpu/cpu_windows.go b/cpu/cpu_windows.go index fbd25e605..a32d2419a 100644 --- a/cpu/cpu_windows.go +++ b/cpu/cpu_windows.go @@ -5,7 +5,6 @@ package cpu import ( "fmt" "syscall" - "time" "unsafe" "github.com/StackExchange/wmi" @@ -85,21 +84,3 @@ func Info() ([]InfoStat, error) { return ret, nil } - -func Percent(interval time.Duration, percpu bool) ([]float64, error) { - var ret []float64 - var dst []Win32_Processor - q := wmi.CreateQuery(&dst, "") - err := wmi.Query(q, &dst) - if err != nil { - return ret, err - } - for _, l := range dst { - // use range but windows can only get one percent. - if l.LoadPercentage == nil { - continue - } - ret = append(ret, float64(*l.LoadPercentage)) - } - return ret, nil -}