c539bda166
This changes how we read performance metrics from the Go runtime. Instead of using runtime.ReadMemStats, we now rely on the API provided by package runtime/metrics. runtime/metrics provides more accurate information. For example, the new interface has better reporting of memory use. In my testing, the reported value of held memory more accurately reflects the usage reported by the OS. The semantics of metrics system/memory/allocs and system/memory/frees have changed to report amounts in bytes. ReadMemStats only reported the count of allocations in number-of-objects. This is imprecise: 'tiny objects' are not counted because the runtime allocates them in batches; and certain improvements in allocation behavior, such as struct size optimizations, will be less visible when the number of allocs doesn't change. Changing allocation reports to be in bytes makes it appear in graphs that lots more is being allocated. I don't think that's a problem because this metric is primarily interesting for geth developers. The metric system/memory/pauses has been changed to report statistical values from the histogram provided by the runtime. Its name in influxdb has changed from geth.system/memory/pauses.meter to geth.system/memory/pauses.histogram. We also have a new histogram metric, system/cpu/schedlatency, reporting the Go scheduler latency.
104 lines
1.7 KiB
Go
104 lines
1.7 KiB
Go
package metrics
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
const FANOUT = 128
|
|
|
|
func TestReadRuntimeValues(t *testing.T) {
|
|
var v runtimeStats
|
|
readRuntimeStats(&v)
|
|
t.Logf("%+v", v)
|
|
}
|
|
|
|
func BenchmarkMetrics(b *testing.B) {
|
|
r := NewRegistry()
|
|
c := NewRegisteredCounter("counter", r)
|
|
g := NewRegisteredGauge("gauge", r)
|
|
gf := NewRegisteredGaugeFloat64("gaugefloat64", r)
|
|
h := NewRegisteredHistogram("histogram", r, NewUniformSample(100))
|
|
m := NewRegisteredMeter("meter", r)
|
|
t := NewRegisteredTimer("timer", r)
|
|
RegisterDebugGCStats(r)
|
|
b.ResetTimer()
|
|
ch := make(chan bool)
|
|
|
|
wgD := &sync.WaitGroup{}
|
|
/*
|
|
wgD.Add(1)
|
|
go func() {
|
|
defer wgD.Done()
|
|
//log.Println("go CaptureDebugGCStats")
|
|
for {
|
|
select {
|
|
case <-ch:
|
|
//log.Println("done CaptureDebugGCStats")
|
|
return
|
|
default:
|
|
CaptureDebugGCStatsOnce(r)
|
|
}
|
|
}
|
|
}()
|
|
//*/
|
|
|
|
wgW := &sync.WaitGroup{}
|
|
/*
|
|
wgW.Add(1)
|
|
go func() {
|
|
defer wgW.Done()
|
|
//log.Println("go Write")
|
|
for {
|
|
select {
|
|
case <-ch:
|
|
//log.Println("done Write")
|
|
return
|
|
default:
|
|
WriteOnce(r, io.Discard)
|
|
}
|
|
}
|
|
}()
|
|
//*/
|
|
|
|
wg := &sync.WaitGroup{}
|
|
wg.Add(FANOUT)
|
|
for i := 0; i < FANOUT; i++ {
|
|
go func(i int) {
|
|
defer wg.Done()
|
|
//log.Println("go", i)
|
|
for i := 0; i < b.N; i++ {
|
|
c.Inc(1)
|
|
g.Update(int64(i))
|
|
gf.Update(float64(i))
|
|
h.Update(int64(i))
|
|
m.Mark(1)
|
|
t.Update(1)
|
|
}
|
|
//log.Println("done", i)
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
close(ch)
|
|
wgD.Wait()
|
|
wgW.Wait()
|
|
}
|
|
|
|
func Example() {
|
|
c := NewCounter()
|
|
Register("money", c)
|
|
c.Inc(17)
|
|
|
|
// Threadsafe registration
|
|
t := GetOrRegisterTimer("db.get.latency", nil)
|
|
t.Time(func() { time.Sleep(10 * time.Millisecond) })
|
|
t.Update(1)
|
|
|
|
fmt.Println(c.Count())
|
|
fmt.Println(t.Min())
|
|
// Output: 17
|
|
// 1
|
|
}
|