From 41208411847841af2dbe9daa36189b35d191b9b2 Mon Sep 17 00:00:00 2001 From: Konstantin Bogomolov Date: Thu, 5 Oct 2023 15:53:40 -0700 Subject: [PATCH] Enable easy creation of independent profiling metrics. When using conditionally compiled metrics there was only one go_tag to rule them all. That's kind of a shame because when profiling something specific it's nicer to know that only your metrics that you care about are compiled in and metrics that you don't care about aren't. This CL makes it easy to create new profiling go_tags, by abstracting the profiling metric init functions under two builder structs: RealMetricBuilder and FakeMetricBuilder; these builder structs are the only things that need to change between the metrics-ON or OFF versions of conditional metric files (aside from the go_tag controlling conditional compilation of course). Ideally having to create these files manually wouldn't be necessary at all, and we could use a go_template build rule instead, but that doesn't support replacing go:build tags AFAIK. PiperOrigin-RevId: 571153131 --- pkg/metric/BUILD | 6 +- pkg/metric/condmetric.go | 155 ++++++++++++++++++ pkg/metric/condmetric_profiling.go | 87 ---------- .../condmetric_profiling_disabled_test.go | 16 +- .../condmetric_profiling_enabled_test.go | 16 +- pkg/metric/condmetric_profiling_fake.go | 61 ------- pkg/metric/fake_metric.go | 104 ------------ pkg/metric/sentry_profiling.go | 23 +++ pkg/metric/sentry_profiling_fake.go | 23 +++ pkg/sentry/kernel/task.go | 4 +- pkg/sentry/platform/kvm/BUILD | 2 + pkg/sentry/platform/kvm/kvm_profiling.go | 27 +++ pkg/sentry/platform/kvm/kvm_profiling_fake.go | 27 +++ pkg/sentry/platform/kvm/machine.go | 12 +- 14 files changed, 284 insertions(+), 279 deletions(-) create mode 100644 pkg/metric/condmetric.go delete mode 100644 pkg/metric/condmetric_profiling.go delete mode 100644 pkg/metric/condmetric_profiling_fake.go delete mode 100644 pkg/metric/fake_metric.go create mode 100644 pkg/metric/sentry_profiling.go create mode 100644 pkg/metric/sentry_profiling_fake.go create mode 100644 pkg/sentry/platform/kvm/kvm_profiling.go create mode 100644 pkg/sentry/platform/kvm/kvm_profiling_fake.go diff --git a/pkg/metric/BUILD b/pkg/metric/BUILD index fc99e4798..cb4ef6ae0 100644 --- a/pkg/metric/BUILD +++ b/pkg/metric/BUILD @@ -8,12 +8,12 @@ package( go_library( name = "metric", srcs = [ - "condmetric_profiling.go", - "condmetric_profiling_fake.go", - "fake_metric.go", + "condmetric.go", "metric.go", "metric_unsafe.go", "profiling_metric.go", + "sentry_profiling.go", + "sentry_profiling_fake.go", ], visibility = ["//:sandbox"], deps = [ diff --git a/pkg/metric/condmetric.go b/pkg/metric/condmetric.go new file mode 100644 index 000000000..f929255f5 --- /dev/null +++ b/pkg/metric/condmetric.go @@ -0,0 +1,155 @@ +// Copyright 2022 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package metric + +import ( + "fmt" + + pb "gvisor.dev/gvisor/pkg/metric/metric_go_proto" +) + +// FakeUint64Metric is a type that implements all the methods of a Uint64Metric +// as a no-op. +type FakeUint64Metric struct{} + +// FakeDistributionMetric is a type that implements all the methods of a +// DistributionMetric as a no-op. +type FakeDistributionMetric struct{} + +// FakeTimerMetric is a type that implements all the methods of a TimerMetric +// as a no-op. +type FakeTimerMetric struct{} + +// FakeTimedOperation is a type that implements all the methods of a +// TimedOperation as a no-op. +type FakeTimedOperation struct{} + +// Value from a FakeUint64Metric always returns a meaningless value. +// +//go:nosplit +func (m *FakeUint64Metric) Value(fieldValues ...*FieldValue) uint64 { + return 0 +} + +// Increment on a FakeUint64Metric does nothing. +// +//go:nosplit +func (m *FakeUint64Metric) Increment(fieldValues ...*FieldValue) {} + +// IncrementBy on a FakeUint64Metric does nothing. +// +//go:nosplit +func (m *FakeUint64Metric) IncrementBy(v uint64, fieldValues ...*FieldValue) {} + +// AddSample on a FakeUint64Metric does nothing. +// +//go:nosplit +func (d *FakeDistributionMetric) AddSample(sample int64, fields ...*FieldValue) {} + +// Start on a FakeUint64Metric returns a FakeTimedOperation struct, which does +// nothing and does not keep the time. +// +//go:nosplit +func (t *FakeTimerMetric) Start(fields ...*FieldValue) FakeTimedOperation { + return FakeTimedOperation{} +} + +// Finish on a FakeTimedOperation does nothing. +// +//go:nosplit +func (o FakeTimedOperation) Finish(extraFields ...*FieldValue) {} + +// FakeMetricBuilder is a type used to produce conditionally compiled metrics. +// Methods of this struct produce fake, inactive metrics. +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) { + return &FakeUint64Metric{}, nil +} + +// MustCreateNewUint64Metric creates a fake Uint64 metric. +func (b *FakeMetricBuilder) MustCreateNewUint64Metric(name string, sync bool, description string, fields ...Field) *FakeUint64Metric { + return &FakeUint64Metric{} +} + +// NewDistributionMetric creates a fake distribution metric. +func (b *FakeMetricBuilder) NewDistributionMetric(name string, sync bool, bucketer Bucketer, unit pb.MetricMetadata_Units, description string, fields ...Field) (*FakeDistributionMetric, error) { + return &FakeDistributionMetric{}, nil +} + +// MustCreateNewDistributionMetric creates a fake distribution metric. +func (b *FakeMetricBuilder) MustCreateNewDistributionMetric(name string, sync bool, bucketer Bucketer, unit pb.MetricMetadata_Units, description string, fields ...Field) *FakeDistributionMetric { + return &FakeDistributionMetric{} +} + +// NewTimerMetric creates a fake timer metric. +func (b *FakeMetricBuilder) NewTimerMetric(name string, nanoBucketer Bucketer, description string, fields ...Field) (*FakeTimerMetric, error) { + return &FakeTimerMetric{}, nil +} + +// MustCreateNewTimerMetric creates a fake timer metric. +func (b *FakeMetricBuilder) MustCreateNewTimerMetric(name string, nanoBucketer Bucketer, description string, fields ...Field) *FakeTimerMetric { + return &FakeTimerMetric{} +} + +// RealMetricBuilder is a type used to produce conditionally compiled metrics. +// Methods of this struct produce real active metrics. +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...) + if err != nil { + return m, err + } + definedProfilingMetrics = append(definedProfilingMetrics, m.name) + return m, err +} + +// 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...) + if err != nil { + panic(fmt.Sprintf("Unable to create metric %q: %s", name, err)) + } + return m +} + +// NewDistributionMetric calls the generic metric.NewDistributionMetric to +// produce a real distribution metric. +func (b *RealMetricBuilder) NewDistributionMetric(name string, sync bool, bucketer Bucketer, unit pb.MetricMetadata_Units, description string, fields ...Field) (*DistributionMetric, error) { + return NewDistributionMetric(name, sync, bucketer, unit, description, fields...) +} + +// MustCreateNewDistributionMetric creates a real distribution metric or panics +// if unable to do so. +func (b *RealMetricBuilder) MustCreateNewDistributionMetric(name string, sync bool, bucketer Bucketer, unit pb.MetricMetadata_Units, description string, fields ...Field) *DistributionMetric { + return MustCreateNewDistributionMetric(name, sync, bucketer, unit, description, fields...) +} + +// NewTimerMetric calls the generic metric.NewTimerMetric to produce a real timer +// metric. +func (b *RealMetricBuilder) NewTimerMetric(name string, nanoBucketer Bucketer, description string, fields ...Field) (*TimerMetric, error) { + return NewTimerMetric(name, nanoBucketer, description, fields...) +} + +// MustCreateNewTimerMetric creates a real timer metric or panics if unable to +// do so. +func (b *RealMetricBuilder) MustCreateNewTimerMetric(name string, nanoBucketer Bucketer, description string, fields ...Field) *TimerMetric { + return MustCreateNewTimerMetric(name, nanoBucketer, description, fields...) +} diff --git a/pkg/metric/condmetric_profiling.go b/pkg/metric/condmetric_profiling.go deleted file mode 100644 index 99a7e35c2..000000000 --- a/pkg/metric/condmetric_profiling.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2022 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build condmetric_profiling -// +build condmetric_profiling - -package metric - -import ( - "fmt" - - pb "gvisor.dev/gvisor/pkg/metric/metric_go_proto" -) - -// This file defines conditional metrics that are meant to be used when profiling -// runsc during benchmark tests. - -// ProfilingUint64Metric is a metric type that is registered and used only when -// the "condmetric_profiling" go tag is specified for go build. -// -// Otherwise it is exactly like a Uint64Metric. -type ProfilingUint64Metric = Uint64Metric - -// ProfilingDistributionMetric is a metric type that is registered and used only -// when the "condmetric_profiling" go tag is specified for go build. -// -// Otherwise it is exactly like a DistributionMetric. -type ProfilingDistributionMetric = DistributionMetric - -// ProfilingTimerMetric is a metric type that is registered and used only when -// the "condmetric_profiling" go tag is specified for go build. -// -// Otherwise it is exactly like a TimerMetric. -type ProfilingTimerMetric = TimerMetric - -// NewProfilingUint64Metric is equivalent to NewUint64Metric except it creates a -// ProfilingUint64Metric -var NewProfilingUint64Metric = newProfilingUint64Metric - -// MustCreateNewProfilingUint64Metric is equivalent to MustCreateNewUint64Metric -// except it creates a ProfilingUint64Metric. -var MustCreateNewProfilingUint64Metric = mustCreateNewProfilingUint64Metric - -// NewProfilingDistributionMetric is equivalent to NewDistributionMetric except -// it creates a ProfilingDistributionMetric. -var NewProfilingDistributionMetric = NewDistributionMetric - -// MustCreateNewProfilingDistributionMetric is equivalent to -// MustCreateNewDistributionMetric except it creates a -// ProfilingDistributionMetric. -var MustCreateNewProfilingDistributionMetric = MustCreateNewDistributionMetric - -// NewProfilingTimerMetric is equivalent to NewTimerMetric except it creates a -// ProfilingTimerMetric. -var NewProfilingTimerMetric = NewTimerMetric - -// MustCreateNewProfilingTimerMetric is equivalent to MustCreateNewTimerMetric -// except it creates a ProfilingTimerMetric. -var MustCreateNewProfilingTimerMetric = MustCreateNewTimerMetric - -func newProfilingUint64Metric(name string, sync bool, units pb.MetricMetadata_Units, description string, fields ...Field) (*Uint64Metric, error) { - m, err := NewUint64Metric(name, sync, units, description, fields...) - if err != nil { - return m, err - } - definedProfilingMetrics = append(definedProfilingMetrics, m.name) - return m, err -} - -func mustCreateNewProfilingUint64Metric(name string, sync bool, description string, fields ...Field) *Uint64Metric { - m, err := newProfilingUint64Metric(name, sync, pb.MetricMetadata_UNITS_NONE, description, fields...) - if err != nil { - panic(fmt.Sprintf("Unable to create metric %q: %s", name, err)) - } - return m -} diff --git a/pkg/metric/condmetric_profiling_disabled_test.go b/pkg/metric/condmetric_profiling_disabled_test.go index ac02caacb..45e86ede4 100644 --- a/pkg/metric/condmetric_profiling_disabled_test.go +++ b/pkg/metric/condmetric_profiling_disabled_test.go @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build !condmetric_profiling -// +build !condmetric_profiling +//go:build !sentry_profiling +// +build !sentry_profiling package metric @@ -26,20 +26,20 @@ import ( func TestProfilingMetricsDisabled(t *testing.T) { defer resetTest() - _, err := NewProfilingUint64Metric("counterM", false, pb.MetricMetadata_UNITS_NONE, "One uint64 metric") + _, err := SentryProfiling.NewUint64Metric("/counterM", false, pb.MetricMetadata_UNITS_NONE, "One uint64 metric") if err != nil { - t.Fatalf("NewProfilingUint64Metric got err %v want nil", err) + t.Fatalf("NewUint64Metric got err %v want nil", err) } bucketer := NewExponentialBucketer(3, 2, 0, 1) - _, err = NewProfilingDistributionMetric("distribM", false, bucketer, pb.MetricMetadata_UNITS_NANOSECONDS, "One distribution metric") + _, err = SentryProfiling.NewDistributionMetric("/distribM", false, bucketer, pb.MetricMetadata_UNITS_NANOSECONDS, "One distribution metric") if err != nil { - t.Fatalf("NewProfilingDistributionMetric got err %v want nil", err) + t.Fatalf("NewDistributionMetric got err %v want nil", err) } - _, err = NewProfilingTimerMetric("timerM", bucketer, "One timer metric") + _, err = SentryProfiling.NewTimerMetric("/timerM", bucketer, "One timer metric") if err != nil { - t.Fatalf("NewProfilingTimerMetric got err %v want nil", err) + t.Fatalf("NewTimerMetric got err %v want nil", err) } if err := Initialize(); err != nil { diff --git a/pkg/metric/condmetric_profiling_enabled_test.go b/pkg/metric/condmetric_profiling_enabled_test.go index db64fe3b0..b45288b69 100644 --- a/pkg/metric/condmetric_profiling_enabled_test.go +++ b/pkg/metric/condmetric_profiling_enabled_test.go @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -//go:build condmetric_profiling -// +build condmetric_profiling +//go:build sentry_profiling +// +build sentry_profiling package metric @@ -26,20 +26,20 @@ import ( func TestProfilingMetricsEnabled(t *testing.T) { defer resetTest() - _, err := NewProfilingUint64Metric("counterM", false, pb.MetricMetadata_UNITS_NONE, "One uint64 metric") + _, err := SentryProfiling.NewUint64Metric("/counterM", false, pb.MetricMetadata_UNITS_NONE, "One uint64 metric") if err != nil { - t.Fatalf("NewProfilingUint64Metric got err %v want nil", err) + t.Fatalf("NewUint64Metric got err %v want nil", err) } bucketer := NewExponentialBucketer(3, 2, 0, 1) - _, err = NewProfilingDistributionMetric("distribM", false, bucketer, pb.MetricMetadata_UNITS_NANOSECONDS, "One distribution metric") + _, err = SentryProfiling.NewDistributionMetric("/distribM", false, bucketer, pb.MetricMetadata_UNITS_NANOSECONDS, "One distribution metric") if err != nil { - t.Fatalf("NewProfilingDistributionMetric got err %v want nil", err) + t.Fatalf("NewDistributionMetric got err %v want nil", err) } - _, err = NewProfilingTimerMetric("timerM", bucketer, "One timer metric") + _, err = SentryProfiling.NewTimerMetric("/timerM", bucketer, "One timer metric") if err != nil { - t.Fatalf("NewProfilingTimerMetric got err %v want nil", err) + t.Fatalf("NewTimerMetric got err %v want nil", err) } if err := Initialize(); err != nil { diff --git a/pkg/metric/condmetric_profiling_fake.go b/pkg/metric/condmetric_profiling_fake.go deleted file mode 100644 index 30433a13e..000000000 --- a/pkg/metric/condmetric_profiling_fake.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2022 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//go:build !condmetric_profiling -// +build !condmetric_profiling - -package metric - -// ProfilingUint64Metric is a metric type that is registered and used only when -// the "condmetric_profiling" go tag is specified when building runsc. -// -// Otherwise it is exactly like a Uint64Metric. -type ProfilingUint64Metric = FakeUint64Metric - -// ProfilingDistributionMetric is a metric type that is registered and used only -// when the "condmetric_profiling" go tag is specified when building runsc. -// -// Otherwise it is exactly like a DistributionMetric. -type ProfilingDistributionMetric = FakeDistributionMetric - -// ProfilingTimerMetric is a metric type that is registered and used only when -// the "condmetric_profiling" go tag is specified when building runsc. -// -// Otherwise it is exactly like a TimerMetric. -type ProfilingTimerMetric = FakeTimerMetric - -// NewProfilingUint64Metric is equivalent to NewUint64Metric except it creates a -// ProfilingUint64Metric -var NewProfilingUint64Metric = NewFakeUint64Metric - -// MustCreateNewProfilingUint64Metric is equivalent to MustCreateNewUint64Metric -// except it creates a ProfilingUint64Metric. -var MustCreateNewProfilingUint64Metric = MustCreateNewFakeUint64Metric - -// NewProfilingDistributionMetric is equivalent to NewDistributionMetric except -// it creates a ProfilingDistributionMetric. -var NewProfilingDistributionMetric = NewFakeDistributionMetric - -// MustCreateNewProfilingDistributionMetric is equivalent to -// MustCreateNewDistributionMetric except it creates a -// ProfilingDistributionMetric. -var MustCreateNewProfilingDistributionMetric = MustCreateNewFakeDistributionMetric - -// NewProfilingTimerMetric is equivalent to NewTimerMetric except it creates a -// ProfilingTimerMetric. -var NewProfilingTimerMetric = NewFakeTimerMetric - -// MustCreateNewProfilingTimerMetric is equivalent to MustCreateNewTimerMetric -// except it creates a ProfilingTimerMetric. -var MustCreateNewProfilingTimerMetric = MustCreateNewFakeTimerMetric diff --git a/pkg/metric/fake_metric.go b/pkg/metric/fake_metric.go deleted file mode 100644 index 323f35af2..000000000 --- a/pkg/metric/fake_metric.go +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2022 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package metric - -import pb "gvisor.dev/gvisor/pkg/metric/metric_go_proto" - -// FakeUint64Metric is a type that implements all the methods of a Uint64Metric -// as a no-op. -type FakeUint64Metric struct{} - -// FakeDistributionMetric is a type that implements all the methods of a -// DistributionMetric as a no-op. -type FakeDistributionMetric struct{} - -// FakeTimerMetric is a type that implements all the methods of a TimerMetric -// as a no-op. -type FakeTimerMetric struct{} - -// FakeTimedOperation is a type that implements all the methods of a -// TimedOperation as a no-op. -type FakeTimedOperation struct{} - -// Value from a FakeUint64Metric always returns a meaningless value. -// -//go:nosplit -func (m *FakeUint64Metric) Value(fieldValues ...*FieldValue) uint64 { - return 0 -} - -// Increment on a FakeUint64Metric does nothing. -// -//go:nosplit -func (m *FakeUint64Metric) Increment(fieldValues ...*FieldValue) {} - -// IncrementBy on a FakeUint64Metric does nothing. -// -//go:nosplit -func (m *FakeUint64Metric) IncrementBy(v uint64, fieldValues ...*FieldValue) {} - -// AddSample on a FakeUint64Metric does nothing. -// -//go:nosplit -func (d *FakeDistributionMetric) AddSample(sample int64, fields ...*FieldValue) {} - -// Start on a FakeUint64Metric returns a FakeTimedOperation struct, which does -// nothing and does not keep the time. -// -//go:nosplit -func (t *FakeTimerMetric) Start(fields ...*FieldValue) FakeTimedOperation { - return FakeTimedOperation{} -} - -// Finish on a FakeTimedOperation does nothing. -// -//go:nosplit -func (o FakeTimedOperation) Finish(extraFields ...*FieldValue) {} - -// NewFakeUint64Metric is equivalent to NewUint64Metric except it creates a -// FakeUint64Metric -func NewFakeUint64Metric(name string, sync bool, units pb.MetricMetadata_Units, description string, fields ...Field) (*FakeUint64Metric, error) { - return &FakeUint64Metric{}, nil -} - -// MustCreateNewFakeUint64Metric is equivalent to MustCreateNewUint64Metric -// except it creates a FakeUint64Metric. -func MustCreateNewFakeUint64Metric(name string, sync bool, description string, fields ...Field) *FakeUint64Metric { - return &FakeUint64Metric{} -} - -// NewFakeDistributionMetric is equivalent to NewDistributionMetric except -// it creates a FakeDistributionMetric. -func NewFakeDistributionMetric(name string, sync bool, bucketer Bucketer, unit pb.MetricMetadata_Units, description string, fields ...Field) (*FakeDistributionMetric, error) { - return &FakeDistributionMetric{}, nil -} - -// MustCreateNewFakeDistributionMetric is equivalent to -// MustCreateNewDistributionMetric except it creates a FakeDistributionMetric. -func MustCreateNewFakeDistributionMetric(name string, sync bool, bucketer Bucketer, unit pb.MetricMetadata_Units, description string, fields ...Field) *FakeDistributionMetric { - return &FakeDistributionMetric{} -} - -// NewFakeTimerMetric is equivalent to NewTimerMetric except it creates a -// FakeTimerMetric. -func NewFakeTimerMetric(name string, nanoBucketer Bucketer, description string, fields ...Field) (*FakeTimerMetric, error) { - return &FakeTimerMetric{}, nil -} - -// MustCreateNewFakeTimerMetric is equivalent to MustCreateNewTimerMetric -// except it creates a FakeTimerMetric. -func MustCreateNewFakeTimerMetric(name string, nanoBucketer Bucketer, description string, fields ...Field) *FakeTimerMetric { - return &FakeTimerMetric{} -} diff --git a/pkg/metric/sentry_profiling.go b/pkg/metric/sentry_profiling.go new file mode 100644 index 000000000..41c1facf6 --- /dev/null +++ b/pkg/metric/sentry_profiling.go @@ -0,0 +1,23 @@ +// Copyright 2023 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build sentry_profiling +// +build sentry_profiling + +package metric + +// SentryProfiling is a builder that produces conditionally compiled metrics. +// Metrics made from this are compiled and active at runtime when the +// "sentry_profiling" go-tag is specified at compilation. +var SentryProfiling = RealMetricBuilder{} diff --git a/pkg/metric/sentry_profiling_fake.go b/pkg/metric/sentry_profiling_fake.go new file mode 100644 index 000000000..29a287c46 --- /dev/null +++ b/pkg/metric/sentry_profiling_fake.go @@ -0,0 +1,23 @@ +// Copyright 2023 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !sentry_profiling +// +build !sentry_profiling + +package metric + +// SentryProfiling is a builder that produces conditionally compiled metrics. +// Metrics made from this are compiled and active at runtime when the +// "sentry_profiling" go-tag is specified at compilation. +var SentryProfiling = FakeMetricBuilder{} diff --git a/pkg/sentry/kernel/task.go b/pkg/sentry/kernel/task.go index b26e2496e..06517f005 100644 --- a/pkg/sentry/kernel/task.go +++ b/pkg/sentry/kernel/task.go @@ -610,12 +610,12 @@ type Task struct { var ( // syscallCounter is a metric that tracks how many syscalls the sentry has // executed. - syscallCounter = metric.MustCreateNewProfilingUint64Metric( + syscallCounter = metric.SentryProfiling.MustCreateNewUint64Metric( "/task/syscalls", false, "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.MustCreateNewProfilingUint64Metric( + faultCounter = metric.SentryProfiling.MustCreateNewUint64Metric( "/task/faults", false, "The number of faults the sentry has handled.") ) diff --git a/pkg/sentry/platform/kvm/BUILD b/pkg/sentry/platform/kvm/BUILD index c0b3e8b87..d836ec796 100644 --- a/pkg/sentry/platform/kvm/BUILD +++ b/pkg/sentry/platform/kvm/BUILD @@ -46,6 +46,8 @@ go_library( "kvm_const.go", "kvm_const_amd64.go", "kvm_const_arm64.go", + "kvm_profiling.go", + "kvm_profiling_fake.go", "machine.go", "machine_amd64.go", "machine_amd64_unsafe.go", diff --git a/pkg/sentry/platform/kvm/kvm_profiling.go b/pkg/sentry/platform/kvm/kvm_profiling.go new file mode 100644 index 000000000..362ff1673 --- /dev/null +++ b/pkg/sentry/platform/kvm/kvm_profiling.go @@ -0,0 +1,27 @@ +// Copyright 2023 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build kvm_profiling +// +build kvm_profiling + +package kvm + +import ( + "gvisor.dev/gvisor/pkg/metric" +) + +// KVMProfiling is a builder that produces conditionally compiled metrics. +// Metrics made from this are compiled and active at runtime when the +// "kvm_profiling" go-tag is specified at compilation. +var KVMProfiling = metric.RealMetricBuilder{} diff --git a/pkg/sentry/platform/kvm/kvm_profiling_fake.go b/pkg/sentry/platform/kvm/kvm_profiling_fake.go new file mode 100644 index 000000000..0bf5132a4 --- /dev/null +++ b/pkg/sentry/platform/kvm/kvm_profiling_fake.go @@ -0,0 +1,27 @@ +// Copyright 2023 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//go:build !kvm_profiling +// +build !kvm_profiling + +package kvm + +import ( + "gvisor.dev/gvisor/pkg/metric" +) + +// KVMProfiling is a builder that produces conditionally compiled metrics. +// Metrics made from this are compiled and active at runtime when the +// "kvm_profiling" go-tag is specified at compilation. +var KVMProfiling = metric.FakeMetricBuilder{} diff --git a/pkg/sentry/platform/kvm/machine.go b/pkg/sentry/platform/kvm/machine.go index d1163b23b..9c103b11e 100644 --- a/pkg/sentry/platform/kvm/machine.go +++ b/pkg/sentry/platform/kvm/machine.go @@ -114,32 +114,32 @@ var ( var ( // hostExitCounter is a metric that tracks how many times the sentry // performed a host to guest world switch. - hostExitCounter = metric.MustCreateNewProfilingUint64Metric( + hostExitCounter = KVMProfiling.MustCreateNewUint64Metric( "/kvm/host_exits", false, "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 = metric.MustCreateNewProfilingUint64Metric( + userExitCounter = KVMProfiling.MustCreateNewUint64Metric( "/kvm/user_exits", false, "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 = metric.MustCreateNewProfilingUint64Metric( + interruptCounter = KVMProfiling.MustCreateNewUint64Metric( "/kvm/interrupts", false, "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 = metric.MustCreateNewProfilingUint64Metric( + mmapCallCounter = KVMProfiling.MustCreateNewUint64Metric( "/kvm/mmap_calls", false, "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 = metric.MustCreateNewProfilingUint64Metric( + 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)) // asInvalidateDuration are durations of calling addressSpace.invalidate(). - asInvalidateDuration = metric.MustCreateNewProfilingTimerMetric("/kvm/address_space_invalidate", + asInvalidateDuration = KVMProfiling.MustCreateNewTimerMetric("/kvm/address_space_invalidate", metric.NewExponentialBucketer(15, uint64(time.Nanosecond*100), 1, 2), "Duration of calling addressSpace.invalidate().") )