From 69f3c67fce94d3f334cf78aaab602cbe36ba24a5 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Fri, 13 Nov 2015 19:38:46 +0200 Subject: [PATCH] Added benchmark for measuring the maximum client throughput --- client.go | 23 ++++++------- client_timing_test.go | 80 +++++++++++++++++++++++++++++++++++++++++++ header.go | 3 ++ 3 files changed, 93 insertions(+), 13 deletions(-) diff --git a/client.go b/client.go index c796b77..c866a1c 100644 --- a/client.go +++ b/client.go @@ -320,13 +320,7 @@ func clientPostURL(dst []byte, url string, postArgs *Args, c clientDoer) (status } func doRequest(req *Request, dst []byte, url string, c clientDoer) (statusCode int, body []byte, err error) { - v := urlBufPool.Get() - if v == nil { - v = make([]byte, 1024) - } - buf := v.([]byte) - buf = AppendBytesStr(buf[:0], url) - req.Header.RequestURI = buf + req.SetRequestURI(url) resp := acquireResponse() resp.Body = dst @@ -338,15 +332,10 @@ func doRequest(req *Request, dst []byte, url string, c clientDoer) (statusCode i resp.Body = nil releaseResponse(resp) - req.Header.RequestURI = nil - urlBufPool.Put(v) - return statusCode, body, err } var ( - urlBufPool sync.Pool - requestPool sync.Pool responsePool sync.Pool ) @@ -392,7 +381,10 @@ func (c *HostClient) Do(req *Request, resp *Response) error { if len(req.Header.host) == 0 { req.Header.host = append(req.Header.host[:0], host...) } - req.Header.RequestURI = req.URI.AppendRequestURI(req.Header.RequestURI[:0]) + + req.Header.clientBuf = req.URI.AppendRequestURI(req.Header.clientBuf[:0]) + requestURIOld := req.Header.RequestURI + req.Header.RequestURI = req.Header.clientBuf userAgentOld := req.Header.userAgent if len(userAgentOld) == 0 { @@ -401,6 +393,10 @@ func (c *HostClient) Do(req *Request, resp *Response) error { cc, err := c.acquireConn() if err != nil { + req.Header.RequestURI = requestURIOld + if len(userAgentOld) == 0 { + req.Header.userAgent = userAgentOld + } return err } conn := cc.c @@ -408,6 +404,7 @@ func (c *HostClient) Do(req *Request, resp *Response) error { bw := c.acquireWriter(conn) err = req.Write(bw) + req.Header.RequestURI = requestURIOld if len(userAgentOld) == 0 { req.Header.userAgent = userAgentOld } diff --git a/client_timing_test.go b/client_timing_test.go index ec515b1..7cacb45 100644 --- a/client_timing_test.go +++ b/client_timing_test.go @@ -1,14 +1,94 @@ package fasthttp import ( + "bytes" + "fmt" "io/ioutil" "net" "net/http" "strings" + "sync" "testing" "time" ) +type fakeClientConn struct { + net.Conn + s []byte + n int + v interface{} +} + +func (c *fakeClientConn) Write(b []byte) (int, error) { + return len(b), nil +} + +func (c *fakeClientConn) Read(b []byte) (int, error) { + n := 0 + for len(b) > 0 { + if c.n == len(c.s) { + c.n = 0 + return n, nil + } + n = copy(b, c.s[c.n:]) + c.n += n + b = b[n:] + } + return n, nil +} + +func (c *fakeClientConn) Close() error { + releaseFakeServerConn(c) + return nil +} + +func releaseFakeServerConn(c *fakeClientConn) { + c.n = 0 + fakeClientConnPool.Put(c.v) +} + +func acquireFakeServerConn(s []byte) *fakeClientConn { + v := fakeClientConnPool.Get() + if v == nil { + c := &fakeClientConn{ + s: s, + } + c.v = c + return c + } + return v.(*fakeClientConn) +} + +var fakeClientConnPool sync.Pool + +func BenchmarkClientGetFastServer(b *testing.B) { + body := []byte("012345678912") + s := []byte(fmt.Sprintf("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s", len(body), body)) + requestURI := []byte("http://foobar.com/aaa/bbb") + c := &Client{ + Dial: func(addr string) (net.Conn, error) { + return acquireFakeServerConn(s), nil + }, + } + + b.RunParallel(func(pb *testing.PB) { + var req Request + var resp Response + req.Header.RequestURI = requestURI + for pb.Next() { + if err := c.Do(&req, &resp); err != nil { + b.Fatalf("unexpected error: %s", err) + } + if resp.Header.StatusCode != StatusOK { + b.Fatalf("unexpected status code: %d", resp.Header.StatusCode) + } + if !bytes.Equal(resp.Body, body) { + b.Fatalf("unexpected response body: %q. Expected %q", resp.Body, body) + } + } + }) +} + func fasthttpEchoHandler(ctx *RequestCtx) { ctx.Success("text/plain", ctx.Request.Header.RequestURI) } diff --git a/header.go b/header.go index c8d9835..ba7d824 100644 --- a/header.go +++ b/header.go @@ -65,6 +65,9 @@ type RequestHeader struct { bufKV argsKV cookies []argsKV + + // aux buffer for Client. + clientBuf []byte } // IsMethodGet returns true if request method is GET.