Skip to content

Commit 915f79f

Browse files
fikunmi-apappetrosyan
authored andcommitted
Add accounts pool based write lock contention to banking bench
1 parent 091a7b4 commit 915f79f

File tree

1 file changed

+117
-57
lines changed

1 file changed

+117
-57
lines changed

banking-bench/src/main.rs

+117-57
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
use {
33
agave_banking_stage_ingress_types::BankingPacketBatch,
44
assert_matches::assert_matches,
5-
clap::{crate_description, crate_name, Arg, ArgEnum, Command},
5+
clap::{crate_description, crate_name, Arg, Command},
66
crossbeam_channel::{unbounded, Receiver},
77
log::*,
8-
rand::{thread_rng, Rng},
8+
rand::{seq::SliceRandom, thread_rng, Rng},
99
rayon::prelude::*,
1010
solana_core::{
1111
banking_stage::{update_bank_forks_and_poh_recorder_for_new_tpu_bank, BankingStage},
@@ -79,28 +79,38 @@ fn check_txs(
7979
no_bank
8080
}
8181

82-
#[derive(ArgEnum, Clone, Copy, PartialEq, Eq)]
82+
#[derive(Clone, Copy, PartialEq, Eq)]
8383
enum WriteLockContention {
8484
/// No transactions lock the same accounts.
8585
None,
8686
/// Transactions don't lock the same account, unless they belong to the same batch.
8787
SameBatchOnly,
8888
/// All transactions write lock the same account.
8989
Full,
90+
/// Transactions randomly lock any two accounts from the pool of accounts, contention depends
91+
/// on the number of accounts.
92+
AccountContention(i64),
9093
}
9194

92-
impl WriteLockContention {
93-
fn possible_values<'a>() -> impl Iterator<Item = clap::PossibleValue<'a>> {
94-
Self::value_variants()
95-
.iter()
96-
.filter_map(|v| v.to_possible_value())
97-
}
98-
}
99-
100-
impl std::str::FromStr for WriteLockContention {
101-
type Err = String;
102-
fn from_str(input: &str) -> Result<Self, String> {
103-
ArgEnum::from_str(input, false)
95+
fn parse_write_lock_contention(argument: &str) -> Result<WriteLockContention, String> {
96+
if let Some(("account-contention", value)) = argument.split_once("=") {
97+
match value.parse::<i64>() {
98+
Ok(num_accts) if num_accts > 1 => Ok(WriteLockContention::AccountContention(num_accts)),
99+
_ => Err("Account contention value must be an integer greater than 1".to_string()),
100+
}
101+
} else {
102+
match argument {
103+
"none" => Ok(WriteLockContention::None),
104+
"same-batch-only" => Ok(WriteLockContention::SameBatchOnly),
105+
"full" => Ok(WriteLockContention::Full),
106+
_ => Err(format!(
107+
"Invalid contention option. Valid options are:\n\
108+
- none\n\
109+
- same-batch-only\n\
110+
- full\n\
111+
- account-contention=N (where N is a positive integer)"
112+
)),
113+
}
104114
}
105115
}
106116

@@ -112,47 +122,95 @@ fn make_accounts_txs(
112122
simulate_mint: bool,
113123
mint_txs_percentage: usize,
114124
) -> Vec<Transaction> {
125+
let payer_keypair = Keypair::new();
115126
let to_pubkey = pubkey::new_rand();
116-
let chunk_pubkeys: Vec<pubkey::Pubkey> = (0..total_num_transactions / packets_per_batch)
117-
.map(|_| pubkey::new_rand())
118-
.collect();
119-
let payer_key = Keypair::new();
120-
(0..total_num_transactions)
121-
.into_par_iter()
122-
.map(|i| {
123-
let is_simulated_mint = is_simulated_mint_transaction(
124-
simulate_mint,
125-
i,
126-
packets_per_batch,
127-
mint_txs_percentage,
128-
);
129-
// simulated mint transactions have higher compute-unit-price
130-
let compute_unit_price = if is_simulated_mint { 5 } else { 1 };
131-
let mut new = make_transfer_transaction_with_compute_unit_price(
132-
&payer_key,
133-
&to_pubkey,
134-
1,
135-
hash,
136-
compute_unit_price,
137-
);
138-
let sig: [u8; 64] = std::array::from_fn(|_| thread_rng().gen::<u8>());
139-
new.message.account_keys[0] = pubkey::new_rand();
140-
new.message.account_keys[1] = match contention {
141-
WriteLockContention::None => pubkey::new_rand(),
142-
WriteLockContention::SameBatchOnly => {
143-
// simulated mint transactions have conflict accounts
144-
if is_simulated_mint {
145-
chunk_pubkeys[i / packets_per_batch]
146-
} else {
147-
pubkey::new_rand()
127+
128+
if let WriteLockContention::AccountContention(num_accts) = contention{
129+
let accounts: Vec<Pubkey> = (0..num_accts)
130+
.map(|_| pubkey::new_rand())
131+
.collect();
132+
133+
(0..total_num_transactions)
134+
.into_par_iter()
135+
.map(|i| {
136+
let mut rng = thread_rng();
137+
let from_pubkey = accounts.choose(&mut rng).unwrap();
138+
let to_pubkey = loop {
139+
let candidate = accounts.choose(&mut rng).unwrap();
140+
if candidate != from_pubkey {break candidate}
141+
};
142+
143+
// simulated mint transactions have higher compute unit price.
144+
let is_simulated_mint = is_simulated_mint_transaction(
145+
simulate_mint, i,
146+
packets_per_batch,
147+
mint_txs_percentage
148+
);
149+
150+
let compute_unit_price = if is_simulated_mint { 5 } else { 1 };
151+
152+
let lamports = (i + 1) as u64; //ensure non zero and non-constant lamports transferred.
153+
154+
let mut new_tx = make_transfer_transaction_with_compute_unit_price(
155+
&payer_keypair,
156+
to_pubkey,
157+
lamports,
158+
hash,
159+
compute_unit_price
160+
);
161+
162+
new_tx.message.account_keys[0] = *from_pubkey;
163+
new_tx.message.account_keys[1] = *to_pubkey;
164+
165+
let sig: [u8;64] = std::array::from_fn(|_| thread_rng().gen::<u8>());
166+
new_tx.signatures = vec![Signature::from(sig)];
167+
new_tx
168+
169+
})
170+
.collect()
171+
} else {
172+
let chunk_pubkeys: Vec<pubkey::Pubkey> = (0..total_num_transactions / packets_per_batch)
173+
.map(|_| pubkey::new_rand())
174+
.collect();
175+
176+
(0..total_num_transactions)
177+
.into_par_iter()
178+
.map(|i| {
179+
let is_simulated_mint = is_simulated_mint_transaction(
180+
simulate_mint,
181+
i,
182+
packets_per_batch,
183+
mint_txs_percentage,
184+
);
185+
// simulated mint transactions have higher compute-unit-price
186+
let compute_unit_price = if is_simulated_mint { 5 } else { 1 };
187+
let mut new = make_transfer_transaction_with_compute_unit_price(
188+
&payer_keypair,
189+
&to_pubkey,
190+
1,
191+
hash,
192+
compute_unit_price,
193+
);
194+
let sig: [u8; 64] = std::array::from_fn(|_| thread_rng().gen::<u8>());
195+
new.message.account_keys[0] = pubkey::new_rand();
196+
new.message.account_keys[1] = match contention {
197+
WriteLockContention::None => pubkey::new_rand(),
198+
WriteLockContention::SameBatchOnly => {
199+
// simulated mint transactions have conflict accounts
200+
if is_simulated_mint {
201+
chunk_pubkeys[i / packets_per_batch]
202+
} else {
203+
pubkey::new_rand()
204+
}
148205
}
149-
}
150-
WriteLockContention::Full => to_pubkey,
151-
};
152-
new.signatures = vec![Signature::from(sig)];
153-
new
154-
})
155-
.collect()
206+
WriteLockContention::Full => to_pubkey,
207+
WriteLockContention::AccountContention(_) => unreachable!(),
208+
};
209+
new.signatures = vec![Signature::from(sig)];
210+
new
211+
})
212+
.collect()
213+
}
156214
}
157215

158216
// In simulating mint, `mint_txs_percentage` transactions in a batch are mint transaction
@@ -271,8 +329,8 @@ fn main() {
271329
Arg::new("write_lock_contention")
272330
.long("write-lock-contention")
273331
.takes_value(true)
274-
.possible_values(WriteLockContention::possible_values())
275-
.help("Accounts that test transactions write lock"),
332+
.value_parser(parse_write_lock_contention)
333+
.help("Accounts that test transactions write lock. Use 'none', 'same-batch-only', 'full',or 'n'/'account-contention n' where n is an integer greater than 1"),
276334
)
277335
.arg(
278336
Arg::new("batches_per_iteration")
@@ -336,7 +394,8 @@ fn main() {
336394
.value_of_t::<usize>("batches_per_iteration")
337395
.unwrap_or(BankingStage::num_threads() as usize);
338396
let write_lock_contention = matches
339-
.value_of_t::<WriteLockContention>("write_lock_contention")
397+
.get_one::<WriteLockContention>("write_lock_contention")
398+
.copied()
340399
.unwrap_or(WriteLockContention::None);
341400
let mint_txs_percentage = matches
342401
.value_of_t::<usize>("mint_txs_percentage")
@@ -397,6 +456,7 @@ fn main() {
397456
let sig: [u8; 64] = std::array::from_fn(|_| thread_rng().gen::<u8>());
398457
fund.signatures = vec![Signature::from(sig)];
399458
bank.process_transaction(&fund).unwrap();
459+
bank.clear_signatures(); // needed for account contention because there is a non-zero chance of funding the same address.
400460
});
401461
});
402462

0 commit comments

Comments
 (0)