2018-08-22 07:57:07 -07:00
|
|
|
#![feature(test)]
|
2018-12-08 21:44:20 -08:00
|
|
|
|
2018-08-22 07:57:07 -07:00
|
|
|
extern crate test;
|
2019-03-29 20:00:36 -07:00
|
|
|
#[macro_use]
|
|
|
|
extern crate solana;
|
2018-07-10 19:33:16 -07:00
|
|
|
|
2018-09-26 05:52:13 -07:00
|
|
|
use rand::{thread_rng, Rng};
|
2018-07-10 19:33:16 -07:00
|
|
|
use rayon::prelude::*;
|
2019-03-03 16:44:06 -08:00
|
|
|
use solana::banking_stage::{create_test_recorder, BankingStage};
|
2019-03-29 20:00:36 -07:00
|
|
|
use solana::blocktree::{get_tmp_ledger_path, Blocktree};
|
2019-03-03 16:44:06 -08:00
|
|
|
use solana::cluster_info::ClusterInfo;
|
|
|
|
use solana::cluster_info::Node;
|
2018-09-24 10:20:58 -07:00
|
|
|
use solana::packet::to_packets_chunked;
|
2019-03-03 16:44:06 -08:00
|
|
|
use solana::poh_recorder::WorkingBankEntries;
|
2019-03-04 20:50:02 -08:00
|
|
|
use solana::service::Service;
|
2019-02-18 22:26:22 -08:00
|
|
|
use solana_runtime::bank::Bank;
|
|
|
|
use solana_sdk::genesis_block::GenesisBlock;
|
2018-11-16 08:04:46 -08:00
|
|
|
use solana_sdk::hash::hash;
|
2018-10-25 11:13:08 -07:00
|
|
|
use solana_sdk::pubkey::Pubkey;
|
2019-02-05 08:03:52 -08:00
|
|
|
use solana_sdk::signature::{KeypairUtil, Signature};
|
2018-12-04 15:37:11 -08:00
|
|
|
use solana_sdk::system_transaction::SystemTransaction;
|
2019-03-02 16:35:13 -08:00
|
|
|
use solana_sdk::timing::{DEFAULT_TICKS_PER_SLOT, MAX_RECENT_BLOCKHASHES};
|
2018-07-10 19:33:16 -07:00
|
|
|
use std::iter;
|
2019-03-04 20:50:02 -08:00
|
|
|
use std::sync::atomic::Ordering;
|
2018-07-10 19:33:16 -07:00
|
|
|
use std::sync::mpsc::{channel, Receiver};
|
2019-03-03 16:44:06 -08:00
|
|
|
use std::sync::{Arc, RwLock};
|
2018-09-24 10:40:42 -07:00
|
|
|
use std::time::Duration;
|
2018-08-22 07:57:07 -07:00
|
|
|
use test::Bencher;
|
2018-07-10 19:33:16 -07:00
|
|
|
|
2019-03-03 16:44:06 -08:00
|
|
|
fn check_txs(receiver: &Receiver<WorkingBankEntries>, ref_tx_count: usize) {
|
2018-07-10 19:33:16 -07:00
|
|
|
let mut total = 0;
|
2018-08-12 10:04:21 -07:00
|
|
|
loop {
|
2018-09-24 10:40:42 -07:00
|
|
|
let entries = receiver.recv_timeout(Duration::new(1, 0));
|
2019-03-03 16:44:06 -08:00
|
|
|
if let Ok((_, entries)) = entries {
|
2019-02-25 17:49:27 -08:00
|
|
|
for (entry, _) in &entries {
|
2018-09-24 10:40:42 -07:00
|
|
|
total += entry.transactions.len();
|
2018-08-07 10:29:57 -07:00
|
|
|
}
|
2018-07-10 19:33:16 -07:00
|
|
|
} else {
|
2018-09-24 10:40:42 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if total >= ref_tx_count {
|
|
|
|
break;
|
2018-07-10 19:33:16 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
assert_eq!(total, ref_tx_count);
|
|
|
|
}
|
|
|
|
|
2018-08-22 07:57:07 -07:00
|
|
|
#[bench]
|
2019-02-24 22:13:15 -08:00
|
|
|
#[ignore]
|
2018-07-10 19:33:16 -07:00
|
|
|
fn bench_banking_stage_multi_accounts(bencher: &mut Bencher) {
|
2018-12-21 13:55:45 -08:00
|
|
|
let num_threads = BankingStage::num_threads() as usize;
|
2019-01-21 10:17:04 -08:00
|
|
|
// a multiple of packet chunk 2X duplicates to avoid races
|
|
|
|
let txes = 192 * 50 * num_threads * 2;
|
2018-07-10 19:33:16 -07:00
|
|
|
let mint_total = 1_000_000_000_000;
|
2019-01-24 12:04:04 -08:00
|
|
|
let (genesis_block, mint_keypair) = GenesisBlock::new(mint_total);
|
2018-07-10 19:33:16 -07:00
|
|
|
|
|
|
|
let (verified_sender, verified_receiver) = channel();
|
2019-01-24 12:04:04 -08:00
|
|
|
let bank = Arc::new(Bank::new(&genesis_block));
|
2019-04-02 20:52:07 -07:00
|
|
|
let dummy = SystemTransaction::new_transfer(
|
2019-01-24 12:04:04 -08:00
|
|
|
&mint_keypair,
|
2019-03-09 19:28:43 -08:00
|
|
|
&mint_keypair.pubkey(),
|
2018-09-26 17:21:43 -07:00
|
|
|
1,
|
2019-03-01 09:49:37 -08:00
|
|
|
genesis_block.hash(),
|
2018-09-26 17:21:43 -07:00
|
|
|
0,
|
|
|
|
);
|
2018-09-26 05:52:13 -07:00
|
|
|
let transactions: Vec<_> = (0..txes)
|
|
|
|
.into_par_iter()
|
|
|
|
.map(|_| {
|
|
|
|
let mut new = dummy.clone();
|
|
|
|
let from: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
|
|
|
let to: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
|
|
|
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
2019-03-29 09:05:06 -07:00
|
|
|
new.message.account_keys[0] = Pubkey::new(&from[0..32]);
|
|
|
|
new.message.account_keys[1] = Pubkey::new(&to[0..32]);
|
2018-10-26 14:43:34 -07:00
|
|
|
new.signatures = vec![Signature::new(&sig[0..64])];
|
2018-09-26 05:52:13 -07:00
|
|
|
new
|
2018-12-07 19:01:28 -08:00
|
|
|
})
|
|
|
|
.collect();
|
2018-09-26 05:52:13 -07:00
|
|
|
// fund all the accounts
|
|
|
|
transactions.iter().for_each(|tx| {
|
2019-04-02 20:52:07 -07:00
|
|
|
let fund = SystemTransaction::new_transfer(
|
2019-01-24 12:04:04 -08:00
|
|
|
&mint_keypair,
|
2019-03-29 09:05:06 -07:00
|
|
|
&tx.message.account_keys[0],
|
2018-11-05 08:36:22 -08:00
|
|
|
mint_total / txes as u64,
|
2019-03-01 09:49:37 -08:00
|
|
|
genesis_block.hash(),
|
2018-09-26 17:21:43 -07:00
|
|
|
0,
|
2018-09-26 05:52:13 -07:00
|
|
|
);
|
2018-11-02 14:32:05 -07:00
|
|
|
let x = bank.process_transaction(&fund);
|
2019-01-28 14:52:35 -08:00
|
|
|
x.unwrap();
|
2018-07-10 19:33:16 -07:00
|
|
|
});
|
2018-09-26 05:52:13 -07:00
|
|
|
//sanity check, make sure all the transactions can execute sequentially
|
|
|
|
transactions.iter().for_each(|tx| {
|
|
|
|
let res = bank.process_transaction(&tx);
|
|
|
|
assert!(res.is_ok(), "sanity test transactions");
|
|
|
|
});
|
|
|
|
bank.clear_signatures();
|
|
|
|
//sanity check, make sure all the transactions can execute in parallel
|
|
|
|
let res = bank.process_transactions(&transactions);
|
|
|
|
for r in res {
|
|
|
|
assert!(r.is_ok(), "sanity parallel execution");
|
2018-07-10 19:33:16 -07:00
|
|
|
}
|
2018-09-26 05:52:13 -07:00
|
|
|
bank.clear_signatures();
|
2018-09-24 10:20:58 -07:00
|
|
|
let verified: Vec<_> = to_packets_chunked(&transactions.clone(), 192)
|
2018-09-26 05:52:13 -07:00
|
|
|
.into_iter()
|
|
|
|
.map(|x| {
|
2018-09-24 10:20:58 -07:00
|
|
|
let len = x.read().unwrap().packets.len();
|
2018-09-26 05:52:13 -07:00
|
|
|
(x, iter::repeat(1).take(len).collect())
|
2018-12-07 19:01:28 -08:00
|
|
|
})
|
|
|
|
.collect();
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
|
|
|
let blocktree = Arc::new(
|
|
|
|
Blocktree::open(&ledger_path).expect("Expected to be able to open database ledger"),
|
|
|
|
);
|
|
|
|
let (exit, poh_recorder, poh_service, signal_receiver) =
|
|
|
|
create_test_recorder(&bank, &blocktree);
|
|
|
|
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
|
|
|
let cluster_info = Arc::new(RwLock::new(cluster_info));
|
|
|
|
let _banking_stage = BankingStage::new(&cluster_info, &poh_recorder, verified_receiver);
|
|
|
|
poh_recorder.lock().unwrap().set_bank(&bank);
|
2018-10-17 16:28:26 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let mut id = genesis_block.hash();
|
|
|
|
for _ in 0..(MAX_RECENT_BLOCKHASHES * DEFAULT_TICKS_PER_SLOT as usize) {
|
|
|
|
id = hash(&id.as_ref());
|
|
|
|
bank.register_tick(&id);
|
2018-09-26 05:52:13 -07:00
|
|
|
}
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
let half_len = verified.len() / 2;
|
|
|
|
let mut start = 0;
|
|
|
|
bencher.iter(move || {
|
|
|
|
// make sure the transactions are still valid
|
|
|
|
bank.register_tick(&genesis_block.hash());
|
|
|
|
for v in verified[start..start + half_len].chunks(verified.len() / num_threads) {
|
|
|
|
verified_sender.send(v.to_vec()).unwrap();
|
|
|
|
}
|
|
|
|
check_txs(&signal_receiver, txes / 2);
|
|
|
|
bank.clear_signatures();
|
|
|
|
start += half_len;
|
|
|
|
start %= verified.len();
|
|
|
|
});
|
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
}
|
|
|
|
Blocktree::destroy(&ledger_path).unwrap();
|
2018-07-10 19:33:16 -07:00
|
|
|
}
|
2018-09-28 16:16:35 -07:00
|
|
|
|
|
|
|
#[bench]
|
2019-02-24 22:13:15 -08:00
|
|
|
#[ignore]
|
2018-09-28 16:16:35 -07:00
|
|
|
fn bench_banking_stage_multi_programs(bencher: &mut Bencher) {
|
2018-10-26 14:43:34 -07:00
|
|
|
let progs = 4;
|
2018-12-21 13:55:45 -08:00
|
|
|
let num_threads = BankingStage::num_threads() as usize;
|
2019-01-21 10:17:04 -08:00
|
|
|
// a multiple of packet chunk 2X duplicates to avoid races
|
|
|
|
let txes = 96 * 100 * num_threads * 2;
|
2018-09-28 16:16:35 -07:00
|
|
|
let mint_total = 1_000_000_000_000;
|
2019-01-24 12:04:04 -08:00
|
|
|
let (genesis_block, mint_keypair) = GenesisBlock::new(mint_total);
|
2018-09-28 16:16:35 -07:00
|
|
|
|
|
|
|
let (verified_sender, verified_receiver) = channel();
|
2019-01-24 12:04:04 -08:00
|
|
|
let bank = Arc::new(Bank::new(&genesis_block));
|
2019-04-02 20:52:07 -07:00
|
|
|
let dummy = SystemTransaction::new_transfer(
|
2019-01-24 12:04:04 -08:00
|
|
|
&mint_keypair,
|
2019-03-09 19:28:43 -08:00
|
|
|
&mint_keypair.pubkey(),
|
2018-09-28 16:16:35 -07:00
|
|
|
1,
|
2019-03-01 09:49:37 -08:00
|
|
|
genesis_block.hash(),
|
2018-09-28 16:16:35 -07:00
|
|
|
0,
|
|
|
|
);
|
|
|
|
let transactions: Vec<_> = (0..txes)
|
|
|
|
.into_par_iter()
|
|
|
|
.map(|_| {
|
|
|
|
let mut new = dummy.clone();
|
|
|
|
let from: Vec<u8> = (0..32).map(|_| thread_rng().gen()).collect();
|
|
|
|
let sig: Vec<u8> = (0..64).map(|_| thread_rng().gen()).collect();
|
|
|
|
let to: Vec<u8> = (0..32).map(|_| thread_rng().gen()).collect();
|
2019-03-29 09:05:06 -07:00
|
|
|
new.message.account_keys[0] = Pubkey::new(&from[0..32]);
|
|
|
|
new.message.account_keys[1] = Pubkey::new(&to[0..32]);
|
|
|
|
let prog = new.message.instructions[0].clone();
|
2018-09-28 16:16:35 -07:00
|
|
|
for i in 1..progs {
|
|
|
|
//generate programs that spend to random keys
|
|
|
|
let to: Vec<u8> = (0..32).map(|_| thread_rng().gen()).collect();
|
|
|
|
let to_key = Pubkey::new(&to[0..32]);
|
2019-03-29 09:05:06 -07:00
|
|
|
new.message.account_keys.push(to_key);
|
|
|
|
assert_eq!(new.message.account_keys.len(), i + 2);
|
|
|
|
new.message.instructions.push(prog.clone());
|
|
|
|
assert_eq!(new.message.instructions.len(), i + 1);
|
|
|
|
new.message.instructions[i].accounts[1] = 1 + i as u8;
|
2018-09-28 16:16:35 -07:00
|
|
|
assert_eq!(new.key(i, 1), Some(&to_key));
|
|
|
|
assert_eq!(
|
2019-03-29 09:05:06 -07:00
|
|
|
new.message.account_keys[new.message.instructions[i].accounts[1] as usize],
|
2018-09-28 16:16:35 -07:00
|
|
|
to_key
|
|
|
|
);
|
|
|
|
}
|
2019-03-29 09:05:06 -07:00
|
|
|
assert_eq!(new.message.instructions.len(), progs);
|
2018-10-26 14:43:34 -07:00
|
|
|
new.signatures = vec![Signature::new(&sig[0..64])];
|
2018-09-28 16:16:35 -07:00
|
|
|
new
|
2018-12-07 19:01:28 -08:00
|
|
|
})
|
|
|
|
.collect();
|
2018-09-28 16:16:35 -07:00
|
|
|
transactions.iter().for_each(|tx| {
|
2019-04-02 20:52:07 -07:00
|
|
|
let fund = SystemTransaction::new_transfer(
|
2019-01-24 12:04:04 -08:00
|
|
|
&mint_keypair,
|
2019-03-29 09:05:06 -07:00
|
|
|
&tx.message.account_keys[0],
|
2018-11-05 08:36:22 -08:00
|
|
|
mint_total / txes as u64,
|
2019-03-01 09:49:37 -08:00
|
|
|
genesis_block.hash(),
|
2018-09-28 16:16:35 -07:00
|
|
|
0,
|
|
|
|
);
|
2019-01-28 14:52:35 -08:00
|
|
|
bank.process_transaction(&fund).unwrap();
|
2018-09-28 16:16:35 -07:00
|
|
|
});
|
|
|
|
//sanity check, make sure all the transactions can execute sequentially
|
|
|
|
transactions.iter().for_each(|tx| {
|
|
|
|
let res = bank.process_transaction(&tx);
|
|
|
|
assert!(res.is_ok(), "sanity test transactions");
|
|
|
|
});
|
|
|
|
bank.clear_signatures();
|
|
|
|
//sanity check, make sure all the transactions can execute in parallel
|
|
|
|
let res = bank.process_transactions(&transactions);
|
|
|
|
for r in res {
|
|
|
|
assert!(r.is_ok(), "sanity parallel execution");
|
|
|
|
}
|
|
|
|
bank.clear_signatures();
|
|
|
|
let verified: Vec<_> = to_packets_chunked(&transactions.clone(), 96)
|
|
|
|
.into_iter()
|
|
|
|
.map(|x| {
|
|
|
|
let len = x.read().unwrap().packets.len();
|
|
|
|
(x, iter::repeat(1).take(len).collect())
|
2018-12-07 19:01:28 -08:00
|
|
|
})
|
|
|
|
.collect();
|
2018-10-17 16:28:26 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let ledger_path = get_tmp_ledger_path!();
|
|
|
|
{
|
|
|
|
let blocktree = Arc::new(
|
|
|
|
Blocktree::open(&ledger_path).expect("Expected to be able to open database ledger"),
|
|
|
|
);
|
|
|
|
let (exit, poh_recorder, poh_service, signal_receiver) =
|
|
|
|
create_test_recorder(&bank, &blocktree);
|
|
|
|
let cluster_info = ClusterInfo::new_with_invalid_keypair(Node::new_localhost().info);
|
|
|
|
let cluster_info = Arc::new(RwLock::new(cluster_info));
|
|
|
|
let _banking_stage = BankingStage::new(&cluster_info, &poh_recorder, verified_receiver);
|
|
|
|
poh_recorder.lock().unwrap().set_bank(&bank);
|
2018-10-17 16:28:26 -07:00
|
|
|
|
2019-03-29 20:00:36 -07:00
|
|
|
let mut id = genesis_block.hash();
|
|
|
|
for _ in 0..(MAX_RECENT_BLOCKHASHES * DEFAULT_TICKS_PER_SLOT as usize) {
|
|
|
|
id = hash(&id.as_ref());
|
|
|
|
bank.register_tick(&id);
|
2018-09-28 16:16:35 -07:00
|
|
|
}
|
2019-03-29 20:00:36 -07:00
|
|
|
|
|
|
|
let half_len = verified.len() / 2;
|
|
|
|
let mut start = 0;
|
|
|
|
bencher.iter(move || {
|
|
|
|
// make sure the transactions are still valid
|
|
|
|
bank.register_tick(&genesis_block.hash());
|
|
|
|
for v in verified[start..start + half_len].chunks(verified.len() / num_threads) {
|
|
|
|
verified_sender.send(v.to_vec()).unwrap();
|
|
|
|
}
|
|
|
|
check_txs(&signal_receiver, txes / 2);
|
|
|
|
bank.clear_signatures();
|
|
|
|
start += half_len;
|
|
|
|
start %= verified.len();
|
|
|
|
});
|
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
poh_service.join().unwrap();
|
|
|
|
}
|
|
|
|
Blocktree::destroy(&ledger_path).unwrap();
|
2018-09-28 16:16:35 -07:00
|
|
|
}
|