mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
core: extend the code reader statistics (#33659)
This PR extends the statistics of contract code read by adding these fields: - **CacheHitBytes**: the total number of bytes served by cache - **CacheMissBytes**: the total number of bytes read on cache miss - **CodeReadBytes**: the total number of bytes for contract code read
This commit is contained in:
parent
9a8e14e77e
commit
c2595381bf
5 changed files with 48 additions and 19 deletions
|
|
@ -76,6 +76,7 @@ var (
|
|||
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
||||
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
||||
codeReadTimer = metrics.NewRegisteredResettingTimer("chain/code/reads", nil)
|
||||
codeReadBytesTimer = metrics.NewRegisteredResettingTimer("chain/code/readbytes", nil)
|
||||
|
||||
accountCacheHitMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/hit", nil)
|
||||
accountCacheMissMeter = metrics.NewRegisteredMeter("chain/account/reads/cache/process/miss", nil)
|
||||
|
|
@ -2238,6 +2239,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s
|
|||
stats.StorageUpdated = int(statedb.StorageUpdated.Load())
|
||||
stats.StorageDeleted = int(statedb.StorageDeleted.Load())
|
||||
stats.CodeLoaded = statedb.CodeLoaded
|
||||
stats.CodeLoadBytes = statedb.CodeLoadBytes
|
||||
|
||||
stats.Execution = ptime - (statedb.AccountReads + statedb.StorageReads + statedb.CodeReads) // The time spent on EVM processing
|
||||
stats.Validation = vtime - (statedb.AccountHashes + statedb.AccountUpdates + statedb.StorageUpdates) // The time spent on block validation
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ type ExecuteStats struct {
|
|||
StorageUpdated int // Number of storage slots updated
|
||||
StorageDeleted int // Number of storage slots deleted
|
||||
CodeLoaded int // Number of contract code loaded
|
||||
CodeLoadBytes int // Number of bytes read from contract code
|
||||
|
||||
Execution time.Duration // Time spent on the EVM execution
|
||||
Validation time.Duration // Time spent on the block validation
|
||||
|
|
@ -74,6 +75,7 @@ func (s *ExecuteStats) reportMetrics() {
|
|||
if s.CodeLoaded != 0 {
|
||||
codeReadTimer.Update(s.CodeReads)
|
||||
codeReadSingleTimer.Update(s.CodeReads / time.Duration(s.CodeLoaded))
|
||||
codeReadBytesTimer.Update(time.Duration(s.CodeLoadBytes))
|
||||
}
|
||||
accountUpdateTimer.Update(s.AccountUpdates) // Account updates are complete(in validation)
|
||||
storageUpdateTimer.Update(s.StorageUpdates) // Storage updates are complete(in validation)
|
||||
|
|
@ -123,7 +125,7 @@ Validation: %v
|
|||
State read: %v
|
||||
Account read: %v(%d)
|
||||
Storage read: %v(%d)
|
||||
Code read: %v(%d)
|
||||
Code read: %v(%d %v)
|
||||
|
||||
State write: %v
|
||||
Trie commit: %v
|
||||
|
|
@ -145,7 +147,7 @@ State write: %v
|
|||
common.PrettyDuration(s.AccountReads+s.StorageReads+s.CodeReads),
|
||||
common.PrettyDuration(s.AccountReads), s.AccountLoaded,
|
||||
common.PrettyDuration(s.StorageReads), s.StorageLoaded,
|
||||
common.PrettyDuration(s.CodeReads), s.CodeLoaded,
|
||||
common.PrettyDuration(s.CodeReads), s.CodeLoaded, common.StorageSize(s.CodeLoadBytes),
|
||||
|
||||
// State write
|
||||
common.PrettyDuration(max(s.AccountCommits, s.StorageCommits)+s.TrieDBCommit+s.SnapshotCommit+s.BlockWrite),
|
||||
|
|
|
|||
|
|
@ -58,11 +58,28 @@ type ContractCodeReader interface {
|
|||
CodeSize(addr common.Address, codeHash common.Hash) (int, error)
|
||||
}
|
||||
|
||||
// ContractCodeReaderStats aggregates statistics for the contract code reader.
|
||||
type ContractCodeReaderStats struct {
|
||||
CacheHit int64 // Number of cache hits
|
||||
CacheMiss int64 // Number of cache misses
|
||||
CacheHitBytes int64 // Total bytes served from cache
|
||||
CacheMissBytes int64 // Total bytes read on cache misses
|
||||
}
|
||||
|
||||
// HitRate returns the cache hit rate.
|
||||
func (s ContractCodeReaderStats) HitRate() float64 {
|
||||
if s.CacheHit == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(s.CacheHit) / float64(s.CacheHit+s.CacheMiss)
|
||||
}
|
||||
|
||||
// ContractCodeReaderWithStats extends ContractCodeReader by adding GetStats to
|
||||
// expose statistics of code reader.
|
||||
type ContractCodeReaderWithStats interface {
|
||||
ContractCodeReader
|
||||
GetStats() (int64, int64)
|
||||
|
||||
GetStats() ContractCodeReaderStats
|
||||
}
|
||||
|
||||
// StateReader defines the interface for accessing accounts and storage slots
|
||||
|
|
@ -99,13 +116,11 @@ type Reader interface {
|
|||
|
||||
// ReaderStats wraps the statistics of reader.
|
||||
type ReaderStats struct {
|
||||
// Cache stats
|
||||
AccountCacheHit int64
|
||||
AccountCacheMiss int64
|
||||
StorageCacheHit int64
|
||||
StorageCacheMiss int64
|
||||
ContractCodeHit int64
|
||||
ContractCodeMiss int64
|
||||
CodeStats ContractCodeReaderStats
|
||||
}
|
||||
|
||||
// String implements fmt.Stringer, returning string format statistics.
|
||||
|
|
@ -113,7 +128,6 @@ func (s ReaderStats) String() string {
|
|||
var (
|
||||
accountCacheHitRate float64
|
||||
storageCacheHitRate float64
|
||||
contractCodeHitRate float64
|
||||
)
|
||||
if s.AccountCacheHit > 0 {
|
||||
accountCacheHitRate = float64(s.AccountCacheHit) / float64(s.AccountCacheHit+s.AccountCacheMiss) * 100
|
||||
|
|
@ -121,13 +135,10 @@ func (s ReaderStats) String() string {
|
|||
if s.StorageCacheHit > 0 {
|
||||
storageCacheHitRate = float64(s.StorageCacheHit) / float64(s.StorageCacheHit+s.StorageCacheMiss) * 100
|
||||
}
|
||||
if s.ContractCodeHit > 0 {
|
||||
contractCodeHitRate = float64(s.ContractCodeHit) / float64(s.ContractCodeHit+s.ContractCodeMiss) * 100
|
||||
}
|
||||
msg := fmt.Sprintf("Reader statistics\n")
|
||||
msg += fmt.Sprintf("account: hit: %d, miss: %d, rate: %.2f\n", s.AccountCacheHit, s.AccountCacheMiss, accountCacheHitRate)
|
||||
msg += fmt.Sprintf("storage: hit: %d, miss: %d, rate: %.2f\n", s.StorageCacheHit, s.StorageCacheMiss, storageCacheHitRate)
|
||||
msg += fmt.Sprintf("code: hit: %d, miss: %d, rate: %.2f\n", s.ContractCodeHit, s.ContractCodeMiss, contractCodeHitRate)
|
||||
msg += fmt.Sprintf("code: hit: %d(%v), miss: %d(%v), rate: %.2f\n", s.CodeStats.CacheHit, common.StorageSize(s.CodeStats.CacheHitBytes), s.CodeStats.CacheMiss, common.StorageSize(s.CodeStats.CacheMissBytes), s.CodeStats.HitRate())
|
||||
return msg
|
||||
}
|
||||
|
||||
|
|
@ -150,8 +161,10 @@ type cachingCodeReader struct {
|
|||
codeSizeCache *lru.Cache[common.Hash, int]
|
||||
|
||||
// Cache statistics
|
||||
hit atomic.Int64 // Number of code lookups found in the cache.
|
||||
miss atomic.Int64 // Number of code lookups not found in the cache.
|
||||
hit atomic.Int64 // Number of code lookups found in the cache
|
||||
miss atomic.Int64 // Number of code lookups not found in the cache
|
||||
hitBytes atomic.Int64 // Total number of bytes read from cache
|
||||
missBytes atomic.Int64 // Total number of bytes read from database
|
||||
}
|
||||
|
||||
// newCachingCodeReader constructs the code reader.
|
||||
|
|
@ -169,6 +182,7 @@ func (r *cachingCodeReader) Code(addr common.Address, codeHash common.Hash) ([]b
|
|||
code, _ := r.codeCache.Get(codeHash)
|
||||
if len(code) > 0 {
|
||||
r.hit.Add(1)
|
||||
r.hitBytes.Add(int64(len(code)))
|
||||
return code, nil
|
||||
}
|
||||
r.miss.Add(1)
|
||||
|
|
@ -177,6 +191,7 @@ func (r *cachingCodeReader) Code(addr common.Address, codeHash common.Hash) ([]b
|
|||
if len(code) > 0 {
|
||||
r.codeCache.Add(codeHash, code)
|
||||
r.codeSizeCache.Add(codeHash, len(code))
|
||||
r.missBytes.Add(int64(len(code)))
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
|
|
@ -202,9 +217,14 @@ func (r *cachingCodeReader) Has(addr common.Address, codeHash common.Hash) bool
|
|||
return len(code) > 0
|
||||
}
|
||||
|
||||
// GetStats returns the cache statistics fo the code reader.
|
||||
func (r *cachingCodeReader) GetStats() (int64, int64) {
|
||||
return r.hit.Load(), r.miss.Load()
|
||||
// GetStats returns the statistics of the code reader.
|
||||
func (r *cachingCodeReader) GetStats() ContractCodeReaderStats {
|
||||
return ContractCodeReaderStats{
|
||||
CacheHit: r.hit.Load(),
|
||||
CacheMiss: r.miss.Load(),
|
||||
CacheHitBytes: r.hitBytes.Load(),
|
||||
CacheMissBytes: r.missBytes.Load(),
|
||||
}
|
||||
}
|
||||
|
||||
// flatReader wraps a database state reader and is safe for concurrent access.
|
||||
|
|
@ -654,13 +674,11 @@ func (r *readerWithStats) Storage(addr common.Address, slot common.Hash) (common
|
|||
|
||||
// GetStats implements ReaderWithStats, returning the statistics of state reader.
|
||||
func (r *readerWithStats) GetStats() ReaderStats {
|
||||
codeHit, codeMiss := r.ContractCodeReaderWithStats.GetStats()
|
||||
return ReaderStats{
|
||||
AccountCacheHit: r.accountCacheHit.Load(),
|
||||
AccountCacheMiss: r.accountCacheMiss.Load(),
|
||||
StorageCacheHit: r.storageCacheHit.Load(),
|
||||
StorageCacheMiss: r.storageCacheMiss.Load(),
|
||||
ContractCodeHit: codeHit,
|
||||
ContractCodeMiss: codeMiss,
|
||||
CodeStats: r.ContractCodeReaderWithStats.GetStats(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -541,6 +541,7 @@ func (s *stateObject) Code() []byte {
|
|||
defer func(start time.Time) {
|
||||
s.db.CodeLoaded += 1
|
||||
s.db.CodeReads += time.Since(start)
|
||||
s.db.CodeLoadBytes += len(s.code)
|
||||
}(time.Now())
|
||||
|
||||
code, err := s.db.reader.Code(s.address, common.BytesToHash(s.CodeHash()))
|
||||
|
|
|
|||
|
|
@ -159,6 +159,12 @@ type StateDB struct {
|
|||
StorageUpdated atomic.Int64 // Number of storage slots updated during the state transition
|
||||
StorageDeleted atomic.Int64 // Number of storage slots deleted during the state transition
|
||||
CodeLoaded int // Number of contract code loaded during the state transition
|
||||
|
||||
// CodeLoadBytes is the total number of bytes read from contract code.
|
||||
// This value may be smaller than the actual number of bytes read, since
|
||||
// some APIs (e.g. CodeSize) may load the entire code from either the
|
||||
// cache or the database when the size is not available in the cache.
|
||||
CodeLoadBytes int
|
||||
}
|
||||
|
||||
// New creates a new state from a given trie.
|
||||
|
|
|
|||
Loading…
Reference in a new issue