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
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)...)
// }
//
func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
- m := make(MIMEHeader)
+ m := make(MIMEHeader, 4)
for {
kv, err := r.readContinuedLineSlice()
if len(kv) == 0 {
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'
+}