From 512532b3d5d58341dc329cbb3f6c9b582430105f Mon Sep 17 00:00:00 2001 From: James Crasta Date: Sat, 4 Jun 2016 16:13:32 -0600 Subject: [PATCH] Encoding speedups for strings and bools: * 20%-75%+ speedup on string encoding and reduce GC garbage * About a 40% speedup on bool encoding and reduce GC garbage --- binary_serialization_test.go | 38 ++++++++++++++++++++++++++++++++++++ encoder.go | 11 ++++++++--- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/binary_serialization_test.go b/binary_serialization_test.go index 7d9a03a..f183a41 100644 --- a/binary_serialization_test.go +++ b/binary_serialization_test.go @@ -39,6 +39,16 @@ func TestBooleanSerialization(t *testing.T) { } } +func BenchmarkBooleanSerialization(b *testing.B) { + buf := &bytes.Buffer{} + enc := NewBinaryEncoder(buf) + b.ResetTimer() + for i := 0; i < b.N; i++ { + enc.WriteBoolean(true) + buf.Reset() + } +} + func TestIntSerialization(t *testing.T) { testPrimitiveSerialization(t, func(i int) interface{} { r := rand.Int31() / (int32(i) * int32(i)) @@ -120,6 +130,34 @@ func TestStringSerialization(t *testing.T) { }) } +func BenchmarkStringSerialization_small(b *testing.B) { + benchStringSerialization(b, 10) +} + +func BenchmarkStringSerialization_med(b *testing.B) { + benchStringSerialization(b, 70) +} + +func BenchmarkStringSerialization_large(b *testing.B) { + benchStringSerialization(b, 2000) +} + +func benchStringSerialization(b *testing.B, n int) { + s := "abcdefghijklmnop" + for len(s) < n { + s += s + } + s = s[:n] + + buf := &bytes.Buffer{} + enc := NewBinaryEncoder(buf) + b.ResetTimer() + for i := 0; i < b.N; i++ { + enc.WriteString(s) + buf.Reset() + } +} + func testPrimitiveSerialization(t *testing.T, random func(int) interface{}, serialize func(interface{}) (interface{}, error)) { for i := 1; i <= testTimes; i++ { r := random(i) diff --git a/encoder.go b/encoder.go index 5679011..23a080f 100644 --- a/encoder.go +++ b/encoder.go @@ -68,12 +68,16 @@ func (be *BinaryEncoder) WriteNull(_ interface{}) { //do nothing } +// The encodings of true and false, for reuse +var encBoolTrue = []byte{0x01} +var encBoolFalse = []byte{0x00} + // WriteBoolean writes a boolean value. func (be *BinaryEncoder) WriteBoolean(x bool) { if x { - _, _ = be.buffer.Write([]byte{0x01}) + _, _ = be.buffer.Write(encBoolTrue) } else { - _, _ = be.buffer.Write([]byte{0x00}) + _, _ = be.buffer.Write(encBoolFalse) } } @@ -115,7 +119,8 @@ func (be *BinaryEncoder) WriteBytes(x []byte) { // WriteString writes a string value. func (be *BinaryEncoder) WriteString(x string) { be.WriteLong(int64(len(x))) - _, _ = be.buffer.Write([]byte(x)) + // call writers that happen to provide WriteString to avoid extra byte allocations for a copy of a string when possible. + _, _ = io.WriteString(be.buffer, x) } // WriteArrayStart should be called when starting to serialize an array providing it with a number of items in