From 5df1cf0475cd5b27601cfe95d94c5e4365f999f3 Mon Sep 17 00:00:00 2001 From: Rob Pike Date: Fri, 11 Mar 2011 16:24:09 -0800 Subject: [PATCH] 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 --- src/pkg/gob/decoder.go | 3 ++- src/pkg/gob/encoder_test.go | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) 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) +} -- 2.50.0