mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
metrics: align percentiles handling in resetting timer with rest of the codebase
This commit is contained in:
parent
fb8e300797
commit
0abadecea1
7 changed files with 95 additions and 122 deletions
|
|
@ -176,13 +176,13 @@ func (exp *exp) publishTimer(name string, metric metrics.Timer) {
|
||||||
|
|
||||||
func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) {
|
func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) {
|
||||||
t := metric.Snapshot()
|
t := metric.Snapshot()
|
||||||
ps := t.Percentiles([]float64{50, 75, 95, 99})
|
ps := t.Percentiles([]float64{0.50, 0.75, 0.95, 0.99})
|
||||||
exp.getInt(name + ".count").Set(int64(t.Count()))
|
exp.getInt(name + ".count").Set(int64(t.Count()))
|
||||||
exp.getFloat(name + ".mean").Set(t.Mean())
|
exp.getFloat(name + ".mean").Set(t.Mean())
|
||||||
exp.getInt(name + ".50-percentile").Set(ps[0])
|
exp.getFloat(name + ".50-percentile").Set(ps[0])
|
||||||
exp.getInt(name + ".75-percentile").Set(ps[1])
|
exp.getFloat(name + ".75-percentile").Set(ps[1])
|
||||||
exp.getInt(name + ".95-percentile").Set(ps[2])
|
exp.getFloat(name + ".95-percentile").Set(ps[2])
|
||||||
exp.getInt(name + ".99-percentile").Set(ps[3])
|
exp.getFloat(name + ".99-percentile").Set(ps[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (exp *exp) syncToExpvar() {
|
func (exp *exp) syncToExpvar() {
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ func readMeter(namespace, name string, i interface{}) (string, map[string]interf
|
||||||
if t.Count() == 0 {
|
if t.Count() == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ps := t.Percentiles([]float64{50, 95, 99})
|
ps := t.Percentiles([]float64{0.50, 0.95, 0.99})
|
||||||
measurement := fmt.Sprintf("%s%s.span", namespace, name)
|
measurement := fmt.Sprintf("%s%s.span", namespace, name)
|
||||||
fields := map[string]interface{}{
|
fields := map[string]interface{}{
|
||||||
"count": t.Count(),
|
"count": t.Count(),
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ func (c *collector) addResettingTimer(name string, m metrics.ResettingTimerSnaps
|
||||||
if m.Count() <= 0 {
|
if m.Count() <= 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ps := m.Percentiles([]float64{50, 95, 99})
|
ps := m.Percentiles([]float64{0.50, 0.95, 0.99})
|
||||||
c.writeSummaryCounter(name, m.Count())
|
c.writeSummaryCounter(name, m.Count())
|
||||||
c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
|
c.buff.WriteString(fmt.Sprintf(typeSummaryTpl, mutateKey(name)))
|
||||||
c.writeSummaryPercentile(name, "0.50", ps[0])
|
c.writeSummaryPercentile(name, "0.50", ps[0])
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initial slice capacity for the values stored in a ResettingTimer
|
// Initial slice capacity for the values stored in a ResettingTimer
|
||||||
|
|
@ -16,7 +13,7 @@ type ResettingTimerSnapshot interface {
|
||||||
Mean() float64
|
Mean() float64
|
||||||
Max() int64
|
Max() int64
|
||||||
Min() int64
|
Min() int64
|
||||||
Percentiles([]float64) []int64
|
Percentiles([]float64) []float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval.
|
// ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval.
|
||||||
|
|
@ -63,7 +60,7 @@ func (NilResettingTimer) Values() []int64 { return nil }
|
||||||
func (n NilResettingTimer) Snapshot() ResettingTimerSnapshot { return n }
|
func (n NilResettingTimer) Snapshot() ResettingTimerSnapshot { return n }
|
||||||
func (NilResettingTimer) Time(f func()) { f() }
|
func (NilResettingTimer) Time(f func()) { f() }
|
||||||
func (NilResettingTimer) Update(time.Duration) {}
|
func (NilResettingTimer) Update(time.Duration) {}
|
||||||
func (NilResettingTimer) Percentiles([]float64) []int64 { return nil }
|
func (NilResettingTimer) Percentiles([]float64) []float64 { return nil }
|
||||||
func (NilResettingTimer) Mean() float64 { return 0.0 }
|
func (NilResettingTimer) Mean() float64 { return 0.0 }
|
||||||
func (NilResettingTimer) Max() int64 { return 0 }
|
func (NilResettingTimer) Max() int64 { return 0 }
|
||||||
func (NilResettingTimer) Min() int64 { return 0 }
|
func (NilResettingTimer) Min() int64 { return 0 }
|
||||||
|
|
@ -116,7 +113,7 @@ type resettingTimerSnapshot struct {
|
||||||
mean float64
|
mean float64
|
||||||
max int64
|
max int64
|
||||||
min int64
|
min int64
|
||||||
thresholdBoundaries []int64
|
thresholdBoundaries []float64
|
||||||
calculated bool
|
calculated bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,7 +124,7 @@ func (t *resettingTimerSnapshot) Count() int {
|
||||||
|
|
||||||
// Percentiles returns the boundaries for the input percentiles.
|
// Percentiles returns the boundaries for the input percentiles.
|
||||||
// note: this method is not thread safe
|
// note: this method is not thread safe
|
||||||
func (t *resettingTimerSnapshot) Percentiles(percentiles []float64) []int64 {
|
func (t *resettingTimerSnapshot) Percentiles(percentiles []float64) []float64 {
|
||||||
t.calc(percentiles)
|
t.calc(percentiles)
|
||||||
return t.thresholdBoundaries
|
return t.thresholdBoundaries
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +145,6 @@ func (t *resettingTimerSnapshot) Max() int64 {
|
||||||
if !t.calculated {
|
if !t.calculated {
|
||||||
t.calc(nil)
|
t.calc(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return t.max
|
return t.max
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -158,52 +154,20 @@ func (t *resettingTimerSnapshot) Min() int64 {
|
||||||
if !t.calculated {
|
if !t.calculated {
|
||||||
t.calc(nil)
|
t.calc(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return t.min
|
return t.min
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *resettingTimerSnapshot) calc(percentiles []float64) {
|
func (t *resettingTimerSnapshot) calc(percentiles []float64) {
|
||||||
slices.Sort(t.values)
|
scores := CalculatePercentiles(t.values, percentiles)
|
||||||
count := len(t.values)
|
t.thresholdBoundaries = scores
|
||||||
if count == 0 {
|
if len(t.values) == 0 {
|
||||||
t.thresholdBoundaries = make([]int64, len(percentiles))
|
|
||||||
t.mean = 0
|
|
||||||
t.calculated = true
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.min = t.values[0]
|
t.min = t.values[0]
|
||||||
t.max = t.values[count-1]
|
t.max = t.values[len(t.values)-1]
|
||||||
|
var sum int64
|
||||||
cumulativeValues := make([]int64, count)
|
for _, v := range t.values {
|
||||||
cumulativeValues[0] = t.min
|
sum += v
|
||||||
for i := 1; i < count; i++ {
|
|
||||||
cumulativeValues[i] = t.values[i] + cumulativeValues[i-1]
|
|
||||||
}
|
}
|
||||||
|
t.mean = float64(sum) / float64(len(t.values))
|
||||||
t.thresholdBoundaries = make([]int64, len(percentiles))
|
|
||||||
|
|
||||||
thresholdBoundary := t.max
|
|
||||||
|
|
||||||
for i, pct := range percentiles {
|
|
||||||
if count > 1 {
|
|
||||||
var abs float64
|
|
||||||
if pct >= 0 {
|
|
||||||
abs = pct
|
|
||||||
} else {
|
|
||||||
abs = 100 + pct
|
|
||||||
}
|
|
||||||
// poor man's math.Round(x):
|
|
||||||
// math.Floor(x + 0.5)
|
|
||||||
indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
|
|
||||||
if pct >= 0 && indexOfPerc > 0 {
|
|
||||||
indexOfPerc -= 1 // index offset=0
|
|
||||||
}
|
|
||||||
thresholdBoundary = t.values[indexOfPerc]
|
|
||||||
}
|
|
||||||
|
|
||||||
t.thresholdBoundaries[i] = thresholdBoundary
|
|
||||||
}
|
|
||||||
|
|
||||||
sum := cumulativeValues[count-1]
|
|
||||||
t.mean = float64(sum) / float64(count)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,9 @@ func TestResettingTimer(t *testing.T) {
|
||||||
values []int64
|
values []int64
|
||||||
start int
|
start int
|
||||||
end int
|
end int
|
||||||
wantP50 int64
|
wantP50 float64
|
||||||
wantP95 int64
|
wantP95 float64
|
||||||
wantP99 int64
|
wantP99 float64
|
||||||
wantMean float64
|
wantMean float64
|
||||||
wantMin int64
|
wantMin int64
|
||||||
wantMax int64
|
wantMax int64
|
||||||
|
|
@ -21,14 +21,14 @@ func TestResettingTimer(t *testing.T) {
|
||||||
values: []int64{},
|
values: []int64{},
|
||||||
start: 1,
|
start: 1,
|
||||||
end: 11,
|
end: 11,
|
||||||
wantP50: 5, wantP95: 10, wantP99: 10,
|
wantP50: 5.5, wantP95: 10, wantP99: 10,
|
||||||
wantMin: 1, wantMax: 10, wantMean: 5.5,
|
wantMin: 1, wantMax: 10, wantMean: 5.5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
values: []int64{},
|
values: []int64{},
|
||||||
start: 1,
|
start: 1,
|
||||||
end: 101,
|
end: 101,
|
||||||
wantP50: 50, wantP95: 95, wantP99: 99,
|
wantP50: 50.5, wantP95: 95.94999999999999, wantP99: 99.99,
|
||||||
wantMin: 1, wantMax: 100, wantMean: 50.5,
|
wantMin: 1, wantMax: 100, wantMean: 50.5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -56,11 +56,11 @@ func TestResettingTimer(t *testing.T) {
|
||||||
values: []int64{1, 10},
|
values: []int64{1, 10},
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
wantP50: 1, wantP95: 10, wantP99: 10,
|
wantP50: 5.5, wantP95: 10, wantP99: 10,
|
||||||
wantMin: 1, wantMax: 10, wantMean: 5.5,
|
wantMin: 1, wantMax: 10, wantMean: 5.5,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for ind, tt := range tests {
|
for i, tt := range tests {
|
||||||
timer := NewResettingTimer()
|
timer := NewResettingTimer()
|
||||||
|
|
||||||
for i := tt.start; i < tt.end; i++ {
|
for i := tt.start; i < tt.end; i++ {
|
||||||
|
|
@ -70,33 +70,27 @@ func TestResettingTimer(t *testing.T) {
|
||||||
for _, v := range tt.values {
|
for _, v := range tt.values {
|
||||||
timer.Update(time.Duration(v))
|
timer.Update(time.Duration(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
snap := timer.Snapshot()
|
snap := timer.Snapshot()
|
||||||
|
|
||||||
ps := snap.Percentiles([]float64{50, 95, 99})
|
ps := snap.Percentiles([]float64{0.50, 0.95, 0.99})
|
||||||
|
|
||||||
if tt.wantMin != snap.Min() {
|
if have, want := snap.Min(), tt.wantMin; have != want {
|
||||||
t.Fatalf("%d: min: got %d, want %d", ind, snap.Min(), tt.wantMin)
|
t.Fatalf("%d: min: have %d, want %d", i, have, want)
|
||||||
}
|
}
|
||||||
|
if have, want := snap.Max(), tt.wantMax; have != want {
|
||||||
if tt.wantMax != snap.Max() {
|
t.Fatalf("%d: max: have %d, want %d", i, have, want)
|
||||||
t.Fatalf("%d: max: got %d, want %d", ind, snap.Max(), tt.wantMax)
|
|
||||||
}
|
}
|
||||||
|
if have, want := snap.Mean(), tt.wantMean; have != want {
|
||||||
if tt.wantMean != snap.Mean() {
|
t.Fatalf("%d: mean: have %v, want %v", i, have, want)
|
||||||
t.Fatalf("%d: mean: got %.2f, want %.2f", ind, snap.Mean(), tt.wantMean)
|
|
||||||
}
|
}
|
||||||
|
if have, want := ps[0], tt.wantP50; have != want {
|
||||||
if tt.wantP50 != ps[0] {
|
t.Errorf("%d: p50: have %v, want %v", i, have, want)
|
||||||
t.Fatalf("%d: p50: got %d, want %d", ind, ps[0], tt.wantP50)
|
|
||||||
}
|
}
|
||||||
|
if have, want := ps[1], tt.wantP95; have != want {
|
||||||
if tt.wantP95 != ps[1] {
|
t.Errorf("%d: p95: have %v, want %v", i, have, want)
|
||||||
t.Fatalf("%d: p95: got %d, want %d", ind, ps[1], tt.wantP95)
|
|
||||||
}
|
}
|
||||||
|
if have, want := ps[2], tt.wantP99; have != want {
|
||||||
if tt.wantP99 != ps[2] {
|
t.Errorf("%d: p99: have %v, want %v", i, have, want)
|
||||||
t.Fatalf("%d: p99: got %d, want %d", ind, ps[2], tt.wantP99)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,11 +100,11 @@ func TestResettingTimerWithFivePercentiles(t *testing.T) {
|
||||||
values []int64
|
values []int64
|
||||||
start int
|
start int
|
||||||
end int
|
end int
|
||||||
wantP05 int64
|
wantP05 float64
|
||||||
wantP20 int64
|
wantP20 float64
|
||||||
wantP50 int64
|
wantP50 float64
|
||||||
wantP95 int64
|
wantP95 float64
|
||||||
wantP99 int64
|
wantP99 float64
|
||||||
wantMean float64
|
wantMean float64
|
||||||
wantMin int64
|
wantMin int64
|
||||||
wantMax int64
|
wantMax int64
|
||||||
|
|
@ -119,14 +113,14 @@ func TestResettingTimerWithFivePercentiles(t *testing.T) {
|
||||||
values: []int64{},
|
values: []int64{},
|
||||||
start: 1,
|
start: 1,
|
||||||
end: 11,
|
end: 11,
|
||||||
wantP05: 1, wantP20: 2, wantP50: 5, wantP95: 10, wantP99: 10,
|
wantP05: 1, wantP20: 2.2, wantP50: 5.5, wantP95: 10, wantP99: 10,
|
||||||
wantMin: 1, wantMax: 10, wantMean: 5.5,
|
wantMin: 1, wantMax: 10, wantMean: 5.5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
values: []int64{},
|
values: []int64{},
|
||||||
start: 1,
|
start: 1,
|
||||||
end: 101,
|
end: 101,
|
||||||
wantP05: 5, wantP20: 20, wantP50: 50, wantP95: 95, wantP99: 99,
|
wantP05: 5.050000000000001, wantP20: 20.200000000000003, wantP50: 50.5, wantP95: 95.94999999999999, wantP99: 99.99,
|
||||||
wantMin: 1, wantMax: 100, wantMean: 50.5,
|
wantMin: 1, wantMax: 100, wantMean: 50.5,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -154,7 +148,7 @@ func TestResettingTimerWithFivePercentiles(t *testing.T) {
|
||||||
values: []int64{1, 10},
|
values: []int64{1, 10},
|
||||||
start: 0,
|
start: 0,
|
||||||
end: 0,
|
end: 0,
|
||||||
wantP05: 1, wantP20: 1, wantP50: 1, wantP95: 10, wantP99: 10,
|
wantP05: 1, wantP20: 1, wantP50: 5.5, wantP95: 10, wantP99: 10,
|
||||||
wantMin: 1, wantMax: 10, wantMean: 5.5,
|
wantMin: 1, wantMax: 10, wantMean: 5.5,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -171,38 +165,33 @@ func TestResettingTimerWithFivePercentiles(t *testing.T) {
|
||||||
|
|
||||||
snap := timer.Snapshot()
|
snap := timer.Snapshot()
|
||||||
|
|
||||||
ps := snap.Percentiles([]float64{5, 20, 50, 95, 99})
|
ps := snap.Percentiles([]float64{0.05, 0.20, 0.50, 0.95, 0.99})
|
||||||
|
|
||||||
if tt.wantMin != snap.Min() {
|
if tt.wantMin != snap.Min() {
|
||||||
t.Fatalf("%d: min: got %d, want %d", ind, snap.Min(), tt.wantMin)
|
t.Errorf("%d: min: got %d, want %d", ind, snap.Min(), tt.wantMin)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.wantMax != snap.Max() {
|
if tt.wantMax != snap.Max() {
|
||||||
t.Fatalf("%d: max: got %d, want %d", ind, snap.Max(), tt.wantMax)
|
t.Errorf("%d: max: got %d, want %d", ind, snap.Max(), tt.wantMax)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.wantMean != snap.Mean() {
|
if tt.wantMean != snap.Mean() {
|
||||||
t.Fatalf("%d: mean: got %.2f, want %.2f", ind, snap.Mean(), tt.wantMean)
|
t.Errorf("%d: mean: got %.2f, want %.2f", ind, snap.Mean(), tt.wantMean)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.wantP05 != ps[0] {
|
if tt.wantP05 != ps[0] {
|
||||||
t.Fatalf("%d: p05: got %d, want %d", ind, ps[0], tt.wantP05)
|
t.Errorf("%d: p05: got %v, want %v", ind, ps[0], tt.wantP05)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.wantP20 != ps[1] {
|
if tt.wantP20 != ps[1] {
|
||||||
t.Fatalf("%d: p20: got %d, want %d", ind, ps[1], tt.wantP20)
|
t.Errorf("%d: p20: got %v, want %v", ind, ps[1], tt.wantP20)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.wantP50 != ps[2] {
|
if tt.wantP50 != ps[2] {
|
||||||
t.Fatalf("%d: p50: got %d, want %d", ind, ps[2], tt.wantP50)
|
t.Errorf("%d: p50: got %v, want %v", ind, ps[2], tt.wantP50)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.wantP95 != ps[3] {
|
if tt.wantP95 != ps[3] {
|
||||||
t.Fatalf("%d: p95: got %d, want %d", ind, ps[3], tt.wantP95)
|
t.Errorf("%d: p95: got %v, want %v", ind, ps[3], tt.wantP95)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tt.wantP99 != ps[4] {
|
if tt.wantP99 != ps[4] {
|
||||||
t.Fatalf("%d: p99: got %d, want %d", ind, ps[4], tt.wantP99)
|
t.Errorf("%d: p99: got %v, want %v", ind, ps[4], tt.wantP99)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,20 +176,27 @@ func (NilSample) Values() []int64 { return []int64{} }
|
||||||
// Variance is a no-op.
|
// Variance is a no-op.
|
||||||
func (NilSample) Variance() float64 { return 0.0 }
|
func (NilSample) Variance() float64 { return 0.0 }
|
||||||
|
|
||||||
// SamplePercentiles returns an arbitrary percentile of the slice of int64.
|
// CalculatePercentiles returns an arbitrary percentile of the slice of int64.
|
||||||
func SamplePercentile(values []int64, p float64) float64 {
|
func SamplePercentile(values []int64, p float64) float64 {
|
||||||
return SamplePercentiles(values, []float64{p})[0]
|
return CalculatePercentiles(values, []float64{p})[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
// SamplePercentiles returns a slice of arbitrary percentiles of the slice of
|
// CalculatePercentiles returns a slice of arbitrary percentiles of the slice of
|
||||||
// int64.
|
// int64. This method returns interpolated results, so e.g if there are only two
|
||||||
func SamplePercentiles(values []int64, ps []float64) []float64 {
|
// values, [0, 10], a 50% percentile will land between them.
|
||||||
|
//
|
||||||
|
// Note: As a side-effect, this method will also sort the slice of values.
|
||||||
|
// Note2: The input format for percentiles is NOT percent! To express 50%, use 0.5, not 50.
|
||||||
|
func CalculatePercentiles(values []int64, ps []float64) []float64 {
|
||||||
scores := make([]float64, len(ps))
|
scores := make([]float64, len(ps))
|
||||||
size := len(values)
|
size := len(values)
|
||||||
if size > 0 {
|
if size == 0 {
|
||||||
|
return scores
|
||||||
|
}
|
||||||
slices.Sort(values)
|
slices.Sort(values)
|
||||||
for i, p := range ps {
|
for i, p := range ps {
|
||||||
pos := p * float64(size+1)
|
pos := p * float64(size+1)
|
||||||
|
|
||||||
if pos < 1.0 {
|
if pos < 1.0 {
|
||||||
scores[i] = float64(values[0])
|
scores[i] = float64(values[0])
|
||||||
} else if pos >= float64(size) {
|
} else if pos >= float64(size) {
|
||||||
|
|
@ -200,7 +207,6 @@ func SamplePercentiles(values []int64, ps []float64) []float64 {
|
||||||
scores[i] = lower + (pos-math.Floor(pos))*(upper-lower)
|
scores[i] = lower + (pos-math.Floor(pos))*(upper-lower)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return scores
|
return scores
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,7 +273,7 @@ func (s *sampleSnapshot) Percentile(p float64) float64 {
|
||||||
// Percentiles returns a slice of arbitrary percentiles of values at the time
|
// Percentiles returns a slice of arbitrary percentiles of values at the time
|
||||||
// the snapshot was taken.
|
// the snapshot was taken.
|
||||||
func (s *sampleSnapshot) Percentiles(ps []float64) []float64 {
|
func (s *sampleSnapshot) Percentiles(ps []float64) []float64 {
|
||||||
return SamplePercentiles(s.values, ps)
|
return CalculatePercentiles(s.values, ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the size of the sample at the time the snapshot was taken.
|
// Size returns the size of the sample at the time the snapshot was taken.
|
||||||
|
|
|
||||||
|
|
@ -367,3 +367,17 @@ func TestUniformSampleConcurrentUpdateCount(t *testing.T) {
|
||||||
}
|
}
|
||||||
quit <- struct{}{}
|
quit <- struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkCalculatePercentiles(b *testing.B) {
|
||||||
|
pss := []float64{0.5, 0.75, 0.95, 0.99, 0.999, 0.9999}
|
||||||
|
var vals []int64
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
vals = append(vals, int64(rand.Int31()))
|
||||||
|
}
|
||||||
|
v := make([]int64, len(vals))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
copy(v, vals)
|
||||||
|
_ = CalculatePercentiles(v, pss)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue