From e82759388df69869fb11b705b81b821b3f56f012 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Mon, 11 Dec 2023 10:35:46 +0100 Subject: [PATCH] added benchmark for bytestream.Consume Signed-off-by: Frederic BIDON --- bytestream.go | 2 +- bytestream_test.go | 108 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/bytestream.go b/bytestream.go index 9f03010..6e338e8 100644 --- a/bytestream.go +++ b/bytestream.go @@ -72,7 +72,7 @@ func ByteStreamConsumer(opts ...byteStreamOpt) Consumer { } // buffers input before writing to data - buf := new(bytes.Buffer) + var buf bytes.Buffer _, err := buf.ReadFrom(reader) if err != nil { return err diff --git a/bytestream_test.go b/bytestream_test.go index c9f6bc0..27ec03c 100644 --- a/bytestream_test.go +++ b/bytestream_test.go @@ -2,8 +2,10 @@ package runtime import ( "bytes" + "crypto/rand" "errors" "fmt" + "io" "sync/atomic" "testing" @@ -27,7 +29,7 @@ func TestByteStreamConsumer(t *testing.T) { assert.Equal(t, expected, dest) }) - t.Run("can consume as an UnmarshalBinary", func(t *testing.T) { + t.Run("can consume as a binary unmarshaler", func(t *testing.T) { var dest binaryUnmarshalDummy require.NoError(t, consumer.Consume(bytes.NewBufferString(expected), &dest)) assert.Equal(t, expected, dest.str) @@ -103,16 +105,114 @@ func TestByteStreamConsumer(t *testing.T) { }) } +func BenchmarkByteStreamConsumer(b *testing.B) { + const bufferSize = 1000 + expected := make([]byte, bufferSize) + _, err := rand.Read(expected) + require.NoError(b, err) + consumer := ByteStreamConsumer() + input := bytes.NewReader([]byte(expected)) + + b.Run("with writer", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + var dest bytes.Buffer + for i := 0; i < b.N; i++ { + err = consumer.Consume(input, &dest) + if err != nil { + b.Fatal(err) + } + input.Seek(io.SeekStart, 0) + dest.Reset() + } + }) + b.Run("with BinaryUnmarshal", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + var dest binaryUnmarshalDummyZeroAlloc + for i := 0; i < b.N; i++ { + err = consumer.Consume(input, &dest) + if err != nil { + b.Fatal(err) + } + input.Seek(io.SeekStart, 0) + } + }) + b.Run("with string", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + var dest string + for i := 0; i < b.N; i++ { + err = consumer.Consume(input, &dest) + if err != nil { + b.Fatal(err) + } + input.Seek(io.SeekStart, 0) + } + }) + b.Run("with []byte", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + var dest []byte + for i := 0; i < b.N; i++ { + err = consumer.Consume(input, &dest) + if err != nil { + b.Fatal(err) + } + input.Seek(io.SeekStart, 0) + } + }) + b.Run("with aliased string", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + type aliasedString string + var dest aliasedString + for i := 0; i < b.N; i++ { + err = consumer.Consume(input, &dest) + if err != nil { + b.Fatal(err) + } + input.Seek(io.SeekStart, 0) + } + }) + b.Run("with aliased []byte", func(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + type binarySlice []byte + var dest binarySlice + for i := 0; i < b.N; i++ { + err = consumer.Consume(input, &dest) + if err != nil { + b.Fatal(err) + } + input.Seek(io.SeekStart, 0) + } + }) +} + type binaryUnmarshalDummy struct { str string } -func (b *binaryUnmarshalDummy) UnmarshalBinary(bytes []byte) error { - if len(bytes) == 0 { +type binaryUnmarshalDummyZeroAlloc struct { + b []byte +} + +func (b *binaryUnmarshalDummy) UnmarshalBinary(data []byte) error { + if len(data) == 0 { + return errors.New("no text given") + } + + b.str = string(data) + return nil +} + +func (b *binaryUnmarshalDummyZeroAlloc) UnmarshalBinary(data []byte) error { + if len(data) == 0 { return errors.New("no text given") } - b.str = string(bytes) + b.b = data return nil }