]> Cypherpunks repositories - gostls13.git/commitdiff
net/textproto: more efficient header parsing
authorDave Cheney <dave@cheney.net>
Thu, 14 Feb 2013 08:35:38 +0000 (19:35 +1100)
committerDave Cheney <dave@cheney.net>
Thu, 14 Feb 2013 08:35:38 +0000 (19:35 +1100)
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

src/pkg/net/textproto/reader.go
src/pkg/net/textproto/textproto.go

index 855350c31f05447e3b0809de67f4122c69e76faf..b61bea862191a90b12550974dcae76949ed62dc4 100644 (file)
@@ -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 {
index e7ad8773dc6a5163bccf56b90708bb81c34ba69d..eb6ced1c52ef53658a2bea26ead08bfcf29b4372 100644 (file)
@@ -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'
+}