diff --git a/core/blockchain.go b/core/blockchain.go index 95240293d6..9a9ebe1196 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -655,13 +655,6 @@ func (bc *BlockChain) processBlockWithAccessList(parentRoot common.Hash, block * // AccountLoaded/StorageLoaded come from the BAL access list (deduplicated); // per-StateDB sums would over-count addresses touched by multiple phases. stats.StateCounts = res.Counts - stats.StateCounts.Add(stateTransition.WriteCounts()) - if al := block.AccessList(); al != nil { - stats.StateCounts.AccountLoaded = al.UniqueAccountCount() - stats.StateCounts.StorageLoaded = al.UniqueStorageSlotCount() - } - stats.StateCounts.CodeLoaded = res.CodeLoaded - stats.StateCounts.CodeLoadBytes = res.CodeLoadBytes stats.Execution = res.ExecTime stats.ExecWall = res.ExecTime @@ -674,19 +667,13 @@ func (bc *BlockChain) processBlockWithAccessList(parentRoot common.Hash, block * stats.DatabaseCommit = m.TrieDBCommits stats.Prefetch = m.StatePrefetch } - // Sum-of-CPU-time across per-tx, BAL state-transition, and prefetcher paths. - var prefetchAccountReads, prefetchStorageReads time.Duration - if pr, ok := prefetchReader.(interface { - PrefetchReadTimes() (time.Duration, time.Duration) - }); ok { - prefetchAccountReads, prefetchStorageReads = pr.PrefetchReadTimes() - } - prefetchAccountReads, prefetchStorageReads = prefetchReader.(*.PrefetchReadTimes() - balAccountReads, balStorageReads := stateTransition.ReadTimes() - stats.AccountReads = res.Reads.Account + prefetchAccountReads + balAccountReads - stats.StorageReads = res.Reads.Storage + prefetchStorageReads + balStorageReads - stats.CodeReads = res.Reads.Code + stats.Prefetch = prefetchReader.(state.PrefetcherMetricer).Metrics().Elapsed + /* + stats.AccountReads = res.Reads.Account + prefetchAccountReads + balAccountReads + stats.StorageReads = res.Reads.Storage + prefetchStorageReads + balStorageReads + stats.CodeReads = res.Reads.Code + */ if r, ok := prefetchReader.(state.ReaderStater); ok { stats.StateReadCacheStats = r.GetStats() diff --git a/core/blockchain_stats.go b/core/blockchain_stats.go index 53834fca9a..b5278fb138 100644 --- a/core/blockchain_stats.go +++ b/core/blockchain_stats.go @@ -38,9 +38,7 @@ type ExecuteStats struct { StorageCommits time.Duration // Time spent on the storage trie commit CodeReads time.Duration // Time spent on the contract code read - // State-mutation counts. StorageUpdated/StorageDeleted are int64 - // (snapshot from atomic.Int64 on StateDB). - state.StateCounts + // TODO: where is code bytes loaded metric? Execution time.Duration // Time spent on the EVM execution Validation time.Duration // Time spent on the block validation diff --git a/core/state/bal_state_transition.go b/core/state/bal_state_transition.go index 7a30c96be5..881bd337f4 100644 --- a/core/state/bal_state_transition.go +++ b/core/state/bal_state_transition.go @@ -3,7 +3,6 @@ package state import ( "maps" "sync" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/common" @@ -41,17 +40,6 @@ type BALStateTransition struct { tries sync.Map //map[common.Address]Trie deletions map[common.Address]struct{} - // Storage/read counters are atomic — written from per-address goroutines. - // account/code counters are plain int — written single-threaded. - accountDeleted int - accountUpdated int - storageDeleted atomic.Int64 - storageUpdated atomic.Int64 - codeUpdated int - codeUpdateBytes int - accountReadNS atomic.Int64 - storageReadNS atomic.Int64 - stateUpdate *stateUpdate metrics BALStateTransitionMetrics @@ -64,23 +52,6 @@ func (s *BALStateTransition) Metrics() *BALStateTransitionMetrics { return &s.metrics } -// ReadTimes returns the accumulated state-read times. -func (s *BALStateTransition) ReadTimes() (account, storage time.Duration) { - return time.Duration(s.accountReadNS.Load()), time.Duration(s.storageReadNS.Load()) -} - -// WriteCounts returns the state-mutation counts from the parallel state-root pass. -func (s *BALStateTransition) WriteCounts() StateCounts { - return StateCounts{ - AccountUpdated: s.accountUpdated, - AccountDeleted: s.accountDeleted, - StorageUpdated: s.storageUpdated.Load(), - StorageDeleted: s.storageDeleted.Load(), - CodeUpdated: s.codeUpdated, - CodeUpdateBytes: s.codeUpdateBytes, - } -} - type BALStateTransitionMetrics struct { // trie hashing metrics AccountUpdate time.Duration @@ -223,9 +194,7 @@ func (s *BALStateTransition) commitAccount(addr common.Address) (*accountUpdate, for key, value := range s.diffs[addr].StorageWrites { hash := crypto.Keccak256Hash(key[:]) op.storages[hash] = encode(value) - storageReadStart := time.Now() storage, err := s.reader.Storage(addr, key) - s.storageReadNS.Add(time.Since(storageReadStart).Nanoseconds()) if err != nil { return nil, nil, err } @@ -365,10 +334,13 @@ func (s *BALStateTransition) CommitWithUpdate(block uint64, deleteEmptyObjects b return common.Hash{}, nil, err } - accountUpdatedMeter.Mark(int64(s.accountUpdated)) - storageUpdatedMeter.Mark(s.storageUpdated.Load()) - accountDeletedMeter.Mark(int64(s.accountDeleted)) - storageDeletedMeter.Mark(s.storageDeleted.Load()) + /* + TODO: derive these from the BAL + accountUpdatedMeter.Mark(int64(s.accountUpdated)) + storageUpdatedMeter.Mark(s.storageUpdated.Load()) + accountDeletedMeter.Mark(int64(s.accountDeleted)) + storageDeletedMeter.Mark(s.storageDeleted.Load()) + */ accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) storageTriesUpdatedMeter.Mark(int64(storageTrieNodesUpdated)) @@ -421,9 +393,7 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash { defer wg.Done() // 1 (c): update each mutated account, producing the post-block state object by applying the state mutations to the prestate (retrieved in 1a). - accountReadStart := time.Now() acct, err := s.reader.Account(address) - s.accountReadNS.Add(time.Since(accountReadStart).Nanoseconds()) if err != nil { s.setError(err) return @@ -450,12 +420,8 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash { if val != (common.Hash{}) { updateKeys = append(updateKeys, key[:]) updateValues = append(updateValues, common.TrimLeftZeroes(val[:])) - - s.storageUpdated.Add(1) } else { deleteKeys = append(deleteKeys, key[:]) - - s.storageDeleted.Add(1) } } if err := tr.UpdateStorageBatch(address, updateKeys, updateValues); err != nil { @@ -509,7 +475,6 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash { return common.Hash{} } s.deletions[mutatedAddr] = struct{}{} - s.accountDeleted++ } else { acct, code := s.updateAccount(mutatedAddr) @@ -520,15 +485,12 @@ func (s *BALStateTransition) IntermediateRoot(_ bool) common.Hash { s.setError(err) return common.Hash{} } - s.codeUpdated++ - s.codeUpdateBytes += len(code) } if err := s.stateTrie.UpdateAccount(mutatedAddr, acct, len(code)); err != nil { s.setError(err) return common.Hash{} } s.postStates[mutatedAddr] = acct - s.accountUpdated++ } } diff --git a/core/state/database.go b/core/state/database.go index da44d383ab..7c85d39a05 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -18,8 +18,6 @@ package state import ( "fmt" - "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/overlay" "github.com/ethereum/go-ethereum/core/rawdb" @@ -241,26 +239,6 @@ func (db *CachingDB) ReadersWithCacheStats(stateRoot common.Hash) (Reader, Reade return ra, rb, nil } -type ReaderEIP7928Metrics struct { - // the total amount of time it took to complete the scheduled workload - WallElapsed time.Duration - // the aggregated total time spent on state loading by all workers - TotalElapsed time.Duration - // the amount of accounts loaded - Accounts int - // the amount of storage slots loaded - Storages int - // number of accounts with code loaded - Codes int - // total amount of code bytes loaded - CodeBytes int -} - -type ReaderEIP7928 interface { - Reader - Metrics() *ReaderEIP7928Metrics -} - // ReaderEIP7928 creates a state reader with the manner of Block-level accessList. func (db *CachingDB) ReaderEIP7928(stateRoot common.Hash, accessList map[common.Address][]common.Hash, threads int) (Reader, error) { base, err := db.StateReader(stateRoot) diff --git a/core/state/reader.go b/core/state/reader.go index e6a6b5022c..4f3aa63667 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -18,10 +18,6 @@ package state import ( "errors" - "sync" - "sync/atomic" - "time" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/overlay" "github.com/ethereum/go-ethereum/core/types" @@ -32,6 +28,8 @@ import ( "github.com/ethereum/go-ethereum/trie/transitiontrie" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/database" + "sync" + "sync/atomic" ) // ContractCodeReader defines the interface for accessing contract code. @@ -564,13 +562,3 @@ func (r *reader) GetStats() ReaderStats { StateStats: r.GetStateStats(), } } - -// PrefetchReadTimes forwards to the wrapped prefetcher, or returns zero. -func (r *reader) PrefetchReadTimes() (account, storage time.Duration) { - if pr, ok := r.StateReader.(interface { - PrefetchReadTimes() (time.Duration, time.Duration) - }); ok { - return pr.PrefetchReadTimes() - } - return 0, 0 -} diff --git a/core/state/reader_eip_7928.go b/core/state/reader_eip_7928.go index 53949619a9..2212c7ac15 100644 --- a/core/state/reader_eip_7928.go +++ b/core/state/reader_eip_7928.go @@ -64,7 +64,6 @@ package state import ( "sync" - "sync/atomic" "time" "github.com/ethereum/go-ethereum/crypto" @@ -88,10 +87,33 @@ type prefetchStateReader struct { done chan struct{} term chan struct{} closeOnce sync.Once + start time.Time + metrics PrefetchMetrics +} - // Atomic — process() runs across N goroutines. - accountReadNS atomic.Int64 - storageReadNS atomic.Int64 +type PrefetchMetrics struct { + // the total amount of time it took to complete the scheduled workload + Elapsed time.Duration + // the aggregated total time spent on state loading by all workers + // TODO (jwasinger): add back in after i finish initial commit(s) with only the changes I think will be ultimately merged + // TotalElapsed time.Duration + + /* + // TODO: source these from the other reader where they are implemented + // the amount of accounts loaded + Accounts int + // the amount of storage slots loaded + Storages int + // number of accounts with code loaded + Codes int + // total amount of code bytes loaded + CodeBytes int + } + */ +} + +type PrefetcherMetricer interface { + Metrics() PrefetchMetrics } func newPrefetchStateReader(reader StateReader, accessList bal.StorageKeys, nThreads int) *prefetchStateReader { @@ -186,13 +208,9 @@ func (r *prefetchStateReader) process(start, limit int) { return default: if j == 0 { - accountReadStart := time.Now() r.StateReader.Account(t.addr) - r.accountReadNS.Add(time.Since(accountReadStart).Nanoseconds()) } else { - storageReadStart := time.Now() r.StateReader.Storage(t.addr, t.slots[j-1]) - r.storageReadNS.Add(time.Since(storageReadStart).Nanoseconds()) } } } @@ -373,6 +391,9 @@ func (r *readerTracker) TouchStorage(addr common.Address, slot common.Hash) { list[slot] = struct{}{} } +/* +// TODO: ensure these are accounted for + // GetStateStats forwards stats from the wrapped reader; without this, BAL // blocks would emit zero cache hit/miss counts. func (r *prefetchStateReader) GetStateStats() StateReaderStats { @@ -387,3 +408,4 @@ func (r *prefetchStateReader) GetStateStats() StateReaderStats { func (r *prefetchStateReader) PrefetchReadTimes() (account, storage time.Duration) { return time.Duration(r.accountReadNS.Load()), time.Duration(r.storageReadNS.Load()) } +*/ diff --git a/core/state/statedb.go b/core/state/statedb.go index 7f97822ca0..230c904541 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -223,6 +223,10 @@ func (s *StateDB) WithReader(reader Reader) *StateDB { return cpy } +/* + +// TODO (jwasinger): add these back in a subsequent commit + // ReadDurations groups the {Account, Storage, Code} state-read times. // Sum-of-CPU-time when aggregated across BAL phase statedbs. type ReadDurations struct { @@ -237,60 +241,7 @@ func (r *ReadDurations) Add(other ReadDurations) { r.Storage += other.Storage r.Code += other.Code } - -// StateCounts is a plain-int snapshot of state-mutation counters. Atomic -// fields on StateDB are Load()'d at the SnapshotCounts boundary. -type StateCounts struct { - AccountLoaded int // accounts retrieved from the database during the state transition - AccountUpdated int // accounts updated during the state transition - AccountDeleted int // accounts deleted during the state transition - StorageLoaded int // storage slots retrieved from the database during the state transition - StorageUpdated int64 // storage slots updated (snapshotted from atomic on StateDB) - StorageDeleted int64 // storage slots deleted (snapshotted from atomic on StateDB) - CodeLoaded int // contract code reads - CodeLoadBytes int // total bytes of resolved code - CodeUpdated int // code writes (CREATE/CREATE2/EIP-7702) - CodeUpdateBytes int // total bytes of persisted code written -} - -// Add merges other into c. -func (c *StateCounts) Add(other StateCounts) { - c.AccountLoaded += other.AccountLoaded - c.AccountUpdated += other.AccountUpdated - c.AccountDeleted += other.AccountDeleted - c.StorageLoaded += other.StorageLoaded - c.StorageUpdated += other.StorageUpdated - c.StorageDeleted += other.StorageDeleted - c.CodeLoaded += other.CodeLoaded - c.CodeLoadBytes += other.CodeLoadBytes - c.CodeUpdated += other.CodeUpdated - c.CodeUpdateBytes += other.CodeUpdateBytes -} - -// SnapshotCounts returns a plain-int copy of the state-mutation counters. -func (s *StateDB) SnapshotCounts() StateCounts { - return StateCounts{ - AccountLoaded: s.AccountLoaded, - AccountUpdated: s.AccountUpdated, - AccountDeleted: s.AccountDeleted, - StorageLoaded: s.StorageLoaded, - StorageUpdated: s.StorageUpdated.Load(), - StorageDeleted: s.StorageDeleted.Load(), - CodeLoaded: s.CodeLoaded, - CodeLoadBytes: s.CodeLoadBytes, - CodeUpdated: s.CodeUpdated, - CodeUpdateBytes: s.CodeUpdateBytes, - } -} - -// SnapshotReads returns the {Account, Storage, Code} read durations. -func (s *StateDB) SnapshotReads() ReadDurations { - return ReadDurations{ - Account: s.AccountReads, - Storage: s.StorageReads, - Code: s.CodeReads, - } -} +*/ // SnapshotCodeLoads returns addresses whose code body was fetched, mapped to // byte length. Used to deduplicate code-load events across BAL phase StateDBs.