mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
Merge branch 'ethereum:master' into master
This commit is contained in:
commit
7fdf11f71a
4 changed files with 140 additions and 20 deletions
|
|
@ -77,6 +77,16 @@ var (
|
||||||
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
||||||
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
||||||
|
|
||||||
|
accountCacheHitMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/hit", nil)
|
||||||
|
accountCacheMissMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/miss", nil)
|
||||||
|
storageCacheHitMeter = metrics.NewRegisteredMeter("chain/storage/reads/cache/process/hit", nil)
|
||||||
|
storageCacheMissMeter = metrics.NewRegisteredMeter("chain/storage/reads/cache/process/miss", nil)
|
||||||
|
|
||||||
|
accountCacheHitPrefetchMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/prefetch/hit", nil)
|
||||||
|
accountCacheMissPrefetchMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/prefetch/miss", nil)
|
||||||
|
storageCacheHitPrefetchMeter = metrics.NewRegisteredMeter("chain/storage/reads/cache/prefetch/hit", nil)
|
||||||
|
storageCacheMissPrefetchMeter = metrics.NewRegisteredMeter("chain/storage/reads/cache/prefetch/miss", nil)
|
||||||
|
|
||||||
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil)
|
accountReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/account/single/reads", nil)
|
||||||
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil)
|
storageReadSingleTimer = metrics.NewRegisteredResettingTimer("chain/storage/single/reads", nil)
|
||||||
|
|
||||||
|
|
@ -1944,18 +1954,32 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
|
||||||
//
|
//
|
||||||
// Note: the main processor and prefetcher share the same reader with a local
|
// Note: the main processor and prefetcher share the same reader with a local
|
||||||
// cache for mitigating the overhead of state access.
|
// cache for mitigating the overhead of state access.
|
||||||
reader, err := bc.statedb.ReaderWithCache(parentRoot)
|
prefetch, process, err := bc.statedb.ReadersWithCacheStats(parentRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
throwaway, err := state.NewWithReader(parentRoot, bc.statedb, reader)
|
throwaway, err := state.NewWithReader(parentRoot, bc.statedb, prefetch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
statedb, err = state.NewWithReader(parentRoot, bc.statedb, reader)
|
statedb, err = state.NewWithReader(parentRoot, bc.statedb, process)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// Upload the statistics of reader at the end
|
||||||
|
defer func() {
|
||||||
|
stats := prefetch.GetStats()
|
||||||
|
accountCacheHitPrefetchMeter.Mark(stats.AccountHit)
|
||||||
|
accountCacheMissPrefetchMeter.Mark(stats.AccountMiss)
|
||||||
|
storageCacheHitPrefetchMeter.Mark(stats.StorageHit)
|
||||||
|
storageCacheMissPrefetchMeter.Mark(stats.StorageMiss)
|
||||||
|
stats = process.GetStats()
|
||||||
|
accountCacheHitMeter.Mark(stats.AccountHit)
|
||||||
|
accountCacheMissMeter.Mark(stats.AccountMiss)
|
||||||
|
storageCacheHitMeter.Mark(stats.StorageHit)
|
||||||
|
storageCacheMissMeter.Mark(stats.StorageMiss)
|
||||||
|
}()
|
||||||
|
|
||||||
go func(start time.Time, throwaway *state.StateDB, block *types.Block) {
|
go func(start time.Time, throwaway *state.StateDB, block *types.Block) {
|
||||||
// Disable tracing for prefetcher executions.
|
// Disable tracing for prefetcher executions.
|
||||||
vmCfg := bc.cfg.VmConfig
|
vmCfg := bc.cfg.VmConfig
|
||||||
|
|
|
||||||
|
|
@ -209,13 +209,16 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil
|
return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReaderWithCache creates a state reader with internal local cache.
|
// ReadersWithCacheStats creates a pair of state readers sharing the same internal cache and
|
||||||
func (db *CachingDB) ReaderWithCache(stateRoot common.Hash) (Reader, error) {
|
// same backing Reader, but exposing separate statistics.
|
||||||
|
// and statistics.
|
||||||
|
func (db *CachingDB) ReadersWithCacheStats(stateRoot common.Hash) (ReaderWithStats, ReaderWithStats, error) {
|
||||||
reader, err := db.Reader(stateRoot)
|
reader, err := db.Reader(stateRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return newReaderWithCache(reader), nil
|
shared := newReaderWithCache(reader)
|
||||||
|
return newReaderWithCacheStats(shared), newReaderWithCacheStats(shared), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenTrie opens the main account trie at a specific root hash.
|
// OpenTrie opens the main account trie at a specific root hash.
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package state
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/lru"
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
|
|
@ -82,6 +83,20 @@ type Reader interface {
|
||||||
StateReader
|
StateReader
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReaderStats wraps the statistics of reader.
|
||||||
|
type ReaderStats struct {
|
||||||
|
AccountHit int64
|
||||||
|
AccountMiss int64
|
||||||
|
StorageHit int64
|
||||||
|
StorageMiss int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReaderWithStats wraps the additional method to retrieve the reader statistics from.
|
||||||
|
type ReaderWithStats interface {
|
||||||
|
Reader
|
||||||
|
GetStats() ReaderStats
|
||||||
|
}
|
||||||
|
|
||||||
// cachingCodeReader implements ContractCodeReader, accessing contract code either in
|
// cachingCodeReader implements ContractCodeReader, accessing contract code either in
|
||||||
// local key-value store or the shared code cache.
|
// local key-value store or the shared code cache.
|
||||||
//
|
//
|
||||||
|
|
@ -414,35 +429,43 @@ func newReaderWithCache(reader Reader) *readerWithCache {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account implements StateReader, retrieving the account specified by the address.
|
// account retrieves the account specified by the address along with a flag
|
||||||
// The returned account might be nil if it's not existent.
|
// indicating whether it's found in the cache or not. The returned account
|
||||||
|
// might be nil if it's not existent.
|
||||||
//
|
//
|
||||||
// An error will be returned if the state is corrupted in the underlying reader.
|
// An error will be returned if the state is corrupted in the underlying reader.
|
||||||
func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, error) {
|
func (r *readerWithCache) account(addr common.Address) (*types.StateAccount, bool, error) {
|
||||||
// Try to resolve the requested account in the local cache
|
// Try to resolve the requested account in the local cache
|
||||||
r.accountLock.RLock()
|
r.accountLock.RLock()
|
||||||
acct, ok := r.accounts[addr]
|
acct, ok := r.accounts[addr]
|
||||||
r.accountLock.RUnlock()
|
r.accountLock.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
return acct, nil
|
return acct, true, nil
|
||||||
}
|
}
|
||||||
// Try to resolve the requested account from the underlying reader
|
// Try to resolve the requested account from the underlying reader
|
||||||
acct, err := r.Reader.Account(addr)
|
acct, err := r.Reader.Account(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
r.accountLock.Lock()
|
r.accountLock.Lock()
|
||||||
r.accounts[addr] = acct
|
r.accounts[addr] = acct
|
||||||
r.accountLock.Unlock()
|
r.accountLock.Unlock()
|
||||||
return acct, nil
|
return acct, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage implements StateReader, retrieving the storage slot specified by the
|
// Account implements StateReader, retrieving the account specified by the address.
|
||||||
// address and slot key. The returned storage slot might be empty if it's not
|
// The returned account might be nil if it's not existent.
|
||||||
// existent.
|
|
||||||
//
|
//
|
||||||
// An error will be returned if the state is corrupted in the underlying reader.
|
// An error will be returned if the state is corrupted in the underlying reader.
|
||||||
func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
|
account, _, err := r.account(addr)
|
||||||
|
return account, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// storage retrieves the storage slot specified by the address and slot key, along
|
||||||
|
// with a flag indicating whether it's found in the cache or not. The returned
|
||||||
|
// storage slot might be empty if it's not existent.
|
||||||
|
func (r *readerWithCache) storage(addr common.Address, slot common.Hash) (common.Hash, bool, error) {
|
||||||
var (
|
var (
|
||||||
value common.Hash
|
value common.Hash
|
||||||
ok bool
|
ok bool
|
||||||
|
|
@ -456,12 +479,12 @@ func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common
|
||||||
}
|
}
|
||||||
bucket.lock.RUnlock()
|
bucket.lock.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
return value, nil
|
return value, true, nil
|
||||||
}
|
}
|
||||||
// Try to resolve the requested storage slot from the underlying reader
|
// Try to resolve the requested storage slot from the underlying reader
|
||||||
value, err := r.Reader.Storage(addr, slot)
|
value, err := r.Reader.Storage(addr, slot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, false, err
|
||||||
}
|
}
|
||||||
bucket.lock.Lock()
|
bucket.lock.Lock()
|
||||||
slots, ok = bucket.storages[addr]
|
slots, ok = bucket.storages[addr]
|
||||||
|
|
@ -472,5 +495,75 @@ func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common
|
||||||
slots[slot] = value
|
slots[slot] = value
|
||||||
bucket.lock.Unlock()
|
bucket.lock.Unlock()
|
||||||
|
|
||||||
|
return value, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage implements StateReader, retrieving the storage slot specified by the
|
||||||
|
// address and slot key. The returned storage slot might be empty if it's not
|
||||||
|
// existent.
|
||||||
|
//
|
||||||
|
// An error will be returned if the state is corrupted in the underlying reader.
|
||||||
|
func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||||
|
value, _, err := r.storage(addr, slot)
|
||||||
|
return value, err
|
||||||
|
}
|
||||||
|
|
||||||
|
type readerWithCacheStats struct {
|
||||||
|
*readerWithCache
|
||||||
|
accountHit atomic.Int64
|
||||||
|
accountMiss atomic.Int64
|
||||||
|
storageHit atomic.Int64
|
||||||
|
storageMiss atomic.Int64
|
||||||
|
}
|
||||||
|
|
||||||
|
// newReaderWithCacheStats constructs the reader with additional statistics tracked.
|
||||||
|
func newReaderWithCacheStats(reader *readerWithCache) *readerWithCacheStats {
|
||||||
|
return &readerWithCacheStats{
|
||||||
|
readerWithCache: reader,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account implements StateReader, retrieving the account specified by the address.
|
||||||
|
// The returned account might be nil if it's not existent.
|
||||||
|
//
|
||||||
|
// An error will be returned if the state is corrupted in the underlying reader.
|
||||||
|
func (r *readerWithCacheStats) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
|
account, incache, err := r.readerWithCache.account(addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if incache {
|
||||||
|
r.accountHit.Add(1)
|
||||||
|
} else {
|
||||||
|
r.accountMiss.Add(1)
|
||||||
|
}
|
||||||
|
return account, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Storage implements StateReader, retrieving the storage slot specified by the
|
||||||
|
// address and slot key. The returned storage slot might be empty if it's not
|
||||||
|
// existent.
|
||||||
|
//
|
||||||
|
// An error will be returned if the state is corrupted in the underlying reader.
|
||||||
|
func (r *readerWithCacheStats) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||||
|
value, incache, err := r.readerWithCache.storage(addr, slot)
|
||||||
|
if err != nil {
|
||||||
|
return common.Hash{}, err
|
||||||
|
}
|
||||||
|
if incache {
|
||||||
|
r.storageHit.Add(1)
|
||||||
|
} else {
|
||||||
|
r.storageMiss.Add(1)
|
||||||
|
}
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetStats implements ReaderWithStats, returning the statistics of state reader.
|
||||||
|
func (r *readerWithCacheStats) GetStats() ReaderStats {
|
||||||
|
return ReaderStats{
|
||||||
|
AccountHit: r.accountHit.Load(),
|
||||||
|
AccountMiss: r.accountMiss.Load(),
|
||||||
|
StorageHit: r.storageHit.Load(),
|
||||||
|
StorageMiss: r.storageMiss.Load(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
workers errgroup.Group
|
workers errgroup.Group
|
||||||
reader = statedb.Reader()
|
reader = statedb.Reader()
|
||||||
)
|
)
|
||||||
workers.SetLimit(runtime.NumCPU() / 2)
|
workers.SetLimit(4 * runtime.NumCPU() / 5) // Aggressively run the prefetching
|
||||||
|
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue