-
Notifications
You must be signed in to change notification settings - Fork 461
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
Remove 14MB from RunPeerCommit allocations #5294
Conversation
Not sure why this change would crash the Test host process; isn't doing anything wild 🤔 |
11c8184
to
0310e62
Compare
96a41fc
to
7a003cb
Compare
public int PersistedNodesCount | ||
public int PersistedNodesCount => GetPersistedNodes().Length; | ||
|
||
public NetworkNode[] GetPersistedNodes() |
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.
Does it have to return an Array? Can it just return IReadOnlyCollection and we could leverage the list itself? We could avoid storing array and list and allocating array all the time.
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.
Recreating the array gets around the concurrency problem of the list being used while the list is being adjusted since its used in a few places and the nodes are created via events from the network; so it would need tighter synchronisation on the iteration in DiscoveryApp.AddPersistedNodes
; NodesLoader.LoadPeersFromDb
and PeerPool.UpdateReputationAndMaxPeersCount()
with the node creation form ProtocolsManager.InitSyncPeerProtocol
; DiscoveryApp.RunDiscoveryCommit()
; DiscoveryManager.GetNodeLifecycleManager
and removal from DiscoveryManager.OnIncomingMsg
and PeerPool.CleanupPersistedPeers
It doesn't have the issue currently as it completely recreates the NetworkNode[]
from scratch from the DB each time the method is called; whereas here its reused form most method calls (and it only reads from the DB once for app lifetime, though it continues to write changes to it, but updates in memory structure instead of reading back)
tl;dr yes it could, but is complicated due to the concurrency
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.
Fair enough, but you could have 2 lists that you would only copy from one to the other without any allocations or GC.
Or maybe we can do without copying and just exchange them?
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 work; though use of the other list isn't guaranteed to have finished before starting to repopulate it
However thinking about that, could maybe get away with one List by taking a bounded Span reference via CollectionsMarshal.AsSpan<T>(List<T>)
; then adding some null checks when the items are returned and skipping them. Would need to look into it a bit more as might be a bit wild 😅
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.
We have this two list approach in TxBroadcaster
with _accumulatedTemporaryTxs
and _txsToSend
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.
Looks like its a single threaded reader and when the method is re-entered you know the iteration is complete? (e.g. timer fire) so safe; whereas here its read and written from a bunch of sources?
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.
Tried the 2 approach + Span, but is tricky to workout when to switch without it immediately switching back (e.g. UpdateNodes(IEnumerable<NetworkNode> nodes)
calls UpdateNode(NetworkNode node)
multiple times); and the Span still suffers from nodes being removed in the middle of the list, so skipping nodes 🤔
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.
Probably better to look at in future PR?
NetworkNode node = GetNode(nodeRlp); | ||
_nodesList.Add(node); | ||
_nodePublicKeys.Add(node.NodeId); |
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.
We could potentially reuse already existing nodes instead of creating new ones all the time
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.
RemoveNode
and UpdateNode
don't set the _nodes
array to null
but just replace it so GenerateNodes()
should only be creating the nodes from scratch once during app lifetime (i.e. this bit of code) and UpdateNode
gets passed in the preconstructed NetworkNode
so it would require a fair bit of refactoring to reuse the nodes from RemoveNode
🤔
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.
So rlp starts with public key, which could be decoded on stack, then it could be reused from existing node instead of creating new one.
We can say it is out of scope of this PR and try to do it in some next one if ever - but sounds doable.
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.
Yeah I think would be good to look at that; as well as wider, as are a lot of temporary byte[]
created for Rlp
only to be fed into KeccakHash.Compute
then thrown away; but the temp byte[]
could be bypassed by feeding direct into KeccakHash
which would also reduce copies by one
c72bf08
to
d0406bd
Compare
Rebased |
Not sure why this test failed
MevRpc doesn't involve the peer nodes? 🤔 |
d0406bd
to
8d776c0
Compare
Rebased again and squashed commits to see if persistent |
Rebased #5271 as was having issues with github 🤔
Changes
Types of changes
What types of changes does your code introduce?
Testing
Requires testing