From 0996b5e245d741d6ccbf3ef0e5c01bc3297b6e63 Mon Sep 17 00:00:00 2001 From: Andrew Fitzgerald Date: Tue, 15 Aug 2023 15:20:04 -0700 Subject: [PATCH] BenchTPS: Allow a fixed compute-unit-price (#32775) --- bench-tps/src/bench.rs | 82 ++++++++++++++++++++++++------------------ bench-tps/src/cli.rs | 26 ++++++++++++-- bench-tps/src/main.rs | 6 ++-- 3 files changed, 72 insertions(+), 42 deletions(-) diff --git a/bench-tps/src/bench.rs b/bench-tps/src/bench.rs index d6444ebe4..df60a24ff 100644 --- a/bench-tps/src/bench.rs +++ b/bench-tps/src/bench.rs @@ -1,7 +1,7 @@ use { crate::{ bench_tps_client::*, - cli::{Config, InstructionPaddingConfig}, + cli::{ComputeUnitPrice, Config, InstructionPaddingConfig}, perf_utils::{sample_txs, SampleStats}, send_batch::*, }, @@ -40,30 +40,36 @@ use { // The point at which transactions become "too old", in seconds. const MAX_TX_QUEUE_AGE: u64 = (MAX_PROCESSING_AGE as f64 * DEFAULT_S_PER_SLOT) as u64; -// Add prioritization fee to transfer transactions, when `--use-randomized-compute-unit-price` -// is used, compute-unit-price is randomly generated in range of (0..MAX_COMPUTE_UNIT_PRICE) -// multiplies by COMPUTE_UNIT_PRICE_MULTIPLIER; +// Add prioritization fee to transfer transactions, if `compute_unit_price` is set. +// If `Random` the compute-unit-price is determined by generating a random number in the range +// 0..MAX_RANDOM_COMPUTE_UNIT_PRICE then multiplying by COMPUTE_UNIT_PRICE_MULTIPLIER. +// If `Fixed` the compute-unit-price is the value of the `compute-unit-price` parameter. // It also sets transaction's compute-unit to TRANSFER_TRANSACTION_COMPUTE_UNIT. Therefore the // max additional cost is: // `TRANSFER_TRANSACTION_COMPUTE_UNIT * MAX_COMPUTE_UNIT_PRICE * COMPUTE_UNIT_PRICE_MULTIPLIER / 1_000_000` -const MAX_COMPUTE_UNIT_PRICE: u64 = 50; +const MAX_RANDOM_COMPUTE_UNIT_PRICE: u64 = 50; const COMPUTE_UNIT_PRICE_MULTIPLIER: u64 = 1_000; const TRANSFER_TRANSACTION_COMPUTE_UNIT: u32 = 600; // 1 transfer is plus 3 compute_budget ixs /// calculate maximum possible prioritization fee, if `use-randomized-compute-unit-price` is /// enabled, round to nearest lamports. -pub fn max_lamports_for_prioritization(use_randomized_compute_unit_price: bool) -> u64 { - if use_randomized_compute_unit_price { - const MICRO_LAMPORTS_PER_LAMPORT: u64 = 1_000_000; - let micro_lamport_fee: u128 = (MAX_COMPUTE_UNIT_PRICE as u128) - .saturating_mul(COMPUTE_UNIT_PRICE_MULTIPLIER as u128) - .saturating_mul(TRANSFER_TRANSACTION_COMPUTE_UNIT as u128); - let fee = micro_lamport_fee - .saturating_add(MICRO_LAMPORTS_PER_LAMPORT.saturating_sub(1) as u128) - .saturating_div(MICRO_LAMPORTS_PER_LAMPORT as u128); - u64::try_from(fee).unwrap_or(u64::MAX) - } else { - 0u64 - } +pub fn max_lamports_for_prioritization(compute_unit_price: &Option) -> u64 { + let Some(compute_unit_price) = compute_unit_price else { + return 0; + }; + + let compute_unit_price = match compute_unit_price { + ComputeUnitPrice::Random => (MAX_RANDOM_COMPUTE_UNIT_PRICE as u128) + .saturating_mul(COMPUTE_UNIT_PRICE_MULTIPLIER as u128), + ComputeUnitPrice::Fixed(compute_unit_price) => *compute_unit_price as u128, + }; + + const MICRO_LAMPORTS_PER_LAMPORT: u64 = 1_000_000; + let micro_lamport_fee: u128 = + compute_unit_price.saturating_mul(TRANSFER_TRANSACTION_COMPUTE_UNIT as u128); + let fee = micro_lamport_fee + .saturating_add(MICRO_LAMPORTS_PER_LAMPORT.saturating_sub(1) as u128) + .saturating_div(MICRO_LAMPORTS_PER_LAMPORT as u128); + u64::try_from(fee).unwrap_or(u64::MAX) } // set transfer transaction's loaded account data size to 30K - large enough yet smaller than @@ -120,7 +126,7 @@ struct TransactionChunkGenerator<'a, 'b, T: ?Sized> { nonce_chunks: Option>, chunk_index: usize, reclaim_lamports_back_to_source_account: bool, - use_randomized_compute_unit_price: bool, + compute_unit_price: Option, instruction_padding_config: Option, } @@ -133,7 +139,7 @@ where gen_keypairs: &'a [Keypair], nonce_keypairs: Option<&'b Vec>, chunk_size: usize, - use_randomized_compute_unit_price: bool, + compute_unit_price: Option, instruction_padding_config: Option, num_conflict_groups: Option, ) -> Self { @@ -151,7 +157,7 @@ where nonce_chunks, chunk_index: 0, reclaim_lamports_back_to_source_account: false, - use_randomized_compute_unit_price, + compute_unit_price, instruction_padding_config, } } @@ -188,7 +194,7 @@ where self.reclaim_lamports_back_to_source_account, blockhash.unwrap(), &self.instruction_padding_config, - self.use_randomized_compute_unit_price, + &self.compute_unit_price, ) }; @@ -379,7 +385,7 @@ where tx_count, sustained, target_slots_per_epoch, - use_randomized_compute_unit_price, + compute_unit_price, use_durable_nonce, instruction_padding_config, num_conflict_groups, @@ -392,7 +398,7 @@ where &gen_keypairs, nonce_keypairs.as_ref(), tx_count, - use_randomized_compute_unit_price, + compute_unit_price, instruction_padding_config, num_conflict_groups, ); @@ -520,7 +526,7 @@ fn generate_system_txs( reclaim: bool, blockhash: &Hash, instruction_padding_config: &Option, - use_randomized_compute_unit_price: bool, + compute_unit_price: &Option, ) -> Vec { let pairs: Vec<_> = if !reclaim { source.iter().zip(dest.iter()).collect() @@ -528,16 +534,22 @@ fn generate_system_txs( dest.iter().zip(source.iter()).collect() }; - if use_randomized_compute_unit_price { - let mut rng = rand::thread_rng(); - let range = Uniform::from(0..MAX_COMPUTE_UNIT_PRICE); - let compute_unit_prices: Vec<_> = (0..pairs.len()) - .map(|_| { - range - .sample(&mut rng) - .saturating_mul(COMPUTE_UNIT_PRICE_MULTIPLIER) - }) - .collect(); + if let Some(compute_unit_price) = compute_unit_price { + let compute_unit_prices = match compute_unit_price { + ComputeUnitPrice::Random => { + let mut rng = rand::thread_rng(); + let range = Uniform::from(0..MAX_RANDOM_COMPUTE_UNIT_PRICE); + (0..pairs.len()) + .map(|_| { + range + .sample(&mut rng) + .saturating_mul(COMPUTE_UNIT_PRICE_MULTIPLIER) + }) + .collect() + } + ComputeUnitPrice::Fixed(compute_unit_price) => vec![*compute_unit_price; pairs.len()], + }; + let pairs_with_compute_unit_prices: Vec<_> = pairs.iter().zip(compute_unit_prices.iter()).collect(); diff --git a/bench-tps/src/cli.rs b/bench-tps/src/cli.rs index 9acf1e74c..39de03473 100644 --- a/bench-tps/src/cli.rs +++ b/bench-tps/src/cli.rs @@ -43,6 +43,12 @@ pub struct InstructionPaddingConfig { pub data_size: u32, } +#[derive(Debug, PartialEq)] +pub enum ComputeUnitPrice { + Fixed(u64), + Random, +} + /// Holds the configuration for a single run of the benchmark #[derive(PartialEq, Debug)] pub struct Config { @@ -68,7 +74,7 @@ pub struct Config { pub external_client_type: ExternalClientType, pub use_quic: bool, pub tpu_connection_pool_size: usize, - pub use_randomized_compute_unit_price: bool, + pub compute_unit_price: Option, pub use_durable_nonce: bool, pub instruction_padding_config: Option, pub num_conflict_groups: Option, @@ -103,7 +109,7 @@ impl Default for Config { external_client_type: ExternalClientType::default(), use_quic: DEFAULT_TPU_USE_QUIC, tpu_connection_pool_size: DEFAULT_TPU_CONNECTION_POOL_SIZE, - use_randomized_compute_unit_price: false, + compute_unit_price: None, use_durable_nonce: false, instruction_padding_config: None, num_conflict_groups: None, @@ -332,10 +338,18 @@ pub fn build_args<'a>(version: &'_ str) -> App<'a, '_> { .help("Controls the connection pool size per remote address; only affects ThinClient (default) \ or TpuClient sends"), ) + .arg( + Arg::with_name("compute_unit_price") + .long("compute-unit-price") + .takes_value(true) + .validator(|s| is_within_range(s, 0..)) + .help("Sets constant compute-unit-price to transfer transactions"), + ) .arg( Arg::with_name("use_randomized_compute_unit_price") .long("use-randomized-compute-unit-price") .takes_value(false) + .conflicts_with("compute_unit_price") .help("Sets random compute-unit-price in range [0..100] to transfer transactions"), ) .arg( @@ -517,8 +531,14 @@ pub fn parse_args(matches: &ArgMatches) -> Result { .map_err(|_| "can't parse target-slots-per-epoch")?; } + if let Some(str) = matches.value_of("compute_unit_price") { + args.compute_unit_price = Some(ComputeUnitPrice::Fixed( + str.parse().map_err(|_| "can't parse compute-unit-price")?, + )); + } + if matches.is_present("use_randomized_compute_unit_price") { - args.use_randomized_compute_unit_price = true; + args.compute_unit_price = Some(ComputeUnitPrice::Random); } if matches.is_present("use_durable_nonce") { diff --git a/bench-tps/src/main.rs b/bench-tps/src/main.rs index 0788181e8..756da9ce7 100644 --- a/bench-tps/src/main.rs +++ b/bench-tps/src/main.rs @@ -251,7 +251,7 @@ fn main() { external_client_type, use_quic, tpu_connection_pool_size, - use_randomized_compute_unit_price, + compute_unit_price, use_durable_nonce, instruction_padding_config, bind_address, @@ -266,9 +266,7 @@ fn main() { let num_accounts = keypairs.len() as u64; let max_fee = FeeRateGovernor::new(*target_lamports_per_signature, 0) .max_lamports_per_signature - .saturating_add(max_lamports_for_prioritization( - *use_randomized_compute_unit_price, - )); + .saturating_add(max_lamports_for_prioritization(compute_unit_price)); let num_lamports_per_account = (num_accounts - 1 + NUM_SIGNATURES_FOR_TXS * max_fee) / num_accounts + num_lamports_per_account;