1
2
3
4
5
6
7
8
9
10
11
12
13
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