|
|
|
@ -142,6 +142,59 @@ func calculateAllBusy(t1, t2 []TimesStat) ([]float64, error) {
|
|
|
|
|
return ret, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func calculateItem(v1, v2, duration float64) float64 {
|
|
|
|
|
if v2 <= v1 {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
if duration <= 0 {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return math.Min(100, math.Max(0, (v2-v1)/(duration)*100))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func calculateItems(t1, t2 TimesStat) TimesStat {
|
|
|
|
|
duration := t2.Total() - t1.Total()
|
|
|
|
|
|
|
|
|
|
items := TimesStat{
|
|
|
|
|
CPU: t1.CPU,
|
|
|
|
|
User: calculateItem(t1.User, t2.User, duration),
|
|
|
|
|
System: calculateItem(t1.System, t2.System, duration),
|
|
|
|
|
Idle: calculateItem(t1.Idle, t2.Idle, duration),
|
|
|
|
|
Nice: calculateItem(t1.Nice, t2.Nice, duration),
|
|
|
|
|
Iowait: calculateItem(t1.Iowait, t2.Iowait, duration),
|
|
|
|
|
Irq: calculateItem(t1.Irq, t2.Irq, duration),
|
|
|
|
|
Softirq: calculateItem(t1.Softirq, t2.Softirq, duration),
|
|
|
|
|
Steal: calculateItem(t1.Steal, t2.Steal, duration),
|
|
|
|
|
Guest: calculateItem(t1.Guest, t2.Guest, duration),
|
|
|
|
|
GuestNice: calculateItem(t1.GuestNice, t2.GuestNice, duration),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return items
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func calculateAllItems(t1, t2 []TimesStat) ([]TimesStat, 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([]TimesStat, len(t1))
|
|
|
|
|
for i, t := range t2 {
|
|
|
|
|
if t1[i].CPU != t.CPU {
|
|
|
|
|
return nil, fmt.Errorf(
|
|
|
|
|
"CPU number mismatch at %d: %s != %s",
|
|
|
|
|
i, t1[i].CPU, t.CPU,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
ret[i] = calculateItems(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.
|
|
|
|
|
// Returns one value per cpu, or a single value if percpu is set to false.
|
|
|
|
@ -149,38 +202,65 @@ func Percent(interval time.Duration, percpu bool) ([]float64, error) {
|
|
|
|
|
return PercentWithContext(context.Background(), interval, percpu)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CPUTimesPercent calculates the percentage of CPU time used for different type of work
|
|
|
|
|
// either per CPU or combined.
|
|
|
|
|
// If an interval of 0 is given it will compare the current cpu times against the last call.
|
|
|
|
|
// Returns one value per cpu, or a single value if percpu is set to false.
|
|
|
|
|
// When interval is too small, returned values can be all zero.
|
|
|
|
|
func CPUTimesPercent(interval time.Duration, percpu bool) ([]TimesStat, error) {
|
|
|
|
|
return CPUTimesPercentWithContext(context.Background(), interval, percpu)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func PercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]float64, error) {
|
|
|
|
|
t1, t2, err := sample(ctx, interval, percpu)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return calculateAllBusy(t1, t2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func CPUTimesPercentWithContext(ctx context.Context, interval time.Duration, percpu bool) ([]TimesStat, error) {
|
|
|
|
|
t1, t2, err := sample(ctx, interval, percpu)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return calculateAllItems(t1, t2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func sample(ctx context.Context, interval time.Duration, percpu bool) (cpuTimes1, cpuTimes2 []TimesStat, err error) {
|
|
|
|
|
if interval <= 0 {
|
|
|
|
|
return percentUsedFromLastCallWithContext(ctx, percpu)
|
|
|
|
|
return sampleAndSaveAsLastWithContext(ctx, percpu)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get CPU usage at the start of the interval.
|
|
|
|
|
cpuTimes1, err := TimesWithContext(ctx, percpu)
|
|
|
|
|
cpuTimes1, err = TimesWithContext(ctx, percpu)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := common.Sleep(ctx, interval); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// And at the end of the interval.
|
|
|
|
|
cpuTimes2, err := TimesWithContext(ctx, percpu)
|
|
|
|
|
cpuTimes2, err = TimesWithContext(ctx, percpu)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return calculateAllBusy(cpuTimes1, cpuTimes2)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func percentUsedFromLastCall(percpu bool) ([]float64, error) {
|
|
|
|
|
return percentUsedFromLastCallWithContext(context.Background(), percpu)
|
|
|
|
|
func sampleAndSaveAsLast(percpu bool) ([]TimesStat, []TimesStat, error) {
|
|
|
|
|
return sampleAndSaveAsLastWithContext(context.Background(), percpu)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func percentUsedFromLastCallWithContext(ctx context.Context, percpu bool) ([]float64, error) {
|
|
|
|
|
func sampleAndSaveAsLastWithContext(ctx context.Context, percpu bool) ([]TimesStat, []TimesStat, error) {
|
|
|
|
|
cpuTimes, err := TimesWithContext(ctx, percpu)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
return nil, nil, err
|
|
|
|
|
}
|
|
|
|
|
lastCPUPercent.Lock()
|
|
|
|
|
defer lastCPUPercent.Unlock()
|
|
|
|
@ -194,7 +274,7 @@ func percentUsedFromLastCallWithContext(ctx context.Context, percpu bool) ([]flo
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if lastTimes == nil {
|
|
|
|
|
return nil, fmt.Errorf("error getting times for cpu percent. lastTimes was nil")
|
|
|
|
|
return nil, nil, fmt.Errorf("error getting times for cpu percent. lastTimes was nil")
|
|
|
|
|
}
|
|
|
|
|
return calculateAllBusy(lastTimes, cpuTimes)
|
|
|
|
|
return lastTimes, cpuTimes, nil
|
|
|
|
|
}
|
|
|
|
|