1package statsd_test
2
3import (
4	"fmt"
5	"io"
6	"log"
7	"net"
8	"os"
9	"sync/atomic"
10	"testing"
11
12	"github.com/DataDog/datadog-go/statsd"
13)
14
15func setupUDSClientServer(b *testing.B, options []statsd.Option) (*statsd.Client, net.Listener) {
16	sockAddr := "/tmp/test.sock"
17	if err := os.RemoveAll(sockAddr); err != nil {
18		log.Fatal(err)
19	}
20	conn, err := net.Listen("unix", sockAddr)
21	if err != nil {
22		log.Fatal("listen error:", err)
23	}
24	go func() {
25		for {
26			_, err := conn.Accept()
27			if err != nil {
28				return
29			}
30		}
31	}()
32	client, err := statsd.New("unix://"+sockAddr, options...)
33	if err != nil {
34		b.Error(err)
35	}
36	return client, conn
37}
38
39func setupUDPClientServer(b *testing.B, options []statsd.Option) (*statsd.Client, *net.UDPConn) {
40	addr, err := net.ResolveUDPAddr("udp", ":0")
41	if err != nil {
42		b.Error(err)
43	}
44	conn, err := net.ListenUDP("udp", addr)
45	if err != nil {
46		b.Error(err)
47	}
48
49	client, err := statsd.New(conn.LocalAddr().String(), options...)
50	if err != nil {
51		b.Error(err)
52	}
53	return client, conn
54}
55
56func setupClient(b *testing.B, transport string, extraOptions []statsd.Option) (*statsd.Client, io.Closer) {
57	options := []statsd.Option{statsd.WithMaxMessagesPerPayload(1024), statsd.WithoutTelemetry()}
58	options = append(options, extraOptions...)
59
60	if transport == statsd.WriterNameUDP {
61		return setupUDPClientServer(b, options)
62	}
63	return setupUDSClientServer(b, options)
64}
65
66func benchmarkStatsdDifferentMetrics(b *testing.B, transport string, extraOptions ...statsd.Option) {
67	client, conn := setupClient(b, transport, extraOptions)
68	defer conn.Close()
69
70	n := int32(0)
71	b.ResetTimer()
72
73	b.RunParallel(func(pb *testing.PB) {
74		testNumber := atomic.AddInt32(&n, 1)
75		name := fmt.Sprintf("test.metric%d", testNumber)
76		for pb.Next() {
77			client.Gauge(name, 1, []string{"tag:tag"}, 1)
78		}
79	})
80	client.Flush()
81	t := client.FlushTelemetryMetrics()
82	reportMetric(b, float64(t.TotalDroppedOnReceive)/float64(t.TotalMetrics)*100, "%_dropRate")
83
84	b.StopTimer()
85	client.Close()
86}
87
88func benchmarkStatsdSameMetrics(b *testing.B, transport string, extraOptions ...statsd.Option) {
89	client, conn := setupClient(b, transport, extraOptions)
90	defer conn.Close()
91
92	b.ResetTimer()
93
94	b.RunParallel(func(pb *testing.PB) {
95		for pb.Next() {
96			client.Gauge("test.metric", 1, []string{"tag:tag"}, 1)
97		}
98	})
99	client.Flush()
100	t := client.FlushTelemetryMetrics()
101	reportMetric(b, float64(t.TotalDroppedOnReceive)/float64(t.TotalMetrics)*100, "%_dropRate")
102
103	b.StopTimer()
104	client.Close()
105}
106
107/*
108UDP with the same metric
109*/
110
111// blocking + no aggregation
112func BenchmarkStatsdUDPSameMetricMutex(b *testing.B) {
113	benchmarkStatsdSameMetrics(b, statsd.WriterNameUDP, statsd.WithMutexMode(), statsd.WithoutClientSideAggregation())
114}
115
116// dropping + no aggregation
117func BenchmarkStatsdUDPSameMetricChannel(b *testing.B) {
118	benchmarkStatsdSameMetrics(b, statsd.WriterNameUDP, statsd.WithChannelMode(), statsd.WithoutClientSideAggregation())
119}
120
121// blocking + aggregation
122func BenchmarkStatsdUDPSameMetricMutexAggregation(b *testing.B) {
123	benchmarkStatsdSameMetrics(b, statsd.WriterNameUDP, statsd.WithMutexMode(), statsd.WithClientSideAggregation())
124}
125
126// dropping + aggregation
127func BenchmarkStatsdUDPSameMetricChannelAggregation(b *testing.B) {
128	benchmarkStatsdSameMetrics(b, statsd.WriterNameUDP, statsd.WithChannelMode(), statsd.WithClientSideAggregation())
129}
130
131/*
132UDP with the different metrics
133*/
134
135// blocking + no aggregation
136func BenchmarkStatsdUDPDifferentMetricMutex(b *testing.B) {
137	benchmarkStatsdDifferentMetrics(b, statsd.WriterNameUDP, statsd.WithMutexMode(), statsd.WithoutClientSideAggregation())
138}
139
140// dropping + no aggregation
141func BenchmarkStatsdUDPDifferentMetricChannel(b *testing.B) {
142	benchmarkStatsdDifferentMetrics(b, statsd.WriterNameUDP, statsd.WithChannelMode(), statsd.WithoutClientSideAggregation())
143}
144
145// blocking + aggregation
146func BenchmarkStatsdUDPDifferentMetricMutexAggregation(b *testing.B) {
147	benchmarkStatsdDifferentMetrics(b, statsd.WriterNameUDP, statsd.WithMutexMode(), statsd.WithClientSideAggregation())
148}
149
150// dropping + aggregation
151func BenchmarkStatsdUDPDifferentMetricChannelAggregation(b *testing.B) {
152	benchmarkStatsdDifferentMetrics(b, statsd.WriterNameUDP, statsd.WithChannelMode(), statsd.WithClientSideAggregation())
153}
154
155/*
156UDS with the same metric
157*/
158// blocking + no aggregation
159func BenchmarkStatsdUDSSameMetricMutex(b *testing.B) {
160	benchmarkStatsdSameMetrics(b, statsd.WriterNameUDS, statsd.WithMutexMode(), statsd.WithoutClientSideAggregation())
161}
162
163// dropping + no aggregation
164func BenchmarkStatsdUDSSameMetricChannel(b *testing.B) {
165	benchmarkStatsdSameMetrics(b, statsd.WriterNameUDS, statsd.WithChannelMode(), statsd.WithoutClientSideAggregation())
166}
167
168// blocking + aggregation
169func BenchmarkStatsdUDSSameMetricMutexAggregation(b *testing.B) {
170	benchmarkStatsdSameMetrics(b, statsd.WriterNameUDS, statsd.WithMutexMode(), statsd.WithClientSideAggregation())
171}
172
173// dropping + aggregation
174func BenchmarkStatsdUDSSameMetricChannelAggregation(b *testing.B) {
175	benchmarkStatsdSameMetrics(b, statsd.WriterNameUDS, statsd.WithChannelMode(), statsd.WithClientSideAggregation())
176}
177
178/*
179UDS with different metrics
180*/
181// blocking + no aggregation
182func BenchmarkStatsdUDPSifferentMetricMutex(b *testing.B) {
183	benchmarkStatsdDifferentMetrics(b, statsd.WriterNameUDS, statsd.WithMutexMode(), statsd.WithoutClientSideAggregation())
184}
185
186// dropping + no aggregation
187func BenchmarkStatsdUDSDifferentMetricChannel(b *testing.B) {
188	benchmarkStatsdDifferentMetrics(b, statsd.WriterNameUDS, statsd.WithChannelMode(), statsd.WithoutClientSideAggregation())
189}
190
191// blocking + aggregation
192func BenchmarkStatsdUDPSifferentMetricMutexAggregation(b *testing.B) {
193	benchmarkStatsdDifferentMetrics(b, statsd.WriterNameUDS, statsd.WithMutexMode(), statsd.WithClientSideAggregation())
194}
195
196// dropping + aggregation
197func BenchmarkStatsdUDSDifferentMetricChannelAggregation(b *testing.B) {
198	benchmarkStatsdDifferentMetrics(b, statsd.WriterNameUDS, statsd.WithChannelMode(), statsd.WithClientSideAggregation())
199}
200