From a0ceacf24f6c8c977957660a8587ca414edacfaf Mon Sep 17 00:00:00 2001 From: Steven Luscher Date: Fri, 6 Dec 2024 20:20:39 +0000 Subject: [PATCH 1/2] Track the signatures of transactions created by the bench runner --- accounts-cluster-bench/src/main.rs | 51 ++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/accounts-cluster-bench/src/main.rs b/accounts-cluster-bench/src/main.rs index b71ad96e400626..fd473f7c83447c 100644 --- a/accounts-cluster-bench/src/main.rs +++ b/accounts-cluster-bench/src/main.rs @@ -8,7 +8,9 @@ use { hidden_unless_forced, input_parsers::pubkey_of, input_validators::is_url_or_moniker, }, solana_cli_config::{ConfigInput, CONFIG_FILE}, - solana_client::transaction_executor::TransactionExecutor, + solana_client::{ + rpc_client::SerializableTransaction, transaction_executor::TransactionExecutor, + }, solana_gossip::gossip_service::discover, solana_inline_spl::token, solana_measure::measure::Measure, @@ -21,7 +23,7 @@ use { message::Message, program_pack::Pack, pubkey::Pubkey, - signature::{read_keypair_file, Keypair, Signer}, + signature::{read_keypair_file, Keypair, Signature, Signer}, system_instruction, system_program, transaction::Transaction, }, @@ -29,11 +31,13 @@ use { spl_token::state::Account, std::{ cmp::min, + collections::VecDeque, + ops::Deref, process::exit, str::FromStr, sync::{ atomic::{AtomicBool, AtomicU64, Ordering}, - Arc, Barrier, + Arc, Barrier, RwLock, }, thread::{sleep, Builder, JoinHandle}, time::{Duration, Instant}, @@ -132,6 +136,36 @@ struct SeedTracker { max_closed: Arc, } +#[derive(Clone)] +struct TransactionSignatureTracker(Arc>>); + +impl TransactionSignatureTracker { + #[allow(dead_code)] + fn get_random(&self) -> Option { + let signatures = self.read().unwrap(); + if signatures.is_empty() { + None + } else { + let random_index = thread_rng().gen_range(0..signatures.len()); + let random_signature = signatures.get(random_index); + random_signature.cloned() + } + } + fn track_transactions(&self, transactions: &[Transaction]) { + let mut lock = self.write().unwrap(); + for signature in transactions.iter().map(Transaction::get_signature) { + lock.push_back(*signature); + } + } +} + +impl Deref for TransactionSignatureTracker { + type Target = Arc>>; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + fn make_create_message( keypair: &Keypair, base_keypair: &Keypair, @@ -341,6 +375,7 @@ struct RpcBenchStats { total_success_time_us: u64, } +#[allow(clippy::too_many_arguments)] fn run_rpc_bench_loop( rpc_bench: RpcBench, thread: usize, @@ -351,6 +386,7 @@ fn run_rpc_bench_loop( max_closed: &AtomicU64, max_created: &AtomicU64, mint: &Option, + _transaction_signature_tracker: &TransactionSignatureTracker, ) { let mut stats = RpcBenchStats::default(); let mut iters = 0; @@ -535,6 +571,7 @@ fn make_rpc_bench_threads( seed_tracker: &SeedTracker, base_keypair_pubkey: Pubkey, num_rpc_bench_threads: usize, + transaction_signature_tracker: &TransactionSignatureTracker, ) -> Vec> { let program_id = if mint.is_some() { token::id() @@ -550,6 +587,7 @@ fn make_rpc_bench_threads( let exit = exit.clone(); let max_closed = seed_tracker.max_closed.clone(); let max_created = seed_tracker.max_created.clone(); + let transaction_signature_tracker = transaction_signature_tracker.clone(); let mint = *mint; Builder::new() .name(format!("rpc-bench-{}", thread)) @@ -565,6 +603,7 @@ fn make_rpc_bench_threads( &max_closed, &max_created, &mint, + &transaction_signature_tracker, ) }) .unwrap() @@ -618,6 +657,8 @@ fn run_accounts_bench( max_created: Arc::new(AtomicU64::default()), max_closed: Arc::new(AtomicU64::default()), }; + let transaction_signature_tracker = + TransactionSignatureTracker(Arc::new(RwLock::new(VecDeque::with_capacity(5000)))); info!("Starting balance(s): {:?}", balances); @@ -657,6 +698,7 @@ fn run_accounts_bench( &seed_tracker, base_keypair_pubkey, num_rpc_bench_threads, + &transaction_signature_tracker, ) } else { Vec::new() @@ -719,6 +761,7 @@ fn run_accounts_bench( .collect(); balances[i] = balances[i].saturating_sub(lamports * txs.len() as u64); info!("txs: {}", txs.len()); + transaction_signature_tracker.track_transactions(&txs); let new_ids = executor.push_transactions(txs); info!("ids: {}", new_ids.len()); tx_sent_count += new_ids.len(); @@ -752,6 +795,7 @@ fn run_accounts_bench( .collect(); balances[0] = balances[0].saturating_sub(fee * txs.len() as u64); info!("close txs: {}", txs.len()); + transaction_signature_tracker.track_transactions(&txs); let new_ids = executor.push_transactions(txs); info!("close ids: {}", new_ids.len()); tx_sent_count += new_ids.len(); @@ -848,6 +892,7 @@ fn run_accounts_bench( .collect(); balances[i] = balances[i].saturating_sub(fee * txs.len() as u64); info!("close txs: {}", txs.len()); + transaction_signature_tracker.track_transactions(&txs); let new_ids = executor.push_transactions(txs); info!("close ids: {}", new_ids.len()); tx_sent_count += new_ids.len(); From 565a3c5a7fa5648e3e73880dac1869ff969bd6a7 Mon Sep 17 00:00:00 2001 From: Steven Luscher Date: Fri, 6 Dec 2024 20:21:29 +0000 Subject: [PATCH 2/2] A benchmark suite for the `getTransaction` RPC call --- accounts-cluster-bench/src/main.rs | 59 +++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/accounts-cluster-bench/src/main.rs b/accounts-cluster-bench/src/main.rs index fd473f7c83447c..5008c659dfa602 100644 --- a/accounts-cluster-bench/src/main.rs +++ b/accounts-cluster-bench/src/main.rs @@ -28,6 +28,7 @@ use { transaction::Transaction, }, solana_streamer::socket::SocketAddrSpace, + solana_transaction_status::UiTransactionEncoding, spl_token::state::Account, std::{ cmp::min, @@ -140,7 +141,6 @@ struct SeedTracker { struct TransactionSignatureTracker(Arc>>); impl TransactionSignatureTracker { - #[allow(dead_code)] fn get_random(&self) -> Option { let signatures = self.read().unwrap(); if signatures.is_empty() { @@ -290,6 +290,8 @@ pub enum RpcBench { TokenAccountsByOwner, Supply, TokenAccountsByDelegate, + Transaction, + TransactionParsed, } #[derive(Debug)] @@ -307,6 +309,8 @@ impl FromStr for RpcBench { "multiple-accounts" => Ok(RpcBench::MultipleAccounts), "token-accounts-by-delegate" => Ok(RpcBench::TokenAccountsByDelegate), "token-accounts-by-owner" => Ok(RpcBench::TokenAccountsByOwner), + "transaction" => Ok(RpcBench::Transaction), + "transaction-parsed" => Ok(RpcBench::TransactionParsed), "version" => Ok(RpcBench::Version), _ => Err(RpcParseError::InvalidOption), } @@ -367,6 +371,37 @@ fn process_get_multiple_accounts( } } +fn process_get_transaction( + test_name: &'static str, + transaction_signature_tracker: &TransactionSignatureTracker, + client: &RpcClient, + stats: &mut RpcBenchStats, + last_error: &mut Instant, + encoding: UiTransactionEncoding, +) { + let Some(signature) = transaction_signature_tracker.get_random() else { + info!("transaction: No transactions have yet been made; skipping"); + return; + }; + let mut measure = Measure::start(test_name); + match client.get_transaction(&signature, encoding) { + Ok(_tx) => { + measure.stop(); + stats.success += 1; + stats.total_success_time_us += measure.as_us(); + } + Err(e) => { + measure.stop(); + stats.errors += 1; + stats.total_errors_time_us += measure.as_us(); + if last_error.elapsed().as_secs() > 2 { + info!("get_transaction error: {:?}", &e); + *last_error = Instant::now(); + } + } + }; +} + #[derive(Default)] struct RpcBenchStats { errors: u64, @@ -386,7 +421,7 @@ fn run_rpc_bench_loop( max_closed: &AtomicU64, max_created: &AtomicU64, mint: &Option, - _transaction_signature_tracker: &TransactionSignatureTracker, + transaction_signature_tracker: &TransactionSignatureTracker, ) { let mut stats = RpcBenchStats::default(); let mut iters = 0; @@ -537,6 +572,26 @@ fn run_rpc_bench_loop( } } } + RpcBench::Transaction => { + process_get_transaction( + "rpc-get-transaction-base64", + transaction_signature_tracker, + client, + &mut stats, + &mut last_error, + UiTransactionEncoding::Base64, + ); + } + RpcBench::TransactionParsed => { + process_get_transaction( + "rpc-get-transaction-parsed", + transaction_signature_tracker, + client, + &mut stats, + &mut last_error, + UiTransactionEncoding::JsonParsed, + ); + } RpcBench::Version => { let mut rpc_time = Measure::start("rpc-get-version"); match client.get_version() {