From e6c6de9494c92cea58338aa6f3aa5bae7b7492dc Mon Sep 17 00:00:00 2001 From: Jack Christensen Date: Sat, 2 May 2020 11:34:14 -0500 Subject: [PATCH] Improved ext/shopspring-numeric binary decoding performance Before: BenchmarkDecode/Zero-Binary-16 3944304 292 ns/op 128 B/op 7 allocs/op BenchmarkDecode/Small-Binary-16 2034132 585 ns/op 184 B/op 13 allocs/op BenchmarkDecode/Medium-Binary-16 1747191 690 ns/op 192 B/op 12 allocs/op BenchmarkDecode/Large-Binary-16 1334006 899 ns/op 304 B/op 14 allocs/op BenchmarkDecode/Huge-Binary-16 702382 1590 ns/op 584 B/op 18 allocs/op After: BenchmarkDecode/Zero-Binary-16 14592645 80.1 ns/op 64 B/op 2 allocs/op BenchmarkDecode/Small-Binary-16 5729318 212 ns/op 104 B/op 7 allocs/op BenchmarkDecode/Medium-Binary-16 4930009 241 ns/op 88 B/op 5 allocs/op BenchmarkDecode/Large-Binary-16 3369573 344 ns/op 144 B/op 7 allocs/op BenchmarkDecode/Huge-Binary-16 2587156 453 ns/op 216 B/op 9 allocs/op --- ext/shopspring-numeric/decimal.go | 12 +------ ext/shopspring-numeric/decimal_test.go | 44 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/ext/shopspring-numeric/decimal.go b/ext/shopspring-numeric/decimal.go index 70906806..148589a4 100644 --- a/ext/shopspring-numeric/decimal.go +++ b/ext/shopspring-numeric/decimal.go @@ -250,17 +250,7 @@ func (dst *Numeric) DecodeBinary(ci *pgtype.ConnInfo, src []byte) error { return err } - buf, err := num.EncodeText(ci, nil) - if err != nil { - return err - } - - dec, err := decimal.NewFromString(string(buf)) - if err != nil { - return err - } - - *dst = Numeric{Decimal: dec, Status: pgtype.Present} + *dst = Numeric{Decimal: decimal.NewFromBigInt(num.Int, num.Exp), Status: pgtype.Present} return nil } diff --git a/ext/shopspring-numeric/decimal_test.go b/ext/shopspring-numeric/decimal_test.go index 0b256b37..bf34e0dd 100644 --- a/ext/shopspring-numeric/decimal_test.go +++ b/ext/shopspring-numeric/decimal_test.go @@ -11,6 +11,7 @@ import ( shopspring "github.com/jackc/pgtype/ext/shopspring-numeric" "github.com/jackc/pgtype/testutil" "github.com/shopspring/decimal" + "github.com/stretchr/testify/require" ) func mustParseDecimal(t *testing.T, src string) decimal.Decimal { @@ -284,3 +285,46 @@ func TestNumericAssignTo(t *testing.T) { } } } + +func BenchmarkDecode(b *testing.B) { + benchmarks := []struct { + name string + numberStr string + }{ + {"Zero", "0"}, + {"Small", "12345"}, + {"Medium", "12345.12345"}, + {"Large", "123457890.1234567890"}, + {"Huge", "123457890123457890123457890.1234567890123457890123457890"}, + } + + for _, bm := range benchmarks { + src := &shopspring.Numeric{} + err := src.Set(bm.numberStr) + require.NoError(b, err) + textFormat, err := src.EncodeText(nil, nil) + require.NoError(b, err) + binaryFormat, err := src.EncodeBinary(nil, nil) + require.NoError(b, err) + + b.Run(fmt.Sprintf("%s-Text", bm.name), func(b *testing.B) { + dst := &shopspring.Numeric{} + for i := 0; i < b.N; i++ { + err := dst.DecodeText(nil, textFormat) + if err != nil { + b.Fatal(err) + } + } + }) + + b.Run(fmt.Sprintf("%s-Binary", bm.name), func(b *testing.B) { + dst := &shopspring.Numeric{} + for i := 0; i < b.N; i++ { + err := dst.DecodeBinary(nil, binaryFormat) + if err != nil { + b.Fatal(err) + } + } + }) + } +}