From: Dave Cheney Date: Thu, 14 Feb 2013 08:35:38 +0000 (+1100) Subject: net/textproto: more efficient header parsing X-Git-Tag: go1.1rc2~1040 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=2803744b86a58054e052a9520d7c17ab41acd96c;p=gostls13.git net/textproto: more efficient header parsing A co creation with bradfitz * add fast path for header lines which are not continuations * pass hint to better size initial mime header map lucky(~/go/src/pkg/net/http) % ~/go/misc/benchcmp {golden,new}.txt benchmark old ns/op new ns/op delta BenchmarkReadRequestChrome 10073 8348 -17.12% BenchmarkReadRequestCurl 4368 4350 -0.41% BenchmarkReadRequestApachebench 4412 4397 -0.34% BenchmarkReadRequestSiege 6431 5924 -7.88% BenchmarkReadRequestWrk 2820 3146 +11.56% benchmark old MB/s new MB/s speedup BenchmarkReadRequestChrome 60.66 73.18 1.21x BenchmarkReadRequestCurl 17.85 17.93 1.00x BenchmarkReadRequestApachebench 18.58 18.65 1.00x BenchmarkReadRequestSiege 23.48 25.49 1.09x BenchmarkReadRequestWrk 14.18 12.71 0.90x benchmark old allocs new allocs delta BenchmarkReadRequestChrome 32 26 -18.75% BenchmarkReadRequestCurl 15 15 0.00% BenchmarkReadRequestApachebench 16 15 -6.25% BenchmarkReadRequestSiege 22 19 -13.64% BenchmarkReadRequestWrk 11 11 0.00% benchmark old bytes new bytes delta BenchmarkReadRequestChrome 3148 2216 -29.61% BenchmarkReadRequestCurl 905 1413 56.13% BenchmarkReadRequestApachebench 956 1413 47.80% BenchmarkReadRequestSiege 1397 1522 8.95% BenchmarkReadRequestWrk 757 1369 80.85% R=bradfitz CC=golang-dev https://golang.org/cl/7300098 --- diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go index 855350c31f..b61bea8621 100644 --- a/src/pkg/net/textproto/reader.go +++ b/src/pkg/net/textproto/reader.go @@ -128,6 +128,17 @@ func (r *Reader) readContinuedLineSlice() ([]byte, error) { return line, nil } + // Optimistically assume that we have started to buffer the next line + // and it starts with an ASCII letter (the next header key), so we can + // avoid copying that buffered data around in memory and skipping over + // non-existent whitespace. + if r.R.Buffered() > 1 { + peek, err := r.R.Peek(1) + if err == nil && isASCIILetter(peek[0]) { + return trim(line), nil + } + } + // ReadByte or the next readLineSlice will flush the read buffer; // copy the slice into buf. r.buf = append(r.buf[:0], trim(line)...) @@ -445,7 +456,7 @@ func (r *Reader) ReadDotLines() ([]string, error) { // } // func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { - m := make(MIMEHeader) + m := make(MIMEHeader, 4) for { kv, err := r.readContinuedLineSlice() if len(kv) == 0 { diff --git a/src/pkg/net/textproto/textproto.go b/src/pkg/net/textproto/textproto.go index e7ad8773dc..eb6ced1c52 100644 --- a/src/pkg/net/textproto/textproto.go +++ b/src/pkg/net/textproto/textproto.go @@ -147,3 +147,8 @@ func TrimBytes(b []byte) []byte { func isASCIISpace(b byte) bool { return b == ' ' || b == '\t' || b == '\n' || b == '\r' } + +func isASCIILetter(b byte) bool { + b |= 0x20 // make lower case + return 'a' <= b && b <= 'z' +}