rlp: reduce allocations for big.Int and byte array encoding (#21291)
This change further improves the performance of RLP encoding by removing allocations for big.Int and [...]byte types. I have added a new benchmark that measures RLP encoding of types.Block to verify that performance is improved.
This commit is contained in:
@ -25,6 +25,8 @@ import (
|
||||
"math/big"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
)
|
||||
|
||||
type testEncoder struct {
|
||||
@ -137,16 +139,43 @@ var encTests = []encTest{
|
||||
// negative ints are not supported
|
||||
{val: big.NewInt(-1), error: "rlp: cannot encode negative *big.Int"},
|
||||
|
||||
// byte slices, strings
|
||||
// byte arrays
|
||||
{val: [0]byte{}, output: "80"},
|
||||
{val: [1]byte{0}, output: "00"},
|
||||
{val: [1]byte{1}, output: "01"},
|
||||
{val: [1]byte{0x7F}, output: "7F"},
|
||||
{val: [1]byte{0x80}, output: "8180"},
|
||||
{val: [1]byte{0xFF}, output: "81FF"},
|
||||
{val: [3]byte{1, 2, 3}, output: "83010203"},
|
||||
{val: [57]byte{1, 2, 3}, output: "B839010203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
|
||||
|
||||
// named byte type arrays
|
||||
{val: [0]namedByteType{}, output: "80"},
|
||||
{val: [1]namedByteType{0}, output: "00"},
|
||||
{val: [1]namedByteType{1}, output: "01"},
|
||||
{val: [1]namedByteType{0x7F}, output: "7F"},
|
||||
{val: [1]namedByteType{0x80}, output: "8180"},
|
||||
{val: [1]namedByteType{0xFF}, output: "81FF"},
|
||||
{val: [3]namedByteType{1, 2, 3}, output: "83010203"},
|
||||
{val: [57]namedByteType{1, 2, 3}, output: "B839010203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"},
|
||||
|
||||
// byte slices
|
||||
{val: []byte{}, output: "80"},
|
||||
{val: []byte{0}, output: "00"},
|
||||
{val: []byte{0x7E}, output: "7E"},
|
||||
{val: []byte{0x7F}, output: "7F"},
|
||||
{val: []byte{0x80}, output: "8180"},
|
||||
{val: []byte{1, 2, 3}, output: "83010203"},
|
||||
|
||||
// named byte type slices
|
||||
{val: []namedByteType{}, output: "80"},
|
||||
{val: []namedByteType{0}, output: "00"},
|
||||
{val: []namedByteType{0x7E}, output: "7E"},
|
||||
{val: []namedByteType{0x7F}, output: "7F"},
|
||||
{val: []namedByteType{0x80}, output: "8180"},
|
||||
{val: []namedByteType{1, 2, 3}, output: "83010203"},
|
||||
{val: [...]namedByteType{1, 2, 3}, output: "83010203"},
|
||||
|
||||
// strings
|
||||
{val: "", output: "80"},
|
||||
{val: "\x7E", output: "7E"},
|
||||
{val: "\x7F", output: "7F"},
|
||||
@ -401,3 +430,36 @@ func TestEncodeToReaderReturnToPool(t *testing.T) {
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
var sink interface{}
|
||||
|
||||
func BenchmarkIntsize(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
sink = intsize(0x12345678)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPutint(b *testing.B) {
|
||||
buf := make([]byte, 8)
|
||||
for i := 0; i < b.N; i++ {
|
||||
putint(buf, 0x12345678)
|
||||
sink = buf
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncodeBigInts(b *testing.B) {
|
||||
ints := make([]*big.Int, 200)
|
||||
for i := range ints {
|
||||
ints[i] = math.BigPow(2, int64(i))
|
||||
}
|
||||
out := bytes.NewBuffer(make([]byte, 0, 4096))
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
out.Reset()
|
||||
if err := Encode(out, ints); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user