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