Skip to content

Commit bf965a7

Browse files
committed
ledger: Build the grouped slot leaders manually
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.
1 parent da1dcd7 commit bf965a7

2 files changed

Lines changed: 29 additions & 13 deletions

File tree

leader-schedule/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,13 @@ agave-random = { workspace = true }
2424
itertools = { workspace = true }
2525
rand_chacha = { workspace = true }
2626
solana-clock = { workspace = true }
27-
solana-pubkey = { workspace = true }
27+
solana-pubkey = { workspace = true, features = ["rand"] }
2828
solana-vote = { workspace = true }
2929

3030
[dev-dependencies]
3131
bs58 = { workspace = true, features = ["alloc"] }
3232
rand = { workspace = true }
3333
sha2 = { workspace = true }
34-
solana-pubkey = { workspace = true, features = ["rand"] }
3534
solana-vote = { path = "../vote", features = ["agave-unstable-api", "dev-context-only-utils"] }
3635
test-case = { workspace = true }
3736

leader-schedule/src/vote_keyed.rs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use {
22
super::{SlotLeader, stake_weighted_slot_leaders},
3-
itertools::Itertools,
43
solana_clock::Epoch,
5-
solana_pubkey::Pubkey,
4+
solana_pubkey::{Pubkey, PubkeyHasherBuilder},
65
solana_vote::vote_account::VoteAccountsHashMap,
76
std::{collections::HashMap, iter, num::NonZeroUsize, ops::Index},
87
};
@@ -11,7 +10,7 @@ use {
1110
pub struct LeaderSchedule {
1211
slot_leaders: Vec<SlotLeader>,
1312
// Inverted index from leader id to indices where they are the leader.
14-
leader_slots_map: HashMap<Pubkey, Vec<usize>>,
13+
leader_slots_map: HashMap<Pubkey, Vec<usize>, PubkeyHasherBuilder>,
1514
repeat: NonZeroUsize,
1615
}
1716

@@ -47,24 +46,42 @@ impl LeaderSchedule {
4746
})
4847
.collect();
4948
let slot_leaders = stake_weighted_slot_leaders(slot_leader_stakes, epoch, len, repeat);
50-
Self::new_from_schedule(slot_leaders, repeat)
49+
Self {
50+
leader_slots_map: Self::invert_slot_leaders(
51+
&slot_leaders,
52+
Some(vote_accounts_map.len()),
53+
),
54+
slot_leaders,
55+
repeat,
56+
}
5157
}
5258

5359
pub fn new_from_schedule(slot_leaders: Vec<SlotLeader>, repeat: NonZeroUsize) -> Self {
54-
let leader_slots_map = Self::invert_slot_leaders(&slot_leaders);
60+
let leader_slots_map = Self::invert_slot_leaders(&slot_leaders, None);
5561
Self {
5662
slot_leaders,
5763
leader_slots_map,
5864
repeat,
5965
}
6066
}
6167

62-
fn invert_slot_leaders(slot_leaders: &[SlotLeader]) -> HashMap<Pubkey, Vec<usize>> {
63-
slot_leaders
64-
.iter()
65-
.enumerate()
66-
.map(|(i, leader)| (leader.id, i))
67-
.into_group_map()
68+
fn invert_slot_leaders(
69+
slot_leaders: &[SlotLeader],
70+
nodes_len: Option<usize>,
71+
) -> HashMap<Pubkey, Vec<usize>, PubkeyHasherBuilder> {
72+
let mut grouped_slot_leaders = match nodes_len {
73+
Some(nodes_len) => {
74+
HashMap::with_capacity_and_hasher(nodes_len, PubkeyHasherBuilder::default())
75+
}
76+
None => HashMap::with_hasher(PubkeyHasherBuilder::default()),
77+
};
78+
for (slot, leader) in slot_leaders.iter().enumerate() {
79+
grouped_slot_leaders
80+
.entry(leader.id)
81+
.and_modify(|slots: &mut Vec<usize>| slots.push(slot))
82+
.or_insert(vec![slot]);
83+
}
84+
grouped_slot_leaders
6885
}
6986

7087
pub fn get_slot_leaders(&self) -> impl Iterator<Item = &SlotLeader> {

0 commit comments

Comments
 (0)