...

Source file src/go.opentelemetry.io/otel/sdk/trace/benchmark_test.go

Documentation: go.opentelemetry.io/otel/sdk/trace

     1  // Copyright The OpenTelemetry Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package trace_test
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"testing"
    21  	"time"
    22  
    23  	"go.opentelemetry.io/otel/attribute"
    24  	sdktrace "go.opentelemetry.io/otel/sdk/trace"
    25  	"go.opentelemetry.io/otel/trace"
    26  )
    27  
    28  func benchmarkSpanLimits(b *testing.B, limits sdktrace.SpanLimits) {
    29  	tp := sdktrace.NewTracerProvider(sdktrace.WithSpanLimits(limits))
    30  	tracer := tp.Tracer(b.Name())
    31  	ctx := context.Background()
    32  
    33  	const count = 8
    34  
    35  	attrs := []attribute.KeyValue{
    36  		attribute.Bool("bool", true),
    37  		attribute.BoolSlice("boolSlice", []bool{true, false}),
    38  		attribute.Int("int", 42),
    39  		attribute.IntSlice("intSlice", []int{42, -1}),
    40  		attribute.Int64("int64", 42),
    41  		attribute.Int64Slice("int64Slice", []int64{42, -1}),
    42  		attribute.Float64("float64", 42),
    43  		attribute.Float64Slice("float64Slice", []float64{42, -1}),
    44  		attribute.String("string", "value"),
    45  		attribute.StringSlice("stringSlice", []string{"value", "value-1"}),
    46  	}
    47  
    48  	links := make([]trace.Link, count)
    49  	for i := range links {
    50  		links[i] = trace.Link{
    51  			SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
    52  				TraceID: [16]byte{0x01},
    53  				SpanID:  [8]byte{0x01},
    54  			}),
    55  			Attributes: attrs,
    56  		}
    57  	}
    58  
    59  	events := make([]struct {
    60  		name string
    61  		attr []attribute.KeyValue
    62  	}, count)
    63  	for i := range events {
    64  		events[i] = struct {
    65  			name string
    66  			attr []attribute.KeyValue
    67  		}{
    68  			name: fmt.Sprintf("event-%d", i),
    69  			attr: attrs,
    70  		}
    71  	}
    72  
    73  	b.ReportAllocs()
    74  	b.ResetTimer()
    75  
    76  	for i := 0; i < b.N; i++ {
    77  		_, span := tracer.Start(ctx, "span-name", trace.WithLinks(links...))
    78  		span.SetAttributes(attrs...)
    79  		for _, e := range events {
    80  			span.AddEvent(e.name, trace.WithAttributes(e.attr...))
    81  		}
    82  		span.End()
    83  	}
    84  }
    85  
    86  func BenchmarkSpanLimits(b *testing.B) {
    87  	b.Run("AttributeValueLengthLimit", func(b *testing.B) {
    88  		limits := sdktrace.NewSpanLimits()
    89  		limits.AttributeValueLengthLimit = 2
    90  		benchmarkSpanLimits(b, limits)
    91  	})
    92  
    93  	b.Run("AttributeCountLimit", func(b *testing.B) {
    94  		limits := sdktrace.NewSpanLimits()
    95  		limits.AttributeCountLimit = 1
    96  		benchmarkSpanLimits(b, limits)
    97  	})
    98  
    99  	b.Run("EventCountLimit", func(b *testing.B) {
   100  		limits := sdktrace.NewSpanLimits()
   101  		limits.EventCountLimit = 1
   102  		benchmarkSpanLimits(b, limits)
   103  	})
   104  
   105  	b.Run("LinkCountLimit", func(b *testing.B) {
   106  		limits := sdktrace.NewSpanLimits()
   107  		limits.LinkCountLimit = 1
   108  		benchmarkSpanLimits(b, limits)
   109  	})
   110  
   111  	b.Run("AttributePerEventCountLimit", func(b *testing.B) {
   112  		limits := sdktrace.NewSpanLimits()
   113  		limits.AttributePerEventCountLimit = 1
   114  		benchmarkSpanLimits(b, limits)
   115  	})
   116  
   117  	b.Run("AttributePerLinkCountLimit", func(b *testing.B) {
   118  		limits := sdktrace.NewSpanLimits()
   119  		limits.AttributePerLinkCountLimit = 1
   120  		benchmarkSpanLimits(b, limits)
   121  	})
   122  }
   123  
   124  func BenchmarkSpanSetAttributesOverCapacity(b *testing.B) {
   125  	limits := sdktrace.NewSpanLimits()
   126  	limits.AttributeCountLimit = 1
   127  	tp := sdktrace.NewTracerProvider(sdktrace.WithSpanLimits(limits))
   128  	tracer := tp.Tracer("BenchmarkSpanSetAttributesOverCapacity")
   129  	ctx := context.Background()
   130  	attrs := make([]attribute.KeyValue, 128)
   131  	for i := range attrs {
   132  		key := fmt.Sprintf("key-%d", i)
   133  		attrs[i] = attribute.Bool(key, true)
   134  	}
   135  
   136  	b.ReportAllocs()
   137  	b.ResetTimer()
   138  
   139  	for i := 0; i < b.N; i++ {
   140  		_, span := tracer.Start(ctx, "/foo")
   141  		span.SetAttributes(attrs...)
   142  		span.End()
   143  	}
   144  }
   145  
   146  func BenchmarkStartEndSpan(b *testing.B) {
   147  	traceBenchmark(b, "Benchmark StartEndSpan", func(b *testing.B, t trace.Tracer) {
   148  		ctx := context.Background()
   149  		b.ResetTimer()
   150  		for i := 0; i < b.N; i++ {
   151  			_, span := t.Start(ctx, "/foo")
   152  			span.End()
   153  		}
   154  	})
   155  }
   156  
   157  func BenchmarkSpanWithAttributes_4(b *testing.B) {
   158  	traceBenchmark(b, "Benchmark Start With 4 Attributes", func(b *testing.B, t trace.Tracer) {
   159  		ctx := context.Background()
   160  		b.ResetTimer()
   161  
   162  		for i := 0; i < b.N; i++ {
   163  			_, span := t.Start(ctx, "/foo")
   164  			span.SetAttributes(
   165  				attribute.Bool("key1", false),
   166  				attribute.String("key2", "hello"),
   167  				attribute.Int64("key3", 123),
   168  				attribute.Float64("key4", 123.456),
   169  			)
   170  			span.End()
   171  		}
   172  	})
   173  }
   174  
   175  func BenchmarkSpanWithAttributes_8(b *testing.B) {
   176  	traceBenchmark(b, "Benchmark Start With 8 Attributes", func(b *testing.B, t trace.Tracer) {
   177  		ctx := context.Background()
   178  		b.ResetTimer()
   179  
   180  		for i := 0; i < b.N; i++ {
   181  			_, span := t.Start(ctx, "/foo")
   182  			span.SetAttributes(
   183  				attribute.Bool("key1", false),
   184  				attribute.String("key2", "hello"),
   185  				attribute.Int64("key3", 123),
   186  				attribute.Float64("key4", 123.456),
   187  				attribute.Bool("key21", false),
   188  				attribute.String("key22", "hello"),
   189  				attribute.Int64("key23", 123),
   190  				attribute.Float64("key24", 123.456),
   191  			)
   192  			span.End()
   193  		}
   194  	})
   195  }
   196  
   197  func BenchmarkSpanWithAttributes_all(b *testing.B) {
   198  	traceBenchmark(b, "Benchmark Start With all Attribute types", func(b *testing.B, t trace.Tracer) {
   199  		ctx := context.Background()
   200  		b.ResetTimer()
   201  
   202  		for i := 0; i < b.N; i++ {
   203  			_, span := t.Start(ctx, "/foo")
   204  			span.SetAttributes(
   205  				attribute.Bool("key1", false),
   206  				attribute.String("key2", "hello"),
   207  				attribute.Int64("key3", 123),
   208  				attribute.Float64("key7", 123.456),
   209  				attribute.Int("key9", 123),
   210  			)
   211  			span.End()
   212  		}
   213  	})
   214  }
   215  
   216  func BenchmarkSpanWithAttributes_all_2x(b *testing.B) {
   217  	traceBenchmark(b, "Benchmark Start With all Attributes types twice", func(b *testing.B, t trace.Tracer) {
   218  		ctx := context.Background()
   219  		b.ResetTimer()
   220  
   221  		for i := 0; i < b.N; i++ {
   222  			_, span := t.Start(ctx, "/foo")
   223  			span.SetAttributes(
   224  				attribute.Bool("key1", false),
   225  				attribute.String("key2", "hello"),
   226  				attribute.Int64("key3", 123),
   227  				attribute.Float64("key7", 123.456),
   228  				attribute.Int("key10", 123),
   229  				attribute.Bool("key21", false),
   230  				attribute.String("key22", "hello"),
   231  				attribute.Int64("key23", 123),
   232  				attribute.Float64("key27", 123.456),
   233  				attribute.Int("key210", 123),
   234  			)
   235  			span.End()
   236  		}
   237  	})
   238  }
   239  
   240  func BenchmarkSpanWithEvents_4(b *testing.B) {
   241  	traceBenchmark(b, "Benchmark Start With 4 Events", func(b *testing.B, t trace.Tracer) {
   242  		ctx := context.Background()
   243  		b.ResetTimer()
   244  
   245  		for i := 0; i < b.N; i++ {
   246  			_, span := t.Start(ctx, "/foo")
   247  			span.AddEvent("event1")
   248  			span.AddEvent("event2")
   249  			span.AddEvent("event3")
   250  			span.AddEvent("event4")
   251  			span.End()
   252  		}
   253  	})
   254  }
   255  
   256  func BenchmarkSpanWithEvents_8(b *testing.B) {
   257  	traceBenchmark(b, "Benchmark Start With 4 Events", func(b *testing.B, t trace.Tracer) {
   258  		ctx := context.Background()
   259  		b.ResetTimer()
   260  
   261  		for i := 0; i < b.N; i++ {
   262  			_, span := t.Start(ctx, "/foo")
   263  			span.AddEvent("event1")
   264  			span.AddEvent("event2")
   265  			span.AddEvent("event3")
   266  			span.AddEvent("event4")
   267  			span.AddEvent("event5")
   268  			span.AddEvent("event6")
   269  			span.AddEvent("event7")
   270  			span.AddEvent("event8")
   271  			span.End()
   272  		}
   273  	})
   274  }
   275  
   276  func BenchmarkSpanWithEvents_WithStackTrace(b *testing.B) {
   277  	traceBenchmark(b, "Benchmark Start With 4 Attributes", func(b *testing.B, t trace.Tracer) {
   278  		ctx := context.Background()
   279  		b.ResetTimer()
   280  
   281  		for i := 0; i < b.N; i++ {
   282  			_, span := t.Start(ctx, "/foo")
   283  			span.AddEvent("event1", trace.WithStackTrace(true))
   284  			span.End()
   285  		}
   286  	})
   287  }
   288  
   289  func BenchmarkSpanWithEvents_WithTimestamp(b *testing.B) {
   290  	traceBenchmark(b, "Benchmark Start With 4 Attributes", func(b *testing.B, t trace.Tracer) {
   291  		ctx := context.Background()
   292  		b.ResetTimer()
   293  
   294  		for i := 0; i < b.N; i++ {
   295  			_, span := t.Start(ctx, "/foo")
   296  			span.AddEvent("event1", trace.WithTimestamp(time.Unix(0, 0)))
   297  			span.End()
   298  		}
   299  	})
   300  }
   301  
   302  func BenchmarkTraceID_DotString(b *testing.B) {
   303  	t, _ := trace.TraceIDFromHex("0000000000000001000000000000002a")
   304  	sc := trace.NewSpanContext(trace.SpanContextConfig{TraceID: t})
   305  
   306  	want := "0000000000000001000000000000002a"
   307  	for i := 0; i < b.N; i++ {
   308  		if got := sc.TraceID().String(); got != want {
   309  			b.Fatalf("got = %q want = %q", got, want)
   310  		}
   311  	}
   312  }
   313  
   314  func BenchmarkSpanID_DotString(b *testing.B) {
   315  	sc := trace.NewSpanContext(trace.SpanContextConfig{SpanID: trace.SpanID{1}})
   316  	want := "0100000000000000"
   317  	for i := 0; i < b.N; i++ {
   318  		if got := sc.SpanID().String(); got != want {
   319  			b.Fatalf("got = %q want = %q", got, want)
   320  		}
   321  	}
   322  }
   323  
   324  func traceBenchmark(b *testing.B, name string, fn func(*testing.B, trace.Tracer)) {
   325  	b.Run("AlwaysSample", func(b *testing.B) {
   326  		b.ReportAllocs()
   327  		fn(b, tracer(b, name, sdktrace.AlwaysSample()))
   328  	})
   329  	b.Run("NeverSample", func(b *testing.B) {
   330  		b.ReportAllocs()
   331  		fn(b, tracer(b, name, sdktrace.NeverSample()))
   332  	})
   333  }
   334  
   335  func tracer(b *testing.B, name string, sampler sdktrace.Sampler) trace.Tracer {
   336  	tp := sdktrace.NewTracerProvider(sdktrace.WithSampler(sampler))
   337  	return tp.Tracer(name)
   338  }
   339  

View as plain text