solana/core/benches/crds_shards.rs
behzad nouri 9b866d79fb
shards crds values based on their hash prefix (#12187)
filter_crds_values checks every crds filter against every hash value:
https://github.com/solana-labs/solana/blob/ee646aa7/core/src/crds_gossip_pull.rs#L432
which can be inefficient if the filter's bit-mask only matches small
portion of the entire crds table.

This commit shards crds values into separate tables based on shard_bits
first bits of their hash prefix. Given a (mask, mask_bits) filter,
filtering crds can be done by inspecting only relevant shards.

If CrdsFilter.mask_bits <= shard_bits, then precisely only the crds
values which match (mask, mask_bits) bit pattern are traversed.
If CrdsFilter.mask_bits > shard_bits, then approximately only
1/2^shard_bits of crds values are inspected.

Benchmarking on a gce cluster of 20 nodes, I see ~10% improvement in
generate_pull_responses metric, but with larger clusters, crds table and
2^mask_bits are both larger, so the impact should be more significant.
2020-09-17 14:05:16 +00:00

70 lines
1.9 KiB
Rust

#![feature(test)]
extern crate test;
use rand::{thread_rng, Rng};
use solana_core::contact_info::ContactInfo;
use solana_core::crds::VersionedCrdsValue;
use solana_core::crds_shards::CrdsShards;
use solana_core::crds_value::{CrdsData, CrdsValue};
use solana_sdk::pubkey::Pubkey;
use solana_sdk::timing::timestamp;
use test::Bencher;
const CRDS_SHARDS_BITS: u32 = 8;
fn new_test_crds_value() -> VersionedCrdsValue {
let data = CrdsData::ContactInfo(ContactInfo::new_localhost(&Pubkey::new_rand(), timestamp()));
VersionedCrdsValue::new(timestamp(), CrdsValue::new_unsigned(data))
}
fn bench_crds_shards_find(bencher: &mut Bencher, num_values: usize, mask_bits: u32) {
let values: Vec<VersionedCrdsValue> = std::iter::repeat_with(new_test_crds_value)
.take(num_values)
.collect();
let mut shards = CrdsShards::new(CRDS_SHARDS_BITS);
for (index, value) in values.iter().enumerate() {
assert!(shards.insert(index, value));
}
let mut rng = thread_rng();
bencher.iter(|| {
let mask = rng.gen();
let _hits = shards.find(mask, mask_bits).count();
});
}
#[bench]
fn bench_crds_shards_find_0(bencher: &mut Bencher) {
bench_crds_shards_find(bencher, 100_000, 0);
}
#[bench]
fn bench_crds_shards_find_1(bencher: &mut Bencher) {
bench_crds_shards_find(bencher, 100_000, 1);
}
#[bench]
fn bench_crds_shards_find_3(bencher: &mut Bencher) {
bench_crds_shards_find(bencher, 100_000, 3);
}
#[bench]
fn bench_crds_shards_find_5(bencher: &mut Bencher) {
bench_crds_shards_find(bencher, 100_000, 5);
}
#[bench]
fn bench_crds_shards_find_7(bencher: &mut Bencher) {
bench_crds_shards_find(bencher, 100_000, 7);
}
#[bench]
fn bench_crds_shards_find_8(bencher: &mut Bencher) {
bench_crds_shards_find(bencher, 100_000, 8);
}
#[bench]
fn bench_crds_shards_find_9(bencher: &mut Bencher) {
bench_crds_shards_find(bencher, 100_000, 9);
}