1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#![allow(clippy::integer_arithmetic)]
#[macro_use]
extern crate log;
use clap::{crate_description, crate_name, value_t, App, Arg};
use rayon::prelude::*;
use solana_measure::measure::Measure;
use solana_runtime::{
    accounts::{create_test_accounts, update_accounts_bench, Accounts},
    accounts_index::Ancestors,
};
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
use std::{collections::HashSet, env, fs, path::PathBuf};

fn main() {
    solana_logger::setup();

    let matches = App::new(crate_name!())
        .about(crate_description!())
        .version(solana_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(env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_owned()))
        .join("accounts-bench");
    println!("cleaning file system: {:?}", path);
    if fs::remove_dir_all(path.clone()).is_err() {
        println!("Warning: Couldn't remove {:?}", path);
    }
    let accounts =
        Accounts::new_with_config(vec![path], &ClusterType::Testnet, HashSet::new(), false);
    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<Pubkey> = 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: Ancestors = 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);
    }
    let mut elapsed = vec![0; iterations];
    let mut elapsed_store = vec![0; iterations];
    for x in 0..iterations {
        if clean {
            let mut time = Measure::start("clean");
            accounts.accounts_db.clean_accounts(None);
            time.stop();
            println!("{}", time);
            for slot in 0..num_slots {
                update_accounts_bench(&accounts, &pubkeys, ((x + 1) * num_slots + slot) as u64);
                accounts.add_root((x * num_slots + slot) as u64);
            }
        } else {
            let mut pubkeys: Vec<Pubkey> = vec![];
            let mut time = Measure::start("hash");
            let results = accounts
                .accounts_db
                .update_accounts_hash(0, &ancestors, true);
            time.stop();
            let mut time_store = Measure::start("hash using store");
            let results_store = accounts.accounts_db.update_accounts_hash_with_index_option(
                false,
                false,
                solana_sdk::clock::Slot::default(),
                &ancestors,
                true,
                None,
            );
            time_store.stop();
            if results != results_store {
                error!("results different: \n{:?}\n{:?}", results, results_store);
            }
            println!(
                "hash,{},{},{},{}%",
                results.0,
                time,
                time_store,
                (time_store.as_us() as f64 / time.as_us() as f64 * 100.0f64) as u32
            );
            create_test_accounts(&accounts, &mut pubkeys, 1, 0);
            elapsed[x] = time.as_us();
            elapsed_store[x] = time_store.as_us();
        }
    }

    for x in elapsed {
        info!("update_accounts_hash(us),{}", x);
    }
    for x in elapsed_store {
        info!("calculate_accounts_hash_without_index(us),{}", x);
    }
}