Perf: Only check executors cache for executable bpf program ids (backport #22624) (#22628)

* Perf: Only check executors cache for executable bpf program ids (#22624)

* Only check executors cache for executable bpf program ids

* switch to native loader check

* clean up tests

* fix tests

* clippy

(cherry picked from commit 7d34a7acac)

# Conflicts:
#	runtime/src/bank.rs

* resolve conflicts

Co-authored-by: Justin Starry <justin@solana.com>
This commit is contained in:
mergify[bot]
2022-01-22 14:12:29 +08:00
committed by GitHub
parent 4b7450e89e
commit de46df6b1b

View File

@ -3394,31 +3394,34 @@ impl Bank {
} }
/// Get any cached executors needed by the transaction /// Get any cached executors needed by the transaction
fn get_executors( fn get_executors<'a>(
&self, &self,
message: &Message, accounts_iter: impl Iterator<Item = &'a (Pubkey, AccountSharedData)>,
loaders: &[Vec<(Pubkey, AccountSharedData)>],
) -> Rc<RefCell<Executors>> { ) -> Rc<RefCell<Executors>> {
let mut num_executors = message.account_keys.len(); let executable_keys: Vec<_> = accounts_iter
for instruction_loaders in loaders.iter() { .filter_map(|(key, account)| {
num_executors += instruction_loaders.len(); if account.executable() && !native_loader::check_id(account.owner()) {
Some(key)
} else {
None
} }
let mut executors = HashMap::with_capacity(num_executors); })
let cache = self.cached_executors.read().unwrap(); .collect();
for key in message.account_keys.iter() { if executable_keys.is_empty() {
if let Some(executor) = cache.get(key) { return Rc::new(RefCell::new(Executors::default()));
executors.insert(*key, TransactionExecutor::new_cached(executor));
}
}
for instruction_loaders in loaders.iter() {
for (key, _) in instruction_loaders.iter() {
if let Some(executor) = cache.get(key) {
executors.insert(*key, TransactionExecutor::new_cached(executor));
}
}
} }
let cache = self.cached_executors.read().unwrap();
let executors = executable_keys
.into_iter()
.filter_map(|key| {
cache
.get(key)
.map(|executor| (*key, TransactionExecutor::new_cached(executor)))
})
.collect();
Rc::new(RefCell::new(executors)) Rc::new(RefCell::new(executors))
} }
@ -3550,8 +3553,15 @@ impl Bank {
if process_result.is_ok() { if process_result.is_ok() {
let mut get_executors_time = Measure::start("get_executors_time"); let mut get_executors_time = Measure::start("get_executors_time");
let executors = let executors = self.get_executors(
self.get_executors(&tx.message, &loaded_transaction.loaders); loaded_transaction.accounts.iter().chain(
loaded_transaction
.loaders
.iter()
.map(|loaders| loaders.iter())
.flatten(),
),
);
get_executors_time.stop(); get_executors_time.stop();
saturating_add_assign!( saturating_add_assign!(
timings.execute_accessories.get_executors_us, timings.execute_accessories.get_executors_us,
@ -5865,6 +5875,7 @@ pub(crate) mod tests {
crossbeam_channel::{bounded, unbounded}, crossbeam_channel::{bounded, unbounded},
solana_sdk::{ solana_sdk::{
account::Account, account::Account,
bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable,
clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT}, clock::{DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT},
compute_budget, compute_budget,
epoch_schedule::MINIMUM_SLOTS_PER_EPOCH, epoch_schedule::MINIMUM_SLOTS_PER_EPOCH,
@ -12084,25 +12095,23 @@ pub(crate) mod tests {
let key2 = solana_sdk::pubkey::new_rand(); let key2 = solana_sdk::pubkey::new_rand();
let key3 = solana_sdk::pubkey::new_rand(); let key3 = solana_sdk::pubkey::new_rand();
let key4 = solana_sdk::pubkey::new_rand(); let key4 = solana_sdk::pubkey::new_rand();
let key5 = solana_sdk::pubkey::new_rand();
let executor: Arc<dyn Executor> = Arc::new(TestExecutor {}); let executor: Arc<dyn Executor> = Arc::new(TestExecutor {});
let message = Message { fn new_executable_account(owner: Pubkey) -> AccountSharedData {
header: MessageHeader { AccountSharedData::from(Account {
num_required_signatures: 1, owner,
num_readonly_signed_accounts: 0, executable: true,
num_readonly_unsigned_accounts: 1, ..Account::default()
}, })
account_keys: vec![key1, key2], }
recent_blockhash: Hash::default(),
instructions: vec![],
};
let loaders = &[ let accounts = &[
vec![ (key1, new_executable_account(bpf_loader_upgradeable::id())),
(key3, AccountSharedData::default()), (key2, new_executable_account(bpf_loader::id())),
(key4, AccountSharedData::default()), (key3, new_executable_account(bpf_loader_deprecated::id())),
], (key4, new_executable_account(native_loader::id())),
vec![(key1, AccountSharedData::default())], (key5, AccountSharedData::default()),
]; ];
// don't do any work if not dirty // don't do any work if not dirty
@ -12118,7 +12127,7 @@ pub(crate) mod tests {
.unwrap() .unwrap()
.clear_miss_for_test(); .clear_miss_for_test();
bank.update_executors(true, executors); bank.update_executors(true, executors);
let executors = bank.get_executors(&message, loaders); let executors = bank.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 0); assert_eq!(executors.borrow().len(), 0);
// do work // do work
@ -12129,33 +12138,27 @@ pub(crate) mod tests {
executors.insert(key4, TransactionExecutor::new_miss(executor.clone())); executors.insert(key4, TransactionExecutor::new_miss(executor.clone()));
let executors = Rc::new(RefCell::new(executors)); let executors = Rc::new(RefCell::new(executors));
bank.update_executors(true, executors); bank.update_executors(true, executors);
let executors = bank.get_executors(&message, loaders); let executors = bank.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 4); assert_eq!(executors.borrow().len(), 3);
assert!(executors.borrow().contains_key(&key1)); assert!(executors.borrow().contains_key(&key1));
assert!(executors.borrow().contains_key(&key2)); assert!(executors.borrow().contains_key(&key2));
assert!(executors.borrow().contains_key(&key3)); assert!(executors.borrow().contains_key(&key3));
assert!(executors.borrow().contains_key(&key4));
// Check inheritance // Check inheritance
let bank = Bank::new_from_parent(&Arc::new(bank), &solana_sdk::pubkey::new_rand(), 1); let bank = Bank::new_from_parent(&Arc::new(bank), &solana_sdk::pubkey::new_rand(), 1);
let executors = bank.get_executors(&message, loaders); let executors = bank.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 4); assert_eq!(executors.borrow().len(), 3);
assert!(executors.borrow().contains_key(&key1)); assert!(executors.borrow().contains_key(&key1));
assert!(executors.borrow().contains_key(&key2)); assert!(executors.borrow().contains_key(&key2));
assert!(executors.borrow().contains_key(&key3)); assert!(executors.borrow().contains_key(&key3));
assert!(executors.borrow().contains_key(&key4));
// Remove all // Remove all
bank.remove_executor(&key1); bank.remove_executor(&key1);
bank.remove_executor(&key2); bank.remove_executor(&key2);
bank.remove_executor(&key3); bank.remove_executor(&key3);
bank.remove_executor(&key4); bank.remove_executor(&key4);
let executors = bank.get_executors(&message, loaders); let executors = bank.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 0); assert_eq!(executors.borrow().len(), 0);
assert!(!executors.borrow().contains_key(&key1));
assert!(!executors.borrow().contains_key(&key2));
assert!(!executors.borrow().contains_key(&key3));
assert!(!executors.borrow().contains_key(&key4));
} }
#[test] #[test]
@ -12168,26 +12171,31 @@ pub(crate) mod tests {
let key1 = solana_sdk::pubkey::new_rand(); let key1 = solana_sdk::pubkey::new_rand();
let key2 = solana_sdk::pubkey::new_rand(); let key2 = solana_sdk::pubkey::new_rand();
let executor: Arc<dyn Executor> = Arc::new(TestExecutor {}); let executor: Arc<dyn Executor> = Arc::new(TestExecutor {});
let executable_account = AccountSharedData::from(Account {
owner: bpf_loader_upgradeable::id(),
executable: true,
..Account::default()
});
let loaders = &[vec![ let accounts = &[
(key1, AccountSharedData::default()), (key1, executable_account.clone()),
(key2, AccountSharedData::default()), (key2, executable_account),
]]; ];
// add one to root bank // add one to root bank
let mut executors = Executors::default(); let mut executors = Executors::default();
executors.insert(key1, TransactionExecutor::new_miss(executor.clone())); executors.insert(key1, TransactionExecutor::new_miss(executor.clone()));
let executors = Rc::new(RefCell::new(executors)); let executors = Rc::new(RefCell::new(executors));
root.update_executors(true, executors); root.update_executors(true, executors);
let executors = root.get_executors(&Message::default(), loaders); let executors = root.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 1); assert_eq!(executors.borrow().len(), 1);
let fork1 = Bank::new_from_parent(&root, &Pubkey::default(), 1); let fork1 = Bank::new_from_parent(&root, &Pubkey::default(), 1);
let fork2 = Bank::new_from_parent(&root, &Pubkey::default(), 1); let fork2 = Bank::new_from_parent(&root, &Pubkey::default(), 2);
let executors = fork1.get_executors(&Message::default(), loaders); let executors = fork1.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 1); assert_eq!(executors.borrow().len(), 1);
let executors = fork2.get_executors(&Message::default(), loaders); let executors = fork2.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 1); assert_eq!(executors.borrow().len(), 1);
let mut executors = Executors::default(); let mut executors = Executors::default();
@ -12195,16 +12203,16 @@ pub(crate) mod tests {
let executors = Rc::new(RefCell::new(executors)); let executors = Rc::new(RefCell::new(executors));
fork1.update_executors(true, executors); fork1.update_executors(true, executors);
let executors = fork1.get_executors(&Message::default(), loaders); let executors = fork1.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 2); assert_eq!(executors.borrow().len(), 2);
let executors = fork2.get_executors(&Message::default(), loaders); let executors = fork2.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 1); assert_eq!(executors.borrow().len(), 1);
fork1.remove_executor(&key1); fork1.remove_executor(&key1);
let executors = fork1.get_executors(&Message::default(), loaders); let executors = fork1.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 1); assert_eq!(executors.borrow().len(), 1);
let executors = fork2.get_executors(&Message::default(), loaders); let executors = fork2.get_executors(accounts.iter());
assert_eq!(executors.borrow().len(), 1); assert_eq!(executors.borrow().len(), 1);
} }