Skip to content

Commit 0e12172

Browse files
authored
Moves accounts benches into accounts-db crate (solana-labs#164)
1 parent 3863bb1 commit 0e12172

File tree

2 files changed

+349
-334
lines changed

2 files changed

+349
-334
lines changed

accounts-db/benches/accounts.rs

+343
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
#![feature(test)]
2+
#![allow(clippy::arithmetic_side_effects)]
3+
4+
extern crate test;
5+
6+
use {
7+
dashmap::DashMap,
8+
rand::Rng,
9+
rayon::iter::{IntoParallelRefIterator, ParallelIterator},
10+
solana_accounts_db::{
11+
accounts::{AccountAddressFilter, Accounts},
12+
accounts_db::{
13+
test_utils::create_test_accounts, AccountShrinkThreshold, AccountsDb,
14+
VerifyAccountsHashAndLamportsConfig, ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS,
15+
},
16+
accounts_index::{AccountSecondaryIndexes, ScanConfig},
17+
ancestors::Ancestors,
18+
},
19+
solana_sdk::{
20+
account::{Account, AccountSharedData, ReadableAccount},
21+
genesis_config::ClusterType,
22+
hash::Hash,
23+
pubkey::Pubkey,
24+
rent_collector::RentCollector,
25+
sysvar::epoch_schedule::EpochSchedule,
26+
},
27+
std::{
28+
collections::{HashMap, HashSet},
29+
path::PathBuf,
30+
sync::{Arc, RwLock},
31+
thread::Builder,
32+
},
33+
test::Bencher,
34+
};
35+
36+
fn new_accounts_db(account_paths: Vec<PathBuf>) -> AccountsDb {
37+
AccountsDb::new_with_config(
38+
account_paths,
39+
&ClusterType::Development,
40+
AccountSecondaryIndexes::default(),
41+
AccountShrinkThreshold::default(),
42+
Some(ACCOUNTS_DB_CONFIG_FOR_BENCHMARKS),
43+
None,
44+
Arc::default(),
45+
)
46+
}
47+
48+
#[bench]
49+
fn bench_accounts_hash_bank_hash(bencher: &mut Bencher) {
50+
let accounts_db = new_accounts_db(vec![PathBuf::from("bench_accounts_hash_internal")]);
51+
let accounts = Accounts::new(Arc::new(accounts_db));
52+
let mut pubkeys: Vec<Pubkey> = vec![];
53+
let num_accounts = 60_000;
54+
let slot = 0;
55+
create_test_accounts(&accounts, &mut pubkeys, num_accounts, slot);
56+
let ancestors = Ancestors::from(vec![0]);
57+
let (_, total_lamports) = accounts
58+
.accounts_db
59+
.update_accounts_hash_for_tests(0, &ancestors, false, false);
60+
accounts.add_root(slot);
61+
accounts.accounts_db.flush_accounts_cache(true, Some(slot));
62+
bencher.iter(|| {
63+
assert!(accounts.verify_accounts_hash_and_lamports(
64+
0,
65+
total_lamports,
66+
None,
67+
VerifyAccountsHashAndLamportsConfig {
68+
ancestors: &ancestors,
69+
test_hash_calculation: false,
70+
epoch_schedule: &EpochSchedule::default(),
71+
rent_collector: &RentCollector::default(),
72+
ignore_mismatch: false,
73+
store_detailed_debug_info: false,
74+
use_bg_thread_pool: false,
75+
}
76+
))
77+
});
78+
}
79+
80+
#[bench]
81+
fn bench_update_accounts_hash(bencher: &mut Bencher) {
82+
solana_logger::setup();
83+
let accounts_db = new_accounts_db(vec![PathBuf::from("update_accounts_hash")]);
84+
let accounts = Accounts::new(Arc::new(accounts_db));
85+
let mut pubkeys: Vec<Pubkey> = vec![];
86+
create_test_accounts(&accounts, &mut pubkeys, 50_000, 0);
87+
let ancestors = Ancestors::from(vec![0]);
88+
bencher.iter(|| {
89+
accounts
90+
.accounts_db
91+
.update_accounts_hash_for_tests(0, &ancestors, false, false);
92+
});
93+
}
94+
95+
#[bench]
96+
fn bench_accounts_delta_hash(bencher: &mut Bencher) {
97+
solana_logger::setup();
98+
let accounts_db = new_accounts_db(vec![PathBuf::from("accounts_delta_hash")]);
99+
let accounts = Accounts::new(Arc::new(accounts_db));
100+
let mut pubkeys: Vec<Pubkey> = vec![];
101+
create_test_accounts(&accounts, &mut pubkeys, 100_000, 0);
102+
bencher.iter(|| {
103+
accounts.accounts_db.calculate_accounts_delta_hash(0);
104+
});
105+
}
106+
107+
#[bench]
108+
fn bench_delete_dependencies(bencher: &mut Bencher) {
109+
solana_logger::setup();
110+
let accounts_db = new_accounts_db(vec![PathBuf::from("accounts_delete_deps")]);
111+
let accounts = Accounts::new(Arc::new(accounts_db));
112+
let mut old_pubkey = Pubkey::default();
113+
let zero_account = AccountSharedData::new(0, 0, AccountSharedData::default().owner());
114+
for i in 0..1000 {
115+
let pubkey = solana_sdk::pubkey::new_rand();
116+
let account = AccountSharedData::new(i + 1, 0, AccountSharedData::default().owner());
117+
accounts.store_slow_uncached(i, &pubkey, &account);
118+
accounts.store_slow_uncached(i, &old_pubkey, &zero_account);
119+
old_pubkey = pubkey;
120+
accounts.add_root(i);
121+
}
122+
bencher.iter(|| {
123+
accounts.accounts_db.clean_accounts_for_tests();
124+
});
125+
}
126+
127+
fn store_accounts_with_possible_contention<F: 'static>(
128+
bench_name: &str,
129+
bencher: &mut Bencher,
130+
reader_f: F,
131+
) where
132+
F: Fn(&Accounts, &[Pubkey]) + Send + Copy,
133+
{
134+
let num_readers = 5;
135+
let accounts_db = new_accounts_db(vec![PathBuf::from(
136+
std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string()),
137+
)
138+
.join(bench_name)]);
139+
let accounts = Arc::new(Accounts::new(Arc::new(accounts_db)));
140+
let num_keys = 1000;
141+
let slot = 0;
142+
143+
let pubkeys: Vec<_> = std::iter::repeat_with(solana_sdk::pubkey::new_rand)
144+
.take(num_keys)
145+
.collect();
146+
let accounts_data: Vec<_> = std::iter::repeat(Account {
147+
lamports: 1,
148+
..Default::default()
149+
})
150+
.take(num_keys)
151+
.collect();
152+
let storable_accounts: Vec<_> = pubkeys.iter().zip(accounts_data.iter()).collect();
153+
accounts.store_accounts_cached((slot, storable_accounts.as_slice()));
154+
accounts.add_root(slot);
155+
accounts
156+
.accounts_db
157+
.flush_accounts_cache_slot_for_tests(slot);
158+
159+
let pubkeys = Arc::new(pubkeys);
160+
for i in 0..num_readers {
161+
let accounts = accounts.clone();
162+
let pubkeys = pubkeys.clone();
163+
Builder::new()
164+
.name(format!("reader{i:02}"))
165+
.spawn(move || {
166+
reader_f(&accounts, &pubkeys);
167+
})
168+
.unwrap();
169+
}
170+
171+
let num_new_keys = 1000;
172+
bencher.iter(|| {
173+
let new_pubkeys: Vec<_> = std::iter::repeat_with(solana_sdk::pubkey::new_rand)
174+
.take(num_new_keys)
175+
.collect();
176+
let new_storable_accounts: Vec<_> = new_pubkeys.iter().zip(accounts_data.iter()).collect();
177+
// Write to a different slot than the one being read from. Because
178+
// there's a new account pubkey being written to every time, will
179+
// compete for the accounts index lock on every store
180+
accounts.store_accounts_cached((slot + 1, new_storable_accounts.as_slice()));
181+
});
182+
}
183+
184+
#[bench]
185+
fn bench_concurrent_read_write(bencher: &mut Bencher) {
186+
store_accounts_with_possible_contention(
187+
"concurrent_read_write",
188+
bencher,
189+
|accounts, pubkeys| {
190+
let mut rng = rand::thread_rng();
191+
loop {
192+
let i = rng.gen_range(0..pubkeys.len());
193+
test::black_box(
194+
accounts
195+
.load_without_fixed_root(&Ancestors::default(), &pubkeys[i])
196+
.unwrap(),
197+
);
198+
}
199+
},
200+
)
201+
}
202+
203+
#[bench]
204+
fn bench_concurrent_scan_write(bencher: &mut Bencher) {
205+
store_accounts_with_possible_contention("concurrent_scan_write", bencher, |accounts, _| loop {
206+
test::black_box(
207+
accounts
208+
.load_by_program(
209+
&Ancestors::default(),
210+
0,
211+
AccountSharedData::default().owner(),
212+
&ScanConfig::default(),
213+
)
214+
.unwrap(),
215+
);
216+
})
217+
}
218+
219+
#[bench]
220+
#[ignore]
221+
fn bench_dashmap_single_reader_with_n_writers(bencher: &mut Bencher) {
222+
let num_readers = 5;
223+
let num_keys = 10000;
224+
let map = Arc::new(DashMap::new());
225+
for i in 0..num_keys {
226+
map.insert(i, i);
227+
}
228+
for _ in 0..num_readers {
229+
let map = map.clone();
230+
Builder::new()
231+
.name("readers".to_string())
232+
.spawn(move || loop {
233+
test::black_box(map.entry(5).or_insert(2));
234+
})
235+
.unwrap();
236+
}
237+
bencher.iter(|| {
238+
for _ in 0..num_keys {
239+
test::black_box(map.get(&5).unwrap().value());
240+
}
241+
})
242+
}
243+
244+
#[bench]
245+
#[ignore]
246+
fn bench_rwlock_hashmap_single_reader_with_n_writers(bencher: &mut Bencher) {
247+
let num_readers = 5;
248+
let num_keys = 10000;
249+
let map = Arc::new(RwLock::new(HashMap::new()));
250+
for i in 0..num_keys {
251+
map.write().unwrap().insert(i, i);
252+
}
253+
for _ in 0..num_readers {
254+
let map = map.clone();
255+
Builder::new()
256+
.name("readers".to_string())
257+
.spawn(move || loop {
258+
test::black_box(map.write().unwrap().get(&5));
259+
})
260+
.unwrap();
261+
}
262+
bencher.iter(|| {
263+
for _ in 0..num_keys {
264+
test::black_box(map.read().unwrap().get(&5));
265+
}
266+
})
267+
}
268+
269+
fn setup_bench_dashmap_iter() -> (Arc<Accounts>, DashMap<Pubkey, (AccountSharedData, Hash)>) {
270+
let accounts_db = new_accounts_db(vec![PathBuf::from(
271+
std::env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string()),
272+
)
273+
.join("bench_dashmap_par_iter")]);
274+
let accounts = Arc::new(Accounts::new(Arc::new(accounts_db)));
275+
276+
let dashmap = DashMap::new();
277+
let num_keys = std::env::var("NUM_BENCH_KEYS")
278+
.map(|num_keys| num_keys.parse::<usize>().unwrap())
279+
.unwrap_or_else(|_| 10000);
280+
for _ in 0..num_keys {
281+
dashmap.insert(
282+
Pubkey::new_unique(),
283+
(
284+
AccountSharedData::new(1, 0, AccountSharedData::default().owner()),
285+
Hash::new_unique(),
286+
),
287+
);
288+
}
289+
290+
(accounts, dashmap)
291+
}
292+
293+
#[bench]
294+
fn bench_dashmap_par_iter(bencher: &mut Bencher) {
295+
let (accounts, dashmap) = setup_bench_dashmap_iter();
296+
297+
bencher.iter(|| {
298+
test::black_box(accounts.accounts_db.thread_pool.install(|| {
299+
dashmap
300+
.par_iter()
301+
.map(|cached_account| (*cached_account.key(), cached_account.value().1))
302+
.collect::<Vec<(Pubkey, Hash)>>()
303+
}));
304+
});
305+
}
306+
307+
#[bench]
308+
fn bench_dashmap_iter(bencher: &mut Bencher) {
309+
let (_accounts, dashmap) = setup_bench_dashmap_iter();
310+
311+
bencher.iter(|| {
312+
test::black_box(
313+
dashmap
314+
.iter()
315+
.map(|cached_account| (*cached_account.key(), cached_account.value().1))
316+
.collect::<Vec<(Pubkey, Hash)>>(),
317+
);
318+
});
319+
}
320+
321+
#[bench]
322+
fn bench_load_largest_accounts(b: &mut Bencher) {
323+
let accounts_db = new_accounts_db(Vec::new());
324+
let accounts = Accounts::new(Arc::new(accounts_db));
325+
let mut rng = rand::thread_rng();
326+
for _ in 0..10_000 {
327+
let lamports = rng.gen();
328+
let pubkey = Pubkey::new_unique();
329+
let account = AccountSharedData::new(lamports, 0, &Pubkey::default());
330+
accounts.store_slow_uncached(0, &pubkey, &account);
331+
}
332+
let ancestors = Ancestors::from(vec![0]);
333+
let bank_id = 0;
334+
b.iter(|| {
335+
accounts.load_largest_accounts(
336+
&ancestors,
337+
bank_id,
338+
20,
339+
&HashSet::new(),
340+
AccountAddressFilter::Exclude,
341+
)
342+
});
343+
}

0 commit comments

Comments
 (0)