ledger: Build the grouped slot leaders manually#8451
ledger: Build the grouped slot leaders manually#8451vadorovsky merged 4 commits intoanza-xyz:masterfrom
Conversation
e42e215 to
cb8fedb
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #8451 +/- ##
=======================================
Coverage 83.1% 83.1%
=======================================
Files 849 849
Lines 321241 321256 +15
=======================================
+ Hits 267026 267069 +43
+ Misses 54215 54187 -28 🚀 New features to boost your workflow:
|
37b32a9 to
b758fe5
Compare
|
Excellent work! I have just one comment! |
HaoranYi
left a comment
There was a problem hiding this comment.
LGTM. Please wait for other reviewer's approval before merge.
|
I'm going to bow out and defer to the other reviewers since I'm OOO. |
|
We should probably review our uses of |
I'm yet to profile all uses of let mut grouped = HashMap::with_capacity_and_hasher(cap, hasher);
for (key, value) in input {
grouped_slot_leaders
.entry(value)
.and_modify(|keys| {
keys.push(key);
})
.or_insert(vec![key]);
}Perhaps I should already move it to some common function in Given the lack of elasticity of itertools (no way of providing capacities and hashers), I think its usage is a footgun. I tried to make it accept custom hashers, but the PR got closed: rust-itertools/itertools#1057. |
| let slots = Arc::get_mut(slots).expect("should be the only reference"); | ||
| slots.push(slot) | ||
| }) | ||
| .or_insert(Arc::new(vec![slot])); |
There was a problem hiding this comment.
could also experiment with smallvec, with just a slot value you could keep like 2-3 elements inline without allocating
There was a problem hiding this comment.
Good idea. Or maybe even arrayvec.
There was a problem hiding this comment.
in the profile, I think you see grow taking a lot of time, so if anything you should allocate with higher capacity?
There was a problem hiding this comment.
Oh it's Vec<usize>, yeah use arrayvec
There was a problem hiding this comment.
Actually we we can't use arrayvec. The amount of non-repeating slots we store for each leader looks like:
curl https://api.mainnet-beta.solana.com -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0", "id":1, "method":"getLeaderSchedule", "params":[null, {"commitment":"finalized"}]}' | jq -r '.result | to_entries | map({identity: .key, slots: ((.value | length)/4)}) | sort_by(.slots) | reverse[] | "\(.slots)\t\(.identity)"' | save -r leader_slots.txt
I'm dividing by 4, because of recently merged #9126.
The top 17 validators have more than 1k non-repeating slots:
3630 HEL1USMZKAL2odpNBj2oCjffnFGaYwmbGmyewGv1e2TU
3438 Fd7btgySsrjuo25CJCj7oE7VPMyezDhnx7pZkj2v69Nk
3412 DRpbCBMxVnDK7maPM5tGv6MvB3v1sRMC86PZ8okm21hy
3142 JupmVLmA8RoyTUbTMMuTtoPWHEiNQobxgTeGTrPNkzT
2139 q9XWcZ7T1wP4bW9SB4XgNNwjnFEJ982nE8aVbbNuwot
1906 EvnRmnMrd69kFdbLMxWkTn1icZ7DCceRhvmb2SJXqDo4
1801 DtdSSG8ZJRZVv5Jx7K1MeWp7Zxcu19GD5wQRGRpQ9uMF
1793 E1r4Psq84tHfQ6aPTvvDka4U3u8zPVD7gEUrH25RdxHL
1764 JD549HsbJHeEKKUrKgg4Fj2iyv2RGjsV7NTZjZUrHybB
1708 Awes4Tr6TX8JDzEhCZY2QVNimT6iD1zWHzf1vNyGvpLM
1626 5pPRHniefFjkiaArbGX3Y8NUysJmQ9tMZg3FrFGwHzSm
1594 CAo1dCGYrB6NhHh5xb1cGjUiu86iyCfMTENxgHumSve4
1289 9jxgosAfHgHzwnxsHw4RAZYaLVokMbnYtmiZBreynGFP
1269 5Cchr1XGEg7dbBXByV5NY2ad8jfxAM7HA3x8D56rq9Ux
1173 9rkJMARqK6VBkcxGfKBAwnA44gPAfGxPbPsfsggFNDSQ
1032 FBKFWadXZJahGtFitAsBvbqh5968gLY7dMBBJUoUjeNi
1015 BkoS26vBuaXnSowACdChi4WKid8UwmuPNhEJWa8KsLHd
That's way too much for arrayvec, we would blow up the stack, since we would need to go with something like ArrayVec<Slot, 4096> and have 1k of them. Then there is always a risk we have to increase it if the dominance of top validators increases.
But also, the last ~500 validators have less than 64 non-repeating slots, and last ~300 validators less than 32, ~70 validators that have less than 10. I'm not even sure if we gain anything from smallvec in that case.
Anyways, can we think of smallvec separately, outside of this PR? First of all, the open question is how large arrays, and how many of them. can we keep on stack. The choice of what size of smallvec we pick (SmallVec<[Slot; 10]>, SmallVec<[Slot; 32]>, ``SmallVec<[Slot; 64]>` etc.) depends on that. Then the other question is if it brings any visible perf improvement.
Good point — applying the same pattern to staked_nodes in stake_cache gave us a 3–4× speed-up as well: #8516 |
cd7b5b6 to
80b2e04
Compare
80b2e04 to
3c4c8de
Compare
3c4c8de to
a4f2f46
Compare
|
If this PR represents a change to the public RPC API:
Thank you for keeping the RPC clients in sync with the server API @vadorovsky. |
vadorovsky
left a comment
There was a problem hiding this comment.
Yes, sorry for letting it stale!
798b7de to
d6416d8
Compare
Building them with `itertools::into_group_map` takes 20.9ms. Building them manually with a pre-allocated hash map, using pubkey hasher, takes 5.2ms.
d6416d8 to
bf965a7
Compare
|
LGTM |
It works even with a custom hasher.
In the context of enumeration in leader schedule, `index` is a more appropriate name.
Problem
Building them with
itertools::into_group_maptakes 20.9ms.Summary of Changes
Building them manually with a pre-allocated hash map, using pubkey hasher, takes 5.2ms.
Ref: #8280