Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 8f8a6a6

Browse files
committed
Add benchmarks to spdy implementation
Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
1 parent 3d0b138 commit 8f8a6a6

1 file changed

Lines changed: 378 additions & 0 deletions

File tree

spdy/bench_test.go

Lines changed: 378 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
package spdy
2+
3+
import (
4+
"io"
5+
"os"
6+
"runtime/pprof"
7+
"testing"
8+
"time"
9+
10+
"github.com/docker/libchan"
11+
)
12+
13+
var (
14+
testPipe = Pipe
15+
)
16+
17+
type SimpleStruct struct {
18+
Value int
19+
}
20+
21+
func SimpleStructFuncs(b *testing.B) (BenchMessageSender, BenchMessageReceiver) {
22+
sender := func(i int, s libchan.Sender) {
23+
if err := s.Send(&SimpleStruct{i}); err != nil {
24+
b.Fatalf("Error sending message: %s", err)
25+
}
26+
}
27+
receiver := func(i int, r libchan.Receiver) {
28+
var v SimpleStruct
29+
if err := r.Receive(&v); err != nil {
30+
b.Fatalf("Error receiving: %s", err)
31+
}
32+
if v.Value != i {
33+
b.Fatalf("Unexpected value received: %d != %d", v, i)
34+
}
35+
}
36+
return sender, receiver
37+
}
38+
39+
func BenchmarkSimpleCopy(b *testing.B) {
40+
sender, receiver := SimpleStructFuncs(b)
41+
SpawnProxyBench(b, sender, receiver)
42+
}
43+
44+
func BenchmarkSimpleLocalProxy(b *testing.B) {
45+
sender, receiver := SimpleStructFuncs(b)
46+
SpawnLocalProxyBench(b, sender, receiver)
47+
}
48+
49+
func BenchmarkSimpleSpdyProxy(b *testing.B) {
50+
sender, receiver := SimpleStructFuncs(b)
51+
SpawnSpdyProxyBench(b, sender, receiver)
52+
}
53+
54+
func BenchmarkSimpleNoProxy(b *testing.B) {
55+
sender, receiver := SimpleStructFuncs(b)
56+
SpawnNoProxyBench(b, sender, receiver)
57+
}
58+
59+
func BenchmarkSimpleLocalPipe(b *testing.B) {
60+
sender, receiver := SimpleStructFuncs(b)
61+
SpawnLocalPipeBench(b, sender, receiver)
62+
}
63+
64+
type ComplexStruct struct {
65+
Value int
66+
Sender libchan.Sender
67+
Reader io.Reader
68+
}
69+
70+
func ComplexStructFuncs(b *testing.B) (BenchMessageSender, BenchMessageReceiver) {
71+
sender := func(i int, s libchan.Sender) {
72+
r, _ := io.Pipe()
73+
_, send := libchan.Pipe()
74+
v := &ComplexStruct{
75+
Value: i,
76+
Sender: send,
77+
Reader: r,
78+
}
79+
if err := s.Send(v); err != nil {
80+
b.Fatalf("Error sending message: %s", err)
81+
}
82+
}
83+
receiver := func(i int, r libchan.Receiver) {
84+
var v ComplexStruct
85+
if err := r.Receive(&v); err != nil {
86+
b.Fatalf("Error receiving: %s", err)
87+
}
88+
if v.Value != i {
89+
b.Fatalf("Unexpected value received: %d != %d", v.Value, i)
90+
}
91+
}
92+
return sender, receiver
93+
}
94+
95+
func BenchmarkComplexCopy(b *testing.B) {
96+
sender, receiver := ComplexStructFuncs(b)
97+
SpawnProxyBench(b, sender, receiver)
98+
}
99+
100+
func BenchmarkComplexLocalProxy(b *testing.B) {
101+
sender, receiver := ComplexStructFuncs(b)
102+
SpawnLocalProxyBench(b, sender, receiver)
103+
}
104+
105+
func BenchmarkComplexSpdyProxy(b *testing.B) {
106+
sender, receiver := ComplexStructFuncs(b)
107+
SpawnSpdyProxyBench(b, sender, receiver)
108+
}
109+
110+
func BenchmarkComplexNoProxy(b *testing.B) {
111+
sender, receiver := ComplexStructFuncs(b)
112+
SpawnNoProxyBench(b, sender, receiver)
113+
}
114+
115+
func BenchmarkComplexLocalPipe(b *testing.B) {
116+
sender, receiver := ComplexStructFuncs(b)
117+
SpawnLocalPipeBench(b, sender, receiver)
118+
}
119+
120+
type BenchMessageSender func(int, libchan.Sender)
121+
type BenchMessageReceiver func(int, libchan.Receiver)
122+
123+
func BenchProxy(b *testing.B, c chan bool, sender libchan.Sender, receiver libchan.Receiver, count int) {
124+
defer close(c)
125+
n, err := libchan.Copy(sender, receiver)
126+
if err != nil {
127+
b.Errorf("Error proxying: %s", err)
128+
}
129+
err = sender.Close()
130+
if err != nil {
131+
b.Errorf("Error closing sender: %s", err)
132+
}
133+
if n != count {
134+
b.Errorf("Wrong proxy count\n\tExpected: %d\n\tActual: %d", count, n)
135+
}
136+
}
137+
138+
func BenchClient(b *testing.B, c chan bool, sender libchan.Sender, sendFunc BenchMessageSender, count int) {
139+
defer close(c)
140+
for i := 0; i < count; i++ {
141+
sendFunc(i, sender)
142+
}
143+
err := sender.Close()
144+
if err != nil {
145+
b.Fatalf("Error closing sender: %s", err)
146+
}
147+
}
148+
149+
func BenchServer(b *testing.B, c chan bool, receiver libchan.Receiver, recvFunc BenchMessageReceiver, count int) {
150+
defer close(c)
151+
for i := 0; i < count; i++ {
152+
recvFunc(i, receiver)
153+
}
154+
}
155+
156+
func SpawnProxyBench(b *testing.B, sender BenchMessageSender, receiver BenchMessageReceiver) {
157+
endClient := make(chan bool)
158+
endServer := make(chan bool)
159+
endProxy := make(chan bool)
160+
161+
receiver1, sender1, err := testPipe()
162+
if err != nil {
163+
b.Fatalf("Error creating pipe: %s", err)
164+
}
165+
receiver2, sender2, err := testPipe()
166+
if err != nil {
167+
b.Fatalf("Error creating pipe: %s", err)
168+
}
169+
170+
go BenchProxy(b, endProxy, sender2, receiver1, b.N)
171+
go BenchClient(b, endClient, sender1, sender, b.N)
172+
go BenchServer(b, endServer, receiver2, receiver, b.N)
173+
174+
timeout := time.After(time.Duration(b.N+1) * 50 * time.Millisecond)
175+
176+
for endClient != nil || endServer != nil || endProxy != nil {
177+
select {
178+
case <-endProxy:
179+
if b.Failed() {
180+
b.Fatal("Proxy failed")
181+
}
182+
endProxy = nil
183+
case <-endClient:
184+
if b.Failed() {
185+
b.Fatal("Client failed")
186+
}
187+
endClient = nil
188+
case <-endServer:
189+
if b.Failed() {
190+
b.Fatal("Server failed")
191+
}
192+
endServer = nil
193+
case <-timeout:
194+
if DumpStackOnTimeout {
195+
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
196+
}
197+
b.Fatal("Timeout")
198+
}
199+
}
200+
}
201+
202+
func SpawnLocalProxyBench(b *testing.B, sender BenchMessageSender, receiver BenchMessageReceiver) {
203+
endClient := make(chan bool)
204+
endServer := make(chan bool)
205+
endProxy1 := make(chan bool)
206+
endProxy2 := make(chan bool)
207+
208+
receiver1, sender1, err := testPipe()
209+
if err != nil {
210+
b.Fatalf("Error creating pipe: %s", err)
211+
}
212+
receiver2, sender2 := libchan.Pipe()
213+
receiver3, sender3, err := testPipe()
214+
if err != nil {
215+
b.Fatalf("Error creating pipe: %s", err)
216+
}
217+
218+
go BenchProxy(b, endProxy1, sender2, receiver1, b.N)
219+
go BenchProxy(b, endProxy2, sender3, receiver2, b.N)
220+
go BenchClient(b, endClient, sender1, sender, b.N)
221+
go BenchServer(b, endServer, receiver3, receiver, b.N)
222+
223+
timeout := time.After(time.Duration(b.N+1) * 100 * time.Millisecond)
224+
225+
for endClient != nil || endServer != nil || endProxy1 != nil || endProxy2 != nil {
226+
select {
227+
case <-endProxy1:
228+
if b.Failed() {
229+
b.Fatal("Proxy failed")
230+
}
231+
endProxy1 = nil
232+
case <-endProxy2:
233+
if b.Failed() {
234+
b.Fatal("Proxy failed")
235+
}
236+
endProxy2 = nil
237+
case <-endClient:
238+
if b.Failed() {
239+
b.Fatal("Client failed")
240+
}
241+
endClient = nil
242+
case <-endServer:
243+
if b.Failed() {
244+
b.Fatal("Server failed")
245+
}
246+
endServer = nil
247+
case <-timeout:
248+
if DumpStackOnTimeout {
249+
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
250+
}
251+
b.Fatal("Timeout")
252+
}
253+
}
254+
}
255+
256+
func SpawnSpdyProxyBench(b *testing.B, sender BenchMessageSender, receiver BenchMessageReceiver) {
257+
endClient := make(chan bool)
258+
endServer := make(chan bool)
259+
endProxy1 := make(chan bool)
260+
endProxy2 := make(chan bool)
261+
262+
receiver1, sender1, err := testPipe()
263+
if err != nil {
264+
b.Fatalf("Error creating pipe: %s", err)
265+
}
266+
receiver2, sender2, err := testPipe()
267+
if err != nil {
268+
b.Fatalf("Error creating pipe: %s", err)
269+
}
270+
receiver3, sender3, err := testPipe()
271+
if err != nil {
272+
b.Fatalf("Error creating pipe: %s", err)
273+
}
274+
275+
go BenchProxy(b, endProxy1, sender2, receiver1, b.N)
276+
go BenchProxy(b, endProxy2, sender3, receiver2, b.N)
277+
go BenchClient(b, endClient, sender1, sender, b.N)
278+
go BenchServer(b, endServer, receiver3, receiver, b.N)
279+
280+
timeout := time.After(time.Duration(b.N+1) * 200 * time.Millisecond)
281+
282+
for endClient != nil || endServer != nil || endProxy1 != nil || endProxy2 != nil {
283+
select {
284+
case <-endProxy1:
285+
if b.Failed() {
286+
b.Fatal("Proxy failed")
287+
}
288+
endProxy1 = nil
289+
case <-endProxy2:
290+
if b.Failed() {
291+
b.Fatal("Proxy failed")
292+
}
293+
endProxy2 = nil
294+
case <-endClient:
295+
if b.Failed() {
296+
b.Fatal("Client failed")
297+
}
298+
endClient = nil
299+
case <-endServer:
300+
if b.Failed() {
301+
b.Fatal("Server failed")
302+
}
303+
endServer = nil
304+
case <-timeout:
305+
if DumpStackOnTimeout {
306+
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
307+
}
308+
b.Fatal("Timeout")
309+
}
310+
}
311+
}
312+
313+
func SpawnNoProxyBench(b *testing.B, sender BenchMessageSender, receiver BenchMessageReceiver) {
314+
endClient := make(chan bool)
315+
endServer := make(chan bool)
316+
317+
receiver1, sender1, err := testPipe()
318+
if err != nil {
319+
b.Fatalf("Error creating pipe: %s", err)
320+
}
321+
322+
go BenchClient(b, endClient, sender1, sender, b.N)
323+
go BenchServer(b, endServer, receiver1, receiver, b.N)
324+
325+
timeout := time.After(time.Duration(b.N+1) * 50 * time.Millisecond)
326+
327+
for endClient != nil || endServer != nil {
328+
select {
329+
case <-endClient:
330+
if b.Failed() {
331+
b.Fatal("Client failed")
332+
}
333+
endClient = nil
334+
case <-endServer:
335+
if b.Failed() {
336+
b.Fatal("Server failed")
337+
}
338+
endServer = nil
339+
case <-timeout:
340+
if DumpStackOnTimeout {
341+
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
342+
}
343+
b.Fatal("Timeout")
344+
}
345+
}
346+
}
347+
348+
func SpawnLocalPipeBench(b *testing.B, sender BenchMessageSender, receiver BenchMessageReceiver) {
349+
endClient := make(chan bool)
350+
endServer := make(chan bool)
351+
352+
receiver1, sender1 := libchan.Pipe()
353+
354+
go BenchClient(b, endClient, sender1, sender, b.N)
355+
go BenchServer(b, endServer, receiver1, receiver, b.N)
356+
357+
timeout := time.After(time.Duration(b.N+1) * 50 * time.Millisecond)
358+
359+
for endClient != nil || endServer != nil {
360+
select {
361+
case <-endClient:
362+
if b.Failed() {
363+
b.Fatal("Client failed")
364+
}
365+
endClient = nil
366+
case <-endServer:
367+
if b.Failed() {
368+
b.Fatal("Server failed")
369+
}
370+
endServer = nil
371+
case <-timeout:
372+
if DumpStackOnTimeout {
373+
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1)
374+
}
375+
b.Fatal("Timeout")
376+
}
377+
}
378+
}

0 commit comments

Comments
 (0)