-
Notifications
You must be signed in to change notification settings - Fork 20.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core/state: trie prefetcher change: calling trie() doesn't stop the associated subfetcher #29035
core/state: trie prefetcher change: calling trie() doesn't stop the associated subfetcher #29035
Conversation
Failed tests... the last commit borks something. |
Okay. CI is running successfully locally on two separate machines (mac/linux) for me. Unsure why it fails in github actions. |
5ecb17e
to
13196b8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please elaborate a bit more about what this PR tries to achieve, and why that is better.
As in, why it's needed for your upcoming work, but also what the effects on the current code is. Does it improve anything? Simplify something? Degrade something?
// repeated. | ||
// 2. Finalize of the main account trie. This happens only once per block. | ||
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) error { | ||
if p.closed { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there ever a multi-thread accessing prefetch / close ? If so, might be better to make closed
into an atomic.Bool
? But if we don't access it that way, it's fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefetcher is manipulated in the statedb, which is not regarded as thread-safe. I believe we never do multi-thread accessing prefetch.
The biggest difference this pull request introduces is: Originally, when a trie is requested, the prefetching tasks are suspended and resumed once the live trie is copied and returned. This approach could cause problems for witness collection. For instance: If slot A is accessed but not modified, the relevant trie nodes should be wrapped as the witness. Subsequently, slot A will be scheduled for prefetching and queued in the task list. However, if the corresponding storage trie is retrieved without slot A being preloaded at that time, then the relevant trie nodes won't be included in the witness. In this pull request, the prefetching tasks scheduled before retrieving the trie will always be executed. Thus the issue is resolved. Besides, the Copy function is dropped for simplification. And actually the original complexity is not worthwhile anyway. The statedb.Copy is mostly used in miner, but after the change made by marius, we don't copy the statedb in miner anymore. Make no sense to copy the prefetcher for the performance gain. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, but we need to run it on the benchmarking infra for a bit
…ssociated subfetcher Co-authored-by: Martin HS <martin@swende.se> Co-authored-by: Péter Szilágyi <peterke@gmail.com>
… until pending tasks on the subfetcher have been resolved.
453f06d
to
287cead
Compare
Unfortunately, the added overhead to block processing and increased memory usage means that this PR is a non-starter. |
I think it's maybe a bit premature to close this. Please add the relevant graphs/charts from the benchmark-run, so we can discuss and reason about it |
@@ -237,7 +194,7 @@ func newSubfetcher(db Database, state common.Hash, owner common.Hash, root commo | |||
owner: owner, | |||
root: root, | |||
addr: addr, | |||
wake: make(chan struct{}, 1), | |||
wake: make(chan struct{}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change seems problematic. Whereas the original code allowed to schedule the request and then fly off continuing execution, the new code (along with L217 below) will block until a previous request is done (actually, block on the second request).
Any particular reason you made the async notifier synchronous?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well spotted!
There's a change in this PR that converted the async wake notifier into a sync one, which can potentially have a really heavy hit on performance as it ill block execution during preloading. Perhaps that's the root of the slowdown. |
Closing and reopening my own because OP didn't permit maintainer changes. |
:'( I don't know why this is suddenly something I have to explicitly enable. Until recently, PRs I've made in the past have been maintainer-modifiable by default.... |
This pulls trie prefetcher changes from #29029 into a separate PR.
It changes the trie prefetcher s.t. a call to
trie
returns a trie (after any pending tasks have been resolved in the subfetcher). After a call totrie
, the subfetcher is now available for more work (instead of terminating).