github.com/rcrowley/go-metrics@v0.0.0-20201227073835-cf1acfcdf475/runtime.go (about)

     1  package metrics
     2  
     3  import (
     4  	"runtime"
     5  	"runtime/pprof"
     6  	"sync"
     7  	"time"
     8  )
     9  
    10  var (
    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  
    53  	threadCreateProfile        = pprof.Lookup("threadcreate")
    54  	registerRuntimeMetricsOnce = sync.Once{}
    55  )
    56  
    57  // Capture new values for the Go runtime statistics exported in
    58  // runtime.MemStats.  This is designed to be called as a goroutine.
    59  func 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.
    73  func 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.
   150  func RegisterRuntimeMemStats(r Registry) {
   151  	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()
   183  
   184  		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  	})
   216  }