diff --git a/core/blockchain.go b/core/blockchain.go index 59f5716638..17deeac42b 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -677,10 +677,6 @@ func (bc *BlockChain) processBlockWithAccessList(parentRoot common.Hash, block * stats.DatabaseCommit = m.TrieDBCommits stats.Prefetch = m.StatePrefetch } - // Refresh BAL read-time cache: commitAccount runs storage reads during - // writeBlockWithState, after the first Metrics() snapshot. - stateTransition.Metrics() - // Sum read times across per-tx execution, BAL state-transition, and // prefetcher async fetches. Sum-of-CPU-time, not wall-clock. if w, ok := prefetchReader.(interface{ WaitPrefetch() }); ok { @@ -692,13 +688,10 @@ func (bc *BlockChain) processBlockWithAccessList(parentRoot common.Hash, block * }); ok { prefetchAccountReads, prefetchStorageReads = pr.PrefetchReadTimes() } - stats.AccountReads = res.PerTxAccountReads + prefetchAccountReads - stats.StorageReads = res.PerTxStorageReads + prefetchStorageReads + balAccountReads, balStorageReads := stateTransition.ReadTimes() + stats.AccountReads = res.PerTxAccountReads + prefetchAccountReads + balAccountReads + stats.StorageReads = res.PerTxStorageReads + prefetchStorageReads + balStorageReads stats.CodeReads = res.PerTxCodeReads - if m := res.StateTransitionMetrics; m != nil { - stats.AccountReads += m.AccountReadTime - stats.StorageReads += m.StorageReadTime - } // Cache stats from the shared prefetch reader (accumulates centrally). if r, ok := prefetchReader.(state.ReaderStater); ok { diff --git a/core/state/bal_state_transition.go b/core/state/bal_state_transition.go index 3bffe934a5..ab7bcf37f8 100644 --- a/core/state/bal_state_transition.go +++ b/core/state/bal_state_transition.go @@ -64,12 +64,20 @@ type BALStateTransition struct { err error } +// Metrics returns the cached commit/hash-phase timings. Read-time atomics +// are exposed separately via ReadTimes; that decoupling avoids the +// snapshot-staleness pitfall when commitAccount runs more reads after +// Metrics is first called. func (s *BALStateTransition) Metrics() *BALStateTransitionMetrics { - s.metrics.AccountReadTime = time.Duration(s.accountReadNS.Load()) - s.metrics.StorageReadTime = time.Duration(s.storageReadNS.Load()) return &s.metrics } +// ReadTimes returns the current accumulated read times from atomic counters. +// Always live; safe to call at any point after IntermediateRoot/Commit work. +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 tracked during the parallel // state-root computation. func (s *BALStateTransition) WriteCounts() StateCounts { @@ -96,11 +104,6 @@ type BALStateTransitionMetrics struct { SnapshotCommits time.Duration TrieDBCommits time.Duration TotalCommitTime time.Duration - - // State-root recomputation read times. Sum of CPU time across the per- - // address goroutines that call s.reader.Account/Storage during commit. - AccountReadTime time.Duration - StorageReadTime time.Duration } func NewBALStateTransition(block *types.Block, prefetchReader Reader, db Database, parentRoot common.Hash) (*BALStateTransition, error) {