Expand bank benches to include async/sync and native_loader (#4026)
This commit is contained in:
parent
c2193a37ce
commit
c545e812d0
|
@ -40,7 +40,10 @@ fi
|
||||||
BENCH_FILE=bench_output.log
|
BENCH_FILE=bench_output.log
|
||||||
BENCH_ARTIFACT=current_bench_results.log
|
BENCH_ARTIFACT=current_bench_results.log
|
||||||
|
|
||||||
# First remove "BENCH_FILE", if it exists so that the following commands can append
|
# Ensure all dependencies are built
|
||||||
|
_ cargo +$rust_nightly build --all --release
|
||||||
|
|
||||||
|
# Remove "BENCH_FILE", if it exists so that the following commands can append
|
||||||
rm -f "$BENCH_FILE"
|
rm -f "$BENCH_FILE"
|
||||||
|
|
||||||
# Run sdk benches
|
# Run sdk benches
|
||||||
|
|
|
@ -2,75 +2,169 @@
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
|
use log::*;
|
||||||
use solana_runtime::bank::*;
|
use solana_runtime::bank::*;
|
||||||
use solana_runtime::bank_client::BankClient;
|
use solana_runtime::bank_client::BankClient;
|
||||||
|
use solana_runtime::loader_utils::{create_invoke_instruction, load_program};
|
||||||
|
use solana_sdk::account::KeyedAccount;
|
||||||
use solana_sdk::client::AsyncClient;
|
use solana_sdk::client::AsyncClient;
|
||||||
|
use solana_sdk::client::SyncClient;
|
||||||
use solana_sdk::genesis_block::GenesisBlock;
|
use solana_sdk::genesis_block::GenesisBlock;
|
||||||
use solana_sdk::hash::hash;
|
use solana_sdk::instruction::InstructionError;
|
||||||
|
use solana_sdk::native_loader;
|
||||||
|
use solana_sdk::pubkey::Pubkey;
|
||||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||||
use solana_sdk::system_transaction;
|
|
||||||
use solana_sdk::timing::{DEFAULT_TICKS_PER_SLOT, MAX_RECENT_BLOCKHASHES};
|
|
||||||
use solana_sdk::transaction::Transaction;
|
use solana_sdk::transaction::Transaction;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
// Create transactions between unrelated parties.
|
const BUILTIN_PROGRAM_ID: [u8; 32] = [
|
||||||
pub fn create_sample_transactions(bank: &Bank, mint_keypair: &Keypair) -> Vec<Transaction> {
|
098, 117, 105, 108, 116, 105, 110, 095, 112, 114, 111, 103, 114, 097, 109, 095, 105, 100, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
|
|
||||||
|
fn process_instruction(
|
||||||
|
_program_id: &Pubkey,
|
||||||
|
_keyed_accounts: &mut [KeyedAccount],
|
||||||
|
_data: &[u8],
|
||||||
|
_tick_height: u64,
|
||||||
|
) -> Result<(), InstructionError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_builtin_transactions(
|
||||||
|
bank_client: &BankClient,
|
||||||
|
mint_keypair: &Keypair,
|
||||||
|
) -> Vec<Transaction> {
|
||||||
|
let program_id = Pubkey::new(&BUILTIN_PROGRAM_ID);
|
||||||
|
|
||||||
(0..4096)
|
(0..4096)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
// Seed the 'from' account.
|
// Seed the signer account
|
||||||
let rando0 = Keypair::new();
|
let rando0 = Keypair::new();
|
||||||
let tx = system_transaction::transfer(
|
bank_client
|
||||||
&mint_keypair,
|
.transfer(10_000, &mint_keypair, &rando0.pubkey())
|
||||||
&rando0.pubkey(),
|
.expect(&format!("{}:{}", line!(), file!()));
|
||||||
10_000,
|
|
||||||
bank.last_blockhash(),
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
|
||||||
|
|
||||||
// Seed the 'to' account and a cell for its signature.
|
let instruction = create_invoke_instruction(rando0.pubkey(), program_id, &1u8);
|
||||||
let rando1 = Keypair::new();
|
Transaction::new_signed_instructions(
|
||||||
system_transaction::transfer(&rando0, &rando1.pubkey(), 1, bank.last_blockhash(), 0)
|
&[&rando0],
|
||||||
|
vec![instruction],
|
||||||
|
bank_client.get_recent_blockhash().unwrap(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
pub fn create_native_loader_transactions(
|
||||||
fn bench_process_transaction(bencher: &mut Bencher) {
|
bank_client: &BankClient,
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new(100_000_000);
|
mint_keypair: &Keypair,
|
||||||
let bank = Bank::new(&genesis_block);
|
) -> Vec<Transaction> {
|
||||||
let transactions = create_sample_transactions(&bank, &mint_keypair);
|
let program = "solana_noop_program".as_bytes().to_vec();
|
||||||
|
let program_id = load_program(&bank_client, &mint_keypair, &native_loader::id(), program);
|
||||||
|
|
||||||
// Run once to create all the 'to' accounts.
|
(0..4096)
|
||||||
let results = bank.process_transactions(&transactions);
|
.into_iter()
|
||||||
assert!(results.iter().all(Result::is_ok));
|
.map(|_| {
|
||||||
|
// Seed the signer account©41
|
||||||
|
let rando0 = Keypair::new();
|
||||||
|
bank_client
|
||||||
|
.transfer(10_000, &mint_keypair, &rando0.pubkey())
|
||||||
|
.expect(&format!("{}:{}", line!(), file!()));
|
||||||
|
|
||||||
let mut id = bank.last_blockhash();
|
let instruction = create_invoke_instruction(rando0.pubkey(), program_id, &1u8);
|
||||||
for _ in 0..(MAX_RECENT_BLOCKHASHES * DEFAULT_TICKS_PER_SLOT as usize) {
|
Transaction::new_signed_instructions(
|
||||||
bank.register_tick(&id);
|
&[&rando0],
|
||||||
id = hash(&id.as_ref())
|
vec![instruction],
|
||||||
}
|
bank_client.get_recent_blockhash().unwrap(),
|
||||||
|
)
|
||||||
bencher.iter(|| {
|
|
||||||
// Since benchmarker runs this multiple times, we need to clear the signatures.
|
|
||||||
bank.clear_signatures();
|
|
||||||
let results = bank.process_transactions(&transactions);
|
|
||||||
assert!(results.iter().all(Result::is_ok));
|
|
||||||
})
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
fn sync_bencher(bank: &Arc<Bank>, _bank_client: &BankClient, transactions: &Vec<Transaction>) {
|
||||||
fn bench_bank_client(bencher: &mut Bencher) {
|
let results = bank.process_transactions(&transactions);
|
||||||
let (genesis_block, mint_keypair) = GenesisBlock::new(100_000_000);
|
assert!(results.iter().all(Result::is_ok));
|
||||||
let bank = Bank::new(&genesis_block);
|
}
|
||||||
let transactions = create_sample_transactions(&bank, &mint_keypair);
|
|
||||||
|
|
||||||
bencher.iter(|| {
|
fn async_bencher(bank: &Arc<Bank>, bank_client: &BankClient, transactions: &Vec<Transaction>) {
|
||||||
let bank = Bank::new(&genesis_block);
|
|
||||||
let bank_client = BankClient::new(bank);
|
|
||||||
for transaction in transactions.clone() {
|
for transaction in transactions.clone() {
|
||||||
bank_client.async_send_transaction(transaction).unwrap();
|
bank_client.async_send_transaction(transaction).unwrap();
|
||||||
}
|
}
|
||||||
})
|
for _ in 0..1_000_000_000_u64 {
|
||||||
|
if bank
|
||||||
|
.get_signature_status(&transactions.last().unwrap().signatures.get(0).unwrap())
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sleep(Duration::from_nanos(1));
|
||||||
|
}
|
||||||
|
if !bank
|
||||||
|
.get_signature_status(&transactions.last().unwrap().signatures.get(0).unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
error!(
|
||||||
|
"transaction failed: {:?}",
|
||||||
|
bank.get_signature_status(&transactions.last().unwrap().signatures.get(0).unwrap())
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_bench_transactions(
|
||||||
|
bencher: &mut Bencher,
|
||||||
|
bench_work: &Fn(&Arc<Bank>, &BankClient, &Vec<Transaction>),
|
||||||
|
create_transactions: &Fn(&BankClient, &Keypair) -> Vec<Transaction>,
|
||||||
|
) {
|
||||||
|
solana_logger::setup();
|
||||||
|
let ns_per_s = 1_000_000_000;
|
||||||
|
let (genesis_block, mint_keypair) = GenesisBlock::new(100_000_000);
|
||||||
|
let mut bank = Bank::new(&genesis_block);
|
||||||
|
bank.add_instruction_processor(Pubkey::new(&BUILTIN_PROGRAM_ID), process_instruction);
|
||||||
|
let bank = Arc::new(bank);
|
||||||
|
let bank_client = BankClient::new_shared(&bank);
|
||||||
|
let transactions = create_transactions(&bank_client, &mint_keypair);
|
||||||
|
|
||||||
|
// Do once to fund accounts, load modules, etc...
|
||||||
|
let results = bank.process_transactions(&transactions);
|
||||||
|
assert!(results.iter().all(Result::is_ok));
|
||||||
|
|
||||||
|
bencher.iter(|| {
|
||||||
|
// Since bencher runs this multiple times, we need to clear the signatures.
|
||||||
|
bank.clear_signatures();
|
||||||
|
bench_work(&bank, &bank_client, &transactions);
|
||||||
|
});
|
||||||
|
|
||||||
|
let summary = bencher.bench(|_bencher| {}).unwrap();
|
||||||
|
info!(" {:?} transactions", transactions.len());
|
||||||
|
info!(" {:?} ns/iter median", summary.median as u64);
|
||||||
|
assert!(0f64 != summary.median);
|
||||||
|
let tps = transactions.len() as u64 * (ns_per_s / summary.median as u64);
|
||||||
|
info!(" {:?} TPS", tps);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_bank_sync_process_builtin_transactions(bencher: &mut Bencher) {
|
||||||
|
do_bench_transactions(bencher, &sync_bencher, &create_builtin_transactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_bank_sync_process_native_loader_transactions(bencher: &mut Bencher) {
|
||||||
|
do_bench_transactions(bencher, &sync_bencher, &create_native_loader_transactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_bank_async_process_builtin_transactions(bencher: &mut Bencher) {
|
||||||
|
do_bench_transactions(bencher, &async_bencher, &create_builtin_transactions);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bench]
|
||||||
|
fn bench_bank_async_process_native_loader_transactions(bencher: &mut Bencher) {
|
||||||
|
do_bench_transactions(bencher, &async_bencher, &create_native_loader_transactions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,8 +191,7 @@ impl BankClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(bank: Bank) -> Self {
|
pub fn new_shared(bank: &Arc<Bank>) -> Self {
|
||||||
let bank = Arc::new(bank);
|
|
||||||
let (transaction_sender, transaction_receiver) = channel();
|
let (transaction_sender, transaction_receiver) = channel();
|
||||||
let transaction_sender = Mutex::new(transaction_sender);
|
let transaction_sender = Mutex::new(transaction_sender);
|
||||||
let thread_bank = bank.clone();
|
let thread_bank = bank.clone();
|
||||||
|
@ -206,6 +205,10 @@ impl BankClient {
|
||||||
transaction_sender,
|
transaction_sender,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new(bank: Bank) -> Self {
|
||||||
|
Self::new_shared(&Arc::new(bank))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue