mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 07:58:40 +00:00
core/state: forward prefetcher read times through the reader aggregator
Without this, the inline interface assertion in processBlockWithAccessList silently fell through (the prefetchReader returned by ReaderEIP7928 is a *reader wrapper, not the inner *prefetchStateReader), causing the prefetcher contribution to state_read_ms to drop to zero in production. Mirrors the existing GetStateStats forwarding pattern. Adds a regression test that asserts *reader exposes PrefetchReadTimes via the BAL chain, plus a fallback test for non-prefetch readers.
This commit is contained in:
parent
812fa198c3
commit
6b1ea9a498
2 changed files with 51 additions and 0 deletions
|
|
@ -20,6 +20,7 @@ import (
|
|||
"errors"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/overlay"
|
||||
|
|
@ -563,3 +564,15 @@ func (r *reader) GetStats() ReaderStats {
|
|||
StateStats: r.GetStateStats(),
|
||||
}
|
||||
}
|
||||
|
||||
// PrefetchReadTimes returns the prefetcher's accumulated read times if the
|
||||
// underlying state reader exposes them (e.g. *prefetchStateReader). Returns
|
||||
// zero if the wrapped reader doesn't track these (sequential paths, tests).
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -290,3 +290,41 @@ func TestPrefetchStateReaderForwardsStats(t *testing.T) {
|
|||
t.Fatalf("forward mismatch: got %+v, want %+v", gotStats, stats)
|
||||
}
|
||||
}
|
||||
|
||||
// TestReaderForwardsPrefetchReadTimes locks down that the *reader aggregator
|
||||
// (the type returned by ReaderEIP7928) exposes PrefetchReadTimes via the
|
||||
// inner *prefetchStateReader. Without the forwarding method on *reader,
|
||||
// callers that hold a Reader interface would not see the prefetcher's
|
||||
// accumulated read times even though the prefetcher tracks them.
|
||||
func TestReaderForwardsPrefetchReadTimes(t *testing.T) {
|
||||
stub := newRefStateReader()
|
||||
cached := newStateReaderWithCache(stub)
|
||||
withStats := newStateReaderWithStats(cached)
|
||||
prefetch := newPrefetchStateReaderInternal(withStats, nil, 1)
|
||||
|
||||
// Seed timer values directly on the prefetcher.
|
||||
prefetch.accountReadNS.Store(123)
|
||||
prefetch.storageReadNS.Store(456)
|
||||
|
||||
// Wrap in *reader the way ReaderEIP7928 does (with a nil code reader for
|
||||
// brevity; PrefetchReadTimes only inspects the state side).
|
||||
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 safe zero fallback when
|
||||
// the wrapped state reader doesn't expose PrefetchReadTimes (sequential path).
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue