package runtime
import (
"runtime/internal/atomic"
"unsafe"
)
var (
metricsSema uint32 = 1
metricsInit bool
metrics map [string ]metricData
sizeClassBuckets []float64
timeHistBuckets []float64
)
type metricData struct {
deps statDepSet
compute func (in *statAggregate , out *metricValue )
}
func initMetrics () {
if metricsInit {
return
}
sizeClassBuckets = make ([]float64 , _NumSizeClasses , _NumSizeClasses +1 )
sizeClassBuckets [0 ] = 1
for i := 1 ; i < _NumSizeClasses ; i ++ {
sizeClassBuckets [i ] = float64 (class_to_size [i ] + 1 )
}
sizeClassBuckets = append (sizeClassBuckets , float64Inf ())
timeHistBuckets = timeHistogramMetricsBuckets ()
metrics = map [string ]metricData {
"/gc/cycles/automatic:gc-cycles" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .gcCyclesDone - in .sysStats .gcCyclesForced
},
},
"/gc/cycles/forced:gc-cycles" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .gcCyclesForced
},
},
"/gc/cycles/total:gc-cycles" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .gcCyclesDone
},
},
"/gc/heap/allocs-by-size:bytes" : {
deps : makeStatDepSet (heapStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
hist := out .float64HistOrInit (sizeClassBuckets )
hist .counts [len (hist .counts )-1 ] = uint64 (in .heapStats .largeAllocCount )
for i , count := range in .heapStats .smallAllocCount [1 :] {
hist .counts [i ] = uint64 (count )
}
},
},
"/gc/heap/frees-by-size:bytes" : {
deps : makeStatDepSet (heapStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
hist := out .float64HistOrInit (sizeClassBuckets )
hist .counts [len (hist .counts )-1 ] = uint64 (in .heapStats .largeFreeCount )
for i , count := range in .heapStats .smallFreeCount [1 :] {
hist .counts [i ] = uint64 (count )
}
},
},
"/gc/heap/goal:bytes" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .heapGoal
},
},
"/gc/heap/objects:objects" : {
deps : makeStatDepSet (heapStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .heapStats .numObjects
},
},
"/gc/pauses:seconds" : {
compute : func (_ *statAggregate , out *metricValue ) {
hist := out .float64HistOrInit (timeHistBuckets )
hist .counts [0 ] = atomic .Load64 (&memstats .gcPauseDist .underflow )
for i := range memstats .gcPauseDist .counts {
hist .counts [i +1 ] = atomic .Load64 (&memstats .gcPauseDist .counts [i ])
}
},
},
"/memory/classes/heap/free:bytes" : {
deps : makeStatDepSet (heapStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = uint64 (in .heapStats .committed - in .heapStats .inHeap -
in .heapStats .inStacks - in .heapStats .inWorkBufs -
in .heapStats .inPtrScalarBits )
},
},
"/memory/classes/heap/objects:bytes" : {
deps : makeStatDepSet (heapStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .heapStats .inObjects
},
},
"/memory/classes/heap/released:bytes" : {
deps : makeStatDepSet (heapStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = uint64 (in .heapStats .released )
},
},
"/memory/classes/heap/stacks:bytes" : {
deps : makeStatDepSet (heapStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = uint64 (in .heapStats .inStacks )
},
},
"/memory/classes/heap/unused:bytes" : {
deps : makeStatDepSet (heapStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = uint64 (in .heapStats .inHeap ) - in .heapStats .inObjects
},
},
"/memory/classes/metadata/mcache/free:bytes" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .mCacheSys - in .sysStats .mCacheInUse
},
},
"/memory/classes/metadata/mcache/inuse:bytes" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .mCacheInUse
},
},
"/memory/classes/metadata/mspan/free:bytes" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .mSpanSys - in .sysStats .mSpanInUse
},
},
"/memory/classes/metadata/mspan/inuse:bytes" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .mSpanInUse
},
},
"/memory/classes/metadata/other:bytes" : {
deps : makeStatDepSet (heapStatsDep , sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = uint64 (in .heapStats .inWorkBufs +in .heapStats .inPtrScalarBits ) + in .sysStats .gcMiscSys
},
},
"/memory/classes/os-stacks:bytes" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .stacksSys
},
},
"/memory/classes/other:bytes" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .otherSys
},
},
"/memory/classes/profiling/buckets:bytes" : {
deps : makeStatDepSet (sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = in .sysStats .buckHashSys
},
},
"/memory/classes/total:bytes" : {
deps : makeStatDepSet (heapStatsDep , sysStatsDep ),
compute : func (in *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = uint64 (in .heapStats .committed +in .heapStats .released ) +
in .sysStats .stacksSys + in .sysStats .mSpanSys +
in .sysStats .mCacheSys + in .sysStats .buckHashSys +
in .sysStats .gcMiscSys + in .sysStats .otherSys
},
},
"/sched/goroutines:goroutines" : {
compute : func (_ *statAggregate , out *metricValue ) {
out .kind = metricKindUint64
out .scalar = uint64 (gcount ())
},
},
}
metricsInit = true
}
type statDep uint
const (
heapStatsDep statDep = iota
sysStatsDep
numStatsDeps
)
type statDepSet [1 ]uint64
func makeStatDepSet (deps ...statDep ) statDepSet {
var s statDepSet
for _ , d := range deps {
s [d /64 ] |= 1 << (d % 64 )
}
return s
}
func (s statDepSet ) difference (b statDepSet ) statDepSet {
var c statDepSet
for i := range s {
c [i ] = s [i ] &^ b [i ]
}
return c
}
func (s statDepSet ) union (b statDepSet ) statDepSet {
var c statDepSet
for i := range s {
c [i ] = s [i ] | b [i ]
}
return c
}
func (s *statDepSet ) empty () bool {
for _ , c := range s {
if c != 0 {
return false
}
}
return true
}
func (s *statDepSet ) has (d statDep ) bool {
return s [d /64 ]&(1 <<(d %64 )) != 0
}
type heapStatsAggregate struct {
heapStatsDelta
inObjects uint64
numObjects uint64
}
func (a *heapStatsAggregate ) compute () {
memstats .heapStats .read (&a .heapStatsDelta )
a .inObjects = uint64 (a .largeAlloc - a .largeFree )
a .numObjects = uint64 (a .largeAllocCount - a .largeFreeCount )
for i := range a .smallAllocCount {
n := uint64 (a .smallAllocCount [i ] - a .smallFreeCount [i ])
a .inObjects += n * uint64 (class_to_size [i ])
a .numObjects += n
}
}
type sysStatsAggregate struct {
stacksSys uint64
mSpanSys uint64
mSpanInUse uint64
mCacheSys uint64
mCacheInUse uint64
buckHashSys uint64
gcMiscSys uint64
otherSys uint64
heapGoal uint64
gcCyclesDone uint64
gcCyclesForced uint64
}
func (a *sysStatsAggregate ) compute () {
a .stacksSys = memstats .stacks_sys .load ()
a .buckHashSys = memstats .buckhash_sys .load ()
a .gcMiscSys = memstats .gcMiscSys .load ()
a .otherSys = memstats .other_sys .load ()
a .heapGoal = atomic .Load64 (&memstats .next_gc )
a .gcCyclesDone = uint64 (memstats .numgc )
a .gcCyclesForced = uint64 (memstats .numforcedgc )
systemstack (func () {
lock (&mheap_ .lock )
a .mSpanSys = memstats .mspan_sys .load ()
a .mSpanInUse = uint64 (mheap_ .spanalloc .inuse )
a .mCacheSys = memstats .mcache_sys .load ()
a .mCacheInUse = uint64 (mheap_ .cachealloc .inuse )
unlock (&mheap_ .lock )
})
}
type statAggregate struct {
ensured statDepSet
heapStats heapStatsAggregate
sysStats sysStatsAggregate
}
func (a *statAggregate ) ensure (deps *statDepSet ) {
missing := deps .difference (a .ensured )
if missing .empty () {
return
}
for i := statDep (0 ); i < numStatsDeps ; i ++ {
if !missing .has (i ) {
continue
}
switch i {
case heapStatsDep :
a .heapStats .compute ()
case sysStatsDep :
a .sysStats .compute ()
}
}
a .ensured = a .ensured .union (missing )
}
type metricKind int
const (
metricKindBad metricKind = iota
metricKindUint64
metricKindFloat64
metricKindFloat64Histogram
)
type metricSample struct {
name string
value metricValue
}
type metricValue struct {
kind metricKind
scalar uint64
pointer unsafe .Pointer
}
func (v *metricValue ) float64HistOrInit (buckets []float64 ) *metricFloat64Histogram {
var hist *metricFloat64Histogram
if v .kind == metricKindFloat64Histogram && v .pointer != nil {
hist = (*metricFloat64Histogram )(v .pointer )
} else {
v .kind = metricKindFloat64Histogram
hist = new (metricFloat64Histogram )
v .pointer = unsafe .Pointer (hist )
}
hist .buckets = buckets
if len (hist .counts ) != len (hist .buckets )-1 {
hist .counts = make ([]uint64 , len (buckets )-1 )
}
return hist
}
type metricFloat64Histogram struct {
counts []uint64
buckets []float64
}
var agg statAggregate
func readMetrics (samplesp unsafe .Pointer , len int , cap int ) {
sl := slice {samplesp , len , cap }
samples := *(*[]metricSample )(unsafe .Pointer (&sl ))
semacquire1 (&metricsSema , true , 0 , 0 )
initMetrics ()
agg = statAggregate {}
for i := range samples {
sample := &samples [i ]
data , ok := metrics [sample .name ]
if !ok {
sample .value .kind = metricKindBad
continue
}
agg .ensure (&data .deps )
data .compute (&agg , &sample .value )
}
semrelease (&metricsSema )
}
The pages are generated with Golds v0.3.6 . (GOOS=darwin GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .