diff --git a/pkg/metric/condmetric.go b/pkg/metric/condmetric.go index f929255f5..d51442e05 100644 --- a/pkg/metric/condmetric.go +++ b/pkg/metric/condmetric.go @@ -48,11 +48,21 @@ func (m *FakeUint64Metric) Value(fieldValues ...*FieldValue) uint64 { //go:nosplit func (m *FakeUint64Metric) Increment(fieldValues ...*FieldValue) {} +// Decrement on a FakeUint64Metric does nothing. +// +//go:nosplit +func (m *FakeUint64Metric) Decrement(fieldValues ...*FieldValue) {} + // IncrementBy on a FakeUint64Metric does nothing. // //go:nosplit func (m *FakeUint64Metric) IncrementBy(v uint64, fieldValues ...*FieldValue) {} +// Set on a FakeUint64Metric does nothing. +// +//go:nosplit +func (m *FakeUint64Metric) Set(v uint64, fieldValues ...*FieldValue) {} + // AddSample on a FakeUint64Metric does nothing. // //go:nosplit @@ -76,12 +86,12 @@ func (o FakeTimedOperation) Finish(extraFields ...*FieldValue) {} type FakeMetricBuilder struct{} // NewUint64Metric creates a fake Uint64 metric. -func (b *FakeMetricBuilder) NewUint64Metric(name string, sync bool, units pb.MetricMetadata_Units, description string, fields ...Field) (*FakeUint64Metric, error) { +func (b *FakeMetricBuilder) NewUint64Metric(name string, metadata Uint64Metadata) (*FakeUint64Metric, error) { return &FakeUint64Metric{}, nil } // MustCreateNewUint64Metric creates a fake Uint64 metric. -func (b *FakeMetricBuilder) MustCreateNewUint64Metric(name string, sync bool, description string, fields ...Field) *FakeUint64Metric { +func (b *FakeMetricBuilder) MustCreateNewUint64Metric(name string, metadata Uint64Metadata) *FakeUint64Metric { return &FakeUint64Metric{} } @@ -111,8 +121,8 @@ type RealMetricBuilder struct{} // NewUint64Metric calls the generic metric.NewUint64Metric to produce a real // Uint64 metric. -func (b *RealMetricBuilder) NewUint64Metric(name string, sync bool, units pb.MetricMetadata_Units, description string, fields ...Field) (*Uint64Metric, error) { - m, err := NewUint64Metric(name, sync, units, description, fields...) +func (b *RealMetricBuilder) NewUint64Metric(name string, metadata Uint64Metadata) (*Uint64Metric, error) { + m, err := NewUint64Metric(name, metadata) if err != nil { return m, err } @@ -122,8 +132,8 @@ func (b *RealMetricBuilder) NewUint64Metric(name string, sync bool, units pb.Met // MustCreateNewUint64Metric creates a real Uint64 metric or panics if unable to // do so. -func (b *RealMetricBuilder) MustCreateNewUint64Metric(name string, sync bool, description string, fields ...Field) *Uint64Metric { - m, err := b.NewUint64Metric(name, sync, pb.MetricMetadata_UNITS_NONE, description, fields...) +func (b *RealMetricBuilder) MustCreateNewUint64Metric(name string, metadata Uint64Metadata) *Uint64Metric { + m, err := b.NewUint64Metric(name, metadata) if err != nil { panic(fmt.Sprintf("Unable to create metric %q: %s", name, err)) } diff --git a/pkg/metric/condmetric_profiling_disabled_test.go b/pkg/metric/condmetric_profiling_disabled_test.go index 45e86ede4..0261d3608 100644 --- a/pkg/metric/condmetric_profiling_disabled_test.go +++ b/pkg/metric/condmetric_profiling_disabled_test.go @@ -26,7 +26,10 @@ import ( func TestProfilingMetricsDisabled(t *testing.T) { defer resetTest() - _, err := SentryProfiling.NewUint64Metric("/counterM", false, pb.MetricMetadata_UNITS_NONE, "One uint64 metric") + _, err := SentryProfiling.NewUint64Metric("/counterM", Uint64Metadata{ + Cumulative: true, + Description: "one uint64 metric", + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } diff --git a/pkg/metric/condmetric_profiling_enabled_test.go b/pkg/metric/condmetric_profiling_enabled_test.go index b45288b69..322bba706 100644 --- a/pkg/metric/condmetric_profiling_enabled_test.go +++ b/pkg/metric/condmetric_profiling_enabled_test.go @@ -26,7 +26,10 @@ import ( func TestProfilingMetricsEnabled(t *testing.T) { defer resetTest() - _, err := SentryProfiling.NewUint64Metric("/counterM", false, pb.MetricMetadata_UNITS_NONE, "One uint64 metric") + _, err := SentryProfiling.NewUint64Metric("/counterM", Uint64Metadata{ + Cumulative: true, + Description: "one uint64 metric", + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } diff --git a/pkg/metric/metric.go b/pkg/metric/metric.go index 30ba8ea47..f3c0d1c77 100644 --- a/pkg/metric/metric.go +++ b/pkg/metric/metric.go @@ -74,21 +74,37 @@ var ( // WeirdnessMetric is a metric with fields created to track the number // of weird occurrences such as time fallback, partial_result, vsyscall // count, watchdog startup timeouts and stuck tasks. - WeirdnessMetric = MustCreateNewUint64Metric("/weirdness", true /* sync */, "Increment for weird occurrences of problems such as time fallback, partial result, vsyscalls invoked in the sandbox, watchdog startup timeouts and stuck tasks.", - NewField("weirdness_type", - &WeirdnessTypeTimeFallback, - &WeirdnessTypePartialResult, - &WeirdnessTypeVsyscallCount, - &WeirdnessTypeWatchdogStuckStartup, - &WeirdnessTypeWatchdogStuckTasks, - )) + WeirdnessMetric = MustCreateNewUint64Metric( + "/weirdness", + Uint64Metadata{ + Cumulative: true, + Sync: true, + Description: "Increment for weird occurrences of problems such as time fallback, partial result, vsyscalls invoked in the sandbox, watchdog startup timeouts and stuck tasks.", + Fields: []Field{ + NewField("weirdness_type", + &WeirdnessTypeTimeFallback, + &WeirdnessTypePartialResult, + &WeirdnessTypeVsyscallCount, + &WeirdnessTypeWatchdogStuckStartup, + &WeirdnessTypeWatchdogStuckTasks, + ), + }, + }) // SuspiciousOperationsMetric is a metric with fields created to detect // operations such as opening an executable file to write from a gofer. - SuspiciousOperationsMetric = MustCreateNewUint64Metric("/suspicious_operations", true /* sync */, "Increment for suspicious operations such as opening an executable file to write from a gofer.", - NewField("operation_type", - &SuspiciousOperationsTypeOpenedWriteExecuteFile, - )) + SuspiciousOperationsMetric = MustCreateNewUint64Metric( + "/suspicious_operations", + Uint64Metadata{ + Cumulative: true, + Sync: true, + Description: "Increment for suspicious operations such as opening an executable file to write from a gofer.", + Fields: []Field{ + NewField("operation_type", + &SuspiciousOperationsTypeOpenedWriteExecuteFile, + ), + }, + }) ) // InitStage is the name of a Sentry initialization stage. @@ -206,6 +222,15 @@ func Disable() error { return nil } +// Uint64Metadata is the metadata for a uint64 metric. +type Uint64Metadata struct { + Cumulative bool + Sync bool + Unit pb.MetricMetadata_Units + Description string + Fields []Field +} + type customUint64Metric struct { // metadata describes the metric. It is immutable. metadata *pb.MetricMetadata @@ -510,7 +535,7 @@ func verifyName(name string) error { // - name must be globally unique. // - Initialize/Disable have not been called. // - value is expected to accept exactly len(fields) arguments. -func RegisterCustomUint64Metric(name string, cumulative, sync bool, units pb.MetricMetadata_Units, description string, value func(...*FieldValue) uint64, fields ...Field) error { +func RegisterCustomUint64Metric(name string, metadata Uint64Metadata, value func(...*FieldValue) uint64) error { if initialized.Load() { return ErrInitializationDone } @@ -523,7 +548,7 @@ func RegisterCustomUint64Metric(name string, cumulative, sync bool, units pb.Met } promType := prometheus.TypeGauge - if cumulative { + if metadata.Cumulative { promType = prometheus.TypeCounter } @@ -531,27 +556,27 @@ func RegisterCustomUint64Metric(name string, cumulative, sync bool, units pb.Met metadata: &pb.MetricMetadata{ Name: name, PrometheusName: nameToPrometheusName(name), - Description: description, - Cumulative: cumulative, - Sync: sync, + Description: metadata.Description, + Cumulative: metadata.Cumulative, + Sync: metadata.Sync, Type: pb.MetricMetadata_TYPE_UINT64, - Units: units, + Units: metadata.Unit, }, prometheusMetric: &prometheus.Metric{ Name: nameToPrometheusName(name), - Help: description, + Help: metadata.Description, Type: promType, }, - fields: fields, + fields: metadata.Fields, value: value, } // Metrics can exist without fields. - if l := len(fields); l > 1 { + if l := len(metadata.Fields); l > 1 { return fmt.Errorf("%d fields provided, must be <= 1", l) } - for _, field := range fields { + for _, field := range metadata.Fields { allMetrics.uint64Metrics[name].metadata.Fields = append(allMetrics.uint64Metrics[name].metadata.Fields, field.toProto()) } return nil @@ -559,8 +584,8 @@ func RegisterCustomUint64Metric(name string, cumulative, sync bool, units pb.Met // MustRegisterCustomUint64Metric calls RegisterCustomUint64Metric for metrics // without fields and panics if it returns an error. -func MustRegisterCustomUint64Metric(name string, cumulative, sync bool, description string, value func(...*FieldValue) uint64, fields ...Field) { - if err := RegisterCustomUint64Metric(name, cumulative, sync, pb.MetricMetadata_UNITS_NONE, description, value, fields...); err != nil { +func MustRegisterCustomUint64Metric(name string, metadata Uint64Metadata, value func(...*FieldValue) uint64) { + if err := RegisterCustomUint64Metric(name, metadata, value); err != nil { panic(fmt.Sprintf("Unable to register metric %q: %s", name, err)) } } @@ -569,11 +594,11 @@ func MustRegisterCustomUint64Metric(name string, cumulative, sync bool, descript // name. // // 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) { +func NewUint64Metric(name string, metadata Uint64Metadata) (*Uint64Metric, error) { if err := verifyName(name); err != nil { return nil, err } - f, err := newFieldMapper(fields...) + f, err := newFieldMapper(metadata.Fields...) if err != nil { return nil, err } @@ -582,7 +607,7 @@ func NewUint64Metric(name string, sync bool, units pb.MetricMetadata_Units, desc fieldMapper: f, fields: make([]atomicbitops.Uint64, f.numKeys()), } - if err := RegisterCustomUint64Metric(name, true /* cumulative */, sync, units, description, m.Value, fields...); err != nil { + if err := RegisterCustomUint64Metric(name, metadata, m.Value); err != nil { return nil, err } cm := allMetrics.uint64Metrics[name] @@ -593,18 +618,8 @@ func NewUint64Metric(name string, sync bool, units pb.MetricMetadata_Units, desc // MustCreateNewUint64Metric calls NewUint64Metric and panics if it returns // an error. -func MustCreateNewUint64Metric(name string, sync bool, description string, fields ...Field) *Uint64Metric { - m, err := NewUint64Metric(name, sync, pb.MetricMetadata_UNITS_NONE, description, fields...) - if err != nil { - panic(fmt.Sprintf("Unable to create metric %q: %s", name, err)) - } - return m -} - -// MustCreateNewUint64NanosecondsMetric calls NewUint64Metric and panics if it -// returns an error. -func MustCreateNewUint64NanosecondsMetric(name string, sync bool, description string) *Uint64Metric { - m, err := NewUint64Metric(name, sync, pb.MetricMetadata_UNITS_NANOSECONDS, description) +func MustCreateNewUint64Metric(name string, metadata Uint64Metadata) *Uint64Metric { + m, err := NewUint64Metric(name, metadata) if err != nil { panic(fmt.Sprintf("Unable to create metric %q: %s", name, err)) } @@ -646,16 +661,25 @@ func (m *Uint64Metric) forEachNonZero(f func(fieldValues []*FieldValue, value ui } } -// Increment increments the metric field by 1. +// Increment increments the metric by 1. // This must be called with the correct number of field values or it will panic. // //go:nosplit func (m *Uint64Metric) Increment(fieldValues ...*FieldValue) { - key := m.fieldMapper.lookupConcat(fieldValues, nil) - m.fields[key].Add(1) + m.IncrementBy(1, fieldValues...) +} + +// Decrement decrements the metric by 1. +// This must be called with the correct number of field values or it will panic. +// +//go:nosplit +func (m *Uint64Metric) Decrement(fieldValues ...*FieldValue) { + m.IncrementBy(0xFFFFFFFFFFFFFFFF, fieldValues...) } // IncrementBy increments the metric by v. +// It is also possible to use this function to decrement the metric by using +// a two's-complement int64 representation of the negative number to add. // This must be called with the correct number of field values or it will panic. // //go:nosplit @@ -664,6 +688,15 @@ func (m *Uint64Metric) IncrementBy(v uint64, fieldValues ...*FieldValue) { m.fields[key].Add(v) } +// Set sets the metric to v. +// This must be called with the correct number of field values or it will panic. +// +//go:nosplit +func (m *Uint64Metric) Set(v uint64, fieldValues ...*FieldValue) { + key := m.fieldMapper.lookupConcat(fieldValues, nil) + m.fields[key].Store(v) +} + // Bucketer is an interface to bucket values into finite, distinct buckets. type Bucketer interface { // NumFiniteBuckets is the number of finite buckets in the distribution. diff --git a/pkg/metric/metric_test.go b/pkg/metric/metric_test.go index 3fa88d223..2f159df83 100644 --- a/pkg/metric/metric_test.go +++ b/pkg/metric/metric_test.go @@ -100,12 +100,20 @@ func TestVerifyName(t *testing.T) { func TestInitialize(t *testing.T) { defer resetTest() - _, err := NewUint64Metric("/foo", false, pb.MetricMetadata_UNITS_NONE, fooDescription) + _, err := NewUint64Metric("/foo", Uint64Metadata{ + Cumulative: true, + Description: fooDescription, + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } - _, err = NewUint64Metric("/bar", true, pb.MetricMetadata_UNITS_NANOSECONDS, barDescription) + _, err = NewUint64Metric("/bar", Uint64Metadata{ + Cumulative: true, + Sync: true, + Description: barDescription, + Unit: pb.MetricMetadata_UNITS_NANOSECONDS, + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } @@ -170,7 +178,7 @@ func TestInitialize(t *testing.T) { t.Errorf("/bar %+v Description got %q want %q", m, m.Description, barDescription) } if !m.Sync { - t.Errorf("/bar %+v Sync got true want false", m) + t.Errorf("/bar %+v Sync got false want true", m) } if m.Units != pb.MetricMetadata_UNITS_NANOSECONDS { t.Errorf("/bar %+v Units got %v want %v", m, m.Units, pb.MetricMetadata_UNITS_NANOSECONDS) @@ -211,12 +219,18 @@ func TestInitialize(t *testing.T) { func TestDisable(t *testing.T) { defer resetTest() - _, err := NewUint64Metric("/foo", false, pb.MetricMetadata_UNITS_NONE, fooDescription) + _, err := NewUint64Metric("/foo", Uint64Metadata{ + Cumulative: true, + Description: fooDescription, + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } - _, err = NewUint64Metric("/bar", true, pb.MetricMetadata_UNITS_NONE, barDescription) + _, err = NewUint64Metric("/bar", Uint64Metadata{ + Cumulative: true, + Description: barDescription, + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } @@ -247,12 +261,18 @@ func TestDisable(t *testing.T) { func TestEmitMetricUpdate(t *testing.T) { defer resetTest() - foo, err := NewUint64Metric("/foo", false, pb.MetricMetadata_UNITS_NONE, fooDescription) + foo, err := NewUint64Metric("/foo", Uint64Metadata{ + Cumulative: true, + Description: fooDescription, + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } - _, err = NewUint64Metric("/bar", true, pb.MetricMetadata_UNITS_NONE, barDescription) + _, err = NewUint64Metric("/bar", Uint64Metadata{ + Cumulative: true, + Description: barDescription, + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } @@ -453,7 +473,11 @@ func TestEmitMetricUpdateWithFields(t *testing.T) { ) field := NewField("weirdness_type", &weird1, &weird2) - counter, err := NewUint64Metric("/weirdness", false, pb.MetricMetadata_UNITS_NONE, counterDescription, field) + counter, err := NewUint64Metric("/weirdness", Uint64Metadata{ + Cumulative: true, + Description: counterDescription, + Fields: []Field{field}, + }) if err != nil { t.Fatalf("NewUint64Metric got err %v want nil", err) } @@ -581,7 +605,10 @@ func TestMetricUpdateStageTiming(t *testing.T) { time.Sleep(100 * time.Millisecond) }) - fooMetric, err := NewUint64Metric("/foo", false, pb.MetricMetadata_UNITS_NONE, fooDescription) + fooMetric, err := NewUint64Metric("/foo", Uint64Metadata{ + Cumulative: true, + Description: fooDescription, + }) if err != nil { t.Fatalf("Cannot register /foo: %v", err) } @@ -1093,7 +1120,11 @@ func TestMetricProfiling(t *testing.T) { metrics := make([]*Uint64Metric, numMetrics) for i, m := range test.metricNames { - newMetric, err := NewUint64Metric(m, true, pb.MetricMetadata_UNITS_NANOSECONDS, fooDescription) + newMetric, err := NewUint64Metric(m, Uint64Metadata{ + Cumulative: true, + Sync: true, + Description: fooDescription, + }) metrics[i] = newMetric if err != nil { t.Fatalf("NewUint64Metric got err '%v' want nil", err) diff --git a/pkg/sentry/fsmetric/BUILD b/pkg/sentry/fsmetric/BUILD index 36175c0e4..c5e3ac5fd 100644 --- a/pkg/sentry/fsmetric/BUILD +++ b/pkg/sentry/fsmetric/BUILD @@ -8,5 +8,8 @@ go_library( name = "fsmetric", srcs = ["fsmetric.go"], visibility = ["//pkg/sentry:internal"], - deps = ["//pkg/metric"], + deps = [ + "//pkg/metric", + "//pkg/metric:metric_go_proto", + ], ) diff --git a/pkg/sentry/fsmetric/fsmetric.go b/pkg/sentry/fsmetric/fsmetric.go index 3855ef7e3..f9cb3d04d 100644 --- a/pkg/sentry/fsmetric/fsmetric.go +++ b/pkg/sentry/fsmetric/fsmetric.go @@ -19,6 +19,7 @@ import ( "time" "gvisor.dev/gvisor/pkg/metric" + metricpb "gvisor.dev/gvisor/pkg/metric/metric_go_proto" ) // RecordWaitTime enables the ReadWait, GoferReadWait9P, GoferReadWaitHost, and @@ -31,27 +32,80 @@ var RecordWaitTime = false // Metrics that apply to all filesystems. var ( - Opens = metric.MustCreateNewUint64Metric("/fs/opens", false /* sync */, "Number of file opens.") - Reads = metric.MustCreateNewUint64Metric("/fs/reads", false /* sync */, "Number of file reads.") - ReadWait = metric.MustCreateNewUint64NanosecondsMetric("/fs/read_wait", false /* sync */, "Time waiting on file reads, in nanoseconds.") + Opens = metric.MustCreateNewUint64Metric("/fs/opens", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of file opens.", + }) + Reads = metric.MustCreateNewUint64Metric("/fs/reads", metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of file reads.", + }) + ReadWait = metric.MustCreateNewUint64Metric("/fs/read_wait", metric.Uint64Metadata{ + Cumulative: true, + Description: "Time waiting on file reads, in nanoseconds.", + Unit: metricpb.MetricMetadata_UNITS_NANOSECONDS, + }) ) // Metrics that only apply to fs/gofer and fsimpl/gofer. var ( - GoferOpens9P = metric.MustCreateNewUint64Metric("/gofer/opens_9p", false /* sync */, "Number of times a file was opened from a gofer and did not have a host file descriptor.") - GoferOpensHost = metric.MustCreateNewUint64Metric("/gofer/opens_host", false /* sync */, "Number of times a file was opened from a gofer and did have a host file descriptor.") - GoferReads9P = metric.MustCreateNewUint64Metric("/gofer/reads_9p", false /* sync */, "Number of 9P file reads from a gofer.") - GoferReadWait9P = metric.MustCreateNewUint64NanosecondsMetric("/gofer/read_wait_9p", false /* sync */, "Time waiting on 9P file reads from a gofer, in nanoseconds.") - GoferReadsHost = metric.MustCreateNewUint64Metric("/gofer/reads_host", false /* sync */, "Number of host file reads from a gofer.") - GoferReadWaitHost = metric.MustCreateNewUint64NanosecondsMetric("/gofer/read_wait_host", false /* sync */, "Time waiting on host file reads from a gofer, in nanoseconds.") + GoferOpens9P = metric.MustCreateNewUint64Metric("/gofer/opens_9p", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of times a file was opened from a gofer and did not have a host file descriptor.", + }) + GoferOpensHost = metric.MustCreateNewUint64Metric("/gofer/opens_host", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of times a file was opened from a gofer and did have a host file descriptor.", + }) + GoferReads9P = metric.MustCreateNewUint64Metric("/gofer/reads_9p", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of 9P file reads from a gofer.", + }) + GoferReadWait9P = metric.MustCreateNewUint64Metric("/gofer/read_wait_9p", metric.Uint64Metadata{ + Cumulative: true, + Description: "Time waiting on 9P file reads from a gofer, in nanoseconds.", + Unit: metricpb.MetricMetadata_UNITS_NANOSECONDS, + }) + GoferReadsHost = metric.MustCreateNewUint64Metric("/gofer/reads_host", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of host file reads from a gofer.", + }) + GoferReadWaitHost = metric.MustCreateNewUint64Metric("/gofer/read_wait_host", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Time waiting on host file reads from a gofer, in nanoseconds.", + Unit: metricpb.MetricMetadata_UNITS_NANOSECONDS, + }) ) // Metrics that only apply to fs/tmpfs and fsimpl/tmpfs. var ( - TmpfsOpensRO = metric.MustCreateNewUint64Metric("/in_memory_file/opens_ro", false /* sync */, "Number of times an in-memory file was opened in read-only mode.") - TmpfsOpensW = metric.MustCreateNewUint64Metric("/in_memory_file/opens_w", false /* sync */, "Number of times an in-memory file was opened in write mode.") - TmpfsReads = metric.MustCreateNewUint64Metric("/in_memory_file/reads", false /* sync */, "Number of in-memory file reads.") - TmpfsReadWait = metric.MustCreateNewUint64NanosecondsMetric("/in_memory_file/read_wait", false /* sync */, "Time waiting on in-memory file reads, in nanoseconds.") + TmpfsOpensRO = metric.MustCreateNewUint64Metric("/in_memory_file/opens_ro", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of times an in-memory file was opened in read-only mode.", + }) + TmpfsOpensW = metric.MustCreateNewUint64Metric("/in_memory_file/opens_w", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of times an in-memory file was opened in write mode.", + }) + TmpfsReads = metric.MustCreateNewUint64Metric("/in_memory_file/reads", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Number of in-memory file reads.", + }) + TmpfsReadWait = metric.MustCreateNewUint64Metric("/in_memory_file/read_wait", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Time waiting on in-memory file reads, in nanoseconds.", + Unit: metricpb.MetricMetadata_UNITS_NANOSECONDS, + }) ) // StartReadWait indicates the beginning of a file read. diff --git a/pkg/sentry/kernel/memevent/memory_events.go b/pkg/sentry/kernel/memevent/memory_events.go index 200565bb8..54bf11ac5 100644 --- a/pkg/sentry/kernel/memevent/memory_events.go +++ b/pkg/sentry/kernel/memevent/memory_events.go @@ -28,8 +28,14 @@ import ( "gvisor.dev/gvisor/pkg/sync" ) -var totalTicks = metric.MustCreateNewUint64Metric("/memory_events/ticks", false /*sync*/, "Total number of memory event periods that have elapsed since startup.") -var totalEvents = metric.MustCreateNewUint64Metric("/memory_events/events", false /*sync*/, "Total number of memory events emitted.") +var totalTicks = metric.MustCreateNewUint64Metric("/memory_events/ticks", metric.Uint64Metadata{ + Cumulative: true, + Description: "Total number of memory event periods that have elapsed since startup.", +}) +var totalEvents = metric.MustCreateNewUint64Metric("/memory_events/events", metric.Uint64Metadata{ + Cumulative: true, + Description: "Total number of memory events emitted.", +}) // MemoryEvents describes the configuration for the global memory event emitter. type MemoryEvents struct { diff --git a/pkg/sentry/kernel/syscalls.go b/pkg/sentry/kernel/syscalls.go index dab7aba12..0c1d62bc1 100644 --- a/pkg/sentry/kernel/syscalls.go +++ b/pkg/sentry/kernel/syscalls.go @@ -392,7 +392,15 @@ func RegisterSyscallTable(s *SyscallTable) { unimplementedSyscallNumbers[i] = []*metric.FieldValue{s} } allowedValues[len(allowedValues)-1] = outOfRangeSyscallNumber[0] - unimplementedSyscallCounter = metric.MustCreateNewUint64Metric("/unimplemented_syscalls", true, "Number of times the application tried to call an unimplemented syscall, broken down by syscall number", metric.NewField("sysno", allowedValues...)) + unimplementedSyscallCounter = metric.MustCreateNewUint64Metric("/unimplemented_syscalls", + metric.Uint64Metadata{ + Cumulative: true, + Sync: true, + Description: "Number of times the application tried to call an unimplemented syscall, broken down by syscall number", + Fields: []metric.Field{ + metric.NewField("sysno", allowedValues...), + }, + }) }) s.Init() } diff --git a/pkg/sentry/kernel/task.go b/pkg/sentry/kernel/task.go index 2089ece06..2df014447 100644 --- a/pkg/sentry/kernel/task.go +++ b/pkg/sentry/kernel/task.go @@ -617,12 +617,18 @@ var ( // syscallCounter is a metric that tracks how many syscalls the sentry has // executed. syscallCounter = metric.SentryProfiling.MustCreateNewUint64Metric( - "/task/syscalls", false, "The number of syscalls the sentry has executed for the user.") + "/task/syscalls", metric.Uint64Metadata{ + Cumulative: true, + Description: "The number of syscalls the sentry has executed for the user.", + }) // faultCounter is a metric that tracks how many faults the sentry has had to // handle. faultCounter = metric.SentryProfiling.MustCreateNewUint64Metric( - "/task/faults", false, "The number of faults the sentry has handled.") + "/task/faults", metric.Uint64Metadata{ + Cumulative: true, + Description: "The number of faults the sentry has handled.", + }) ) func (t *Task) savePtraceTracer() *Task { diff --git a/pkg/sentry/platform/kvm/machine.go b/pkg/sentry/platform/kvm/machine.go index 63d61ec8c..365e94b1e 100644 --- a/pkg/sentry/platform/kvm/machine.go +++ b/pkg/sentry/platform/kvm/machine.go @@ -115,28 +115,50 @@ var ( // hostExitCounter is a metric that tracks how many times the sentry // performed a host to guest world switch. hostExitCounter = KVMProfiling.MustCreateNewUint64Metric( - "/kvm/host_exits", false, "The number of times the sentry performed a host to guest world switch.") + "/kvm/host_exits", + metric.Uint64Metadata{ + Cumulative: true, + Description: "The number of times the sentry performed a host to guest world switch.", + }) // userExitCounter is a metric that tracks how many times the sentry has // had an exit from userspace. Analogous to vCPU.userExits. userExitCounter = KVMProfiling.MustCreateNewUint64Metric( - "/kvm/user_exits", false, "The number of times the sentry has had an exit from userspace.") + "/kvm/user_exits", + metric.Uint64Metadata{ + Cumulative: true, + Description: "The number of times the sentry has had an exit from userspace.", + }) // interruptCounter is a metric that tracks how many times execution returned // to the KVM host to handle a pending signal. interruptCounter = KVMProfiling.MustCreateNewUint64Metric( - "/kvm/interrupts", false, "The number of times the signal handler was invoked.") + "/kvm/interrupts", + metric.Uint64Metadata{ + Cumulative: true, + Description: "The number of times the signal handler was invoked.", + }) // mmapCallCounter is a metric that tracks how many times the function // seccompMmapSyscall has been called. mmapCallCounter = KVMProfiling.MustCreateNewUint64Metric( - "/kvm/mmap_calls", false, "The number of times seccompMmapSyscall has been called.") + "/kvm/mmap_calls", + metric.Uint64Metadata{ + Cumulative: true, + Description: "The number of times seccompMmapSyscall has been called.", + }) // getVCPUCounter is a metric that tracks how many times different paths of // machine.Get() are triggered. getVCPUCounter = KVMProfiling.MustCreateNewUint64Metric( - "/kvm/get_vcpu", false, "The number of times that machine.Get() was called, split by path the function took.", - metric.NewField("acquisition_type", &getVCPUAcquisitionFastReused, &getVCPUAcquisitionReused, &getVCPUAcquisitionUnused, &getVCPUAcquisitionStolen)) + "/kvm/get_vcpu", + metric.Uint64Metadata{ + Cumulative: true, + Description: "The number of times that machine.Get() was called, split by path the function took.", + Fields: []metric.Field{ + metric.NewField("acquisition_type", &getVCPUAcquisitionFastReused, &getVCPUAcquisitionReused, &getVCPUAcquisitionUnused, &getVCPUAcquisitionStolen), + }, + }) // asInvalidateDuration are durations of calling addressSpace.invalidate(). asInvalidateDuration = KVMProfiling.MustCreateNewTimerMetric("/kvm/address_space_invalidate", diff --git a/pkg/sentry/platform/systrap/metrics.go b/pkg/sentry/platform/systrap/metrics.go index a67c63a22..1a31d7234 100644 --- a/pkg/sentry/platform/systrap/metrics.go +++ b/pkg/sentry/platform/systrap/metrics.go @@ -19,6 +19,7 @@ import ( "gvisor.dev/gvisor/pkg/atomicbitops" "gvisor.dev/gvisor/pkg/hostarch" + "gvisor.dev/gvisor/pkg/metric" ) // This file contains all logic related to context switch latency metrics. @@ -569,23 +570,23 @@ func sentryOnStubOn(s *fastPathState) { // Profiling metrics intended for debugging purposes. var ( - numTimesSentryFastPathDisabled = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesSentryFastPathDisabled", false, "") - numTimesSentryFastPathEnabled = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesSentryFastPathEnabled", false, "") - numTimesStubFastPathDisabled = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesStubFastPathDisabled", false, "") - numTimesStubFastPathEnabled = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesStubFastPathEnabled", false, "") - numTimesStubKicked = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesStubKicked", false, "") + numTimesSentryFastPathDisabled = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesSentryFastPathDisabled", metric.Uint64Metadata{Cumulative: true}) + numTimesSentryFastPathEnabled = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesSentryFastPathEnabled", metric.Uint64Metadata{Cumulative: true}) + numTimesStubFastPathDisabled = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesStubFastPathDisabled", metric.Uint64Metadata{Cumulative: true}) + numTimesStubFastPathEnabled = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesStubFastPathEnabled", metric.Uint64Metadata{Cumulative: true}) + numTimesStubKicked = SystrapProfiling.MustCreateNewUint64Metric("/systrap/numTimesStubKicked", metric.Uint64Metadata{Cumulative: true}) - stubLatWithin1kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin1kUS", false, "") - stubLatWithin5kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin5kUS", false, "") - stubLatWithin10kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin10kUS", false, "") - stubLatWithin20kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin20kUS", false, "") - stubLatWithin40kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin40kUS", false, "") - stubLatGreater40kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatGreater40kUS", false, "") + stubLatWithin1kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin1kUS", metric.Uint64Metadata{Cumulative: true}) + stubLatWithin5kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin5kUS", metric.Uint64Metadata{Cumulative: true}) + stubLatWithin10kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin10kUS", metric.Uint64Metadata{Cumulative: true}) + stubLatWithin20kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin20kUS", metric.Uint64Metadata{Cumulative: true}) + stubLatWithin40kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatWithin40kUS", metric.Uint64Metadata{Cumulative: true}) + stubLatGreater40kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/stubLatGreater40kUS", metric.Uint64Metadata{Cumulative: true}) - sentryLatWithin1kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin1kUS", false, "") - sentryLatWithin5kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin5kUS", false, "") - sentryLatWithin10kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin10kUS", false, "") - sentryLatWithin20kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin20kUS", false, "") - sentryLatWithin40kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin40kUS", false, "") - sentryLatGreater40kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatGreater40kUS", false, "") + sentryLatWithin1kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin1kUS", metric.Uint64Metadata{Cumulative: true}) + sentryLatWithin5kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin5kUS", metric.Uint64Metadata{Cumulative: true}) + sentryLatWithin10kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin10kUS", metric.Uint64Metadata{Cumulative: true}) + sentryLatWithin20kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin20kUS", metric.Uint64Metadata{Cumulative: true}) + sentryLatWithin40kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatWithin40kUS", metric.Uint64Metadata{Cumulative: true}) + sentryLatGreater40kUS = SystrapProfiling.MustCreateNewUint64Metric("/systrap/sentryLatGreater40kUS", metric.Uint64Metadata{Cumulative: true}) ) diff --git a/pkg/sentry/seccheck/config.go b/pkg/sentry/seccheck/config.go index 56c071edf..411f4569f 100644 --- a/pkg/sentry/seccheck/config.go +++ b/pkg/sentry/seccheck/config.go @@ -33,7 +33,11 @@ var ( sessions = make(map[string]*State) ) -var sessionCounter = metric.MustCreateNewUint64Metric("/trace/sessions_created", false /* sync */, "Counts the number of trace sessions created.") +var sessionCounter = metric.MustCreateNewUint64Metric("/trace/sessions_created", + metric.Uint64Metadata{ + Cumulative: true, + Description: "Counts the number of trace sessions created.", + }) // SessionConfig describes a new session configuration. A session consists of a // set of points to be enabled and sinks where the points are sent to. diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go index 3e8a6b006..3089f982c 100644 --- a/pkg/sentry/socket/netstack/netstack.go +++ b/pkg/sentry/socket/netstack/netstack.go @@ -80,13 +80,21 @@ func statCounterValue(cm *tcpip.StatCounter) func(...*metric.FieldValue) uint64 func mustCreateMetric(name, description string) *tcpip.StatCounter { var cm tcpip.StatCounter - metric.MustRegisterCustomUint64Metric(name, true /* cumulative */, false /* sync */, description, statCounterValue(&cm)) + metric.MustRegisterCustomUint64Metric(name, + metric.Uint64Metadata{ + Cumulative: true, + Description: description, + }, statCounterValue(&cm)) return &cm } func mustCreateGauge(name, description string) *tcpip.StatCounter { var cm tcpip.StatCounter - metric.MustRegisterCustomUint64Metric(name, false /* cumulative */, false /* sync */, description, statCounterValue(&cm)) + metric.MustRegisterCustomUint64Metric(name, + metric.Uint64Metadata{ + Cumulative: false, + Description: description, + }, statCounterValue(&cm)) return &cm } diff --git a/test/metricsviz/metricsviz_cli/metricsviz_cli_test.go b/test/metricsviz/metricsviz_cli/metricsviz_cli_test.go index dd2e21f6d..47f65353c 100644 --- a/test/metricsviz/metricsviz_cli/metricsviz_cli_test.go +++ b/test/metricsviz/metricsviz_cli/metricsviz_cli_test.go @@ -38,7 +38,11 @@ func TestMetricsvizCLI(t *testing.T) { t.Fatalf("Failed to find metricsviz_cli: %v", err) } const testMetricName = "/metricsviz_cli_test/counter" - testMetric := metric.MustCreateNewUint64Metric(testMetricName, true, fmt.Sprintf("test counter for %s", t.Name())) + testMetric := metric.MustCreateNewUint64Metric(testMetricName, metric.Uint64Metadata{ + Cumulative: true, + Sync: true, + Description: fmt.Sprintf("test counter for %s", t.Name()), + }) if err := metric.Initialize(); err != nil { t.Fatalf("Failed to initialize metrics: %v", err) }