1package lightstep_test
2
3import (
4	"bytes"
5	"net/http"
6	"sync/atomic"
7	"testing"
8
9	"github.com/lightstep/lightstep-tracer-common/golang/gogo/collectorpb/collectorpbfakes"
10	. "github.com/lightstep/lightstep-tracer-go"
11	"github.com/opentracing/opentracing-go"
12)
13
14type CountingRecorder int32
15
16func (c *CountingRecorder) RecordSpan(r RawSpan) {
17	atomic.AddInt32((*int32)(c), 1)
18}
19
20func newTestTracer(recorder SpanRecorder) opentracing.Tracer {
21	opts := Options{
22		AccessToken: "token",
23		ConnFactory: fakeGrpcConnection(new(collectorpbfakes.FakeCollectorServiceClient)),
24		Recorder:    recorder,
25	}
26	return NewTracer(opts)
27}
28
29var tags []string
30
31func init() {
32	tags = make([]string, 1000)
33	for j := 0; j < len(tags); j++ {
34		tags[j] = "big string very big huuuuuuuuge"
35	}
36}
37
38func executeOps(sp opentracing.Span, numEvent, numTag, numItems int) {
39	for j := 0; j < numEvent; j++ {
40		sp.LogEvent("event")
41	}
42	for j := 0; j < numTag; j++ {
43		sp.SetTag(tags[j], nil)
44	}
45	for j := 0; j < numItems; j++ {
46		sp.SetBaggageItem(tags[j], tags[j])
47	}
48}
49
50func benchmarkWithOps(b *testing.B, numEvent, numTag, numItems int) {
51	var r CountingRecorder
52	t := newTestTracer(&r)
53	benchmarkWithOpsAndCB(b, func() opentracing.Span {
54		return t.StartSpan("test")
55	}, numEvent, numTag, numItems)
56	if int(r) != b.N {
57		b.Fatalf("missing traces: expected %d, got %d", b.N, r)
58	}
59}
60
61func benchmarkWithOpsAndCB(b *testing.B, create func() opentracing.Span,
62	numEvent, numTag, numItems int) {
63	b.ResetTimer()
64	for i := 0; i < b.N; i++ {
65		sp := create()
66		executeOps(sp, numEvent, numTag, numItems)
67		sp.Finish()
68	}
69	b.StopTimer()
70}
71
72func BenchmarkSpan_Empty(b *testing.B) {
73	benchmarkWithOps(b, 0, 0, 0)
74}
75
76func BenchmarkSpan_100Events(b *testing.B) {
77	benchmarkWithOps(b, 100, 0, 0)
78}
79
80func BenchmarkSpan_1000Events(b *testing.B) {
81	benchmarkWithOps(b, 100, 0, 0)
82}
83
84func BenchmarkSpan_100Tags(b *testing.B) {
85	benchmarkWithOps(b, 0, 100, 0)
86}
87
88func BenchmarkSpan_1000Tags(b *testing.B) {
89	benchmarkWithOps(b, 0, 100, 0)
90}
91
92func BenchmarkSpan_100BaggageItems(b *testing.B) {
93	benchmarkWithOps(b, 0, 0, 100)
94}
95
96func BenchmarkSpan_100Events_100Tags_100BaggageItems(b *testing.B) {
97	var r CountingRecorder
98	t := newTestTracer(&r)
99
100	benchmarkWithOpsAndCB(b, func() opentracing.Span {
101		sp := t.StartSpan("test")
102		return sp
103	}, 100, 100, 100)
104	if int(r) != b.N {
105		b.Fatalf("missing traces: expected %d, got %d", b.N, r)
106	}
107}
108
109func benchmarkInject(b *testing.B, format opentracing.BuiltinFormat, numItems int) {
110	var r CountingRecorder
111	tracer := newTestTracer(&r)
112	sp := tracer.StartSpan("testing")
113	executeOps(sp, 0, 0, numItems)
114	var carrier interface{}
115	switch format {
116	case opentracing.TextMap:
117		carrier = opentracing.HTTPHeadersCarrier(http.Header{})
118	case opentracing.Binary:
119		carrier = &bytes.Buffer{}
120	default:
121		b.Fatalf("unhandled format %d", format)
122	}
123	b.ResetTimer()
124	for i := 0; i < b.N; i++ {
125		err := tracer.Inject(sp.Context(), format, carrier)
126		if err != nil {
127			b.Fatal(err)
128		}
129	}
130}
131
132func benchmarkExtract(b *testing.B, format opentracing.BuiltinFormat, numItems int) {
133	var r CountingRecorder
134	tracer := newTestTracer(&r)
135	sp := tracer.StartSpan("testing")
136	executeOps(sp, 0, 0, numItems)
137	var carrier interface{}
138	switch format {
139	case opentracing.TextMap:
140		carrier = opentracing.HTTPHeadersCarrier(http.Header{})
141	case opentracing.Binary:
142		carrier = &bytes.Buffer{}
143	default:
144		b.Fatalf("unhandled format %d", format)
145	}
146	if err := tracer.Inject(sp.Context(), format, carrier); err != nil {
147		b.Fatal(err)
148	}
149
150	// We create a new bytes.Buffer every time for tracer.Extract() to keep
151	// this benchmark realistic.
152	var rawBinaryBytes []byte
153	if format == opentracing.Binary {
154		rawBinaryBytes = carrier.(*bytes.Buffer).Bytes()
155	}
156	b.ResetTimer()
157	for i := 0; i < b.N; i++ {
158		if format == opentracing.Binary {
159			carrier = bytes.NewBuffer(rawBinaryBytes)
160		}
161		_, err := tracer.Extract(format, carrier)
162		if err != nil {
163			b.Fatal(err)
164		}
165	}
166}
167
168func BenchmarkInject_TextMap_Empty(b *testing.B) {
169	benchmarkInject(b, opentracing.TextMap, 0)
170}
171
172func BenchmarkInject_TextMap_100BaggageItems(b *testing.B) {
173	benchmarkInject(b, opentracing.TextMap, 100)
174}
175
176func BenchmarkJoin_TextMap_Empty(b *testing.B) {
177	benchmarkExtract(b, opentracing.TextMap, 0)
178}
179
180func BenchmarkJoin_TextMap_100BaggageItems(b *testing.B) {
181	benchmarkExtract(b, opentracing.TextMap, 100)
182}
183