Reduce allocations when reusing a Builder.
authorrw <me@rwinslow.com>
Fri, 3 Apr 2015 02:33:00 +0000 (19:33 -0700)
committerrw <me@rwinslow.com>
Fri, 3 Apr 2015 02:33:00 +0000 (19:33 -0700)
Add the function `Reset` to the Builder, which facilitates reuse of the
underlying byte slice.

go/builder.go
tests/GoTest.sh
tests/go_test.go

index cdae695..d8be204 100644 (file)
@@ -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.
index 2011434..f9cc410 100755 (executable)
@@ -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 \
index 87a81c3..df88705 100644 (file)
@@ -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)