aboutsummaryrefslogtreecommitdiff
path: root/client_timing_test.go
diff options
context:
space:
mode:
authorGravatar Aliaksandr Valialkin <valyala@gmail.com> 2016-01-11 14:21:28 +0200
committerGravatar Aliaksandr Valialkin <valyala@gmail.com> 2016-01-11 14:21:28 +0200
commitce706fbda79525df975d885b3c81faf28a458e1e (patch)
treec250ea3a92da876c557ca0d386ac91106d24733f /client_timing_test.go
parentReturn clearer error when TLS certFile and/or keyFile cannot be loaded (diff)
downloadfasthttp-ce706fbda79525df975d885b3c81faf28a458e1e.tar.gz
fasthttp-ce706fbda79525df975d885b3c81faf28a458e1e.tar.bz2
fasthttp-ce706fbda79525df975d885b3c81faf28a458e1e.zip
Improved client benchmarks: explicitly set the maximum number of concurrent client connections, added end-to-end benchmarks for inmemory dialer<->listener
Diffstat (limited to 'client_timing_test.go')
-rw-r--r--client_timing_test.go219
1 files changed, 204 insertions, 15 deletions
diff --git a/client_timing_test.go b/client_timing_test.go
index a378651..29ac6e4 100644
--- a/client_timing_test.go
+++ b/client_timing_test.go
@@ -105,6 +105,7 @@ func BenchmarkClientDoFastServer(b *testing.B) {
Dial: func(addr string) (net.Conn, error) {
return acquireFakeServerConn(s), nil
},
+ MaxConnsPerHost: runtime.GOMAXPROCS(-1),
}
nn := uint32(0)
@@ -134,6 +135,7 @@ func BenchmarkNetHTTPClientDoFastServer(b *testing.B) {
Dial: func(network, addr string) (net.Conn, error) {
return acquireFakeServerConn(s), nil
},
+ MaxIdleConnsPerHost: runtime.GOMAXPROCS(-1),
},
}
@@ -172,19 +174,19 @@ func nethttpEchoHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(r.RequestURI))
}
-func BenchmarkClientGetEndToEnd1(b *testing.B) {
- benchmarkClientGetEndToEnd(b, 1)
+func BenchmarkClientGetEndToEnd1TCP(b *testing.B) {
+ benchmarkClientGetEndToEndTCP(b, 1)
}
-func BenchmarkClientGetEndToEnd10(b *testing.B) {
- benchmarkClientGetEndToEnd(b, 10)
+func BenchmarkClientGetEndToEnd10TCP(b *testing.B) {
+ benchmarkClientGetEndToEndTCP(b, 10)
}
-func BenchmarkClientGetEndToEnd100(b *testing.B) {
- benchmarkClientGetEndToEnd(b, 100)
+func BenchmarkClientGetEndToEnd100TCP(b *testing.B) {
+ benchmarkClientGetEndToEndTCP(b, 100)
}
-func benchmarkClientGetEndToEnd(b *testing.B, parallelism int) {
+func benchmarkClientGetEndToEndTCP(b *testing.B, parallelism int) {
addr := "127.0.0.1:8543"
ln, err := net.Listen("tcp4", addr)
@@ -232,19 +234,19 @@ func benchmarkClientGetEndToEnd(b *testing.B, parallelism int) {
}
}
-func BenchmarkNetHTTPClientGetEndToEnd1(b *testing.B) {
- benchmarkNetHTTPClientGetEndToEnd(b, 1)
+func BenchmarkNetHTTPClientGetEndToEnd1TCP(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndTCP(b, 1)
}
-func BenchmarkNetHTTPClientGetEndToEnd10(b *testing.B) {
- benchmarkNetHTTPClientGetEndToEnd(b, 10)
+func BenchmarkNetHTTPClientGetEndToEnd10TCP(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndTCP(b, 10)
}
-func BenchmarkNetHTTPClientGetEndToEnd100(b *testing.B) {
- benchmarkNetHTTPClientGetEndToEnd(b, 100)
+func BenchmarkNetHTTPClientGetEndToEnd100TCP(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndTCP(b, 100)
}
-func benchmarkNetHTTPClientGetEndToEnd(b *testing.B, parallelism int) {
+func benchmarkNetHTTPClientGetEndToEndTCP(b *testing.B, parallelism int) {
addr := "127.0.0.1:8542"
ln, err := net.Listen("tcp4", addr)
@@ -261,12 +263,18 @@ func benchmarkNetHTTPClientGetEndToEnd(b *testing.B, parallelism int) {
close(ch)
}()
+ c := &http.Client{
+ Transport: &http.Transport{
+ MaxIdleConnsPerHost: parallelism * runtime.GOMAXPROCS(-1),
+ },
+ }
+
requestURI := "/foo/bar?baz=123"
url := "http://" + addr + requestURI
b.SetParallelism(parallelism)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
- resp, err := http.Get(url)
+ resp, err := c.Get(url)
if err != nil {
b.Fatalf("unexpected error: %s", err)
}
@@ -291,3 +299,184 @@ func benchmarkNetHTTPClientGetEndToEnd(b *testing.B, parallelism int) {
b.Fatalf("server wasn't stopped")
}
}
+
+func BenchmarkClientGetEndToEnd1Inmemory(b *testing.B) {
+ benchmarkClientGetEndToEndInmemory(b, 1)
+}
+
+func BenchmarkClientGetEndToEnd10Inmemory(b *testing.B) {
+ benchmarkClientGetEndToEndInmemory(b, 10)
+}
+
+func BenchmarkClientGetEndToEnd100Inmemory(b *testing.B) {
+ benchmarkClientGetEndToEndInmemory(b, 100)
+}
+
+func BenchmarkClientGetEndToEnd1000Inmemory(b *testing.B) {
+ benchmarkClientGetEndToEndInmemory(b, 1000)
+}
+
+func benchmarkClientGetEndToEndInmemory(b *testing.B, parallelism int) {
+ ln := newInmemoryListener()
+
+ ch := make(chan struct{})
+ go func() {
+ if err := Serve(ln, fasthttpEchoHandler); err != nil {
+ b.Fatalf("error when serving requests: %s", err)
+ }
+ close(ch)
+ }()
+
+ c := &Client{
+ MaxConnsPerHost: runtime.GOMAXPROCS(-1) * parallelism,
+ Dial: func(addr string) (net.Conn, error) { return ln.Dial("inmemory", addr) },
+ }
+
+ requestURI := "/foo/bar?baz=123"
+ url := "http://unused.host" + requestURI
+ b.SetParallelism(parallelism)
+ b.RunParallel(func(pb *testing.PB) {
+ var buf []byte
+ for pb.Next() {
+ statusCode, body, err := c.Get(buf, url)
+ if err != nil {
+ b.Fatalf("unexpected error: %s", err)
+ }
+ if statusCode != StatusOK {
+ b.Fatalf("unexpected status code: %d. Expecting %d", statusCode, StatusOK)
+ }
+ if string(body) != requestURI {
+ b.Fatalf("unexpected response %q. Expecting %q", body, requestURI)
+ }
+ buf = body
+ }
+ })
+
+ ln.Close()
+ select {
+ case <-ch:
+ case <-time.After(time.Second):
+ b.Fatalf("server wasn't stopped")
+ }
+}
+
+func BenchmarkNetHTTPClientGetEndToEnd1Inmemory(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndInmemory(b, 1)
+}
+
+func BenchmarkNetHTTPClientGetEndToEnd10Inmemory(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndInmemory(b, 10)
+}
+
+func BenchmarkNetHTTPClientGetEndToEnd100Inmemory(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndInmemory(b, 100)
+}
+
+func BenchmarkNetHTTPClientGetEndToEnd1000Inmemory(b *testing.B) {
+ benchmarkNetHTTPClientGetEndToEndInmemory(b, 1000)
+}
+
+func benchmarkNetHTTPClientGetEndToEndInmemory(b *testing.B, parallelism int) {
+ ln := newInmemoryListener()
+
+ ch := make(chan struct{})
+ go func() {
+ if err := http.Serve(ln, http.HandlerFunc(nethttpEchoHandler)); err != nil && !strings.Contains(
+ err.Error(), "use of closed network connection") {
+ b.Fatalf("error when serving requests: %s", err)
+ }
+ close(ch)
+ }()
+
+ c := &http.Client{
+ Transport: &http.Transport{
+ Dial: ln.Dial,
+ MaxIdleConnsPerHost: parallelism * runtime.GOMAXPROCS(-1),
+ },
+ }
+
+ requestURI := "/foo/bar?baz=123"
+ url := "http://unused.host" + requestURI
+ b.SetParallelism(parallelism)
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ resp, err := c.Get(url)
+ if err != nil {
+ b.Fatalf("unexpected error: %s", err)
+ }
+ if resp.StatusCode != http.StatusOK {
+ b.Fatalf("unexpected status code: %d. Expecting %d", resp.StatusCode, http.StatusOK)
+ }
+ body, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ b.Fatalf("unexpected error when reading response body: %s", err)
+ }
+ if string(body) != requestURI {
+ b.Fatalf("unexpected response %q. Expecting %q", body, requestURI)
+ }
+ }
+ })
+
+ ln.Close()
+ select {
+ case <-ch:
+ case <-time.After(time.Second):
+ b.Fatalf("server wasn't stopped")
+ }
+}
+
+type inmemoryListener struct {
+ lock sync.Mutex
+ closed bool
+ conns chan net.Conn
+}
+
+func newInmemoryListener() *inmemoryListener {
+ return &inmemoryListener{
+ conns: make(chan net.Conn),
+ }
+}
+
+func (ln *inmemoryListener) Accept() (net.Conn, error) {
+ c, ok := <-ln.conns
+ if !ok {
+ return nil, fmt.Errorf("inmemoryListener is already closed: use of closed network connection")
+ }
+ return c, nil
+}
+
+func (ln *inmemoryListener) Close() error {
+ ln.lock.Lock()
+ if !ln.closed {
+ close(ln.conns)
+ ln.closed = true
+ }
+ ln.lock.Unlock()
+ return nil
+}
+
+func (ln *inmemoryListener) Addr() net.Addr {
+ return &net.UnixAddr{
+ Name: "inmemoryListener",
+ Net: "memory",
+ }
+}
+
+func (ln *inmemoryListener) Dial(network, addr string) (net.Conn, error) {
+ cConn, sConn := net.Pipe()
+ ln.lock.Lock()
+ if !ln.closed {
+ ln.conns <- sConn
+ } else {
+ sConn.Close()
+ cConn.Close()
+ cConn = nil
+ }
+ ln.lock.Unlock()
+
+ if cConn == nil {
+ return nil, fmt.Errorf("inmemoryListener is already closed")
+ }
+ return cConn, nil
+}