diff --git a/Cargo.lock b/Cargo.lock index f82c3cbaa3..dc4c44ad7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3569,6 +3569,21 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "solana-accounts-bench" +version = "1.1.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "solana-logger 1.1.0", + "solana-measure 1.1.0", + "solana-runtime 1.1.0", + "solana-sdk 1.1.0", +] + [[package]] name = "solana-archiver" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 14c61c1d1b..1763e84eeb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "bench-exchange", "bench-streamer", "bench-tps", + "accounts-bench", "banking-bench", "chacha", "chacha-cuda", diff --git a/accounts-bench/Cargo.toml b/accounts-bench/Cargo.toml new file mode 100644 index 0000000000..c96bfb9f4f --- /dev/null +++ b/accounts-bench/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["Solana Maintainers "] +edition = "2018" +name = "solana-accounts-bench" +version = "1.1.0" +repository = "https://github.com/solana-labs/solana" +license = "Apache-2.0" +homepage = "https://solana.com/" + +[dependencies] +log = "0.4.6" +rayon = "1.3.0" +solana-logger = { path = "../logger", version = "1.1.0" } +solana-runtime = { path = "../runtime", version = "1.1.0" } +solana-measure = { path = "../measure", version = "1.1.0" } +solana-sdk = { path = "../sdk", version = "1.1.0" } +rand = "0.6.5" +clap = "2.33.0" +crossbeam-channel = "0.3" diff --git a/accounts-bench/src/main.rs b/accounts-bench/src/main.rs new file mode 100644 index 0000000000..2a69df223e --- /dev/null +++ b/accounts-bench/src/main.rs @@ -0,0 +1,103 @@ +use clap::{value_t, App, Arg}; +use rayon::prelude::*; +use solana_measure::measure::Measure; +use solana_runtime::accounts::{create_test_accounts, update_accounts, Accounts}; +use solana_sdk::pubkey::Pubkey; +use std::collections::HashMap; +use std::fs; +use std::path::PathBuf; + +fn main() { + solana_logger::setup(); + + let matches = App::new("crate") + .about("about") + .version("version") + .arg( + Arg::with_name("num_slots") + .long("num_slots") + .takes_value(true) + .value_name("SLOTS") + .help("Number of slots to store to."), + ) + .arg( + Arg::with_name("num_accounts") + .long("num_accounts") + .takes_value(true) + .value_name("NUM_ACCOUNTS") + .help("Total number of accounts"), + ) + .arg( + Arg::with_name("iterations") + .long("iterations") + .takes_value(true) + .value_name("ITERATIONS") + .help("Number of bench iterations"), + ) + .arg( + Arg::with_name("clean") + .long("clean") + .takes_value(false) + .help("Run clean"), + ) + .get_matches(); + + let num_slots = value_t!(matches, "num_slots", usize).unwrap_or(4); + let num_accounts = value_t!(matches, "num_accounts", usize).unwrap_or(10_000); + let iterations = value_t!(matches, "iterations", usize).unwrap_or(20); + let clean = matches.is_present("clean"); + println!("clean: {:?}", clean); + + let path = PathBuf::from("farf/accounts-bench"); + if fs::remove_dir_all(path.clone()).is_err() { + println!("Warning: Couldn't remove {:?}", path); + } + let accounts = Accounts::new(vec![path]); + println!("Creating {} accounts", num_accounts); + let mut create_time = Measure::start("create accounts"); + let pubkeys: Vec<_> = (0..num_slots) + .into_par_iter() + .map(|slot| { + let mut pubkeys: Vec = vec![]; + create_test_accounts( + &accounts, + &mut pubkeys, + num_accounts / num_slots, + slot as u64, + ); + pubkeys + }) + .collect(); + let pubkeys: Vec<_> = pubkeys.into_iter().flatten().collect(); + create_time.stop(); + println!( + "created {} accounts in {} slots {}", + (num_accounts / num_slots) * num_slots, + num_slots, + create_time + ); + let mut ancestors: HashMap = vec![(0, 0)].into_iter().collect(); + for i in 1..num_slots { + ancestors.insert(i as u64, i - 1); + accounts.add_root(i as u64); + } + for x in 0..iterations { + if clean { + let mut time = Measure::start("clean"); + accounts.accounts_db.clean_accounts(); + time.stop(); + println!("{}", time); + for slot in 0..num_slots { + update_accounts(&accounts, &pubkeys, ((x + 1) * num_slots + slot) as u64); + accounts.add_root((x * num_slots + slot) as u64); + } + } else { + let mut pubkeys: Vec = vec![]; + let mut time = Measure::start("hash"); + let hash = accounts.accounts_db.update_accounts_hash(0, &ancestors); + time.stop(); + println!("hash: {} {}", hash, time); + create_test_accounts(&accounts, &mut pubkeys, 1, 0); + } + } +} diff --git a/ci/test-bench.sh b/ci/test-bench.sh index 16087363d1..2acb09fd00 100755 --- a/ci/test-bench.sh +++ b/ci/test-bench.sh @@ -67,8 +67,9 @@ _ cargo +$rust_nightly bench --manifest-path core/Cargo.toml ${V:+--verbose} \ _ cargo +$rust_nightly bench --manifest-path programs/bpf/Cargo.toml ${V:+--verbose} --features=bpf_c \ -- -Z unstable-options --format=json --nocapture | tee -a "$BENCH_FILE" -# Run banking bench. Doesn't require nightly, but use since it is already built. +# Run banking/accounts bench. Doesn't require nightly, but use since it is already built. _ cargo +$rust_nightly run --release --manifest-path banking-bench/Cargo.toml ${V:+--verbose} | tee -a "$BENCH_FILE" +_ cargo +$rust_nightly run --release --manifest-path accounts-bench/Cargo.toml ${V:+--verbose} -- --num_accounts 10000 --num_slots 4 | tee -a "$BENCH_FILE" # `solana-upload-perf` disabled as it can take over 30 minutes to complete for some # reason diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index c5e52bcde8..6b459d2049 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -12,6 +12,7 @@ use crate::{ transaction_utils::OrderedIterator, }; use log::*; +use rand::{thread_rng, Rng}; use rayon::slice::ParallelSliceMut; use solana_sdk::{ account::Account, @@ -658,6 +659,14 @@ pub fn create_test_accounts( } } +pub fn update_accounts(accounts: &Accounts, pubkeys: &[Pubkey], slot: u64) { + for pubkey in pubkeys { + let amount = thread_rng().gen_range(0, 10); + let account = Account::new(amount, 0, &Account::default().owner); + accounts.store_slow(slot, &pubkey, &account); + } +} + #[cfg(test)] mod tests { // TODO: all the bank tests are bank specific, issue: 2194