From: Rob Pike Date: Sat, 12 Mar 2011 00:24:09 +0000 (-0800) Subject: gob: use bufio on the decode to avoid a system call on each read. X-Git-Tag: weekly.2011-03-15~30 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=5df1cf0475cd5b27601cfe95d94c5e4365f999f3;p=gostls13.git gob: use bufio on the decode to avoid a system call on each read. Add a benchmark. BenchmarkEndToEndPipe gives 14.3microseconds/op before, 13.1microseconds/op after, or about 76e3 round trips per second through the kernel. With a bytes buffer, and therefore no system calls for I/O, the numbers go to 7.3microseconds/op, or about 137e3 round trips per second. R=rsc CC=golang-dev https://golang.org/cl/4279045 --- diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go index 7192745836..0c5fbbd7ea 100644 --- a/src/pkg/gob/decoder.go +++ b/src/pkg/gob/decoder.go @@ -5,6 +5,7 @@ package gob import ( + "bufio" "bytes" "io" "os" @@ -30,7 +31,7 @@ type Decoder struct { // NewDecoder returns a new decoder that reads from the io.Reader. func NewDecoder(r io.Reader) *Decoder { dec := new(Decoder) - dec.r = r + dec.r = bufio.NewReader(r) dec.wireType = make(map[typeId]*wireType) dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine) dec.ignorerCache = make(map[typeId]**decEngine) diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/gob/encoder_test.go index a0c713b81d..8155a9511b 100644 --- a/src/pkg/gob/encoder_test.go +++ b/src/pkg/gob/encoder_test.go @@ -514,3 +514,39 @@ func TestNestedInterfaces(t *testing.T) { t.Fatalf("final value %d; expected %d", inner.A, 7) } } + +type Bench struct { + A int + B float64 + C string + D []byte +} + +func benchmarkEndToEnd(r io.Reader, w io.Writer, b *testing.B) { + b.StopTimer() + enc := NewEncoder(w) + dec := NewDecoder(r) + bench := &Bench{7, 3.2, "now is the time", []byte("for all good men")} + b.StartTimer() + for i := 0; i < b.N; i++ { + if enc.Encode(bench) != nil { + panic("encode error") + } + if dec.Decode(bench) != nil { + panic("decode error") + } + } +} + +func BenchmarkEndToEndPipe(b *testing.B) { + r, w, err := os.Pipe() + if err != nil { + panic("can't get pipe:" + err.String()) + } + benchmarkEndToEnd(r, w, b) +} + +func BenchmarkEndToEndByteBuffer(b *testing.B) { + var buf bytes.Buffer + benchmarkEndToEnd(&buf, &buf, b) +}