This commit is contained in:
Jared Wasinger 2026-05-06 14:43:40 -04:00
parent aa8745521f
commit b7118dccfe
7 changed files with 23 additions and 165 deletions

View file

@ -656,7 +656,6 @@ func (bc *BlockChain) processBlockWithAccessList(parentRoot common.Hash, block *
writeTime := time.Since(writeStart) writeTime := time.Since(writeStart)
var stats ExecuteStats var stats ExecuteStats
stats.Execution = res.ExecTime
stats.ExecWall = res.ExecTime stats.ExecWall = res.ExecTime
stats.PostProcess = res.PostProcessTime stats.PostProcess = res.PostProcessTime
@ -669,11 +668,6 @@ func (bc *BlockChain) processBlockWithAccessList(parentRoot common.Hash, block *
} }
stats.Prefetch = prefetchReader.(state.PrefetcherMetricer).Metrics().Elapsed 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 { if r, ok := prefetchReader.(state.ReaderStater); ok {
stats.StateReadCacheStats = r.GetStats() stats.StateReadCacheStats = r.GetStats()
@ -2449,6 +2443,18 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
stats.AccountHashes = statedb.AccountHashes // Account hashes are complete(in validation) stats.AccountHashes = statedb.AccountHashes // Account hashes are complete(in validation)
stats.CodeReads = statedb.CodeReads stats.CodeReads = statedb.CodeReads
stats.AccountLoaded = statedb.AccountLoaded
stats.AccountUpdated = statedb.AccountUpdated
stats.AccountDeleted = statedb.AccountDeleted
stats.StorageLoaded = statedb.StorageLoaded
stats.StorageUpdated = int(statedb.StorageUpdated.Load())
stats.StorageDeleted = int(statedb.StorageDeleted.Load())
stats.CodeLoaded = statedb.CodeLoaded
stats.CodeLoadBytes = statedb.CodeLoadBytes
stats.CodeUpdated = statedb.CodeUpdated
stats.CodeUpdateBytes = statedb.CodeUpdateBytes
stats.Execution = ptime - (statedb.AccountReads + statedb.StorageReads + statedb.CodeReads) // The time spent on EVM processing 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 stats.Validation = vtime - (statedb.AccountHashes + statedb.AccountUpdates + statedb.StorageUpdates) // The time spent on block validation
stats.CrossValidation = xvtime // The time spent on stateless cross validation stats.CrossValidation = xvtime // The time spent on stateless cross validation

View file

@ -341,7 +341,6 @@ func (p *ParallelStateProcessor) processBlockPreTx(block *types.Block, statedb *
if !accessList.MutationsAt(0).Eq(mutations) { if !accessList.MutationsAt(0).Eq(mutations) {
return nil, fmt.Errorf("invalid block access list: mismatch between local/remote access list mutations at idx 0") return nil, fmt.Errorf("invalid block access list: mismatch between local/remote access list mutations at idx 0")
} }
// Snapshot pre-tx counts/reads/code-loads: sdb is local and otherwise discarded.
return reads, nil return reads, nil
} }

View file

@ -335,11 +335,13 @@ func (s *BALStateTransition) CommitWithUpdate(block uint64, deleteEmptyObjects b
} }
/* /*
TODO: derive these from the BAL TODO: derive these from the BAL
accountUpdatedMeter.Mark(int64(s.accountUpdated)) ^ I think even then, there is a semantic difference with how these metrics were calculated previously
storageUpdatedMeter.Mark(s.storageUpdated.Load()) I don't know if it makes sense to recompute those, or just derive new ones from the BAL
accountDeletedMeter.Mark(int64(s.accountDeleted)) accountUpdatedMeter.Mark(int64(s.accountUpdated))
storageDeletedMeter.Mark(s.storageDeleted.Load()) storageUpdatedMeter.Mark(s.storageUpdated.Load())
accountDeletedMeter.Mark(int64(s.accountDeleted))
storageDeletedMeter.Mark(s.storageDeleted.Load())
*/ */
accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated)) accountTrieUpdatedMeter.Mark(int64(accountTrieNodesUpdated))
accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted)) accountTrieDeletedMeter.Mark(int64(accountTrieNodesDeleted))

View file

@ -94,22 +94,6 @@ type prefetchStateReader struct {
type PrefetchMetrics struct { type PrefetchMetrics struct {
// the total amount of time it took to complete the scheduled workload // the total amount of time it took to complete the scheduled workload
Elapsed time.Duration 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 { type PrefetcherMetricer interface {
@ -395,22 +379,3 @@ func (r *readerTracker) TouchStorage(addr common.Address, slot common.Hash) {
} }
list[slot] = struct{}{} 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 {
if stater, ok := r.StateReader.(StateReaderStater); ok {
return stater.GetStateStats()
}
return StateReaderStats{}
}
// PrefetchReadTimes returns sum-of-CPU-time across worker goroutines (not
// wall-clock).
func (r *prefetchStateReader) PrefetchReadTimes() (account, storage time.Duration) {
return time.Duration(r.accountReadNS.Load()), time.Duration(r.storageReadNS.Load())
}
*/

View file

@ -209,10 +209,10 @@ func TestReaderWithTracker(t *testing.T) {
// transactions read without hitting the reader, causing the BAL to be incomplete. // transactions read without hitting the reader, causing the BAL to be incomplete.
func TestTrackerSurvivesStateDBCache(t *testing.T) { func TestTrackerSurvivesStateDBCache(t *testing.T) {
var ( var (
sdb = NewDatabaseForTesting() sdb = NewDatabaseForTesting()
statedb, _ = New(types.EmptyRootHash, sdb) statedb, _ = New(types.EmptyRootHash, sdb)
addr = common.HexToAddress("0xaaaa") addr = common.HexToAddress("0xaaaa")
slot = common.HexToHash("0x01") slot = common.HexToHash("0x01")
) )
// Set up committed state with one account that has a storage slot. // Set up committed state with one account that has a storage slot.
statedb.SetBalance(addr, uint256.NewInt(1e18), tracing.BalanceChangeUnspecified) statedb.SetBalance(addr, uint256.NewInt(1e18), tracing.BalanceChangeUnspecified)
@ -263,62 +263,3 @@ func TestTrackerSurvivesStateDBCache(t *testing.T) {
t.Fatal("slot must be tracked on cache hit (storage)") t.Fatal("slot must be tracked on cache hit (storage)")
} }
} }
// TestPrefetchStateReaderForwardsStats locks down that prefetchStateReader
// exposes the underlying stateReaderWithStats counters via GetStateStats.
func TestPrefetchStateReaderForwardsStats(t *testing.T) {
stub := newRefStateReader()
addr := testrand.Address()
cached := newStateReaderWithCache(stub)
withStats := newStateReaderWithStats(cached)
prefetch := newPrefetchStateReaderInternal(withStats, nil, 1)
if _, err := prefetch.Account(addr); err != nil {
t.Fatalf("Account: %v", err)
}
if _, err := prefetch.Account(addr); err != nil {
t.Fatalf("Account (second): %v", err)
}
stats := withStats.GetStateStats()
if stats.AccountCacheHit == 0 || stats.AccountCacheMiss == 0 {
t.Fatalf("inner stats not populated: %+v", stats)
}
gotStats := prefetch.GetStateStats()
if gotStats != stats {
t.Fatalf("forward mismatch: got %+v, want %+v", gotStats, stats)
}
}
// TestReaderForwardsPrefetchReadTimes locks down that *reader exposes the
// inner prefetcher's read-time counters via PrefetchReadTimes.
func TestReaderForwardsPrefetchReadTimes(t *testing.T) {
stub := newRefStateReader()
cached := newStateReaderWithCache(stub)
withStats := newStateReaderWithStats(cached)
prefetch := newPrefetchStateReaderInternal(withStats, nil, 1)
prefetch.accountReadNS.Store(123)
prefetch.storageReadNS.Store(456)
r := newReader(nil, prefetch)
a, s := r.PrefetchReadTimes()
if a != 123 {
t.Errorf("account: got %v, want 123", a)
}
if s != 456 {
t.Errorf("storage: got %v, want 456", s)
}
}
// TestReaderPrefetchReadTimesNonPrefetch verifies the zero fallback when the
// wrapped reader doesn't expose PrefetchReadTimes.
func TestReaderPrefetchReadTimesNonPrefetch(t *testing.T) {
r := newReader(nil, newRefStateReader())
a, s := r.PrefetchReadTimes()
if a != 0 || s != 0 {
t.Errorf("expected (0, 0), got (%v, %v)", a, s)
}
}

View file

@ -223,44 +223,6 @@ func (s *StateDB) WithReader(reader Reader) *StateDB {
return cpy 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 {
Account time.Duration
Storage time.Duration
Code time.Duration
}
// Add merges other into r.
func (r *ReadDurations) Add(other ReadDurations) {
r.Account += other.Account
r.Storage += other.Storage
r.Code += other.Code
}
*/
// SnapshotCodeLoads returns addresses whose code body was fetched, mapped to
// byte length. Used to deduplicate code-load events across BAL phase StateDBs.
func (s *StateDB) SnapshotCodeLoads() map[common.Address]int {
if len(s.stateObjects) == 0 {
return nil
}
var m map[common.Address]int
for addr, obj := range s.stateObjects {
if l := len(obj.code); l > 0 {
if m == nil {
m = make(map[common.Address]int)
}
m[addr] = l
}
}
return m
}
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
// state trie concurrently while the state is mutated so that when we reach the // state trie concurrently while the state is mutated so that when we reach the
// commit phase, most of the needed data is already hot. // commit phase, most of the needed data is already hot.

View file

@ -44,23 +44,6 @@ import (
// BlockAccessList is the encoding format of AccessListBuilder. // BlockAccessList is the encoding format of AccessListBuilder.
type BlockAccessList []AccountAccess type BlockAccessList []AccountAccess
// UniqueAccountCount returns the number of distinct account addresses in
// the block access list.
func (e BlockAccessList) UniqueAccountCount() int {
return len(e)
}
// UniqueStorageSlotCount returns the total number of distinct (address, slot)
// pairs accessed across all accounts. Reads and writes are disjoint per
// account by spec validation, so we can sum them directly.
func (e BlockAccessList) UniqueStorageSlotCount() int {
var n int
for i := range e {
n += len(e[i].StorageReads) + len(e[i].StorageChanges)
}
return n
}
func (e BlockAccessList) EncodeRLP(_w io.Writer) error { func (e BlockAccessList) EncodeRLP(_w io.Writer) error {
w := rlp.NewEncoderBuffer(_w) w := rlp.NewEncoderBuffer(_w)
l := w.List() l := w.List()