mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add support for more than one field for uint64 metrics.
This change simply mimics what's already done for distribution metrics, by reusing the same fieldMapper to create field-to-integer mappings that are go:nosplit safe. In this refactor, since all field slots are pre-allocated and we use atomicbitops for atomically adding/loading uint64 values, it should be safe to remove the mutex that backed the original single-field implementation. PiperOrigin-RevId: 445576069
This commit is contained in:
committed by
gVisor bot
parent
b286d1c1ba
commit
bd1dbb001c
+22
-61
@@ -91,24 +91,16 @@ var (
|
||||
)
|
||||
|
||||
// Uint64Metric encapsulates a uint64 that represents some kind of metric to be
|
||||
// monitored. We currently support metrics with at most one field.
|
||||
// monitored.
|
||||
//
|
||||
// Metrics are not saved across save/restore and thus reset to zero on restore.
|
||||
//
|
||||
// TODO(b/67298427): Support metric fields.
|
||||
type Uint64Metric struct {
|
||||
// value is the actual value of the metric. It must be accessed atomically.
|
||||
value atomicbitops.Uint64
|
||||
// fields is the map of field-value combination index keys to Uint64 counters.
|
||||
fields []atomicbitops.Uint64
|
||||
|
||||
// numFields is the number of metric fields. It is immutable once
|
||||
// initialized.
|
||||
numFields int
|
||||
|
||||
// mu protects the below fields.
|
||||
mu sync.RWMutex `state:"nosave"`
|
||||
|
||||
// fields is the map of fields in the metric.
|
||||
fields map[string]uint64
|
||||
// fieldMapper is used to generate index keys for the fields array (above)
|
||||
// based on field value combinations, and vice-versa.
|
||||
fieldMapper fieldMapper
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -390,15 +382,13 @@ func MustRegisterCustomUint64Metric(name string, cumulative, sync bool, descript
|
||||
//
|
||||
// Metrics must be statically defined (i.e., at init).
|
||||
func NewUint64Metric(name string, sync bool, units pb.MetricMetadata_Units, description string, fields ...Field) (*Uint64Metric, error) {
|
||||
m := Uint64Metric{
|
||||
numFields: len(fields),
|
||||
f, err := newFieldMapper(fields...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if m.numFields == 1 {
|
||||
m.fields = make(map[string]uint64)
|
||||
for _, fieldValue := range fields[0].allowedValues {
|
||||
m.fields[fieldValue] = 0
|
||||
}
|
||||
m := Uint64Metric{
|
||||
fieldMapper: f,
|
||||
fields: make([]atomicbitops.Uint64, f.numKeys()),
|
||||
}
|
||||
return &m, RegisterCustomUint64Metric(name, true /* cumulative */, sync, units, description, m.Value, fields...)
|
||||
}
|
||||
@@ -424,55 +414,26 @@ func MustCreateNewUint64NanosecondsMetric(name string, sync bool, description st
|
||||
}
|
||||
|
||||
// Value returns the current value of the metric for the given set of fields.
|
||||
// This must be called with the correct number of field values or it will panic.
|
||||
//go:nosplit
|
||||
func (m *Uint64Metric) Value(fieldValues ...string) uint64 {
|
||||
if m.numFields != len(fieldValues) {
|
||||
panic(fmt.Sprintf("Number of fieldValues %d is not equal to the number of metric fields %d", len(fieldValues), m.numFields))
|
||||
}
|
||||
|
||||
switch m.numFields {
|
||||
case 0:
|
||||
return m.value.Load()
|
||||
case 1:
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
fieldValue := fieldValues[0]
|
||||
if _, ok := m.fields[fieldValue]; !ok {
|
||||
panic(fmt.Sprintf("Metric does not allow to have field value %s", fieldValue))
|
||||
}
|
||||
return m.fields[fieldValue]
|
||||
default:
|
||||
panic("Sentry metrics do not support more than one field")
|
||||
}
|
||||
key := m.fieldMapper.lookup(fieldValues...)
|
||||
return m.fields[key].Load()
|
||||
}
|
||||
|
||||
// Increment increments the metric field by 1.
|
||||
// This must be called with the correct number of field values or it will panic.
|
||||
//go:nosplit
|
||||
func (m *Uint64Metric) Increment(fieldValues ...string) {
|
||||
m.IncrementBy(1, fieldValues...)
|
||||
}
|
||||
|
||||
// IncrementBy increments the metric by v.
|
||||
// This must be called with the correct number of field values or it will panic.
|
||||
//go:nosplit
|
||||
func (m *Uint64Metric) IncrementBy(v uint64, fieldValues ...string) {
|
||||
if m.numFields != len(fieldValues) {
|
||||
panic(fmt.Sprintf("Number of fieldValues %d is not equal to the number of metric fields %d", len(fieldValues), m.numFields))
|
||||
}
|
||||
|
||||
switch m.numFields {
|
||||
case 0:
|
||||
m.value.Add(v)
|
||||
return
|
||||
case 1:
|
||||
fieldValue := fieldValues[0]
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if _, ok := m.fields[fieldValue]; !ok {
|
||||
panic(fmt.Sprintf("Metric does not allow to have field value %s", fieldValue))
|
||||
}
|
||||
m.fields[fieldValue] += v
|
||||
default:
|
||||
panic("Sentry metrics do not support more than one field")
|
||||
}
|
||||
key := m.fieldMapper.lookup(fieldValues...)
|
||||
m.fields[key].Add(v)
|
||||
}
|
||||
|
||||
// Bucketer is an interface to bucket values into finite, distinct buckets.
|
||||
|
||||
Reference in New Issue
Block a user