consumer.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. #![allow(clippy::arithmetic_side_effects)]
  2. #![feature(test)]
  3. use {
  4. crossbeam_channel::Receiver,
  5. rayon::{
  6. iter::IndexedParallelIterator,
  7. prelude::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator},
  8. },
  9. solana_account::{Account, ReadableAccount},
  10. solana_clock::Epoch,
  11. solana_core::banking_stage::consumer::Consumer,
  12. solana_entry::entry::Entry,
  13. solana_keypair::Keypair,
  14. solana_ledger::{
  15. blockstore::Blockstore,
  16. genesis_utils::{create_genesis_config, GenesisConfigInfo},
  17. },
  18. solana_poh::{
  19. poh_recorder::create_test_recorder, poh_service::PohService,
  20. transaction_recorder::TransactionRecorder,
  21. },
  22. solana_runtime::{bank::Bank, bank_forks::BankForks},
  23. solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
  24. solana_signer::Signer,
  25. solana_system_interface::program as system_program,
  26. solana_system_transaction as system_transaction,
  27. solana_transaction::sanitized::SanitizedTransaction,
  28. std::sync::{
  29. atomic::{AtomicBool, Ordering},
  30. Arc, RwLock,
  31. },
  32. tempfile::TempDir,
  33. test::Bencher,
  34. };
  35. extern crate test;
  36. fn create_accounts(num: usize) -> Vec<Keypair> {
  37. (0..num).into_par_iter().map(|_| Keypair::new()).collect()
  38. }
  39. fn create_funded_accounts(bank: &Bank, num: usize) -> Vec<Keypair> {
  40. assert!(
  41. num.is_power_of_two(),
  42. "must be power of 2 for parallel funding tree"
  43. );
  44. let accounts = create_accounts(num);
  45. accounts.par_iter().for_each(|account| {
  46. bank.store_account(
  47. &account.pubkey(),
  48. &Account {
  49. lamports: 5100,
  50. data: vec![],
  51. owner: system_program::id(),
  52. executable: false,
  53. rent_epoch: Epoch::MAX,
  54. }
  55. .to_account_shared_data(),
  56. );
  57. });
  58. accounts
  59. }
  60. fn create_transactions(bank: &Bank, num: usize) -> Vec<RuntimeTransaction<SanitizedTransaction>> {
  61. let funded_accounts = create_funded_accounts(bank, 2 * num);
  62. funded_accounts
  63. .into_par_iter()
  64. .chunks(2)
  65. .map(|chunk| {
  66. let from = &chunk[0];
  67. let to = &chunk[1];
  68. system_transaction::transfer(from, &to.pubkey(), 1, bank.last_blockhash())
  69. })
  70. .map(RuntimeTransaction::from_transaction_for_tests)
  71. .collect()
  72. }
  73. struct BenchFrame {
  74. bank: Arc<Bank>,
  75. _bank_forks: Arc<RwLock<BankForks>>,
  76. ledger_path: TempDir,
  77. exit: Arc<AtomicBool>,
  78. transaction_recorder: TransactionRecorder,
  79. poh_service: PohService,
  80. signal_receiver: Receiver<(Arc<Bank>, (Entry, u64))>,
  81. }
  82. fn setup() -> BenchFrame {
  83. let mint_total = u64::MAX;
  84. let GenesisConfigInfo {
  85. mut genesis_config, ..
  86. } = create_genesis_config(mint_total);
  87. // Set a high ticks_per_slot so we don't run out of ticks
  88. // during the benchmark
  89. genesis_config.ticks_per_slot = 10_000;
  90. let mut bank = Bank::new_for_benches(&genesis_config);
  91. // Allow arbitrary transaction processing time for the purposes of this bench
  92. bank.ns_per_slot = u128::MAX;
  93. // set cost tracker limits to MAX so it will not filter out TXs
  94. bank.write_cost_tracker()
  95. .unwrap()
  96. .set_limits(u64::MAX, u64::MAX, u64::MAX);
  97. let (bank, bank_forks) = bank.wrap_with_bank_forks_for_tests();
  98. let ledger_path = TempDir::new().unwrap();
  99. let blockstore = Arc::new(
  100. Blockstore::open(ledger_path.path()).expect("Expected to be able to open database ledger"),
  101. );
  102. let (exit, _poh_recorder, transaction_recorder, poh_service, signal_receiver) =
  103. create_test_recorder(bank.clone(), blockstore, None, None);
  104. BenchFrame {
  105. bank,
  106. _bank_forks: bank_forks,
  107. ledger_path,
  108. exit,
  109. transaction_recorder,
  110. poh_service,
  111. signal_receiver,
  112. }
  113. }
  114. fn bench_process_and_record_transactions(bencher: &mut Bencher, batch_size: usize) {
  115. const TRANSACTIONS_PER_ITERATION: usize = 64;
  116. assert_eq!(
  117. TRANSACTIONS_PER_ITERATION % batch_size,
  118. 0,
  119. "batch_size must be a factor of `TRANSACTIONS_PER_ITERATION` \
  120. ({TRANSACTIONS_PER_ITERATION}) so that bench results are easily comparable"
  121. );
  122. let batches_per_iteration = TRANSACTIONS_PER_ITERATION / batch_size;
  123. let BenchFrame {
  124. bank,
  125. _bank_forks,
  126. ledger_path: _ledger_path,
  127. exit,
  128. transaction_recorder,
  129. poh_service,
  130. signal_receiver: _signal_receiver,
  131. } = setup();
  132. let consumer = Consumer::from(&transaction_recorder);
  133. let transactions = create_transactions(&bank, 2_usize.pow(20));
  134. let mut transaction_iter = transactions.chunks(batch_size);
  135. bencher.iter(move || {
  136. for _ in 0..batches_per_iteration {
  137. let summary =
  138. consumer.process_and_record_transactions(&bank, transaction_iter.next().unwrap());
  139. assert!(summary
  140. .execute_and_commit_transactions_output
  141. .commit_transactions_result
  142. .is_ok());
  143. }
  144. });
  145. exit.store(true, Ordering::Relaxed);
  146. poh_service.join().unwrap();
  147. }
  148. #[bench]
  149. fn bench_process_and_record_transactions_unbatched(bencher: &mut Bencher) {
  150. bench_process_and_record_transactions(bencher, 1);
  151. }
  152. #[bench]
  153. fn bench_process_and_record_transactions_half_batch(bencher: &mut Bencher) {
  154. bench_process_and_record_transactions(bencher, 32);
  155. }
  156. #[bench]
  157. fn bench_process_and_record_transactions_full_batch(bencher: &mut Bencher) {
  158. bench_process_and_record_transactions(bencher, 64);
  159. }