Source file
src/runtime/metrics.go
Documentation: runtime
1
2
3
4
5 package runtime
6
7
8
9 import (
10 "runtime/internal/atomic"
11 "unsafe"
12 )
13
14 var (
15
16
17
18
19
20
21 metricsSema uint32 = 1
22 metricsInit bool
23 metrics map[string]metricData
24
25 sizeClassBuckets []float64
26 timeHistBuckets []float64
27 )
28
29 type metricData struct {
30
31
32
33 deps statDepSet
34
35
36
37 compute func(in *statAggregate, out *metricValue)
38 }
39
40 func metricsLock() {
41
42
43
44 semacquire1(&metricsSema, true, 0, 0)
45 if raceenabled {
46 raceacquire(unsafe.Pointer(&metricsSema))
47 }
48 }
49
50 func metricsUnlock() {
51 if raceenabled {
52 racerelease(unsafe.Pointer(&metricsSema))
53 }
54 semrelease(&metricsSema)
55 }
56
57
58
59
60 func initMetrics() {
61 if metricsInit {
62 return
63 }
64
65 sizeClassBuckets = make([]float64, _NumSizeClasses, _NumSizeClasses+1)
66
67
68
69 sizeClassBuckets[0] = 1
70 for i := 1; i < _NumSizeClasses; i++ {
71
72
73
74
75
76
77
78
79
80
81
82 sizeClassBuckets[i] = float64(class_to_size[i] + 1)
83 }
84 sizeClassBuckets = append(sizeClassBuckets, float64Inf())
85
86 timeHistBuckets = timeHistogramMetricsBuckets()
87 metrics = map[string]metricData{
88 "/cgo/go-to-c-calls:calls": {
89 compute: func(_ *statAggregate, out *metricValue) {
90 out.kind = metricKindUint64
91 out.scalar = uint64(NumCgoCall())
92 },
93 },
94 "/gc/cycles/automatic:gc-cycles": {
95 deps: makeStatDepSet(sysStatsDep),
96 compute: func(in *statAggregate, out *metricValue) {
97 out.kind = metricKindUint64
98 out.scalar = in.sysStats.gcCyclesDone - in.sysStats.gcCyclesForced
99 },
100 },
101 "/gc/cycles/forced:gc-cycles": {
102 deps: makeStatDepSet(sysStatsDep),
103 compute: func(in *statAggregate, out *metricValue) {
104 out.kind = metricKindUint64
105 out.scalar = in.sysStats.gcCyclesForced
106 },
107 },
108 "/gc/cycles/total:gc-cycles": {
109 deps: makeStatDepSet(sysStatsDep),
110 compute: func(in *statAggregate, out *metricValue) {
111 out.kind = metricKindUint64
112 out.scalar = in.sysStats.gcCyclesDone
113 },
114 },
115 "/gc/heap/allocs-by-size:bytes": {
116 deps: makeStatDepSet(heapStatsDep),
117 compute: func(in *statAggregate, out *metricValue) {
118 hist := out.float64HistOrInit(sizeClassBuckets)
119 hist.counts[len(hist.counts)-1] = uint64(in.heapStats.largeAllocCount)
120
121
122 for i, count := range in.heapStats.smallAllocCount[1:] {
123 hist.counts[i] = uint64(count)
124 }
125 },
126 },
127 "/gc/heap/allocs:bytes": {
128 deps: makeStatDepSet(heapStatsDep),
129 compute: func(in *statAggregate, out *metricValue) {
130 out.kind = metricKindUint64
131 out.scalar = in.heapStats.totalAllocated
132 },
133 },
134 "/gc/heap/allocs:objects": {
135 deps: makeStatDepSet(heapStatsDep),
136 compute: func(in *statAggregate, out *metricValue) {
137 out.kind = metricKindUint64
138 out.scalar = in.heapStats.totalAllocs
139 },
140 },
141 "/gc/heap/frees-by-size:bytes": {
142 deps: makeStatDepSet(heapStatsDep),
143 compute: func(in *statAggregate, out *metricValue) {
144 hist := out.float64HistOrInit(sizeClassBuckets)
145 hist.counts[len(hist.counts)-1] = uint64(in.heapStats.largeFreeCount)
146
147
148 for i, count := range in.heapStats.smallFreeCount[1:] {
149 hist.counts[i] = uint64(count)
150 }
151 },
152 },
153 "/gc/heap/frees:bytes": {
154 deps: makeStatDepSet(heapStatsDep),
155 compute: func(in *statAggregate, out *metricValue) {
156 out.kind = metricKindUint64
157 out.scalar = in.heapStats.totalFreed
158 },
159 },
160 "/gc/heap/frees:objects": {
161 deps: makeStatDepSet(heapStatsDep),
162 compute: func(in *statAggregate, out *metricValue) {
163 out.kind = metricKindUint64
164 out.scalar = in.heapStats.totalFrees
165 },
166 },
167 "/gc/heap/goal:bytes": {
168 deps: makeStatDepSet(sysStatsDep),
169 compute: func(in *statAggregate, out *metricValue) {
170 out.kind = metricKindUint64
171 out.scalar = in.sysStats.heapGoal
172 },
173 },
174 "/gc/heap/objects:objects": {
175 deps: makeStatDepSet(heapStatsDep),
176 compute: func(in *statAggregate, out *metricValue) {
177 out.kind = metricKindUint64
178 out.scalar = in.heapStats.numObjects
179 },
180 },
181 "/gc/heap/tiny/allocs:objects": {
182 deps: makeStatDepSet(heapStatsDep),
183 compute: func(in *statAggregate, out *metricValue) {
184 out.kind = metricKindUint64
185 out.scalar = uint64(in.heapStats.tinyAllocCount)
186 },
187 },
188 "/gc/limiter/last-enabled:gc-cycle": {
189 compute: func(_ *statAggregate, out *metricValue) {
190 out.kind = metricKindUint64
191 out.scalar = uint64(gcCPULimiter.lastEnabledCycle.Load())
192 },
193 },
194 "/gc/pauses:seconds": {
195 compute: func(_ *statAggregate, out *metricValue) {
196 hist := out.float64HistOrInit(timeHistBuckets)
197
198
199
200 hist.counts[0] = atomic.Load64(&memstats.gcPauseDist.underflow)
201 for i := range memstats.gcPauseDist.counts {
202 hist.counts[i+1] = atomic.Load64(&memstats.gcPauseDist.counts[i])
203 }
204 },
205 },
206 "/gc/stack/starting-size:bytes": {
207 compute: func(in *statAggregate, out *metricValue) {
208 out.kind = metricKindUint64
209 out.scalar = uint64(startingStackSize)
210 },
211 },
212 "/memory/classes/heap/free:bytes": {
213 deps: makeStatDepSet(heapStatsDep),
214 compute: func(in *statAggregate, out *metricValue) {
215 out.kind = metricKindUint64
216 out.scalar = uint64(in.heapStats.committed - in.heapStats.inHeap -
217 in.heapStats.inStacks - in.heapStats.inWorkBufs -
218 in.heapStats.inPtrScalarBits)
219 },
220 },
221 "/memory/classes/heap/objects:bytes": {
222 deps: makeStatDepSet(heapStatsDep),
223 compute: func(in *statAggregate, out *metricValue) {
224 out.kind = metricKindUint64
225 out.scalar = in.heapStats.inObjects
226 },
227 },
228 "/memory/classes/heap/released:bytes": {
229 deps: makeStatDepSet(heapStatsDep),
230 compute: func(in *statAggregate, out *metricValue) {
231 out.kind = metricKindUint64
232 out.scalar = uint64(in.heapStats.released)
233 },
234 },
235 "/memory/classes/heap/stacks:bytes": {
236 deps: makeStatDepSet(heapStatsDep),
237 compute: func(in *statAggregate, out *metricValue) {
238 out.kind = metricKindUint64
239 out.scalar = uint64(in.heapStats.inStacks)
240 },
241 },
242 "/memory/classes/heap/unused:bytes": {
243 deps: makeStatDepSet(heapStatsDep),
244 compute: func(in *statAggregate, out *metricValue) {
245 out.kind = metricKindUint64
246 out.scalar = uint64(in.heapStats.inHeap) - in.heapStats.inObjects
247 },
248 },
249 "/memory/classes/metadata/mcache/free:bytes": {
250 deps: makeStatDepSet(sysStatsDep),
251 compute: func(in *statAggregate, out *metricValue) {
252 out.kind = metricKindUint64
253 out.scalar = in.sysStats.mCacheSys - in.sysStats.mCacheInUse
254 },
255 },
256 "/memory/classes/metadata/mcache/inuse:bytes": {
257 deps: makeStatDepSet(sysStatsDep),
258 compute: func(in *statAggregate, out *metricValue) {
259 out.kind = metricKindUint64
260 out.scalar = in.sysStats.mCacheInUse
261 },
262 },
263 "/memory/classes/metadata/mspan/free:bytes": {
264 deps: makeStatDepSet(sysStatsDep),
265 compute: func(in *statAggregate, out *metricValue) {
266 out.kind = metricKindUint64
267 out.scalar = in.sysStats.mSpanSys - in.sysStats.mSpanInUse
268 },
269 },
270 "/memory/classes/metadata/mspan/inuse:bytes": {
271 deps: makeStatDepSet(sysStatsDep),
272 compute: func(in *statAggregate, out *metricValue) {
273 out.kind = metricKindUint64
274 out.scalar = in.sysStats.mSpanInUse
275 },
276 },
277 "/memory/classes/metadata/other:bytes": {
278 deps: makeStatDepSet(heapStatsDep, sysStatsDep),
279 compute: func(in *statAggregate, out *metricValue) {
280 out.kind = metricKindUint64
281 out.scalar = uint64(in.heapStats.inWorkBufs+in.heapStats.inPtrScalarBits) + in.sysStats.gcMiscSys
282 },
283 },
284 "/memory/classes/os-stacks:bytes": {
285 deps: makeStatDepSet(sysStatsDep),
286 compute: func(in *statAggregate, out *metricValue) {
287 out.kind = metricKindUint64
288 out.scalar = in.sysStats.stacksSys
289 },
290 },
291 "/memory/classes/other:bytes": {
292 deps: makeStatDepSet(sysStatsDep),
293 compute: func(in *statAggregate, out *metricValue) {
294 out.kind = metricKindUint64
295 out.scalar = in.sysStats.otherSys
296 },
297 },
298 "/memory/classes/profiling/buckets:bytes": {
299 deps: makeStatDepSet(sysStatsDep),
300 compute: func(in *statAggregate, out *metricValue) {
301 out.kind = metricKindUint64
302 out.scalar = in.sysStats.buckHashSys
303 },
304 },
305 "/memory/classes/total:bytes": {
306 deps: makeStatDepSet(heapStatsDep, sysStatsDep),
307 compute: func(in *statAggregate, out *metricValue) {
308 out.kind = metricKindUint64
309 out.scalar = uint64(in.heapStats.committed+in.heapStats.released) +
310 in.sysStats.stacksSys + in.sysStats.mSpanSys +
311 in.sysStats.mCacheSys + in.sysStats.buckHashSys +
312 in.sysStats.gcMiscSys + in.sysStats.otherSys
313 },
314 },
315 "/sched/gomaxprocs:threads": {
316 compute: func(_ *statAggregate, out *metricValue) {
317 out.kind = metricKindUint64
318 out.scalar = uint64(gomaxprocs)
319 },
320 },
321 "/sched/goroutines:goroutines": {
322 compute: func(_ *statAggregate, out *metricValue) {
323 out.kind = metricKindUint64
324 out.scalar = uint64(gcount())
325 },
326 },
327 "/sched/latencies:seconds": {
328 compute: func(_ *statAggregate, out *metricValue) {
329 hist := out.float64HistOrInit(timeHistBuckets)
330 hist.counts[0] = atomic.Load64(&sched.timeToRun.underflow)
331 for i := range sched.timeToRun.counts {
332 hist.counts[i+1] = atomic.Load64(&sched.timeToRun.counts[i])
333 }
334 },
335 },
336 }
337 metricsInit = true
338 }
339
340
341
342 type statDep uint
343
344 const (
345 heapStatsDep statDep = iota
346 sysStatsDep
347 numStatsDeps
348 )
349
350
351
352
353 type statDepSet [1]uint64
354
355
356 func makeStatDepSet(deps ...statDep) statDepSet {
357 var s statDepSet
358 for _, d := range deps {
359 s[d/64] |= 1 << (d % 64)
360 }
361 return s
362 }
363
364
365 func (s statDepSet) difference(b statDepSet) statDepSet {
366 var c statDepSet
367 for i := range s {
368 c[i] = s[i] &^ b[i]
369 }
370 return c
371 }
372
373
374 func (s statDepSet) union(b statDepSet) statDepSet {
375 var c statDepSet
376 for i := range s {
377 c[i] = s[i] | b[i]
378 }
379 return c
380 }
381
382
383 func (s *statDepSet) empty() bool {
384 for _, c := range s {
385 if c != 0 {
386 return false
387 }
388 }
389 return true
390 }
391
392
393 func (s *statDepSet) has(d statDep) bool {
394 return s[d/64]&(1<<(d%64)) != 0
395 }
396
397
398
399
400
401
402 type heapStatsAggregate struct {
403 heapStatsDelta
404
405
406
407
408 inObjects uint64
409
410
411 numObjects uint64
412
413
414
415 totalAllocated uint64
416
417
418
419 totalFreed uint64
420
421
422
423 totalAllocs uint64
424
425
426
427 totalFrees uint64
428 }
429
430
431 func (a *heapStatsAggregate) compute() {
432 memstats.heapStats.read(&a.heapStatsDelta)
433
434
435 a.totalAllocs = a.largeAllocCount
436 a.totalFrees = a.largeFreeCount
437 a.totalAllocated = a.largeAlloc
438 a.totalFreed = a.largeFree
439 for i := range a.smallAllocCount {
440 na := a.smallAllocCount[i]
441 nf := a.smallFreeCount[i]
442 a.totalAllocs += na
443 a.totalFrees += nf
444 a.totalAllocated += na * uint64(class_to_size[i])
445 a.totalFreed += nf * uint64(class_to_size[i])
446 }
447 a.inObjects = a.totalAllocated - a.totalFreed
448 a.numObjects = a.totalAllocs - a.totalFrees
449 }
450
451
452
453
454
455
456
457
458 type sysStatsAggregate struct {
459 stacksSys uint64
460 mSpanSys uint64
461 mSpanInUse uint64
462 mCacheSys uint64
463 mCacheInUse uint64
464 buckHashSys uint64
465 gcMiscSys uint64
466 otherSys uint64
467 heapGoal uint64
468 gcCyclesDone uint64
469 gcCyclesForced uint64
470 }
471
472
473 func (a *sysStatsAggregate) compute() {
474 a.stacksSys = memstats.stacks_sys.load()
475 a.buckHashSys = memstats.buckhash_sys.load()
476 a.gcMiscSys = memstats.gcMiscSys.load()
477 a.otherSys = memstats.other_sys.load()
478 a.heapGoal = gcController.heapGoal()
479 a.gcCyclesDone = uint64(memstats.numgc)
480 a.gcCyclesForced = uint64(memstats.numforcedgc)
481
482 systemstack(func() {
483 lock(&mheap_.lock)
484 a.mSpanSys = memstats.mspan_sys.load()
485 a.mSpanInUse = uint64(mheap_.spanalloc.inuse)
486 a.mCacheSys = memstats.mcache_sys.load()
487 a.mCacheInUse = uint64(mheap_.cachealloc.inuse)
488 unlock(&mheap_.lock)
489 })
490 }
491
492
493
494
495
496
497 type statAggregate struct {
498 ensured statDepSet
499 heapStats heapStatsAggregate
500 sysStats sysStatsAggregate
501 }
502
503
504
505 func (a *statAggregate) ensure(deps *statDepSet) {
506 missing := deps.difference(a.ensured)
507 if missing.empty() {
508 return
509 }
510 for i := statDep(0); i < numStatsDeps; i++ {
511 if !missing.has(i) {
512 continue
513 }
514 switch i {
515 case heapStatsDep:
516 a.heapStats.compute()
517 case sysStatsDep:
518 a.sysStats.compute()
519 }
520 }
521 a.ensured = a.ensured.union(missing)
522 }
523
524
525
526 type metricKind int
527
528 const (
529
530
531 metricKindBad metricKind = iota
532 metricKindUint64
533 metricKindFloat64
534 metricKindFloat64Histogram
535 )
536
537
538
539 type metricSample struct {
540 name string
541 value metricValue
542 }
543
544
545
546 type metricValue struct {
547 kind metricKind
548 scalar uint64
549 pointer unsafe.Pointer
550 }
551
552
553
554
555 func (v *metricValue) float64HistOrInit(buckets []float64) *metricFloat64Histogram {
556 var hist *metricFloat64Histogram
557 if v.kind == metricKindFloat64Histogram && v.pointer != nil {
558 hist = (*metricFloat64Histogram)(v.pointer)
559 } else {
560 v.kind = metricKindFloat64Histogram
561 hist = new(metricFloat64Histogram)
562 v.pointer = unsafe.Pointer(hist)
563 }
564 hist.buckets = buckets
565 if len(hist.counts) != len(hist.buckets)-1 {
566 hist.counts = make([]uint64, len(buckets)-1)
567 }
568 return hist
569 }
570
571
572
573 type metricFloat64Histogram struct {
574 counts []uint64
575 buckets []float64
576 }
577
578
579
580
581
582
583 var agg statAggregate
584
585
586
587
588 func readMetrics(samplesp unsafe.Pointer, len int, cap int) {
589
590 sl := slice{samplesp, len, cap}
591 samples := *(*[]metricSample)(unsafe.Pointer(&sl))
592
593 metricsLock()
594
595
596 initMetrics()
597
598
599 agg = statAggregate{}
600
601
602 for i := range samples {
603 sample := &samples[i]
604 data, ok := metrics[sample.name]
605 if !ok {
606 sample.value.kind = metricKindBad
607 continue
608 }
609
610
611 agg.ensure(&data.deps)
612
613
614 data.compute(&agg, &sample.value)
615 }
616
617 metricsUnlock()
618 }
619
View as plain text