blob: 4047ab3d3732db31e1d59ec40bdfbc13ebe15124 [file] [log] [blame]
Scott Bakereee8dd82019-09-24 12:52:34 -07001package metrics
2
3import (
4 "runtime"
5 "runtime/pprof"
Scott Baker611f6bd2019-10-18 13:45:19 -07006 "sync"
Scott Bakereee8dd82019-09-24 12:52:34 -07007 "time"
8)
9
10var (
11 memStats runtime.MemStats
12 runtimeMetrics struct {
13 MemStats struct {
14 Alloc Gauge
15 BuckHashSys Gauge
16 DebugGC Gauge
17 EnableGC Gauge
18 Frees Gauge
19 HeapAlloc Gauge
20 HeapIdle Gauge
21 HeapInuse Gauge
22 HeapObjects Gauge
23 HeapReleased Gauge
24 HeapSys Gauge
25 LastGC Gauge
26 Lookups Gauge
27 Mallocs Gauge
28 MCacheInuse Gauge
29 MCacheSys Gauge
30 MSpanInuse Gauge
31 MSpanSys Gauge
32 NextGC Gauge
33 NumGC Gauge
34 GCCPUFraction GaugeFloat64
35 PauseNs Histogram
36 PauseTotalNs Gauge
37 StackInuse Gauge
38 StackSys Gauge
39 Sys Gauge
40 TotalAlloc Gauge
41 }
42 NumCgoCall Gauge
43 NumGoroutine Gauge
44 NumThread Gauge
45 ReadMemStats Timer
46 }
47 frees uint64
48 lookups uint64
49 mallocs uint64
50 numGC uint32
51 numCgoCalls int64
52
Scott Baker611f6bd2019-10-18 13:45:19 -070053 threadCreateProfile = pprof.Lookup("threadcreate")
54 registerRuntimeMetricsOnce = sync.Once{}
Scott Bakereee8dd82019-09-24 12:52:34 -070055)
56
57// Capture new values for the Go runtime statistics exported in
58// runtime.MemStats. This is designed to be called as a goroutine.
59func CaptureRuntimeMemStats(r Registry, d time.Duration) {
60 for _ = range time.Tick(d) {
61 CaptureRuntimeMemStatsOnce(r)
62 }
63}
64
65// Capture new values for the Go runtime statistics exported in
66// runtime.MemStats. This is designed to be called in a background
67// goroutine. Giving a registry which has not been given to
68// RegisterRuntimeMemStats will panic.
69//
70// Be very careful with this because runtime.ReadMemStats calls the C
71// functions runtime·semacquire(&runtime·worldsema) and runtime·stoptheworld()
72// and that last one does what it says on the tin.
73func CaptureRuntimeMemStatsOnce(r Registry) {
74 t := time.Now()
75 runtime.ReadMemStats(&memStats) // This takes 50-200us.
76 runtimeMetrics.ReadMemStats.UpdateSince(t)
77
78 runtimeMetrics.MemStats.Alloc.Update(int64(memStats.Alloc))
79 runtimeMetrics.MemStats.BuckHashSys.Update(int64(memStats.BuckHashSys))
80 if memStats.DebugGC {
81 runtimeMetrics.MemStats.DebugGC.Update(1)
82 } else {
83 runtimeMetrics.MemStats.DebugGC.Update(0)
84 }
85 if memStats.EnableGC {
86 runtimeMetrics.MemStats.EnableGC.Update(1)
87 } else {
88 runtimeMetrics.MemStats.EnableGC.Update(0)
89 }
90
91 runtimeMetrics.MemStats.Frees.Update(int64(memStats.Frees - frees))
92 runtimeMetrics.MemStats.HeapAlloc.Update(int64(memStats.HeapAlloc))
93 runtimeMetrics.MemStats.HeapIdle.Update(int64(memStats.HeapIdle))
94 runtimeMetrics.MemStats.HeapInuse.Update(int64(memStats.HeapInuse))
95 runtimeMetrics.MemStats.HeapObjects.Update(int64(memStats.HeapObjects))
96 runtimeMetrics.MemStats.HeapReleased.Update(int64(memStats.HeapReleased))
97 runtimeMetrics.MemStats.HeapSys.Update(int64(memStats.HeapSys))
98 runtimeMetrics.MemStats.LastGC.Update(int64(memStats.LastGC))
99 runtimeMetrics.MemStats.Lookups.Update(int64(memStats.Lookups - lookups))
100 runtimeMetrics.MemStats.Mallocs.Update(int64(memStats.Mallocs - mallocs))
101 runtimeMetrics.MemStats.MCacheInuse.Update(int64(memStats.MCacheInuse))
102 runtimeMetrics.MemStats.MCacheSys.Update(int64(memStats.MCacheSys))
103 runtimeMetrics.MemStats.MSpanInuse.Update(int64(memStats.MSpanInuse))
104 runtimeMetrics.MemStats.MSpanSys.Update(int64(memStats.MSpanSys))
105 runtimeMetrics.MemStats.NextGC.Update(int64(memStats.NextGC))
106 runtimeMetrics.MemStats.NumGC.Update(int64(memStats.NumGC - numGC))
107 runtimeMetrics.MemStats.GCCPUFraction.Update(gcCPUFraction(&memStats))
108
109 // <https://code.google.com/p/go/source/browse/src/pkg/runtime/mgc0.c>
110 i := numGC % uint32(len(memStats.PauseNs))
111 ii := memStats.NumGC % uint32(len(memStats.PauseNs))
112 if memStats.NumGC-numGC >= uint32(len(memStats.PauseNs)) {
113 for i = 0; i < uint32(len(memStats.PauseNs)); i++ {
114 runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i]))
115 }
116 } else {
117 if i > ii {
118 for ; i < uint32(len(memStats.PauseNs)); i++ {
119 runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i]))
120 }
121 i = 0
122 }
123 for ; i < ii; i++ {
124 runtimeMetrics.MemStats.PauseNs.Update(int64(memStats.PauseNs[i]))
125 }
126 }
127 frees = memStats.Frees
128 lookups = memStats.Lookups
129 mallocs = memStats.Mallocs
130 numGC = memStats.NumGC
131
132 runtimeMetrics.MemStats.PauseTotalNs.Update(int64(memStats.PauseTotalNs))
133 runtimeMetrics.MemStats.StackInuse.Update(int64(memStats.StackInuse))
134 runtimeMetrics.MemStats.StackSys.Update(int64(memStats.StackSys))
135 runtimeMetrics.MemStats.Sys.Update(int64(memStats.Sys))
136 runtimeMetrics.MemStats.TotalAlloc.Update(int64(memStats.TotalAlloc))
137
138 currentNumCgoCalls := numCgoCall()
139 runtimeMetrics.NumCgoCall.Update(currentNumCgoCalls - numCgoCalls)
140 numCgoCalls = currentNumCgoCalls
141
142 runtimeMetrics.NumGoroutine.Update(int64(runtime.NumGoroutine()))
143
144 runtimeMetrics.NumThread.Update(int64(threadCreateProfile.Count()))
145}
146
147// Register runtimeMetrics for the Go runtime statistics exported in runtime and
148// specifically runtime.MemStats. The runtimeMetrics are named by their
149// fully-qualified Go symbols, i.e. runtime.MemStats.Alloc.
150func RegisterRuntimeMemStats(r Registry) {
Scott Baker611f6bd2019-10-18 13:45:19 -0700151 registerRuntimeMetricsOnce.Do(func() {
152 runtimeMetrics.MemStats.Alloc = NewGauge()
153 runtimeMetrics.MemStats.BuckHashSys = NewGauge()
154 runtimeMetrics.MemStats.DebugGC = NewGauge()
155 runtimeMetrics.MemStats.EnableGC = NewGauge()
156 runtimeMetrics.MemStats.Frees = NewGauge()
157 runtimeMetrics.MemStats.HeapAlloc = NewGauge()
158 runtimeMetrics.MemStats.HeapIdle = NewGauge()
159 runtimeMetrics.MemStats.HeapInuse = NewGauge()
160 runtimeMetrics.MemStats.HeapObjects = NewGauge()
161 runtimeMetrics.MemStats.HeapReleased = NewGauge()
162 runtimeMetrics.MemStats.HeapSys = NewGauge()
163 runtimeMetrics.MemStats.LastGC = NewGauge()
164 runtimeMetrics.MemStats.Lookups = NewGauge()
165 runtimeMetrics.MemStats.Mallocs = NewGauge()
166 runtimeMetrics.MemStats.MCacheInuse = NewGauge()
167 runtimeMetrics.MemStats.MCacheSys = NewGauge()
168 runtimeMetrics.MemStats.MSpanInuse = NewGauge()
169 runtimeMetrics.MemStats.MSpanSys = NewGauge()
170 runtimeMetrics.MemStats.NextGC = NewGauge()
171 runtimeMetrics.MemStats.NumGC = NewGauge()
172 runtimeMetrics.MemStats.GCCPUFraction = NewGaugeFloat64()
173 runtimeMetrics.MemStats.PauseNs = NewHistogram(NewExpDecaySample(1028, 0.015))
174 runtimeMetrics.MemStats.PauseTotalNs = NewGauge()
175 runtimeMetrics.MemStats.StackInuse = NewGauge()
176 runtimeMetrics.MemStats.StackSys = NewGauge()
177 runtimeMetrics.MemStats.Sys = NewGauge()
178 runtimeMetrics.MemStats.TotalAlloc = NewGauge()
179 runtimeMetrics.NumCgoCall = NewGauge()
180 runtimeMetrics.NumGoroutine = NewGauge()
181 runtimeMetrics.NumThread = NewGauge()
182 runtimeMetrics.ReadMemStats = NewTimer()
Scott Bakereee8dd82019-09-24 12:52:34 -0700183
Scott Baker611f6bd2019-10-18 13:45:19 -0700184 r.Register("runtime.MemStats.Alloc", runtimeMetrics.MemStats.Alloc)
185 r.Register("runtime.MemStats.BuckHashSys", runtimeMetrics.MemStats.BuckHashSys)
186 r.Register("runtime.MemStats.DebugGC", runtimeMetrics.MemStats.DebugGC)
187 r.Register("runtime.MemStats.EnableGC", runtimeMetrics.MemStats.EnableGC)
188 r.Register("runtime.MemStats.Frees", runtimeMetrics.MemStats.Frees)
189 r.Register("runtime.MemStats.HeapAlloc", runtimeMetrics.MemStats.HeapAlloc)
190 r.Register("runtime.MemStats.HeapIdle", runtimeMetrics.MemStats.HeapIdle)
191 r.Register("runtime.MemStats.HeapInuse", runtimeMetrics.MemStats.HeapInuse)
192 r.Register("runtime.MemStats.HeapObjects", runtimeMetrics.MemStats.HeapObjects)
193 r.Register("runtime.MemStats.HeapReleased", runtimeMetrics.MemStats.HeapReleased)
194 r.Register("runtime.MemStats.HeapSys", runtimeMetrics.MemStats.HeapSys)
195 r.Register("runtime.MemStats.LastGC", runtimeMetrics.MemStats.LastGC)
196 r.Register("runtime.MemStats.Lookups", runtimeMetrics.MemStats.Lookups)
197 r.Register("runtime.MemStats.Mallocs", runtimeMetrics.MemStats.Mallocs)
198 r.Register("runtime.MemStats.MCacheInuse", runtimeMetrics.MemStats.MCacheInuse)
199 r.Register("runtime.MemStats.MCacheSys", runtimeMetrics.MemStats.MCacheSys)
200 r.Register("runtime.MemStats.MSpanInuse", runtimeMetrics.MemStats.MSpanInuse)
201 r.Register("runtime.MemStats.MSpanSys", runtimeMetrics.MemStats.MSpanSys)
202 r.Register("runtime.MemStats.NextGC", runtimeMetrics.MemStats.NextGC)
203 r.Register("runtime.MemStats.NumGC", runtimeMetrics.MemStats.NumGC)
204 r.Register("runtime.MemStats.GCCPUFraction", runtimeMetrics.MemStats.GCCPUFraction)
205 r.Register("runtime.MemStats.PauseNs", runtimeMetrics.MemStats.PauseNs)
206 r.Register("runtime.MemStats.PauseTotalNs", runtimeMetrics.MemStats.PauseTotalNs)
207 r.Register("runtime.MemStats.StackInuse", runtimeMetrics.MemStats.StackInuse)
208 r.Register("runtime.MemStats.StackSys", runtimeMetrics.MemStats.StackSys)
209 r.Register("runtime.MemStats.Sys", runtimeMetrics.MemStats.Sys)
210 r.Register("runtime.MemStats.TotalAlloc", runtimeMetrics.MemStats.TotalAlloc)
211 r.Register("runtime.NumCgoCall", runtimeMetrics.NumCgoCall)
212 r.Register("runtime.NumGoroutine", runtimeMetrics.NumGoroutine)
213 r.Register("runtime.NumThread", runtimeMetrics.NumThread)
214 r.Register("runtime.ReadMemStats", runtimeMetrics.ReadMemStats)
215 })
Scott Bakereee8dd82019-09-24 12:52:34 -0700216}