use {
criterion::{Criterion, criterion_group, criterion_main},
rand::{Rng, SeedableRng, rngs::SmallRng},
solana_accounts_db::ancestors::Ancestors,
solana_hash::Hash,
solana_runtime::bank::BankStatusCache,
solana_signature::{SIGNATURE_BYTES, Signature},
std::time::Duration,
};
#[cfg(not(feature = "shuttle-test"))]
use {
solana_hash::HASH_BYTES, solana_runtime::serde_snapshot::serialize_status_cache_into,
solana_sha256_hasher::hash,
};
#[cfg(not(feature = "shuttle-test"))]
fn bench_status_cache_serialize(c: &mut Criterion) {
let mut status_cache = BankStatusCache::default();
status_cache.add_root(0);
status_cache.clear();
for hash_index in 0..100 {
let blockhash = Hash::new_from_array([hash_index; HASH_BYTES]);
let mut id = blockhash;
for _ in 0..100 {
id = hash(id.as_ref());
let mut sigbytes = Vec::from(id.as_ref());
id = hash(id.as_ref());
sigbytes.extend(id.as_ref());
let sig = Signature::try_from(sigbytes).unwrap();
status_cache.insert(&blockhash, sig, 0, Ok(()));
}
}
assert!(status_cache.roots().contains(&0));
c.bench_function("bench_status_cache_serialize", |b| {
b.iter(|| {
let mut buffer = Vec::new();
serialize_status_cache_into(&mut buffer, &status_cache.root_slot_deltas()).unwrap();
buffer
})
});
}
#[cfg(not(feature = "shuttle-test"))]
fn bench_status_cache_serialize_max(c: &mut Criterion) {
let mut status_cache = BankStatusCache::default();
let max_root_entries = status_cache.max_root_entries() as u64;
fill_status_cache(&mut status_cache, max_root_entries, 100_000);
assert!(status_cache.roots().contains(&0));
c.bench_function("bench_status_cache_serialize_max", |b| {
b.iter(|| {
let mut buffer = Vec::new();
serialize_status_cache_into(&mut buffer, &status_cache.root_slot_deltas()).unwrap();
buffer
})
});
}
fn bench_status_cache_root_slot_deltas(c: &mut Criterion) {
let mut status_cache = BankStatusCache::default();
let slots: Vec<_> = (42..).take(status_cache.max_root_entries()).collect();
for slot in &slots {
for _ in 0..5 {
status_cache.insert(&Hash::new_unique(), Hash::new_unique(), *slot, Ok(()));
}
status_cache.add_root(*slot);
}
c.bench_function("bench_status_cache_root_slot_deltas", |b| {
b.iter(|| status_cache.root_slot_deltas())
});
}
fn fill_status_cache(status_cache: &mut BankStatusCache, max_root_entries: u64, num_txs: usize) {
for slot in 0..max_root_entries {
let blockhash = Hash::new_unique();
fill_status_cache_slot(status_cache, &blockhash, slot, num_txs);
}
}
fn fill_status_cache_slot(
status_cache: &mut BankStatusCache,
blockhash: &Hash,
slot: u64,
num_txs: usize,
) {
for _ in 0..num_txs {
let tx_hash = Hash::new_unique();
status_cache.insert(blockhash, tx_hash, slot, Ok(()));
}
}
#[allow(clippy::arithmetic_side_effects)]
fn bench_status_cache_check_and_insert(c: &mut Criterion) {
let mut status_cache = BankStatusCache::default();
let max_root_entries = status_cache.max_root_entries() as u64;
fill_status_cache(&mut status_cache, max_root_entries - 1, 100_000);
let blockhash = Hash::new_unique();
fill_status_cache_slot(&mut status_cache, &blockhash, max_root_entries, 100_000);
let slot = max_root_entries + 1;
let ancestors = Ancestors::from((slot - 32..slot).collect::<Vec<u64>>());
let batch_size = 1_000;
let mut tx_hashes = Vec::with_capacity(batch_size);
let mut rng = SmallRng::seed_from_u64(0);
for _ in 0..batch_size {
let mut sigbytes = [0u8; SIGNATURE_BYTES];
rng.fill(&mut sigbytes);
tx_hashes.push(Signature::from(sigbytes));
}
c.bench_function("bench_status_cache_check_and_insert", |b| {
b.iter(|| {
for tx_hash in &tx_hashes {
if status_cache
.get_status(*tx_hash, &blockhash, &ancestors)
.is_none()
{
status_cache.insert(&blockhash, *tx_hash, slot, Ok(()));
}
}
})
});
}
#[allow(clippy::arithmetic_side_effects)]
fn bench_status_cache_add_roots(c: &mut Criterion) {
let mut status_cache = BankStatusCache::default();
let max_root_entries = status_cache.max_root_entries() as u64;
fill_status_cache(&mut status_cache, max_root_entries, 100_000);
let start_slot = max_root_entries + 1;
c.bench_function("bench_status_cache_add_roots", |b| {
b.iter(|| {
for root in start_slot..start_slot + max_root_entries {
status_cache.add_root(root);
}
})
});
}
fn bench_status_cache(c: &mut Criterion) {
#[cfg(not(feature = "shuttle-test"))]
bench_status_cache_serialize(c);
#[cfg(not(feature = "shuttle-test"))]
bench_status_cache_serialize_max(c);
bench_status_cache_root_slot_deltas(c);
bench_status_cache_check_and_insert(c);
bench_status_cache_add_roots(c);
}
criterion_group! {
name = benches;
config = Criterion::default()
.warm_up_time(Duration::from_millis(150))
.measurement_time(Duration::from_millis(750))
.sample_size(10)
.without_plots();
targets = bench_status_cache
}
criterion_main!(benches);