You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-09-16 09:26:25 +02:00
Refactor the metric SDK benchmarks (#3992)
Benchmark all instruments, not just an int64 counter. Include benchmarks for all synchronous measurement methods. Include benchmarks for all collections.
This commit is contained in:
@@ -16,134 +16,353 @@ package metric // import "go.opentelemetry.io/otel/sdk/metric"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/metric"
|
||||
"go.opentelemetry.io/otel/metric/instrument"
|
||||
"go.opentelemetry.io/otel/sdk/metric/aggregation"
|
||||
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
||||
)
|
||||
|
||||
func benchCounter(b *testing.B, views ...View) (context.Context, Reader, instrument.Int64Counter) {
|
||||
var viewBenchmarks = []struct {
|
||||
Name string
|
||||
Views []View
|
||||
}{
|
||||
{"NoView", []View{}},
|
||||
{
|
||||
"DropView",
|
||||
[]View{NewView(
|
||||
Instrument{Name: "*"},
|
||||
Stream{Aggregation: aggregation.Drop{}},
|
||||
)},
|
||||
},
|
||||
{
|
||||
"AttrFilterView",
|
||||
[]View{NewView(
|
||||
Instrument{Name: "*"},
|
||||
Stream{AttributeFilter: func(kv attribute.KeyValue) bool {
|
||||
return kv.Key == attribute.Key("K")
|
||||
}},
|
||||
)},
|
||||
},
|
||||
}
|
||||
|
||||
func BenchmarkSyncMeasure(b *testing.B) {
|
||||
for _, bc := range viewBenchmarks {
|
||||
b.Run(bc.Name, benchSyncViews(bc.Views...))
|
||||
}
|
||||
}
|
||||
|
||||
func benchSyncViews(views ...View) func(*testing.B) {
|
||||
ctx := context.Background()
|
||||
rdr := NewManualReader()
|
||||
provider := NewMeterProvider(WithReader(rdr), WithView(views...))
|
||||
cntr, _ := provider.Meter("test").Int64Counter("hello")
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
return ctx, rdr, cntr
|
||||
}
|
||||
|
||||
func BenchmarkCounterAddNoAttrs(b *testing.B) {
|
||||
ctx, _, cntr := benchCounter(b)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
cntr.Add(ctx, 1)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterAddOneAttr(b *testing.B) {
|
||||
ctx, _, cntr := benchCounter(b)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
cntr.Add(ctx, 1, attribute.String("K", "V"))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterAddOneInvalidAttr(b *testing.B) {
|
||||
ctx, _, cntr := benchCounter(b)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
cntr.Add(ctx, 1, attribute.String("", "V"), attribute.String("K", "V"))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterAddSingleUseAttrs(b *testing.B) {
|
||||
ctx, _, cntr := benchCounter(b)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
cntr.Add(ctx, 1, attribute.Int("K", i))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterAddSingleUseInvalidAttrs(b *testing.B) {
|
||||
ctx, _, cntr := benchCounter(b)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
cntr.Add(ctx, 1, attribute.Int("", i), attribute.Int("K", i))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterAddSingleUseFilteredAttrs(b *testing.B) {
|
||||
ctx, _, cntr := benchCounter(b, NewView(
|
||||
Instrument{Name: "*"},
|
||||
Stream{AttributeFilter: func(kv attribute.KeyValue) bool {
|
||||
return kv.Key == attribute.Key("K")
|
||||
}},
|
||||
))
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
cntr.Add(ctx, 1, attribute.Int("L", i), attribute.Int("K", i))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterCollectOneAttr(b *testing.B) {
|
||||
ctx, rdr, cntr := benchCounter(b)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
cntr.Add(ctx, 1, attribute.Int("K", 1))
|
||||
|
||||
_ = rdr.Collect(ctx, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterCollectTenAttrs(b *testing.B) {
|
||||
ctx, rdr, cntr := benchCounter(b)
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
for j := 0; j < 10; j++ {
|
||||
cntr.Add(ctx, 1, attribute.Int("K", j))
|
||||
}
|
||||
_ = rdr.Collect(ctx, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCollectHistograms(b *testing.B) {
|
||||
b.Run("1", benchCollectHistograms(1))
|
||||
b.Run("5", benchCollectHistograms(5))
|
||||
b.Run("10", benchCollectHistograms(10))
|
||||
b.Run("25", benchCollectHistograms(25))
|
||||
}
|
||||
|
||||
func benchCollectHistograms(count int) func(*testing.B) {
|
||||
ctx := context.Background()
|
||||
r := NewManualReader()
|
||||
mtr := NewMeterProvider(
|
||||
WithReader(r),
|
||||
).Meter("sdk/metric/bench/histogram")
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
name := fmt.Sprintf("fake data %d", i)
|
||||
h, _ := mtr.Int64Histogram(name)
|
||||
|
||||
h.Record(ctx, 1)
|
||||
}
|
||||
|
||||
// Store benchmark results in a closure to prevent the compiler from
|
||||
// inlining and skipping the function.
|
||||
var (
|
||||
collectedMetrics metricdata.ResourceMetrics
|
||||
)
|
||||
|
||||
meter := provider.Meter("benchSyncViews")
|
||||
return func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
iCtr, err := meter.Int64Counter("int64-counter")
|
||||
assert.NoError(b, err)
|
||||
b.Run("Int64Counter", benchMeasAttrs(func() measF {
|
||||
return func(attr []attribute.KeyValue) func() {
|
||||
return func() { iCtr.Add(ctx, 1, attr...) }
|
||||
}
|
||||
}()))
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = r.Collect(ctx, &collectedMetrics)
|
||||
if len(collectedMetrics.ScopeMetrics[0].Metrics) != count {
|
||||
b.Fatalf("got %d metrics, want %d", len(collectedMetrics.ScopeMetrics[0].Metrics), count)
|
||||
fCtr, err := meter.Float64Counter("float64-counter")
|
||||
assert.NoError(b, err)
|
||||
b.Run("Float64Counter", benchMeasAttrs(func() measF {
|
||||
return func(attr []attribute.KeyValue) func() {
|
||||
return func() { fCtr.Add(ctx, 1, attr...) }
|
||||
}
|
||||
}()))
|
||||
|
||||
iUDCtr, err := meter.Int64UpDownCounter("int64-up-down-counter")
|
||||
assert.NoError(b, err)
|
||||
b.Run("Int64UpDownCounter", benchMeasAttrs(func() measF {
|
||||
return func(attr []attribute.KeyValue) func() {
|
||||
return func() { iUDCtr.Add(ctx, 1, attr...) }
|
||||
}
|
||||
}()))
|
||||
|
||||
fUDCtr, err := meter.Float64UpDownCounter("float64-up-down-counter")
|
||||
assert.NoError(b, err)
|
||||
b.Run("Float64UpDownCounter", benchMeasAttrs(func() measF {
|
||||
return func(attr []attribute.KeyValue) func() {
|
||||
return func() { fUDCtr.Add(ctx, 1, attr...) }
|
||||
}
|
||||
}()))
|
||||
|
||||
iHist, err := meter.Int64Histogram("int64-histogram")
|
||||
assert.NoError(b, err)
|
||||
b.Run("Int64Histogram", benchMeasAttrs(func() measF {
|
||||
return func(attr []attribute.KeyValue) func() {
|
||||
return func() { iHist.Record(ctx, 1, attr...) }
|
||||
}
|
||||
}()))
|
||||
|
||||
fHist, err := meter.Float64Histogram("float64-histogram")
|
||||
assert.NoError(b, err)
|
||||
b.Run("Float64Histogram", benchMeasAttrs(func() measF {
|
||||
return func(attr []attribute.KeyValue) func() {
|
||||
return func() { fHist.Record(ctx, 1, attr...) }
|
||||
}
|
||||
}()))
|
||||
}
|
||||
}
|
||||
|
||||
type measF func(attr []attribute.KeyValue) func()
|
||||
|
||||
func benchMeasAttrs(meas measF) func(*testing.B) {
|
||||
return func(b *testing.B) {
|
||||
b.Run("Attributes/0", func(b *testing.B) {
|
||||
f := meas(nil)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
f()
|
||||
}
|
||||
})
|
||||
b.Run("Attributes/1", func(b *testing.B) {
|
||||
attrs := []attribute.KeyValue{attribute.Bool("K", true)}
|
||||
f := meas(attrs)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
f()
|
||||
}
|
||||
})
|
||||
b.Run("Attributes/10", func(b *testing.B) {
|
||||
n := 10
|
||||
attrs := make([]attribute.KeyValue, 0)
|
||||
attrs = append(attrs, attribute.Bool("K", true))
|
||||
for i := 2; i < n; i++ {
|
||||
attrs = append(attrs, attribute.Int(strconv.Itoa(i), i))
|
||||
}
|
||||
f := meas(attrs)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
f()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCollect(b *testing.B) {
|
||||
for _, bc := range viewBenchmarks {
|
||||
b.Run(bc.Name, benchCollectViews(bc.Views...))
|
||||
}
|
||||
}
|
||||
|
||||
func benchCollectViews(views ...View) func(*testing.B) {
|
||||
setup := func(name string) (metric.Meter, Reader) {
|
||||
r := NewManualReader()
|
||||
mp := NewMeterProvider(WithReader(r), WithView(views...))
|
||||
return mp.Meter(name), r
|
||||
}
|
||||
ctx := context.Background()
|
||||
return func(b *testing.B) {
|
||||
b.Run("Int64Counter/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64Counter")
|
||||
i, err := m.Int64Counter("int64-counter")
|
||||
assert.NoError(b, err)
|
||||
i.Add(ctx, 1, attr...)
|
||||
return r
|
||||
}))
|
||||
b.Run("Int64Counter/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64Counter")
|
||||
i, err := m.Int64Counter("int64-counter")
|
||||
assert.NoError(b, err)
|
||||
for n := 0; n < 10; n++ {
|
||||
i.Add(ctx, 1, attr...)
|
||||
}
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Float64Counter/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64Counter")
|
||||
i, err := m.Float64Counter("float64-counter")
|
||||
assert.NoError(b, err)
|
||||
i.Add(ctx, 1, attr...)
|
||||
return r
|
||||
}))
|
||||
b.Run("Float64Counter/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64Counter")
|
||||
i, err := m.Float64Counter("float64-counter")
|
||||
assert.NoError(b, err)
|
||||
for n := 0; n < 10; n++ {
|
||||
i.Add(ctx, 1, attr...)
|
||||
}
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Int64UpDownCounter/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64UpDownCounter")
|
||||
i, err := m.Int64UpDownCounter("int64-up-down-counter")
|
||||
assert.NoError(b, err)
|
||||
i.Add(ctx, 1, attr...)
|
||||
return r
|
||||
}))
|
||||
b.Run("Int64UpDownCounter/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64UpDownCounter")
|
||||
i, err := m.Int64UpDownCounter("int64-up-down-counter")
|
||||
assert.NoError(b, err)
|
||||
for n := 0; n < 10; n++ {
|
||||
i.Add(ctx, 1, attr...)
|
||||
}
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Float64UpDownCounter/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64UpDownCounter")
|
||||
i, err := m.Float64UpDownCounter("float64-up-down-counter")
|
||||
assert.NoError(b, err)
|
||||
i.Add(ctx, 1, attr...)
|
||||
return r
|
||||
}))
|
||||
b.Run("Float64UpDownCounter/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64UpDownCounter")
|
||||
i, err := m.Float64UpDownCounter("float64-up-down-counter")
|
||||
assert.NoError(b, err)
|
||||
for n := 0; n < 10; n++ {
|
||||
i.Add(ctx, 1, attr...)
|
||||
}
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Int64Histogram/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64Histogram")
|
||||
i, err := m.Int64Histogram("int64-histogram")
|
||||
assert.NoError(b, err)
|
||||
i.Record(ctx, 1, attr...)
|
||||
return r
|
||||
}))
|
||||
b.Run("Int64Histogram/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64Histogram")
|
||||
i, err := m.Int64Histogram("int64-histogram")
|
||||
assert.NoError(b, err)
|
||||
for n := 0; n < 10; n++ {
|
||||
i.Record(ctx, 1, attr...)
|
||||
}
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Float64Histogram/1", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64Histogram")
|
||||
i, err := m.Float64Histogram("float64-histogram")
|
||||
assert.NoError(b, err)
|
||||
i.Record(ctx, 1, attr...)
|
||||
return r
|
||||
}))
|
||||
b.Run("Float64Histogram/10", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64Histogram")
|
||||
i, err := m.Float64Histogram("float64-histogram")
|
||||
assert.NoError(b, err)
|
||||
for n := 0; n < 10; n++ {
|
||||
i.Record(ctx, 1, attr...)
|
||||
}
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Int64ObservableCounter", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64ObservableCounter")
|
||||
_, err := m.Int64ObservableCounter(
|
||||
"int64-observable-counter",
|
||||
instrument.WithInt64Callback(int64Cback(attr)),
|
||||
)
|
||||
assert.NoError(b, err)
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Float64ObservableCounter", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64ObservableCounter")
|
||||
_, err := m.Float64ObservableCounter(
|
||||
"float64-observable-counter",
|
||||
instrument.WithFloat64Callback(float64Cback(attr)),
|
||||
)
|
||||
assert.NoError(b, err)
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Int64ObservableUpDownCounter", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64ObservableUpDownCounter")
|
||||
_, err := m.Int64ObservableUpDownCounter(
|
||||
"int64-observable-up-down-counter",
|
||||
instrument.WithInt64Callback(int64Cback(attr)),
|
||||
)
|
||||
assert.NoError(b, err)
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Float64ObservableUpDownCounter", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64ObservableUpDownCounter")
|
||||
_, err := m.Float64ObservableUpDownCounter(
|
||||
"float64-observable-up-down-counter",
|
||||
instrument.WithFloat64Callback(float64Cback(attr)),
|
||||
)
|
||||
assert.NoError(b, err)
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Int64ObservableGauge", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Int64ObservableGauge")
|
||||
_, err := m.Int64ObservableGauge(
|
||||
"int64-observable-gauge",
|
||||
instrument.WithInt64Callback(int64Cback(attr)),
|
||||
)
|
||||
assert.NoError(b, err)
|
||||
return r
|
||||
}))
|
||||
|
||||
b.Run("Float64ObservableGauge", benchCollectAttrs(func(attr []attribute.KeyValue) Reader {
|
||||
m, r := setup("benchCollectViews/Float64ObservableGauge")
|
||||
_, err := m.Float64ObservableGauge(
|
||||
"float64-observable-gauge",
|
||||
instrument.WithFloat64Callback(float64Cback(attr)),
|
||||
)
|
||||
assert.NoError(b, err)
|
||||
return r
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func int64Cback(attr []attribute.KeyValue) instrument.Int64Callback {
|
||||
return func(_ context.Context, o instrument.Int64Observer) error {
|
||||
o.Observe(1, attr...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func float64Cback(attr []attribute.KeyValue) instrument.Float64Callback {
|
||||
return func(_ context.Context, o instrument.Float64Observer) error {
|
||||
o.Observe(1, attr...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func benchCollectAttrs(setup func([]attribute.KeyValue) Reader) func(*testing.B) {
|
||||
ctx := context.Background()
|
||||
out := new(metricdata.ResourceMetrics)
|
||||
run := func(reader Reader) func(b *testing.B) {
|
||||
return func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for n := 0; n < b.N; n++ {
|
||||
_ = reader.Collect(ctx, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
return func(b *testing.B) {
|
||||
b.Run("Attributes/0", run(setup(nil)))
|
||||
|
||||
attrs := []attribute.KeyValue{attribute.Bool("K", true)}
|
||||
b.Run("Attributes/1", run(setup(attrs)))
|
||||
|
||||
for i := 2; i < 10; i++ {
|
||||
attrs = append(attrs, attribute.Int(strconv.Itoa(i), i))
|
||||
}
|
||||
b.Run("Attributes/10", run(setup(attrs)))
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user