1
0
Fork 0
forked from forks/go-ethereum
go-ethereum-modded-tocallarg/metrics/resetting_timer.go
Martin HS 9045b79bc2
metrics, cmd/geth: change init-process of metrics (#30814)
This PR modifies how the metrics library handles `Enabled`: previously,
the package `init` decided whether to serve real metrics or just
dummy-types.

This has several drawbacks: 
- During pkg init, we need to determine whether metrics are enabled or
not. So we first hacked in a check if certain geth-specific
commandline-flags were enabled. Then we added a similar check for
geth-env-vars. Then we almost added a very elaborate check for
toml-config-file, plus toml parsing.

- Using "real" types and dummy types interchangeably means that
everything is hidden behind interfaces. This has a performance penalty,
and also it just adds a lot of code.

This PR removes the interface stuff, uses concrete types, and allows for
the setting of Enabled to happen later. It is still assumed that
`metrics.Enable()` is invoked early on.

The somewhat 'heavy' operations, such as ticking meters and exp-decay,
now checks the enable-flag to prevent resource leak.

The change may be large, but it's mostly pretty trivial, and from the
last time I gutted the metrics, I ensured that we have fairly good test
coverage.

---------

Co-authored-by: Felix Lange <fjl@twurst.com>
2024-12-10 13:27:29 +01:00

137 lines
3.3 KiB
Go

package metrics
import (
"sync"
"time"
)
// GetOrRegisterResettingTimer returns an existing ResettingTimer or constructs and registers a
// new ResettingTimer.
func GetOrRegisterResettingTimer(name string, r Registry) *ResettingTimer {
if nil == r {
r = DefaultRegistry
}
return r.GetOrRegister(name, NewResettingTimer).(*ResettingTimer)
}
// NewRegisteredResettingTimer constructs and registers a new ResettingTimer.
func NewRegisteredResettingTimer(name string, r Registry) *ResettingTimer {
c := NewResettingTimer()
if nil == r {
r = DefaultRegistry
}
r.Register(name, c)
return c
}
// NewResettingTimer constructs a new ResettingTimer
func NewResettingTimer() *ResettingTimer {
return &ResettingTimer{
values: make([]int64, 0, 10),
}
}
// ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval.
type ResettingTimer struct {
values []int64
sum int64 // sum is a running count of the total sum, used later to calculate mean
mutex sync.Mutex
}
// Snapshot resets the timer and returns a read-only copy of its contents.
func (t *ResettingTimer) Snapshot() *ResettingTimerSnapshot {
t.mutex.Lock()
defer t.mutex.Unlock()
snapshot := &ResettingTimerSnapshot{}
if len(t.values) > 0 {
snapshot.mean = float64(t.sum) / float64(len(t.values))
snapshot.values = t.values
t.values = make([]int64, 0, 10)
}
t.sum = 0
return snapshot
}
// Record the duration of the execution of the given function.
func (t *ResettingTimer) Time(f func()) {
ts := time.Now()
f()
t.Update(time.Since(ts))
}
// Record the duration of an event.
func (t *ResettingTimer) Update(d time.Duration) {
if !metricsEnabled {
return
}
t.mutex.Lock()
defer t.mutex.Unlock()
t.values = append(t.values, int64(d))
t.sum += int64(d)
}
// Record the duration of an event that started at a time and ends now.
func (t *ResettingTimer) UpdateSince(ts time.Time) {
t.Update(time.Since(ts))
}
// ResettingTimerSnapshot is a point-in-time copy of another ResettingTimer.
type ResettingTimerSnapshot struct {
values []int64
mean float64
max int64
min int64
thresholdBoundaries []float64
calculated bool
}
// Count return the length of the values from snapshot.
func (t *ResettingTimerSnapshot) Count() int {
return len(t.values)
}
// Percentiles returns the boundaries for the input percentiles.
// note: this method is not thread safe
func (t *ResettingTimerSnapshot) Percentiles(percentiles []float64) []float64 {
t.calc(percentiles)
return t.thresholdBoundaries
}
// Mean returns the mean of the snapshotted values
// note: this method is not thread safe
func (t *ResettingTimerSnapshot) Mean() float64 {
if !t.calculated {
t.calc(nil)
}
return t.mean
}
// Max returns the max of the snapshotted values
// note: this method is not thread safe
func (t *ResettingTimerSnapshot) Max() int64 {
if !t.calculated {
t.calc(nil)
}
return t.max
}
// Min returns the min of the snapshotted values
// note: this method is not thread safe
func (t *ResettingTimerSnapshot) Min() int64 {
if !t.calculated {
t.calc(nil)
}
return t.min
}
func (t *ResettingTimerSnapshot) calc(percentiles []float64) {
scores := CalculatePercentiles(t.values, percentiles)
t.thresholdBoundaries = scores
if len(t.values) == 0 {
return
}
t.min = t.values[0]
t.max = t.values[len(t.values)-1]
}