2019-03-31 18:54:12 -07:00
|
|
|
#![feature(test)]
|
|
|
|
|
|
|
|
extern crate test;
|
|
|
|
|
2020-10-21 12:54:09 -07:00
|
|
|
use dashmap::DashMap;
|
2020-10-13 18:29:50 -07:00
|
|
|
use rand::Rng;
|
2020-01-28 17:03:20 -08:00
|
|
|
use solana_runtime::{
|
|
|
|
accounts::{create_test_accounts, Accounts},
|
|
|
|
bank::*,
|
|
|
|
};
|
2020-09-02 00:37:36 -07:00
|
|
|
use solana_sdk::{
|
|
|
|
account::Account,
|
2020-09-08 23:55:09 +09:00
|
|
|
genesis_config::{create_genesis_config, ClusterType},
|
2020-09-02 00:37:36 -07:00
|
|
|
pubkey::Pubkey,
|
|
|
|
};
|
2020-10-21 12:54:09 -07:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
path::PathBuf,
|
|
|
|
sync::{Arc, RwLock},
|
|
|
|
thread::Builder,
|
|
|
|
};
|
2019-03-31 18:54:12 -07:00
|
|
|
use test::Bencher;
|
|
|
|
|
2019-03-31 21:31:19 -07:00
|
|
|
fn deposit_many(bank: &Bank, pubkeys: &mut Vec<Pubkey>, num: usize) {
|
2019-03-31 18:54:12 -07:00
|
|
|
for t in 0..num {
|
2019-03-31 21:31:19 -07:00
|
|
|
let pubkey = Pubkey::new_rand();
|
|
|
|
let account = Account::new((t + 1) as u64, 0, &Account::default().owner);
|
2020-06-09 01:38:14 +01:00
|
|
|
pubkeys.push(pubkey);
|
2019-03-31 18:54:12 -07:00
|
|
|
assert!(bank.get_account(&pubkey).is_none());
|
|
|
|
bank.deposit(&pubkey, (t + 1) as u64);
|
2019-03-31 21:31:19 -07:00
|
|
|
assert_eq!(bank.get_account(&pubkey).unwrap(), account);
|
2019-03-31 18:54:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 09:11:56 -08:00
|
|
|
#[bench]
|
|
|
|
fn bench_has_duplicates(bencher: &mut Bencher) {
|
|
|
|
bencher.iter(|| {
|
|
|
|
let data = test::black_box([1, 2, 3]);
|
|
|
|
assert!(!Accounts::has_duplicates(&data));
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-03-31 18:54:12 -07:00
|
|
|
#[bench]
|
|
|
|
fn test_accounts_create(bencher: &mut Bencher) {
|
2019-11-08 23:56:57 -05:00
|
|
|
let (genesis_config, _) = create_genesis_config(10_000);
|
2020-09-24 12:23:09 -07:00
|
|
|
let bank0 = Bank::new_with_paths(
|
|
|
|
&genesis_config,
|
|
|
|
vec![PathBuf::from("bench_a0")],
|
|
|
|
&[],
|
|
|
|
None,
|
|
|
|
None,
|
|
|
|
);
|
2019-03-31 18:54:12 -07:00
|
|
|
bencher.iter(|| {
|
|
|
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
2019-03-31 21:31:19 -07:00
|
|
|
deposit_many(&bank0, &mut pubkeys, 1000);
|
2019-03-31 18:54:12 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn test_accounts_squash(bencher: &mut Bencher) {
|
2020-10-09 12:19:50 -07:00
|
|
|
let (mut genesis_config, _) = create_genesis_config(100_000);
|
|
|
|
genesis_config.rent.burn_percent = 100; // Avoid triggering an assert in Bank::distribute_rent_to_validators()
|
2020-05-05 23:33:41 +08:00
|
|
|
let bank1 = Arc::new(Bank::new_with_paths(
|
2019-11-08 23:56:57 -05:00
|
|
|
&genesis_config,
|
2019-12-05 21:41:29 -05:00
|
|
|
vec![PathBuf::from("bench_a1")],
|
2020-03-22 11:10:04 -07:00
|
|
|
&[],
|
2020-09-23 18:46:42 -07:00
|
|
|
None,
|
2020-09-24 12:23:09 -07:00
|
|
|
None,
|
2020-05-05 23:33:41 +08:00
|
|
|
));
|
2019-03-31 18:54:12 -07:00
|
|
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
2020-06-09 01:38:14 +01:00
|
|
|
deposit_many(&bank1, &mut pubkeys, 250_000);
|
2020-05-05 23:33:41 +08:00
|
|
|
bank1.freeze();
|
|
|
|
|
|
|
|
// Measures the performance of the squash operation.
|
|
|
|
// This mainly consists of the freeze operation which calculates the
|
|
|
|
// merkle hash of the account state and distribution of fees and rent
|
|
|
|
let mut slot = 1u64;
|
2019-03-31 18:54:12 -07:00
|
|
|
bencher.iter(|| {
|
2020-05-05 23:33:41 +08:00
|
|
|
let bank2 = Arc::new(Bank::new_from_parent(&bank1, &Pubkey::default(), slot));
|
|
|
|
bank2.deposit(&pubkeys[0], 1);
|
|
|
|
bank2.squash();
|
|
|
|
slot += 1;
|
2019-03-31 18:54:12 -07:00
|
|
|
});
|
|
|
|
}
|
2019-07-19 10:32:29 -06:00
|
|
|
|
|
|
|
#[bench]
|
2019-12-20 09:39:30 +09:00
|
|
|
fn test_accounts_hash_bank_hash(bencher: &mut Bencher) {
|
2020-09-02 00:37:36 -07:00
|
|
|
let accounts = Accounts::new(
|
|
|
|
vec![PathBuf::from("bench_accounts_hash_internal")],
|
2020-09-08 23:55:09 +09:00
|
|
|
&ClusterType::Development,
|
2020-09-02 00:37:36 -07:00
|
|
|
);
|
2019-07-19 10:32:29 -06:00
|
|
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
2020-09-12 01:48:06 +09:00
|
|
|
let num_accounts = 60_000;
|
|
|
|
let slot = 0;
|
|
|
|
create_test_accounts(&accounts, &mut pubkeys, num_accounts, slot);
|
2019-10-18 12:59:47 -07:00
|
|
|
let ancestors = vec![(0, 0)].into_iter().collect();
|
2020-09-12 01:48:06 +09:00
|
|
|
let (_, total_lamports) = accounts.accounts_db.update_accounts_hash(0, &ancestors);
|
|
|
|
bencher.iter(|| assert!(accounts.verify_bank_hash_and_lamports(0, &ancestors, total_lamports)));
|
2019-07-19 10:32:29 -06:00
|
|
|
}
|
2020-02-22 13:46:40 -08:00
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn test_update_accounts_hash(bencher: &mut Bencher) {
|
|
|
|
solana_logger::setup();
|
2020-09-02 00:37:36 -07:00
|
|
|
let accounts = Accounts::new(
|
|
|
|
vec![PathBuf::from("update_accounts_hash")],
|
2020-09-08 23:55:09 +09:00
|
|
|
&ClusterType::Development,
|
2020-09-02 00:37:36 -07:00
|
|
|
);
|
2020-02-22 13:46:40 -08:00
|
|
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
|
|
|
create_test_accounts(&accounts, &mut pubkeys, 50_000, 0);
|
|
|
|
let ancestors = vec![(0, 0)].into_iter().collect();
|
|
|
|
bencher.iter(|| {
|
|
|
|
accounts.accounts_db.update_accounts_hash(0, &ancestors);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn test_accounts_delta_hash(bencher: &mut Bencher) {
|
|
|
|
solana_logger::setup();
|
2020-09-02 00:37:36 -07:00
|
|
|
let accounts = Accounts::new(
|
|
|
|
vec![PathBuf::from("accounts_delta_hash")],
|
2020-09-08 23:55:09 +09:00
|
|
|
&ClusterType::Development,
|
2020-09-02 00:37:36 -07:00
|
|
|
);
|
2020-02-22 13:46:40 -08:00
|
|
|
let mut pubkeys: Vec<Pubkey> = vec![];
|
|
|
|
create_test_accounts(&accounts, &mut pubkeys, 100_000, 0);
|
|
|
|
bencher.iter(|| {
|
|
|
|
accounts.accounts_db.get_accounts_delta_hash(0);
|
|
|
|
});
|
|
|
|
}
|
2020-07-15 06:49:22 -07:00
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn bench_delete_dependencies(bencher: &mut Bencher) {
|
|
|
|
solana_logger::setup();
|
2020-09-02 00:37:36 -07:00
|
|
|
let accounts = Accounts::new(
|
|
|
|
vec![PathBuf::from("accounts_delete_deps")],
|
2020-09-08 23:55:09 +09:00
|
|
|
&ClusterType::Development,
|
2020-09-02 00:37:36 -07:00
|
|
|
);
|
2020-07-15 06:49:22 -07:00
|
|
|
let mut old_pubkey = Pubkey::default();
|
|
|
|
let zero_account = Account::new(0, 0, &Account::default().owner);
|
|
|
|
for i in 0..1000 {
|
|
|
|
let pubkey = Pubkey::new_rand();
|
|
|
|
let account = Account::new((i + 1) as u64, 0, &Account::default().owner);
|
|
|
|
accounts.store_slow(i, &pubkey, &account);
|
|
|
|
accounts.store_slow(i, &old_pubkey, &zero_account);
|
|
|
|
old_pubkey = pubkey;
|
|
|
|
accounts.add_root(i);
|
|
|
|
}
|
|
|
|
bencher.iter(|| {
|
2020-09-28 16:04:46 -07:00
|
|
|
accounts.accounts_db.clean_accounts(None);
|
2020-07-15 06:49:22 -07:00
|
|
|
});
|
|
|
|
}
|
2020-10-13 18:29:50 -07:00
|
|
|
|
2020-10-21 17:05:27 -07:00
|
|
|
fn store_accounts_with_possible_contention<F: 'static>(
|
|
|
|
bench_name: &str,
|
|
|
|
bencher: &mut Bencher,
|
|
|
|
reader_f: F,
|
|
|
|
) where
|
|
|
|
F: Fn(&Accounts, &[Pubkey]) + Send + Copy,
|
|
|
|
{
|
2020-10-13 18:29:50 -07:00
|
|
|
let num_readers = 5;
|
|
|
|
let accounts = Arc::new(Accounts::new(
|
|
|
|
vec![
|
|
|
|
PathBuf::from(std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string()))
|
2020-10-21 17:05:27 -07:00
|
|
|
.join(bench_name),
|
2020-10-13 18:29:50 -07:00
|
|
|
],
|
|
|
|
&ClusterType::Development,
|
|
|
|
));
|
|
|
|
let num_keys = 1000;
|
|
|
|
let slot = 0;
|
|
|
|
accounts.add_root(slot);
|
|
|
|
let pubkeys: Arc<Vec<_>> = Arc::new(
|
|
|
|
(0..num_keys)
|
|
|
|
.map(|_| {
|
|
|
|
let pubkey = Pubkey::new_rand();
|
|
|
|
let account = Account::new(1, 0, &Account::default().owner);
|
|
|
|
accounts.store_slow(slot, &pubkey, &account);
|
|
|
|
pubkey
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
);
|
|
|
|
|
|
|
|
for _ in 0..num_readers {
|
|
|
|
let accounts = accounts.clone();
|
|
|
|
let pubkeys = pubkeys.clone();
|
|
|
|
Builder::new()
|
|
|
|
.name("readers".to_string())
|
|
|
|
.spawn(move || {
|
2020-10-21 17:05:27 -07:00
|
|
|
reader_f(&accounts, &pubkeys);
|
2020-10-13 18:29:50 -07:00
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
let num_new_keys = 1000;
|
|
|
|
let new_accounts: Vec<_> = (0..num_new_keys)
|
|
|
|
.map(|_| Account::new(1, 0, &Account::default().owner))
|
|
|
|
.collect();
|
|
|
|
bencher.iter(|| {
|
|
|
|
for account in &new_accounts {
|
|
|
|
// Write to a different slot than the one being read from. Because
|
|
|
|
// there's a new account pubkey being written to every time, will
|
|
|
|
// compete for the accounts index lock on every store
|
|
|
|
accounts.store_slow(slot + 1, &Pubkey::new_rand(), &account);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2020-10-21 12:54:09 -07:00
|
|
|
|
2020-10-21 17:05:27 -07:00
|
|
|
#[bench]
|
|
|
|
#[ignore]
|
|
|
|
fn bench_concurrent_read_write(bencher: &mut Bencher) {
|
|
|
|
store_accounts_with_possible_contention(
|
|
|
|
"concurrent_read_write",
|
|
|
|
bencher,
|
|
|
|
|accounts, pubkeys| {
|
|
|
|
let mut rng = rand::thread_rng();
|
|
|
|
loop {
|
|
|
|
let i = rng.gen_range(0, pubkeys.len());
|
|
|
|
test::black_box(accounts.load_slow(&HashMap::new(), &pubkeys[i]).unwrap());
|
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
#[ignore]
|
|
|
|
fn bench_concurrent_scan_write(bencher: &mut Bencher) {
|
|
|
|
store_accounts_with_possible_contention("concurrent_scan_write", bencher, |accounts, _| loop {
|
|
|
|
test::black_box(accounts.load_by_program(&HashMap::new(), &Account::default().owner));
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-10-21 12:54:09 -07:00
|
|
|
#[bench]
|
|
|
|
#[ignore]
|
|
|
|
fn bench_dashmap_single_reader_with_n_writers(bencher: &mut Bencher) {
|
|
|
|
let num_readers = 5;
|
|
|
|
let num_keys = 10000;
|
|
|
|
let map = Arc::new(DashMap::new());
|
|
|
|
for i in 0..num_keys {
|
|
|
|
map.insert(i, i);
|
|
|
|
}
|
|
|
|
for _ in 0..num_readers {
|
|
|
|
let map = map.clone();
|
|
|
|
Builder::new()
|
|
|
|
.name("readers".to_string())
|
|
|
|
.spawn(move || loop {
|
|
|
|
test::black_box(map.entry(5).or_insert(2));
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
bencher.iter(|| {
|
|
|
|
for _ in 0..num_keys {
|
|
|
|
test::black_box(map.get(&5).unwrap().value());
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
#[ignore]
|
|
|
|
fn bench_rwlock_hashmap_single_reader_with_n_writers(bencher: &mut Bencher) {
|
|
|
|
let num_readers = 5;
|
|
|
|
let num_keys = 10000;
|
|
|
|
let map = Arc::new(RwLock::new(HashMap::new()));
|
|
|
|
for i in 0..num_keys {
|
|
|
|
map.write().unwrap().insert(i, i);
|
|
|
|
}
|
|
|
|
for _ in 0..num_readers {
|
|
|
|
let map = map.clone();
|
|
|
|
Builder::new()
|
|
|
|
.name("readers".to_string())
|
|
|
|
.spawn(move || loop {
|
|
|
|
test::black_box(map.write().unwrap().get(&5));
|
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
bencher.iter(|| {
|
|
|
|
for _ in 0..num_keys {
|
|
|
|
test::black_box(map.read().unwrap().get(&5));
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|