bench get_retransmit_peers (#23292)
This commit is contained in:
parent
2a17a661e6
commit
c69e3b73ff
|
@ -0,0 +1,112 @@
|
||||||
|
#![feature(test)]
|
||||||
|
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
|
use {
|
||||||
|
rand::{seq::SliceRandom, Rng},
|
||||||
|
solana_core::{
|
||||||
|
cluster_nodes::{make_test_cluster, new_cluster_nodes, ClusterNodes},
|
||||||
|
retransmit_stage::RetransmitStage,
|
||||||
|
},
|
||||||
|
solana_gossip::contact_info::ContactInfo,
|
||||||
|
solana_sdk::{clock::Slot, hash::hashv, pubkey::Pubkey, signature::Signature},
|
||||||
|
test::Bencher,
|
||||||
|
};
|
||||||
|
|
||||||
|
const NUM_SIMULATED_SHREDS: usize = 4;
|
||||||
|
|
||||||
|
fn make_cluster_nodes<R: Rng>(
|
||||||
|
rng: &mut R,
|
||||||
|
unstaked_ratio: Option<(u32, u32)>,
|
||||||
|
) -> (Vec<ContactInfo>, ClusterNodes<RetransmitStage>) {
|
||||||
|
let (nodes, stakes, cluster_info) = make_test_cluster(rng, 5_000, unstaked_ratio);
|
||||||
|
let cluster_nodes = new_cluster_nodes::<RetransmitStage>(&cluster_info, &stakes);
|
||||||
|
(nodes, cluster_nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_retransmit_peers_deterministic(
|
||||||
|
cluster_nodes: &ClusterNodes<RetransmitStage>,
|
||||||
|
slot: &Slot,
|
||||||
|
slot_leader: &Pubkey,
|
||||||
|
num_simulated_shreds: usize,
|
||||||
|
) {
|
||||||
|
for i in 0..num_simulated_shreds {
|
||||||
|
// see Shred::seed
|
||||||
|
let shred_seed = hashv(&[
|
||||||
|
&slot.to_le_bytes(),
|
||||||
|
&(i as u32).to_le_bytes(),
|
||||||
|
&slot_leader.to_bytes(),
|
||||||
|
])
|
||||||
|
.to_bytes();
|
||||||
|
|
||||||
|
let (_neighbors, _children) = cluster_nodes.get_retransmit_peers_deterministic(
|
||||||
|
shred_seed,
|
||||||
|
solana_gossip::cluster_info::DATA_PLANE_FANOUT,
|
||||||
|
*slot_leader,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_retransmit_peers_compat(
|
||||||
|
cluster_nodes: &ClusterNodes<RetransmitStage>,
|
||||||
|
slot_leader: &Pubkey,
|
||||||
|
signatures: &[Signature],
|
||||||
|
) {
|
||||||
|
for signature in signatures.iter() {
|
||||||
|
// see Shred::seed
|
||||||
|
let signature = signature.as_ref();
|
||||||
|
let offset = signature.len().checked_sub(32).unwrap();
|
||||||
|
let shred_seed = signature[offset..].try_into().unwrap();
|
||||||
|
|
||||||
|
let (_neighbors, _children) = cluster_nodes.get_retransmit_peers_compat(
|
||||||
|
shred_seed,
|
||||||
|
solana_gossip::cluster_info::DATA_PLANE_FANOUT,
|
||||||
|
*slot_leader,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_retransmit_peers_deterministic_wrapper(b: &mut Bencher, unstaked_ratio: Option<(u32, u32)>) {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let (nodes, cluster_nodes) = make_cluster_nodes(&mut rng, unstaked_ratio);
|
||||||
|
let slot_leader = nodes[1..].choose(&mut rng).unwrap().id;
|
||||||
|
let slot = rand::random::<u64>();
|
||||||
|
b.iter(|| {
|
||||||
|
get_retransmit_peers_deterministic(
|
||||||
|
&cluster_nodes,
|
||||||
|
&slot,
|
||||||
|
&slot_leader,
|
||||||
|
NUM_SIMULATED_SHREDS,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_retransmit_peers_compat_wrapper(b: &mut Bencher, unstaked_ratio: Option<(u32, u32)>) {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let (nodes, cluster_nodes) = make_cluster_nodes(&mut rng, unstaked_ratio);
|
||||||
|
let slot_leader = nodes[1..].choose(&mut rng).unwrap().id;
|
||||||
|
let signatures: Vec<_> = std::iter::repeat_with(Signature::new_unique)
|
||||||
|
.take(NUM_SIMULATED_SHREDS)
|
||||||
|
.collect();
|
||||||
|
b.iter(|| get_retransmit_peers_compat(&cluster_nodes, &slot_leader, &signatures));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_get_retransmit_peers_deterministic_unstaked_ratio_1_2(b: &mut Bencher) {
|
||||||
|
get_retransmit_peers_deterministic_wrapper(b, Some((1, 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_get_retransmit_peers_compat_unstaked_ratio_1_2(b: &mut Bencher) {
|
||||||
|
get_retransmit_peers_compat_wrapper(b, Some((1, 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_get_retransmit_peers_deterministic_unstaked_ratio_1_32(b: &mut Bencher) {
|
||||||
|
get_retransmit_peers_deterministic_wrapper(b, Some((1, 32)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_get_retransmit_peers_compat_unstaked_ratio_1_32(b: &mut Bencher) {
|
||||||
|
get_retransmit_peers_compat_wrapper(b, Some((1, 32)));
|
||||||
|
}
|
|
@ -2,12 +2,14 @@ use {
|
||||||
crate::{broadcast_stage::BroadcastStage, retransmit_stage::RetransmitStage},
|
crate::{broadcast_stage::BroadcastStage, retransmit_stage::RetransmitStage},
|
||||||
itertools::Itertools,
|
itertools::Itertools,
|
||||||
lru::LruCache,
|
lru::LruCache,
|
||||||
rand::SeedableRng,
|
rand::{seq::SliceRandom, Rng, SeedableRng},
|
||||||
rand_chacha::ChaChaRng,
|
rand_chacha::ChaChaRng,
|
||||||
solana_gossip::{
|
solana_gossip::{
|
||||||
cluster_info::{compute_retransmit_peers, ClusterInfo},
|
cluster_info::{compute_retransmit_peers, ClusterInfo},
|
||||||
contact_info::ContactInfo,
|
contact_info::ContactInfo,
|
||||||
|
crds::GossipRoute,
|
||||||
crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS,
|
crds_gossip_pull::CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS,
|
||||||
|
crds_value::{CrdsData, CrdsValue},
|
||||||
weighted_shuffle::{weighted_best, weighted_shuffle, WeightedShuffle},
|
weighted_shuffle::{weighted_best, weighted_shuffle, WeightedShuffle},
|
||||||
},
|
},
|
||||||
solana_ledger::shred::Shred,
|
solana_ledger::shred::Shred,
|
||||||
|
@ -16,6 +18,7 @@ use {
|
||||||
clock::{Epoch, Slot},
|
clock::{Epoch, Slot},
|
||||||
feature_set,
|
feature_set,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
|
signature::Keypair,
|
||||||
timing::timestamp,
|
timing::timestamp,
|
||||||
},
|
},
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
solana_streamer::socket::SocketAddrSpace,
|
||||||
|
@ -23,6 +26,7 @@ use {
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
cmp::Reverse,
|
cmp::Reverse,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
iter::repeat_with,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
net::SocketAddr,
|
net::SocketAddr,
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
|
@ -39,7 +43,7 @@ enum NodeId {
|
||||||
Pubkey(Pubkey),
|
Pubkey(Pubkey),
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Node {
|
pub struct Node {
|
||||||
node: NodeId,
|
node: NodeId,
|
||||||
stake: u64,
|
stake: u64,
|
||||||
}
|
}
|
||||||
|
@ -233,6 +237,18 @@ impl ClusterNodes<RetransmitStage> {
|
||||||
if !enable_turbine_peers_shuffle_patch(shred.slot(), root_bank) {
|
if !enable_turbine_peers_shuffle_patch(shred.slot(), root_bank) {
|
||||||
return self.get_retransmit_peers_compat(shred_seed, fanout, slot_leader);
|
return self.get_retransmit_peers_compat(shred_seed, fanout, slot_leader);
|
||||||
}
|
}
|
||||||
|
self.get_retransmit_peers_deterministic(shred_seed, fanout, slot_leader)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_retransmit_peers_deterministic(
|
||||||
|
&self,
|
||||||
|
shred_seed: [u8; 32],
|
||||||
|
fanout: usize,
|
||||||
|
slot_leader: Pubkey,
|
||||||
|
) -> (
|
||||||
|
Vec<&Node>, // neighbors
|
||||||
|
Vec<&Node>, // children
|
||||||
|
) {
|
||||||
let mut weighted_shuffle = self.weighted_shuffle.clone();
|
let mut weighted_shuffle = self.weighted_shuffle.clone();
|
||||||
// Exclude slot leader from list of nodes.
|
// Exclude slot leader from list of nodes.
|
||||||
if slot_leader == self.pubkey {
|
if slot_leader == self.pubkey {
|
||||||
|
@ -256,7 +272,7 @@ impl ClusterNodes<RetransmitStage> {
|
||||||
(neighbors, children)
|
(neighbors, children)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_retransmit_peers_compat(
|
pub fn get_retransmit_peers_compat(
|
||||||
&self,
|
&self,
|
||||||
shred_seed: [u8; 32],
|
shred_seed: [u8; 32],
|
||||||
fanout: usize,
|
fanout: usize,
|
||||||
|
@ -297,7 +313,7 @@ impl ClusterNodes<RetransmitStage> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_cluster_nodes<T: 'static>(
|
pub fn new_cluster_nodes<T: 'static>(
|
||||||
cluster_info: &ClusterInfo,
|
cluster_info: &ClusterInfo,
|
||||||
stakes: &HashMap<Pubkey, u64>,
|
stakes: &HashMap<Pubkey, u64>,
|
||||||
) -> ClusterNodes<T> {
|
) -> ClusterNodes<T> {
|
||||||
|
@ -462,59 +478,25 @@ impl From<Pubkey> for NodeId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
pub fn make_test_cluster<R: Rng>(
|
||||||
mod tests {
|
|
||||||
use {
|
|
||||||
super::*,
|
|
||||||
rand::{seq::SliceRandom, Rng},
|
|
||||||
solana_gossip::{
|
|
||||||
crds::GossipRoute,
|
|
||||||
crds_value::{CrdsData, CrdsValue},
|
|
||||||
deprecated::{
|
|
||||||
shuffle_peers_and_index, sorted_retransmit_peers_and_stakes,
|
|
||||||
sorted_stakes_with_index,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
solana_sdk::{signature::Keypair, timing::timestamp},
|
|
||||||
solana_streamer::socket::SocketAddrSpace,
|
|
||||||
std::{iter::repeat_with, sync::Arc},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Legacy methods copied for testing backward compatibility.
|
|
||||||
|
|
||||||
fn get_broadcast_peers(
|
|
||||||
cluster_info: &ClusterInfo,
|
|
||||||
stakes: Option<&HashMap<Pubkey, u64>>,
|
|
||||||
) -> (Vec<ContactInfo>, Vec<(u64, usize)>) {
|
|
||||||
let mut peers = cluster_info.tvu_peers();
|
|
||||||
let peers_and_stakes = stake_weight_peers(&mut peers, stakes);
|
|
||||||
(peers, peers_and_stakes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stake_weight_peers(
|
|
||||||
peers: &mut Vec<ContactInfo>,
|
|
||||||
stakes: Option<&HashMap<Pubkey, u64>>,
|
|
||||||
) -> Vec<(u64, usize)> {
|
|
||||||
peers.dedup();
|
|
||||||
sorted_stakes_with_index(peers, stakes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_cluster<R: Rng>(
|
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> (
|
num_nodes: usize,
|
||||||
|
unstaked_ratio: Option<(u32, u32)>,
|
||||||
|
) -> (
|
||||||
Vec<ContactInfo>,
|
Vec<ContactInfo>,
|
||||||
HashMap<Pubkey, u64>, // stakes
|
HashMap<Pubkey, u64>, // stakes
|
||||||
ClusterInfo,
|
ClusterInfo,
|
||||||
) {
|
) {
|
||||||
|
let (unstaked_numerator, unstaked_denominator) = unstaked_ratio.unwrap_or((1, 7));
|
||||||
let mut nodes: Vec<_> = repeat_with(|| ContactInfo::new_rand(rng, None))
|
let mut nodes: Vec<_> = repeat_with(|| ContactInfo::new_rand(rng, None))
|
||||||
.take(1000)
|
.take(num_nodes)
|
||||||
.collect();
|
.collect();
|
||||||
nodes.shuffle(rng);
|
nodes.shuffle(rng);
|
||||||
let this_node = nodes[0].clone();
|
let this_node = nodes[0].clone();
|
||||||
let mut stakes: HashMap<Pubkey, u64> = nodes
|
let mut stakes: HashMap<Pubkey, u64> = nodes
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|node| {
|
.filter_map(|node| {
|
||||||
if rng.gen_ratio(1, 7) {
|
if rng.gen_ratio(unstaked_numerator, unstaked_denominator) {
|
||||||
None // No stake for some of the nodes.
|
None // No stake for some of the nodes.
|
||||||
} else {
|
} else {
|
||||||
Some((node.id, rng.gen_range(0, 20)))
|
Some((node.id, rng.gen_range(0, 20)))
|
||||||
|
@ -542,12 +524,40 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(nodes, stakes, cluster_info)
|
(nodes, stakes, cluster_info)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use {
|
||||||
|
super::*,
|
||||||
|
solana_gossip::deprecated::{
|
||||||
|
shuffle_peers_and_index, sorted_retransmit_peers_and_stakes, sorted_stakes_with_index,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Legacy methods copied for testing backward compatibility.
|
||||||
|
|
||||||
|
fn get_broadcast_peers(
|
||||||
|
cluster_info: &ClusterInfo,
|
||||||
|
stakes: Option<&HashMap<Pubkey, u64>>,
|
||||||
|
) -> (Vec<ContactInfo>, Vec<(u64, usize)>) {
|
||||||
|
let mut peers = cluster_info.tvu_peers();
|
||||||
|
let peers_and_stakes = stake_weight_peers(&mut peers, stakes);
|
||||||
|
(peers, peers_and_stakes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stake_weight_peers(
|
||||||
|
peers: &mut Vec<ContactInfo>,
|
||||||
|
stakes: Option<&HashMap<Pubkey, u64>>,
|
||||||
|
) -> Vec<(u64, usize)> {
|
||||||
|
peers.dedup();
|
||||||
|
sorted_stakes_with_index(peers, stakes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cluster_nodes_retransmit() {
|
fn test_cluster_nodes_retransmit() {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let (nodes, stakes, cluster_info) = make_cluster(&mut rng);
|
let (nodes, stakes, cluster_info) = make_test_cluster(&mut rng, 1_000, None);
|
||||||
let this_node = cluster_info.my_contact_info();
|
let this_node = cluster_info.my_contact_info();
|
||||||
// ClusterInfo::tvu_peers excludes the node itself.
|
// ClusterInfo::tvu_peers excludes the node itself.
|
||||||
assert_eq!(cluster_info.tvu_peers().len(), nodes.len() - 1);
|
assert_eq!(cluster_info.tvu_peers().len(), nodes.len() - 1);
|
||||||
|
@ -628,7 +638,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cluster_nodes_broadcast() {
|
fn test_cluster_nodes_broadcast() {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let (nodes, stakes, cluster_info) = make_cluster(&mut rng);
|
let (nodes, stakes, cluster_info) = make_test_cluster(&mut rng, 1_000, None);
|
||||||
// ClusterInfo::tvu_peers excludes the node itself.
|
// ClusterInfo::tvu_peers excludes the node itself.
|
||||||
assert_eq!(cluster_info.tvu_peers().len(), nodes.len() - 1);
|
assert_eq!(cluster_info.tvu_peers().len(), nodes.len() - 1);
|
||||||
let cluster_nodes = ClusterNodes::<BroadcastStage>::new(&cluster_info, &stakes);
|
let cluster_nodes = ClusterNodes::<BroadcastStage>::new(&cluster_info, &stakes);
|
||||||
|
|
|
@ -416,7 +416,7 @@ pub fn retransmitter(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct RetransmitStage {
|
pub struct RetransmitStage {
|
||||||
retransmit_thread_handle: JoinHandle<()>,
|
retransmit_thread_handle: JoinHandle<()>,
|
||||||
window_service: WindowService,
|
window_service: WindowService,
|
||||||
cluster_slots_service: ClusterSlotsService,
|
cluster_slots_service: ClusterSlotsService,
|
||||||
|
|
Loading…
Reference in New Issue