From 158fb2b60648403c1d93b73a149c3d7280bc4002 Mon Sep 17 00:00:00 2001 From: Victor Shyba Date: Tue, 14 Mar 2023 04:17:04 -0300 Subject: [PATCH] Optimize memory buffer, simplify set32, use sha256-simd (#7060) Hi, I'm syncing Gnosis on a Celeron N5100 to get familiar with the codebase. In the process I managed to optimize some things from profiling. Since I'm not yet on the project Discord, I decided to open this PR as a suggestion. This pass all tests here and gave me a nice boost for that platform, although I didn't have time to benchmark it yet. * reuse VM Memory objects with sync.Pool. It starts with 4k as `evmone` [code suggested](https://github.com/ethereum/evmone/blob/0897edb00179ac3d27f27c82749119003df851e7/lib/evmone/execution_state.hpp#L49) as a good value. * set32 simplification: mostly cosmetic * sha256-simd: Celeron has SHA instructions. We should probably do the same for torrent later, but this already helped as it is very CPU bound on such a low end processor. Maybe that helps ARM as well. --- cl/utils/crypto.go | 2 +- cmd/erigon-cl/core/state/state.go | 2 +- core/vm/contracts.go | 2 +- core/vm/interpreter.go | 16 +++++++++++++--- core/vm/memory.go | 14 ++++++++++---- crypto/ecies/ecies_test.go | 2 +- crypto/ecies/params.go | 2 +- p2p/discover/v5wire/crypto_test.go | 2 +- p2p/discover/v5wire/encoding.go | 2 +- p2p/server_test.go | 2 +- turbo/trie/vtree/verkle_utils_test.go | 2 +- 11 files changed, 32 insertions(+), 16 deletions(-) diff --git a/cl/utils/crypto.go b/cl/utils/crypto.go index 23104caf2..bf2acc47e 100644 --- a/cl/utils/crypto.go +++ b/cl/utils/crypto.go @@ -14,7 +14,7 @@ package utils import ( - "crypto/sha256" + "github.com/minio/sha256-simd" "hash" "sync" ) diff --git a/cmd/erigon-cl/core/state/state.go b/cmd/erigon-cl/core/state/state.go index 1f12d3b43..55cb9184d 100644 --- a/cmd/erigon-cl/core/state/state.go +++ b/cmd/erigon-cl/core/state/state.go @@ -1,8 +1,8 @@ package state import ( - "crypto/sha256" "encoding/binary" + "github.com/minio/sha256-simd" lru2 "github.com/hashicorp/golang-lru/v2" libcommon "github.com/ledgerwatch/erigon-lib/common" diff --git a/core/vm/contracts.go b/core/vm/contracts.go index c3a4beb23..9227f65f7 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -17,9 +17,9 @@ package vm import ( - "crypto/sha256" "encoding/binary" "errors" + "github.com/minio/sha256-simd" "math/big" "github.com/holiman/uint256" diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 4fef7499c..f26e272bb 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -18,6 +18,7 @@ package vm import ( "hash" + "sync" "github.com/ledgerwatch/erigon-lib/chain" libcommon "github.com/ledgerwatch/erigon-lib/common" @@ -43,6 +44,12 @@ type Config struct { ExtraEips []int // Additional EIPS that are to be enabled } +var pool = sync.Pool{ + New: func() any { + return NewMemory() + }, +} + func (vmConfig *Config) HasEip3860(rules *chain.Rules) bool { for _, eip := range vmConfig.ExtraEips { if eip == 3860 { @@ -192,8 +199,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( in.returnData = nil var ( - op OpCode // current opcode - mem = NewMemory() // bound memory + op OpCode // current opcode + mem = pool.Get().(*Memory) locStack = stack.New() callContext = &ScopeContext{ Memory: mem, @@ -215,6 +222,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // Don't move this deferrred function, it's placed before the capturestate-deferred method, // so that it get's executed _after_: the capturestate needs the stacks before // they are returned to the pools + mem.Reset() + defer pool.Put(mem) defer stack.ReturnNormalStack(locStack) contract.Input = input @@ -304,7 +313,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( err = nil // clear stop token error } - return res, err + ret = append(ret, res...) + return } // Depth returns the current call stack depth. diff --git a/core/vm/memory.go b/core/vm/memory.go index 14ebad8b7..9a9f72c66 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -30,7 +30,9 @@ type Memory struct { // NewMemory returns a new memory model. func NewMemory() *Memory { - return &Memory{} + return &Memory{ + store: make([]byte, 0, 4*1024), + } } // Set sets offset + size to value @@ -56,9 +58,8 @@ func (m *Memory) Set32(offset uint64, val *uint256.Int) { panic("invalid memory: store empty") } // Zero the memory area - copy(m.store[offset:offset+32], []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) - // Fill in relevant bits - val.WriteToSlice(m.store[offset:]) + copy(m.store[offset:offset+32], zeroes) + val.WriteToSlice(m.store[offset : offset+32]) } // zeroes - pre-allocated zeroes for Resize() @@ -77,6 +78,11 @@ func (m *Memory) Resize(size uint64) { m.store = append(m.store, zeroes[:l]...) } +func (m *Memory) Reset() { + m.lastGasCost = 0 + m.store = m.store[:0] +} + // GetCopy returns offset + size as a new slice func (m *Memory) GetCopy(offset, size int64) (cpy []byte) { if size == 0 { diff --git a/crypto/ecies/ecies_test.go b/crypto/ecies/ecies_test.go index 7aa033921..b04820dbb 100644 --- a/crypto/ecies/ecies_test.go +++ b/crypto/ecies/ecies_test.go @@ -33,10 +33,10 @@ import ( "bytes" "crypto/elliptic" "crypto/rand" - "crypto/sha256" "encoding/hex" "flag" "fmt" + "github.com/minio/sha256-simd" "math/big" "os" "testing" diff --git a/crypto/ecies/params.go b/crypto/ecies/params.go index 0c63c1381..ddde8eda2 100644 --- a/crypto/ecies/params.go +++ b/crypto/ecies/params.go @@ -37,9 +37,9 @@ import ( "crypto/aes" "crypto/cipher" "crypto/elliptic" - "crypto/sha256" "crypto/sha512" "fmt" + "github.com/minio/sha256-simd" "hash" ethcrypto "github.com/ledgerwatch/erigon/crypto" diff --git a/p2p/discover/v5wire/crypto_test.go b/p2p/discover/v5wire/crypto_test.go index 7f28528c1..76c5677c6 100644 --- a/p2p/discover/v5wire/crypto_test.go +++ b/p2p/discover/v5wire/crypto_test.go @@ -20,7 +20,7 @@ import ( "bytes" "crypto/ecdsa" "crypto/elliptic" - "crypto/sha256" + "github.com/minio/sha256-simd" "reflect" "strings" "testing" diff --git a/p2p/discover/v5wire/encoding.go b/p2p/discover/v5wire/encoding.go index 3b8023022..fc01c27d3 100644 --- a/p2p/discover/v5wire/encoding.go +++ b/p2p/discover/v5wire/encoding.go @@ -22,10 +22,10 @@ import ( "crypto/cipher" "crypto/ecdsa" crand "crypto/rand" - "crypto/sha256" "encoding/binary" "errors" "fmt" + "github.com/minio/sha256-simd" "hash" "github.com/ledgerwatch/erigon/common/mclock" diff --git a/p2p/server_test.go b/p2p/server_test.go index 1decb3ead..030be8556 100644 --- a/p2p/server_test.go +++ b/p2p/server_test.go @@ -19,8 +19,8 @@ package p2p import ( "context" "crypto/ecdsa" - "crypto/sha256" "errors" + "github.com/minio/sha256-simd" "io" "math/rand" "net" diff --git a/turbo/trie/vtree/verkle_utils_test.go b/turbo/trie/vtree/verkle_utils_test.go index 6b029f4b1..385b79fe6 100644 --- a/turbo/trie/vtree/verkle_utils_test.go +++ b/turbo/trie/vtree/verkle_utils_test.go @@ -1,7 +1,7 @@ package vtree import ( - "crypto/sha256" + "github.com/minio/sha256-simd" "math/big" "math/rand" "testing"