From 101f688317518289029307c8da4ec76325e4db6d Mon Sep 17 00:00:00 2001 From: kyrie-yl Date: Tue, 12 Oct 2021 10:16:27 +0800 Subject: [PATCH 1/3] change cache type of GetCode from fastcache to lrucache Signed-off-by: kyrie-yl --- core/state/database.go | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index 0bcde2d5a9..e2fa618023 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -21,7 +21,6 @@ import ( "fmt" "time" - "github.com/VictoriaMetrics/fastcache" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/ethdb" @@ -134,22 +133,24 @@ func NewDatabase(db ethdb.Database) Database { // large memory cache. func NewDatabaseWithConfig(db ethdb.Database, config *trie.Config) Database { csc, _ := lru.New(codeSizeCacheSize) + cc, _ := lru.New(codeCacheSize) return &cachingDB{ db: trie.NewDatabaseWithConfig(db, config), codeSizeCache: csc, - codeCache: fastcache.New(codeCacheSize), + codeCache: cc, } } func NewDatabaseWithConfigAndCache(db ethdb.Database, config *trie.Config) Database { csc, _ := lru.New(codeSizeCacheSize) + cc, _ := lru.New(codeCacheSize) atc, _ := lru.New(accountTrieCacheSize) stc, _ := lru.New(storageTrieCacheSize) database := &cachingDB{ db: trie.NewDatabaseWithConfig(db, config), codeSizeCache: csc, - codeCache: fastcache.New(codeCacheSize), + codeCache: cc, accountTrieCache: atc, storageTrieCache: stc, } @@ -160,7 +161,7 @@ func NewDatabaseWithConfigAndCache(db ethdb.Database, config *trie.Config) Datab type cachingDB struct { db *trie.Database codeSizeCache *lru.Cache - codeCache *fastcache.Cache + codeCache *lru.Cache accountTrieCache *lru.Cache storageTrieCache *lru.Cache } @@ -266,12 +267,16 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { // ContractCode retrieves a particular contract's code. func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { - if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { - return code, nil + if v, ok := db.codeCache.Get(codeHash.Bytes()); ok { + code := v.([]byte) + if len(code) > 0 { + return code, nil + } } code := rawdb.ReadCode(db.db.DiskDB(), codeHash) if len(code) > 0 { - db.codeCache.Set(codeHash.Bytes(), code) + + db.codeCache.Add(codeHash.Bytes(), code) db.codeSizeCache.Add(codeHash, len(code)) return code, nil } @@ -282,12 +287,15 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error // code can't be found in the cache, then check the existence with **new** // db scheme. func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) { - if code := db.codeCache.Get(nil, codeHash.Bytes()); len(code) > 0 { - return code, nil + if v, ok := db.codeCache.Get(codeHash.Bytes()); ok { + code := v.([]byte) + if len(code) > 0 { + return code, nil + } } code := rawdb.ReadCodeWithPrefix(db.db.DiskDB(), codeHash) if len(code) > 0 { - db.codeCache.Set(codeHash.Bytes(), code) + db.codeCache.Add(codeHash.Bytes(), code) db.codeSizeCache.Add(codeHash, len(code)) return code, nil } From 8abef2980c1c6065cbf5ac93e4285d31da8c6e08 Mon Sep 17 00:00:00 2001 From: kyrie-yl Date: Tue, 12 Oct 2021 14:54:41 +0800 Subject: [PATCH 2/3] add cache for contract code bitmap Signed-off-by: kyrie-yl --- core/state/database.go | 8 ++++---- core/vm/contract.go | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/core/state/database.go b/core/state/database.go index e2fa618023..24a1474d57 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -267,8 +267,8 @@ func (db *cachingDB) CopyTrie(t Trie) Trie { // ContractCode retrieves a particular contract's code. func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) { - if v, ok := db.codeCache.Get(codeHash.Bytes()); ok { - code := v.([]byte) + if cached, ok := db.codeCache.Get(codeHash.Bytes()); ok { + code := cached.([]byte) if len(code) > 0 { return code, nil } @@ -287,8 +287,8 @@ func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error // code can't be found in the cache, then check the existence with **new** // db scheme. func (db *cachingDB) ContractCodeWithPrefix(addrHash, codeHash common.Hash) ([]byte, error) { - if v, ok := db.codeCache.Get(codeHash.Bytes()); ok { - code := v.([]byte) + if cached, ok := db.codeCache.Get(codeHash.Bytes()); ok { + code := cached.([]byte) if len(code) > 0 { return code, nil } diff --git a/core/vm/contract.go b/core/vm/contract.go index 61dbd5007a..6fac7f9858 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -19,10 +19,16 @@ package vm import ( "math/big" + lru "github.com/hashicorp/golang-lru" + "github.com/ethereum/go-ethereum/common" "github.com/holiman/uint256" ) +const codeBitmapCacheSize = 2000 + +var codeBitmapCache, _ = lru.New(codeBitmapCacheSize) + // ContractRef is a reference to the contract's backing object type ContractRef interface { Address() common.Address @@ -110,10 +116,15 @@ func (c *Contract) isCode(udest uint64) bool { // Does parent context have the analysis? analysis, exist := c.jumpdests[c.CodeHash] if !exist { - // Do the analysis and save in parent context - // We do not need to store it in c.analysis - analysis = codeBitmap(c.Code) - c.jumpdests[c.CodeHash] = analysis + if cached, ok := codeBitmapCache.Get(c.CodeHash); ok { + analysis = cached.(bitvec) + } else { + // Do the analysis and save in parent context + // We do not need to store it in c.analysis + analysis = codeBitmap(c.Code) + c.jumpdests[c.CodeHash] = analysis + codeBitmapCache.Add(c.CodeHash, analysis) + } } // Also stash it in current contract for faster access c.analysis = analysis From 37ce6d6d461461b9d67f01db8938302d3c670fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 30 Aug 2021 14:13:06 +0200 Subject: [PATCH 3/3] core/vm: rework jumpdest analysis benchmarks (#23499) * core/vm: rework jumpdest analysis benchmarks For BenchmarkJumpdestOpAnalysis use fixed code size of ~1.2MB and classic benchmark loop. * core/vm: clear bitvec in jumpdest analysis benchmark --- core/vm/analysis_test.go | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index 585bb3097f..d7f21e04aa 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -55,9 +55,12 @@ func TestJumpDestAnalysis(t *testing.T) { } } +const analysisCodeSize = 1200 * 1024 + func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) { // 1.4 ms - code := make([]byte, 1200000) + code := make([]byte, analysisCodeSize) + bench.SetBytes(analysisCodeSize) bench.ResetTimer() for i := 0; i < bench.N; i++ { codeBitmap(code) @@ -66,7 +69,8 @@ func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) { } func BenchmarkJumpdestHashing_1200k(bench *testing.B) { // 4 ms - code := make([]byte, 1200000) + code := make([]byte, analysisCodeSize) + bench.SetBytes(analysisCodeSize) bench.ResetTimer() for i := 0; i < bench.N; i++ { crypto.Keccak256Hash(code) @@ -77,13 +81,19 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) { func BenchmarkJumpdestOpAnalysis(bench *testing.B) { var op OpCode bencher := func(b *testing.B) { - code := make([]byte, 32*b.N) + code := make([]byte, analysisCodeSize) + b.SetBytes(analysisCodeSize) for i := range code { code[i] = byte(op) } bits := make(bitvec, len(code)/8+1+4) b.ResetTimer() - codeBitmapInternal(code, bits) + for i := 0; i < b.N; i++ { + for j := range bits { + bits[j] = 0 + } + codeBitmapInternal(code, bits) + } } for op = PUSH1; op <= PUSH32; op++ { bench.Run(op.String(), bencher)