Skip to content

Commit

Permalink
cache bitmap and change the cache type of GetCode (ethereum#449)
Browse files Browse the repository at this point in the history
* change cache type of GetCode from fastcache to lrucache

Signed-off-by: kyrie-yl <yl.on.the.way@gmail.com>

* add cache for contract code bitmap

Signed-off-by: kyrie-yl <yl.on.the.way@gmail.com>

* core/vm: rework jumpdest analysis benchmarks (ethereum#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

Co-authored-by: Paweł Bylica <chfast@gmail.com>
  • Loading branch information
kyrie-yl and chfast authored Oct 15, 2021
1 parent 610f6a5 commit 33aa779
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 18 deletions.
28 changes: 18 additions & 10 deletions core/state/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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 cached, ok := db.codeCache.Get(codeHash.Bytes()); ok {
code := cached.([]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
}
Expand All @@ -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 cached, ok := db.codeCache.Get(codeHash.Bytes()); ok {
code := cached.([]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
}
Expand Down
18 changes: 14 additions & 4 deletions core/vm/analysis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down
19 changes: 15 additions & 4 deletions core/vm/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 33aa779

Please sign in to comment.