1package metrics
2
3import (
4	"runtime/debug"
5	"time"
6)
7
8var (
9	debugMetrics struct {
10		GCStats struct {
11			LastGC Gauge
12			NumGC  Gauge
13			Pause  Histogram
14			//PauseQuantiles Histogram
15			PauseTotal Gauge
16		}
17		ReadGCStats Timer
18	}
19	gcStats debug.GCStats
20)
21
22// Capture new values for the Go garbage collector statistics exported in
23// debug.GCStats.  This is designed to be called as a goroutine.
24func CaptureDebugGCStats(r Registry, d time.Duration) {
25	for _ = range time.Tick(d) {
26		CaptureDebugGCStatsOnce(r)
27	}
28}
29
30// Capture new values for the Go garbage collector statistics exported in
31// debug.GCStats.  This is designed to be called in a background goroutine.
32// Giving a registry which has not been given to RegisterDebugGCStats will
33// panic.
34//
35// Be careful (but much less so) with this because debug.ReadGCStats calls
36// the C function runtime·lock(runtime·mheap) which, while not a stop-the-world
37// operation, isn't something you want to be doing all the time.
38func CaptureDebugGCStatsOnce(r Registry) {
39	lastGC := gcStats.LastGC
40	t := time.Now()
41	debug.ReadGCStats(&gcStats)
42	debugMetrics.ReadGCStats.UpdateSince(t)
43
44	debugMetrics.GCStats.LastGC.Update(int64(gcStats.LastGC.UnixNano()))
45	debugMetrics.GCStats.NumGC.Update(int64(gcStats.NumGC))
46	if lastGC != gcStats.LastGC && 0 < len(gcStats.Pause) {
47		debugMetrics.GCStats.Pause.Update(int64(gcStats.Pause[0]))
48	}
49	//debugMetrics.GCStats.PauseQuantiles.Update(gcStats.PauseQuantiles)
50	debugMetrics.GCStats.PauseTotal.Update(int64(gcStats.PauseTotal))
51}
52
53// Register metrics for the Go garbage collector statistics exported in
54// debug.GCStats.  The metrics are named by their fully-qualified Go symbols,
55// i.e. debug.GCStats.PauseTotal.
56func RegisterDebugGCStats(r Registry) {
57	debugMetrics.GCStats.LastGC = NewGauge()
58	debugMetrics.GCStats.NumGC = NewGauge()
59	debugMetrics.GCStats.Pause = NewHistogram(NewExpDecaySample(1028, 0.015))
60	//debugMetrics.GCStats.PauseQuantiles = NewHistogram(NewExpDecaySample(1028, 0.015))
61	debugMetrics.GCStats.PauseTotal = NewGauge()
62	debugMetrics.ReadGCStats = NewTimer()
63
64	r.Register("debug.GCStats.LastGC", debugMetrics.GCStats.LastGC)
65	r.Register("debug.GCStats.NumGC", debugMetrics.GCStats.NumGC)
66	r.Register("debug.GCStats.Pause", debugMetrics.GCStats.Pause)
67	//r.Register("debug.GCStats.PauseQuantiles", debugMetrics.GCStats.PauseQuantiles)
68	r.Register("debug.GCStats.PauseTotal", debugMetrics.GCStats.PauseTotal)
69	r.Register("debug.ReadGCStats", debugMetrics.ReadGCStats)
70}
71
72// Allocate an initial slice for gcStats.Pause to avoid allocations during
73// normal operation.
74func init() {
75	gcStats.Pause = make([]time.Duration, 11)
76}
77