Skip to content

Commit

Permalink
Reduce ProgramCache write lock contention (#1037)
Browse files Browse the repository at this point in the history
* Reduce ProgramCache write-lock contention

* Also consider programs modified by tx

* Memoize program cache write lock
  • Loading branch information
ryoqun authored Apr 27, 2024
1 parent 3f7b352 commit 90bea33
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 11 deletions.
11 changes: 11 additions & 0 deletions program-runtime/src/loaded_programs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,6 +666,8 @@ pub struct ProgramCacheForTxBatch {
/// The epoch of the last rerooting
pub latest_root_epoch: Epoch,
pub hit_max_limit: bool,
pub loaded_missing: bool,
pub merged_modified: bool,
}

impl ProgramCacheForTxBatch {
Expand All @@ -682,6 +684,8 @@ impl ProgramCacheForTxBatch {
upcoming_environments,
latest_root_epoch,
hit_max_limit: false,
loaded_missing: false,
merged_modified: false,
}
}

Expand All @@ -697,6 +701,8 @@ impl ProgramCacheForTxBatch {
upcoming_environments: cache.get_upcoming_environments_for_epoch(epoch),
latest_root_epoch: cache.latest_root_epoch,
hit_max_limit: false,
loaded_missing: false,
merged_modified: false,
}
}

Expand Down Expand Up @@ -750,9 +756,14 @@ impl ProgramCacheForTxBatch {

pub fn merge(&mut self, other: &Self) {
other.entries.iter().for_each(|(key, entry)| {
self.merged_modified = true;
self.replenish(*key, entry.clone());
})
}

pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}

pub enum ProgramCacheMatchCriteria {
Expand Down
11 changes: 8 additions & 3 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4156,18 +4156,23 @@ impl Bank {

let mut store_executors_which_were_deployed_time =
Measure::start("store_executors_which_were_deployed_time");
let mut cache = None;
for execution_result in &execution_results {
if let TransactionExecutionResult::Executed {
details,
programs_modified_by_tx,
} = execution_result
{
if details.status.is_ok() {
let mut cache = self.transaction_processor.program_cache.write().unwrap();
cache.merge(programs_modified_by_tx);
if details.status.is_ok() && !programs_modified_by_tx.is_empty() {
cache
.get_or_insert_with(|| {
self.transaction_processor.program_cache.write().unwrap()
})
.merge(programs_modified_by_tx);
}
}
}
drop(cache);
store_executors_which_were_deployed_time.stop();
saturating_add_assign!(
timings.execute_accessories.update_executors_us,
Expand Down
25 changes: 17 additions & 8 deletions svm/src/transaction_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,14 +292,22 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {

execution_time.stop();

const SHRINK_LOADED_PROGRAMS_TO_PERCENTAGE: u8 = 90;
self.program_cache
.write()
.unwrap()
.evict_using_2s_random_selection(
Percentage::from(SHRINK_LOADED_PROGRAMS_TO_PERCENTAGE),
self.slot,
);
// Skip eviction when there's no chance this particular tx batch has increased the size of
// ProgramCache entries. Note that loaded_missing is deliberately defined, so that there's
// still at least one other batch, which will evict the program cache, even after the
// occurrences of cooperative loading.
if programs_loaded_for_tx_batch.borrow().loaded_missing
|| programs_loaded_for_tx_batch.borrow().merged_modified
{
const SHRINK_LOADED_PROGRAMS_TO_PERCENTAGE: u8 = 90;
self.program_cache
.write()
.unwrap()
.evict_using_2s_random_selection(
Percentage::from(SHRINK_LOADED_PROGRAMS_TO_PERCENTAGE),
self.slot,
);
}

debug!(
"load: {}us execute: {}us txs_len={}",
Expand Down Expand Up @@ -395,6 +403,7 @@ impl<FG: ForkGraph> TransactionBatchProcessor<FG> {
}
// Submit our last completed loading task.
if let Some((key, program)) = program_to_store.take() {
loaded_programs_for_txs.as_mut().unwrap().loaded_missing = true;
if program_cache.finish_cooperative_loading_task(self.slot, key, program)
&& limit_to_load_programs
{
Expand Down

0 comments on commit 90bea33

Please sign in to comment.