diff --git a/metrics/histogram.go b/metrics/histogram.go index ef146d8f4d..44de588bc1 100644 --- a/metrics/histogram.go +++ b/metrics/histogram.go @@ -1,15 +1,7 @@ package metrics type HistogramSnapshot interface { - Count() int64 - Max() int64 - Mean() float64 - Min() int64 - Percentile(float64) float64 - Percentiles([]float64) []float64 - StdDev() float64 - Sum() int64 - Variance() float64 + SampleSnapshot } // Histograms calculate distribution statistics from a series of int64 values. @@ -56,52 +48,6 @@ func NewRegisteredHistogram(name string, r Registry, s Sample) Histogram { return c } -// histogramSnapshot is a read-only copy of another Histogram. -type histogramSnapshot struct { - sample *sampleSnapshot -} - -// Count returns the number of samples recorded at the time the snapshot was -// taken. -func (h *histogramSnapshot) Count() int64 { return h.sample.Count() } - -// Max returns the maximum value in the sample at the time the snapshot was -// taken. -func (h *histogramSnapshot) Max() int64 { return h.sample.Max() } - -// Mean returns the mean of the values in the sample at the time the snapshot -// was taken. -func (h *histogramSnapshot) Mean() float64 { return h.sample.Mean() } - -// Min returns the minimum value in the sample at the time the snapshot was -// taken. -func (h *histogramSnapshot) Min() int64 { return h.sample.Min() } - -// Percentile returns an arbitrary percentile of values in the sample at the -// time the snapshot was taken. -func (h *histogramSnapshot) Percentile(p float64) float64 { - return h.sample.Percentile(p) -} - -// Percentiles returns a slice of arbitrary percentiles of values in the sample -// at the time the snapshot was taken. -func (h *histogramSnapshot) Percentiles(ps []float64) []float64 { - return h.sample.Percentiles(ps) -} - -// Snapshot returns the snapshot. -func (h *histogramSnapshot) Snapshot() HistogramSnapshot { return h } - -// StdDev returns the standard deviation of the values in the sample at the -// time the snapshot was taken. -func (h *histogramSnapshot) StdDev() float64 { return h.sample.StdDev() } - -// Sum returns the sum in the sample at the time the snapshot was taken. -func (h *histogramSnapshot) Sum() int64 { return h.sample.Sum() } - -// Variance returns the variance of inputs at the time the snapshot was taken. -func (h *histogramSnapshot) Variance() float64 { return h.sample.Variance() } - // NilHistogram is a no-op Histogram. type NilHistogram struct{} @@ -120,7 +66,7 @@ func (h *StandardHistogram) Clear() { h.sample.Clear() } // Snapshot returns a read-only copy of the histogram. func (h *StandardHistogram) Snapshot() HistogramSnapshot { - return &histogramSnapshot{sample: h.sample.Snapshot().(*sampleSnapshot)} + return h.sample.Snapshot() } // Update samples a new value. diff --git a/metrics/runtimehistogram.go b/metrics/runtimehistogram.go index a074b88e0d..0a72f8ad62 100644 --- a/metrics/runtimehistogram.go +++ b/metrics/runtimehistogram.go @@ -78,6 +78,11 @@ func (h *runtimeHistogramSnapshot) Count() int64 { return count } +// Size returns the size of the sample at the time the snapshot was taken. +func (h *runtimeHistogramSnapshot) Size() int { + return len(h.Counts) +} + // Mean returns an approximation of the mean. func (h *runtimeHistogramSnapshot) Mean() float64 { if len(h.Counts) == 0 { diff --git a/metrics/sample.go b/metrics/sample.go index a5713edacb..96598aec71 100644 --- a/metrics/sample.go +++ b/metrics/sample.go @@ -21,7 +21,6 @@ type SampleSnapshot interface { Size() int StdDev() float64 Sum() int64 - Values() []int64 Variance() float64 } diff --git a/metrics/sample_test.go b/metrics/sample_test.go index f0edfbcae7..7967357055 100644 --- a/metrics/sample_test.go +++ b/metrics/sample_test.go @@ -87,68 +87,42 @@ func BenchmarkUniformSample1028(b *testing.B) { benchmarkSample(b, NewUniformSample(1028)) } -func TestExpDecaySample10(t *testing.T) { - sw := NewExpDecaySample(100, 0.99) - for i := 0; i < 10; i++ { - sw.Update(int64(i)) - } - s := sw.Snapshot() - if size := s.Count(); size != 10 { - t.Errorf("s.Count(): 10 != %v\n", size) - } - if size := s.Size(); size != 10 { - t.Errorf("s.Size(): 10 != %v\n", size) - } - if l := len(s.Values()); l != 10 { - t.Errorf("len(s.Values()): 10 != %v\n", l) - } - for _, v := range s.Values() { - if v > 10 || v < 0 { - t.Errorf("out of range [0, 10): %v\n", v) - } +func min(a, b int) int { + if a < b { + return a } + return b } -func TestExpDecaySample100(t *testing.T) { - sw := NewExpDecaySample(1000, 0.01) - for i := 0; i < 100; i++ { - sw.Update(int64(i)) - } - s := sw.Snapshot() - if size := s.Count(); size != 100 { - t.Errorf("s.Count(): 100 != %v\n", size) - } - if size := s.Size(); size != 100 { - t.Errorf("s.Size(): 100 != %v\n", size) - } - if l := len(s.Values()); l != 100 { - t.Errorf("len(s.Values()): 100 != %v\n", l) - } - for _, v := range s.Values() { - if v > 100 || v < 0 { - t.Errorf("out of range [0, 100): %v\n", v) +func TestExpDecaySample(t *testing.T) { + for _, tc := range []struct { + reservoirSize int + alpha float64 + updates int + }{ + {100, 0.99, 10}, + {1000, 0.01, 100}, + {100, 0.99, 1000}, + } { + sample := NewExpDecaySample(tc.reservoirSize, tc.alpha) + for i := 0; i < tc.updates; i++ { + sample.Update(int64(i)) } - } -} - -func TestExpDecaySample1000(t *testing.T) { - sw := NewExpDecaySample(100, 0.99) - for i := 0; i < 1000; i++ { - sw.Update(int64(i)) - } - s := sw.Snapshot() - if size := s.Count(); size != 1000 { - t.Errorf("s.Count(): 1000 != %v\n", size) - } - if size := s.Size(); size != 100 { - t.Errorf("s.Size(): 100 != %v\n", size) - } - if l := len(s.Values()); l != 100 { - t.Errorf("len(s.Values()): 100 != %v\n", l) - } - for _, v := range s.Values() { - if v > 1000 || v < 0 { - t.Errorf("out of range [0, 1000): %v\n", v) + snap := sample.Snapshot() + if have, want := int(snap.Count()), tc.updates; have != want { + t.Errorf("have %d want %d", have, want) + } + if have, want := snap.Size(), min(tc.updates, tc.reservoirSize); have != want { + t.Errorf("have %d want %d", have, want) + } + values := snap.(*sampleSnapshot).values + if have, want := len(values), min(tc.updates, tc.reservoirSize); have != want { + t.Errorf("have %d want %d", have, want) + } + for _, v := range values { + if v > int64(tc.updates) || v < 0 { + t.Errorf("out of range [0, %d): %v", tc.updates, v) + } } } } @@ -167,7 +141,7 @@ func TestExpDecaySampleNanosecondRegression(t *testing.T) { sw.Update(20) } s := sw.Snapshot() - v := s.Values() + v := s.(*sampleSnapshot).values avg := float64(0) for i := 0; i < len(v); i++ { avg += float64(v[i]) @@ -221,10 +195,12 @@ func TestUniformSample(t *testing.T) { if size := s.Size(); size != 100 { t.Errorf("s.Size(): 100 != %v\n", size) } - if l := len(s.Values()); l != 100 { + values := s.(*sampleSnapshot).values + + if l := len(values); l != 100 { t.Errorf("len(s.Values()): 100 != %v\n", l) } - for _, v := range s.Values() { + for _, v := range values { if v > 1000 || v < 0 { t.Errorf("out of range [0, 100): %v\n", v) } @@ -238,7 +214,7 @@ func TestUniformSampleIncludesTail(t *testing.T) { sw.Update(int64(i)) } s := sw.Snapshot() - v := s.Values() + v := s.(*sampleSnapshot).values sum := 0 exp := (max - 1) * max / 2 for i := 0; i < len(v); i++ { diff --git a/metrics/timer.go b/metrics/timer.go index 26d1bb81d2..576ad8aa3e 100644 --- a/metrics/timer.go +++ b/metrics/timer.go @@ -89,8 +89,8 @@ func (t *StandardTimer) Snapshot() TimerSnapshot { t.mutex.Lock() defer t.mutex.Unlock() return &timerSnapshot{ - histogram: t.histogram.Snapshot().(*histogramSnapshot), - meter: t.meter.Snapshot().(*meterSnapshot), + histogram: t.histogram.Snapshot(), + meter: t.meter.Snapshot(), } } @@ -124,8 +124,8 @@ func (t *StandardTimer) UpdateSince(ts time.Time) { // timerSnapshot is a read-only copy of another Timer. type timerSnapshot struct { - histogram *histogramSnapshot - meter *meterSnapshot + histogram HistogramSnapshot + meter MeterSnapshot } // Count returns the number of events recorded at the time the snapshot was @@ -135,6 +135,9 @@ func (t *timerSnapshot) Count() int64 { return t.histogram.Count() } // Max returns the maximum value at the time the snapshot was taken. func (t *timerSnapshot) Max() int64 { return t.histogram.Max() } +// Size returns the size of the sample at the time the snapshot was taken. +func (t *timerSnapshot) Size() int { return t.histogram.Size() } + // Mean returns the mean value at the time the snapshot was taken. func (t *timerSnapshot) Mean() float64 { return t.histogram.Mean() }