-
Notifications
You must be signed in to change notification settings - Fork 90
/
cpuusage.go
86 lines (71 loc) · 2.9 KB
/
cpuusage.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// +build linux
package linux
import (
"time"
"github.com/mackerelio/go-osstat/cpu"
"github.com/mackerelio/golib/logging"
"github.com/mackerelio/mackerel-agent/metrics"
)
/*
collect CPU usage
`cpu.{metric}.percentage`: The increased amount of CPU time per minute as percentage of total CPU cores x 100
metric = "user", "nice", "system", "idle", "iowait", "irq", "softirq", "steal", "guest"
graph: stacks `cpu.{metric}.percentage`
*/
// CPUUsageGenerator generates CPU metric values
type CPUUsageGenerator struct {
Interval time.Duration
}
var cpuUsageLogger = logging.GetLogger("metrics.cpuUsage")
// Generate CPU metric values
func (g *CPUUsageGenerator) Generate() (metrics.Values, error) {
previous, err := g.collectProcStatValues()
if err != nil {
return nil, err
}
time.Sleep(g.Interval)
current, err := g.collectProcStatValues()
if err != nil {
return nil, err
}
totalDiff := float64(current.Total - previous.Total)
cpuCount := float64(current.CPUCount)
// Since cpustat[CPUTIME_USER] includes cpustat[CPUTIME_GUEST], we subtract guest from user for the stacked graph of Mackerel.
// https://github.com/torvalds/linux/blob/4ec9f7a18/kernel/sched/cputime.c#L151-L158
// We should also subtract guest_nice from nice, but guest_nice is not supported in Mackerel yet.
ret := map[string]float64{
"cpu.user.percentage": float64((current.User-current.Guest)-(previous.User-previous.Guest)) * cpuCount * 100.0 / totalDiff,
"cpu.nice.percentage": float64(current.Nice-previous.Nice) * cpuCount * 100.0 / totalDiff,
"cpu.system.percentage": float64(current.System-previous.System) * cpuCount * 100.0 / totalDiff,
"cpu.idle.percentage": float64(current.Idle-previous.Idle) * cpuCount * 100.0 / totalDiff,
}
if current.StatCount >= 5 {
ret["cpu.iowait.percentage"] = float64(current.Iowait-previous.Iowait) * cpuCount * 100.0 / totalDiff
}
if current.StatCount >= 6 {
ret["cpu.irq.percentage"] = float64(current.Irq-previous.Irq) * cpuCount * 100.0 / totalDiff
}
if current.StatCount >= 7 {
ret["cpu.softirq.percentage"] = float64(current.Softirq-previous.Softirq) * cpuCount * 100.0 / totalDiff
}
if current.StatCount >= 8 {
ret["cpu.steal.percentage"] = float64(current.Steal-previous.Steal) * cpuCount * 100.0 / totalDiff
}
if current.StatCount >= 9 {
ret["cpu.guest.percentage"] = float64(current.Guest-previous.Guest) * cpuCount * 100.0 / totalDiff
}
// guest_nice is not yet supported in Mackerel
// if current.StatCount >= 10 {
// ret["cpu.guest_nice.percentage"]= float64(current.GuestNice - previous.GuestNice) * cpuCount * 100.0 / totalDiff
// }
return metrics.Values(ret), nil
}
// returns values corresponding to cpuUsageMetricNames, those total and the number of CPUs
func (g *CPUUsageGenerator) collectProcStatValues() (*cpu.Stats, error) {
cpu, err := cpu.Get()
if err != nil {
cpuUsageLogger.Errorf("failed to get cpu statistics: %s", err)
return nil, err
}
return cpu, nil
}