-
Notifications
You must be signed in to change notification settings - Fork 20k
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
A lot of time is spent determining the size of the pending/queued transaction pool #16717
Comments
Looks like Len() function is getting called quite a lot on the elements of pool.pending. It looks like pool.pending is not mutated inside the promoteExecutables(), so a simple assignment to a variable should do the job. |
This seems odd: https://golang.org/src/runtime/hashmap.go#L1232 My guess is its actually the number of operations done on pool.pending rather than the actual |
Done a bit of debug-print digging, most invocations are indeed done when estabilishing the for _, list := range pool.pending {
pending += uint64(list.Len())
}
pending map[common.Address]*txList to Perhaps it is EDIT: This section seems related to PR #16720, which might have made it obsolete. The profiling graph doesn't show this, but the addrs := make([]common.Address, 0, len(dirty))
for addr := range dirty {
addrs = append(addrs, addr)
}
pool.promoteExecutables(addrs) In other words, |
P.S. Although in current network conditions this manifests mostly with The crux of the issue is that these are "hash maps of (non-homogenous) lists", and their size is determined by iterating over the elements. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
AFAIK nothing has changed between v1.8.7 and v1.8.27: I haven't run profiling on v1.8.27, but would guess the inefficiency is still present. |
The 1.9 release family changed the way transactions are shuffled within the bool from a synchronous one after every insert to an async one that runs in the background. This means that if there's high churn, the shuffling (and inherently the iterating) will run much much rarer. Could you perhaps try if a latest release still exhibits this behavior? My initial guess would be that it does not. |
I'm not able to replicate the experiment completely (the machine has been "beefed up" resource-wise). Below is with However, the situation seems to have gotten "worse". Running:
Notice the inclusion of Profiling graph: https://veox.pw/dump/fiddled-v1.9.6.svg It's now at 18.93% (another round shows 19.20%, another one 18.00%). Most likely an indicator of how everything else improved... I still see no solution for this other than to have a But that is patently unfriendly to multi-processing, and I don't know the proper |
We've made a lot of improvements lately:
I believe this is mostly fixed now, so closing. Please open a new ticket if this problem still is present |
EDIT: Original title: A lot of time is spent determining the length of txSortedMap
System information
Geth version:
Geth/v1.8.7-stable-66432f38/linux-amd64/go1.10
OS & Version: Ubuntu 16.04.4 LTS (Xenial Xerus)
Background
I've tried to do txpool analysis, retaining as much of it as possible (e.g. having 32768 slots). My assumption was that this would mostly require copious amounts of memory, but it seemed to increase CPU load, too.
I've dropped the count down to 8192 and ran some profiling. (See link at the very bottom.)
Possible optimisation?..
In
core/tx_pool.go
,TxPool promoteExecutables()
has a lot of nested loops that iterate over various lists of transactions.Calls are made to
txSortedMap
'sLen()
(comes fromcore/tx_list.go
); it seems that the structure does not have a specific field for this, so the determination is made on-the-fly.In my tests, 5-10% of a "production" node's time is spent determining the length of these maps. This would seem to be true for most any
txpool
settings, unless severely restrictingtxpool.pricelimit
.(BTW, the default for that is 1 wei, which also contributes to the issue: the txpool is pretty much guaranteed to be immediately filled up by "default policy" peers, and remain in a constant state of churn from then on.)
Since this probably can't be avoided, perhaps it can be optimised for?..
Steps to reproduce the behaviour
Run
geth
something like:/usr/bin/geth --metrics \ --datadir /home/geth/.ethereum \ --cache 3072 \ --txpool.pricelimit 31337000 --txpool.accountslots 4 --txpool.globalslots 8192 --txpool.accountqueue 4 \ --lightserv 50 --lightpeers 1000 --maxpeers 1025
In
console
:Generate SVG:
go tool pprof fiddled.prof (pprof) svg > fiddled.svg
CPU profiling graph
https://veox.pw/dump/fiddled.svg
Note: this was intentionally timed to a window with little DB flushing.
Cc: @AlexeyAkhunov - not sure if you're mostly interested is sync optimisation, or runtime also.
The text was updated successfully, but these errors were encountered: