From d756efbf764af942ef0563b2a1141349fbc4e72b Mon Sep 17 00:00:00 2001 From: rw Date: Thu, 2 Apr 2015 19:33:00 -0700 Subject: [PATCH] Reduce allocations when reusing a Builder. Add the function `Reset` to the Builder, which facilitates reuse of the underlying byte slice. --- go/builder.go | 31 +++++++++++++++++++++++++------ tests/GoTest.sh | 2 +- tests/go_test.go | 4 +++- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/go/builder.go b/go/builder.go index cdae695..d8be204 100644 --- a/go/builder.go +++ b/go/builder.go @@ -31,6 +31,15 @@ func NewBuilder(initialSize int) *Builder { return b } +// Reset truncates the underlying Builder buffer, facilitating alloc-free +// reuse of a Builder. +func (b *Builder) Reset() { + b.Bytes = b.Bytes[:0] + b.head = UOffsetT(0) + b.minalign = 1 + b.vtables = b.vtables[:0] +} + // StartObject initializes bookkeeping for writing a new object. func (b *Builder) StartObject(numfields int) { b.notNested() @@ -155,13 +164,23 @@ func (b *Builder) growByteBuffer() { if (int64(len(b.Bytes)) & int64(0xC0000000)) != 0 { panic("cannot grow buffer beyond 2 gigabytes") } - newSize := len(b.Bytes) * 2 - if newSize == 0 { - newSize = 1 + newLen := len(b.Bytes) * 2 + if newLen == 0 { + newLen = 1 + } + + if cap(b.Bytes) >= newLen { + b.Bytes = b.Bytes[:newLen] + } else { + extension := make([]byte, newLen-len(b.Bytes)) + b.Bytes = append(b.Bytes, extension...) + } + + middle := newLen / 2 + copy(b.Bytes[middle:], b.Bytes[:middle]) + for i := 0 ; i < middle; i++ { + b.Bytes[i] = 0 } - bytes2 := make([]byte, newSize) - copy(bytes2[newSize-len(b.Bytes):], b.Bytes) - b.Bytes = bytes2 } // Head gives the start of useful data in the underlying byte buffer. diff --git a/tests/GoTest.sh b/tests/GoTest.sh index 2011434..f9cc410 100755 --- a/tests/GoTest.sh +++ b/tests/GoTest.sh @@ -43,7 +43,7 @@ GOPATH=${go_path} go test flatbuffers_test \ --test.coverpkg=github.com/google/flatbuffers/go \ --cpp_data=${test_dir}/monsterdata_test.mon \ --out_data=${test_dir}/monsterdata_go_wire.mon \ - --test.bench=Build \ + --test.bench=. \ --test.benchtime=3s \ --fuzz=true \ --fuzz_fields=4 \ diff --git a/tests/go_test.go b/tests/go_test.go index 87a81c3..df88705 100644 --- a/tests/go_test.go +++ b/tests/go_test.go @@ -1254,9 +1254,11 @@ func BenchmarkBuildGold(b *testing.B) { reuse_fred := []byte("Fred") b.SetBytes(bytes_length) + bldr := flatbuffers.NewBuilder(512) b.ReportAllocs() for i := 0; i < b.N; i++ { - bldr := flatbuffers.NewBuilder(0) + bldr.Reset() + str := bldr.CreateByteString(reuse_str) test1 := bldr.CreateByteString(reuse_test1) test2 := bldr.CreateByteString(reuse_test2) -- 2.7.4