Skip to content

Commit be2aec0

Browse files
nonsensekaralabe
authored andcommitted
metrics: expvar support for ResettingTimer (ethereum#16878)
* metrics: expvar support for ResettingTimer * metrics: use integers for percentiles; remove Overall * metrics: fix edge-case panic for index-out-of-range
1 parent 143c434 commit be2aec0

File tree

4 files changed

+154
-1
lines changed

4 files changed

+154
-1
lines changed

metrics/exp/exp.go

+13
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ func (exp *exp) publishTimer(name string, metric metrics.Timer) {
134134
exp.getFloat(name + ".mean-rate").Set(t.RateMean())
135135
}
136136

137+
func (exp *exp) publishResettingTimer(name string, metric metrics.ResettingTimer) {
138+
t := metric.Snapshot()
139+
ps := t.Percentiles([]float64{50, 75, 95, 99})
140+
exp.getInt(name + ".count").Set(int64(len(t.Values())))
141+
exp.getFloat(name + ".mean").Set(t.Mean())
142+
exp.getInt(name + ".50-percentile").Set(ps[0])
143+
exp.getInt(name + ".75-percentile").Set(ps[1])
144+
exp.getInt(name + ".95-percentile").Set(ps[2])
145+
exp.getInt(name + ".99-percentile").Set(ps[3])
146+
}
147+
137148
func (exp *exp) syncToExpvar() {
138149
exp.registry.Each(func(name string, i interface{}) {
139150
switch i.(type) {
@@ -149,6 +160,8 @@ func (exp *exp) syncToExpvar() {
149160
exp.publishMeter(name, i.(metrics.Meter))
150161
case metrics.Timer:
151162
exp.publishTimer(name, i.(metrics.Timer))
163+
case metrics.ResettingTimer:
164+
exp.publishResettingTimer(name, i.(metrics.ResettingTimer))
152165
default:
153166
panic(fmt.Sprintf("unsupported type for '%s': %T", name, i))
154167
}

metrics/resetting_timer.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ func (t *ResettingTimerSnapshot) calc(percentiles []float64) {
210210
// poor man's math.Round(x):
211211
// math.Floor(x + 0.5)
212212
indexOfPerc := int(math.Floor(((abs / 100.0) * float64(count)) + 0.5))
213-
if pct >= 0 {
213+
if pct >= 0 && indexOfPerc > 0 {
214214
indexOfPerc -= 1 // index offset=0
215215
}
216216
thresholdBoundary = t.values[indexOfPerc]

metrics/resetting_timer_test.go

+110
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,113 @@ func TestResettingTimer(t *testing.T) {
104104
}
105105
}
106106
}
107+
108+
func TestResettingTimerWithFivePercentiles(t *testing.T) {
109+
tests := []struct {
110+
values []int64
111+
start int
112+
end int
113+
wantP05 int64
114+
wantP20 int64
115+
wantP50 int64
116+
wantP95 int64
117+
wantP99 int64
118+
wantMean float64
119+
wantMin int64
120+
wantMax int64
121+
}{
122+
{
123+
values: []int64{},
124+
start: 1,
125+
end: 11,
126+
wantP05: 1, wantP20: 2, wantP50: 5, wantP95: 10, wantP99: 10,
127+
wantMin: 1, wantMax: 10, wantMean: 5.5,
128+
},
129+
{
130+
values: []int64{},
131+
start: 1,
132+
end: 101,
133+
wantP05: 5, wantP20: 20, wantP50: 50, wantP95: 95, wantP99: 99,
134+
wantMin: 1, wantMax: 100, wantMean: 50.5,
135+
},
136+
{
137+
values: []int64{1},
138+
start: 0,
139+
end: 0,
140+
wantP05: 1, wantP20: 1, wantP50: 1, wantP95: 1, wantP99: 1,
141+
wantMin: 1, wantMax: 1, wantMean: 1,
142+
},
143+
{
144+
values: []int64{0},
145+
start: 0,
146+
end: 0,
147+
wantP05: 0, wantP20: 0, wantP50: 0, wantP95: 0, wantP99: 0,
148+
wantMin: 0, wantMax: 0, wantMean: 0,
149+
},
150+
{
151+
values: []int64{},
152+
start: 0,
153+
end: 0,
154+
wantP05: 0, wantP20: 0, wantP50: 0, wantP95: 0, wantP99: 0,
155+
wantMin: 0, wantMax: 0, wantMean: 0,
156+
},
157+
{
158+
values: []int64{1, 10},
159+
start: 0,
160+
end: 0,
161+
wantP05: 1, wantP20: 1, wantP50: 1, wantP95: 10, wantP99: 10,
162+
wantMin: 1, wantMax: 10, wantMean: 5.5,
163+
},
164+
}
165+
for ind, tt := range tests {
166+
timer := NewResettingTimer()
167+
168+
for i := tt.start; i < tt.end; i++ {
169+
tt.values = append(tt.values, int64(i))
170+
}
171+
172+
for _, v := range tt.values {
173+
timer.Update(time.Duration(v))
174+
}
175+
176+
snap := timer.Snapshot()
177+
178+
ps := snap.Percentiles([]float64{5, 20, 50, 95, 99})
179+
180+
val := snap.Values()
181+
182+
if len(val) > 0 {
183+
if tt.wantMin != val[0] {
184+
t.Fatalf("%d: min: got %d, want %d", ind, val[0], tt.wantMin)
185+
}
186+
187+
if tt.wantMax != val[len(val)-1] {
188+
t.Fatalf("%d: max: got %d, want %d", ind, val[len(val)-1], tt.wantMax)
189+
}
190+
}
191+
192+
if tt.wantMean != snap.Mean() {
193+
t.Fatalf("%d: mean: got %.2f, want %.2f", ind, snap.Mean(), tt.wantMean)
194+
}
195+
196+
if tt.wantP05 != ps[0] {
197+
t.Fatalf("%d: p05: got %d, want %d", ind, ps[0], tt.wantP05)
198+
}
199+
200+
if tt.wantP20 != ps[1] {
201+
t.Fatalf("%d: p20: got %d, want %d", ind, ps[1], tt.wantP20)
202+
}
203+
204+
if tt.wantP50 != ps[2] {
205+
t.Fatalf("%d: p50: got %d, want %d", ind, ps[2], tt.wantP50)
206+
}
207+
208+
if tt.wantP95 != ps[3] {
209+
t.Fatalf("%d: p95: got %d, want %d", ind, ps[3], tt.wantP95)
210+
}
211+
212+
if tt.wantP99 != ps[4] {
213+
t.Fatalf("%d: p99: got %d, want %d", ind, ps[4], tt.wantP99)
214+
}
215+
}
216+
}

node/api.go

+30
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,21 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
338338
},
339339
}
340340

341+
case metrics.ResettingTimer:
342+
t := metric.Snapshot()
343+
ps := t.Percentiles([]float64{5, 20, 50, 80, 95})
344+
root[name] = map[string]interface{}{
345+
"Measurements": len(t.Values()),
346+
"Mean": time.Duration(t.Mean()).String(),
347+
"Percentiles": map[string]interface{}{
348+
"5": time.Duration(ps[0]).String(),
349+
"20": time.Duration(ps[1]).String(),
350+
"50": time.Duration(ps[2]).String(),
351+
"80": time.Duration(ps[3]).String(),
352+
"95": time.Duration(ps[4]).String(),
353+
},
354+
}
355+
341356
default:
342357
root[name] = "Unknown metric type"
343358
}
@@ -373,6 +388,21 @@ func (api *PublicDebugAPI) Metrics(raw bool) (map[string]interface{}, error) {
373388
},
374389
}
375390

391+
case metrics.ResettingTimer:
392+
t := metric.Snapshot()
393+
ps := t.Percentiles([]float64{5, 20, 50, 80, 95})
394+
root[name] = map[string]interface{}{
395+
"Measurements": len(t.Values()),
396+
"Mean": time.Duration(t.Mean()).String(),
397+
"Percentiles": map[string]interface{}{
398+
"5": time.Duration(ps[0]).String(),
399+
"20": time.Duration(ps[1]).String(),
400+
"50": time.Duration(ps[2]).String(),
401+
"80": time.Duration(ps[3]).String(),
402+
"95": time.Duration(ps[4]).String(),
403+
},
404+
}
405+
376406
default:
377407
root[name] = "Unknown metric type"
378408
}

0 commit comments

Comments
 (0)