1package diodes_test
2
3import (
4	"crypto/rand"
5	"io/ioutil"
6	"log"
7	"os"
8	"sync"
9	"testing"
10	"time"
11
12	"code.cloudfoundry.org/go-diodes"
13)
14
15var randData = randDataGen()
16
17func TestMain(m *testing.M) {
18	log.SetOutput(ioutil.Discard)
19
20	os.Exit(m.Run())
21}
22
23func BenchmarkOneToOnePoller(b *testing.B) {
24	d := diodes.NewPoller(diodes.NewOneToOne(b.N, diodes.AlertFunc(func(missed int) {
25		panic("Oops...")
26	})))
27
28	var wg sync.WaitGroup
29	wg.Add(1)
30	defer wg.Wait()
31
32	go func() {
33		defer wg.Done()
34		for i := 0; i < b.N; i++ {
35			data := randData(i)
36			d.Set(diodes.GenericDataType(data))
37		}
38	}()
39
40	b.ResetTimer()
41
42	for i := 0; i < b.N; i++ {
43		d.Next()
44	}
45}
46
47func BenchmarkOneToOneWaiter(b *testing.B) {
48	d := diodes.NewWaiter(diodes.NewOneToOne(b.N, diodes.AlertFunc(func(missed int) {
49		panic("Oops...")
50	})))
51
52	var wg sync.WaitGroup
53	wg.Add(1)
54	defer wg.Wait()
55
56	go func() {
57		defer wg.Done()
58		for i := 0; i < b.N; i++ {
59			data := randData(i)
60			d.Set(diodes.GenericDataType(data))
61		}
62	}()
63
64	b.ResetTimer()
65
66	for i := 0; i < b.N; i++ {
67		d.Next()
68	}
69}
70
71func BenchmarkManyToOnePoller(b *testing.B) {
72	d := diodes.NewPoller(diodes.NewManyToOne(b.N, diodes.AlertFunc(func(missed int) {
73		panic("Oops...")
74	})))
75
76	var wg sync.WaitGroup
77	wg.Add(1)
78	defer wg.Wait()
79
80	go func() {
81		defer wg.Done()
82		for i := 0; i < b.N; i++ {
83			data := randData(i)
84			d.Set(diodes.GenericDataType(data))
85		}
86	}()
87
88	b.ResetTimer()
89
90	for i := 0; i < b.N; i++ {
91		d.Next()
92	}
93}
94
95func BenchmarkManyToOneWaiter(b *testing.B) {
96	d := diodes.NewWaiter(diodes.NewManyToOne(b.N, diodes.AlertFunc(func(missed int) {
97		panic("Oops...")
98	})))
99
100	var wg sync.WaitGroup
101	wg.Add(1)
102	defer wg.Wait()
103
104	go func() {
105		defer wg.Done()
106		for i := 0; i < b.N; i++ {
107			data := randData(i)
108			d.Set(diodes.GenericDataType(data))
109		}
110	}()
111
112	b.ResetTimer()
113
114	for i := 0; i < b.N; i++ {
115		d.Next()
116	}
117}
118
119func BenchmarkChannel(b *testing.B) {
120	c := make(chan []byte, b.N)
121
122	var wg sync.WaitGroup
123	wg.Add(1)
124	defer wg.Wait()
125
126	go func() {
127		defer wg.Done()
128		for i := 0; i < b.N; i++ {
129			data := randData(i)
130			c <- *data
131		}
132	}()
133
134	b.ResetTimer()
135
136	for i := 0; i < b.N; i++ {
137		<-c
138	}
139}
140
141func BenchmarkOneToOnePollerDrain(b *testing.B) {
142	d := diodes.NewPoller(diodes.NewOneToOne(100, diodes.AlertFunc(func(missed int) {
143		// NOP
144	})))
145
146	var wg sync.WaitGroup
147	wg.Add(1)
148
149	go func() {
150		wg.Done()
151		for {
152			d.Next()
153		}
154	}()
155
156	wg.Wait()
157	b.ResetTimer()
158
159	for i := 0; i < b.N; i++ {
160		data := randData(i)
161		d.Set(diodes.GenericDataType(data))
162	}
163}
164
165func BenchmarkOneToOneWaiterDrain(b *testing.B) {
166	d := diodes.NewWaiter(diodes.NewOneToOne(100, diodes.AlertFunc(func(missed int) {
167		// NOP
168	})))
169
170	var wg sync.WaitGroup
171	wg.Add(1)
172	go func() {
173		wg.Done()
174		for {
175			d.Next()
176		}
177	}()
178
179	wg.Wait()
180	b.ResetTimer()
181
182	for i := 0; i < b.N; i++ {
183		data := randData(i)
184		d.Set(diodes.GenericDataType(data))
185	}
186}
187
188func BenchmarkChannelDrain(b *testing.B) {
189	c := make(chan []byte, 100)
190	var wg sync.WaitGroup
191	wg.Add(1)
192
193	go func() {
194		wg.Done()
195		for range c {
196		}
197	}()
198
199	wg.Wait()
200	b.ResetTimer()
201
202	for i := 0; i < b.N; i++ {
203		data := randData(i)
204		select {
205		case c <- *data:
206		default:
207			drainChannel(c)
208		}
209	}
210}
211
212func BenchmarkManyWritersDiode(b *testing.B) {
213	d := diodes.NewWaiter(diodes.NewManyToOne(10000, diodes.AlertFunc(func(int) {
214		// NOP
215	})))
216
217	var wg sync.WaitGroup
218	wg.Add(1)
219
220	go func() {
221		wg.Done()
222		for {
223			d.Next()
224			time.Sleep(100 * time.Millisecond)
225		}
226	}()
227
228	wg.Wait()
229	b.ResetTimer()
230	b.RunParallel(func(pb *testing.PB) {
231		var i int
232		for pb.Next() {
233			data := randData(i)
234			i++
235			d.Set(diodes.GenericDataType(data))
236		}
237	})
238}
239
240func BenchmarkManyWritersChannel(b *testing.B) {
241	c := make(chan []byte, 10000)
242
243	var wg sync.WaitGroup
244	wg.Add(1)
245
246	go func() {
247		wg.Done()
248		for range c {
249			time.Sleep(100 * time.Millisecond)
250		}
251	}()
252
253	wg.Wait()
254	b.ResetTimer()
255	b.RunParallel(func(pb *testing.PB) {
256		var i int
257		for pb.Next() {
258			data := randData(i)
259			i++
260			select {
261			case c <- *data:
262			default:
263				drainChannel(c)
264			}
265		}
266	})
267}
268
269func drainChannel(c chan []byte) {
270	for {
271		select {
272		case <-c:
273		default:
274			return
275		}
276	}
277}
278
279func randDataGen() func(int) *[]byte {
280	var (
281		data [][]byte
282	)
283
284	for j := 0; j < 5; j++ {
285		buffer := make([]byte, 100)
286		rand.Read(buffer)
287		data = append(data, buffer)
288	}
289
290	return func(i int) *[]byte {
291		return &data[i%len(data)]
292	}
293}
294