Skip to content

Commit

Permalink
Update metercacher to use vectors (#2979)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph authored May 2, 2024
1 parent 9a89b5e commit fd447ed
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 65 deletions.
49 changes: 29 additions & 20 deletions cache/metercacher/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,70 @@
package metercacher

import (
"time"

"github.com/prometheus/client_golang/prometheus"

"github.com/ava-labs/avalanchego/cache"
"github.com/ava-labs/avalanchego/utils/timer/mockable"
)

var _ cache.Cacher[struct{}, struct{}] = (*Cache[struct{}, struct{}])(nil)

type Cache[K comparable, V any] struct {
metrics
cache.Cacher[K, V]

clock mockable.Clock
metrics *metrics
}

func New[K comparable, V any](
namespace string,
registerer prometheus.Registerer,
cache cache.Cacher[K, V],
) (cache.Cacher[K, V], error) {
meterCache := &Cache[K, V]{Cacher: cache}
return meterCache, meterCache.metrics.Initialize(namespace, registerer)
) (*Cache[K, V], error) {
metrics, err := newMetrics(namespace, registerer)
return &Cache[K, V]{
Cacher: cache,
metrics: metrics,
}, err
}

func (c *Cache[K, V]) Put(key K, value V) {
start := c.clock.Time()
start := time.Now()
c.Cacher.Put(key, value)
end := c.clock.Time()
c.put.Observe(float64(end.Sub(start)))
c.len.Set(float64(c.Cacher.Len()))
c.portionFilled.Set(c.Cacher.PortionFilled())
putDuration := time.Since(start)

c.metrics.putCount.Inc()
c.metrics.putTime.Add(float64(putDuration))
c.metrics.len.Set(float64(c.Cacher.Len()))
c.metrics.portionFilled.Set(c.Cacher.PortionFilled())
}

func (c *Cache[K, V]) Get(key K) (V, bool) {
start := c.clock.Time()
start := time.Now()
value, has := c.Cacher.Get(key)
end := c.clock.Time()
c.get.Observe(float64(end.Sub(start)))
getDuration := time.Since(start)

if has {
c.hit.Inc()
c.metrics.getCount.With(hitLabels).Inc()
c.metrics.getTime.With(hitLabels).Add(float64(getDuration))
} else {
c.miss.Inc()
c.metrics.getCount.With(missLabels).Inc()
c.metrics.getTime.With(missLabels).Add(float64(getDuration))
}

return value, has
}

func (c *Cache[K, _]) Evict(key K) {
c.Cacher.Evict(key)
c.len.Set(float64(c.Cacher.Len()))
c.portionFilled.Set(c.Cacher.PortionFilled())

c.metrics.len.Set(float64(c.Cacher.Len()))
c.metrics.portionFilled.Set(c.Cacher.PortionFilled())
}

func (c *Cache[_, _]) Flush() {
c.Cacher.Flush()
c.len.Set(float64(c.Cacher.Len()))
c.portionFilled.Set(c.Cacher.PortionFilled())

c.metrics.len.Set(float64(c.Cacher.Len()))
c.metrics.portionFilled.Set(c.Cacher.PortionFilled())
}
105 changes: 62 additions & 43 deletions cache/metercacher/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,67 +4,86 @@
package metercacher

import (
"fmt"

"github.com/prometheus/client_golang/prometheus"

"github.com/ava-labs/avalanchego/utils/metric"
"github.com/ava-labs/avalanchego/utils/wrappers"
"github.com/ava-labs/avalanchego/utils"
)

func newAveragerMetric(namespace, name string, reg prometheus.Registerer, errs *wrappers.Errs) metric.Averager {
return metric.NewAveragerWithErrs(
namespace,
name,
"time (in ns) of a "+name,
reg,
errs,
)
}
const (
resultLabel = "result"
hitResult = "hit"
missResult = "miss"
)

func newCounterMetric(namespace, name string, reg prometheus.Registerer, errs *wrappers.Errs) prometheus.Counter {
c := prometheus.NewCounter(prometheus.CounterOpts{
Namespace: namespace,
Name: name,
Help: fmt.Sprintf("# of times a %s occurred", name),
})
errs.Add(reg.Register(c))
return c
}
var (
resultLabels = []string{resultLabel}
hitLabels = prometheus.Labels{
resultLabel: hitResult,
}
missLabels = prometheus.Labels{
resultLabel: missResult,
}
)

type metrics struct {
get metric.Averager
put metric.Averager
getCount *prometheus.CounterVec
getTime *prometheus.CounterVec

putCount prometheus.Counter
putTime prometheus.Counter

len prometheus.Gauge
portionFilled prometheus.Gauge
hit prometheus.Counter
miss prometheus.Counter
}

func (m *metrics) Initialize(
func newMetrics(
namespace string,
reg prometheus.Registerer,
) error {
errs := wrappers.Errs{}
m.get = newAveragerMetric(namespace, "get", reg, &errs)
m.put = newAveragerMetric(namespace, "put", reg, &errs)
m.len = prometheus.NewGauge(
prometheus.GaugeOpts{
) (*metrics, error) {
m := &metrics{
getCount: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Name: "get_count",
Help: "number of get calls",
},
resultLabels,
),
getTime: prometheus.NewCounterVec(
prometheus.CounterOpts{
Namespace: namespace,
Name: "get_time",
Help: "time spent (ns) in get calls",
},
resultLabels,
),
putCount: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: namespace,
Name: "put_count",
Help: "number of put calls",
}),
putTime: prometheus.NewCounter(prometheus.CounterOpts{
Namespace: namespace,
Name: "put_time",
Help: "time spent (ns) in put calls",
}),
len: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Name: "len",
Help: "number of entries",
},
)
errs.Add(reg.Register(m.len))
m.portionFilled = prometheus.NewGauge(
prometheus.GaugeOpts{
}),
portionFilled: prometheus.NewGauge(prometheus.GaugeOpts{
Namespace: namespace,
Name: "portion_filled",
Help: "fraction of cache filled",
},
}),
}
return m, utils.Err(
reg.Register(m.getCount),
reg.Register(m.getTime),
reg.Register(m.putCount),
reg.Register(m.putTime),
reg.Register(m.len),
reg.Register(m.portionFilled),
)
errs.Add(reg.Register(m.portionFilled))
m.hit = newCounterMetric(namespace, "hit", reg, &errs)
m.miss = newCounterMetric(namespace, "miss", reg, &errs)
return errs.Err
}
3 changes: 1 addition & 2 deletions vms/components/chain/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"github.com/ava-labs/avalanchego/snow/consensus/snowman"
"github.com/ava-labs/avalanchego/snow/consensus/snowman/snowmantest"
"github.com/ava-labs/avalanchego/utils/hashing"
"github.com/ava-labs/avalanchego/utils/metric"
)

var (
Expand Down Expand Up @@ -532,7 +531,7 @@ func TestMeteredCache(t *testing.T) {
_, err := NewMeteredState(registry, config)
require.NoError(err)
_, err = NewMeteredState(registry, config)
require.ErrorIs(err, metric.ErrFailedRegistering)
require.Error(err) //nolint:forbidigo // error is not exported https://github.com/prometheus/client_golang/blob/main/prometheus/registry.go#L315
}

// Test the bytesToIDCache
Expand Down

0 comments on commit fd447ed

Please sign in to comment.