Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
cost model nits (#18528)
Browse files Browse the repository at this point in the history
  • Loading branch information
jackcmay authored Jul 9, 2021
1 parent 761de8b commit e9ace3a
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 61 deletions.
24 changes: 12 additions & 12 deletions core/src/cost_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl CostModel {

pub fn initialize_cost_table(&mut self, cost_table: &[(Pubkey, u64)]) {
for (program_id, cost) in cost_table {
match self.upsert_instruction_cost(program_id, cost) {
match self.upsert_instruction_cost(program_id, *cost) {
Ok(c) => {
debug!(
"initiating cost table, instruction {:?} has cost {}",
Expand Down Expand Up @@ -147,7 +147,7 @@ impl CostModel {
pub fn upsert_instruction_cost(
&mut self,
program_key: &Pubkey,
cost: &u64,
cost: u64,
) -> Result<u64, &'static str> {
self.instruction_execution_cost_table
.upsert(program_key, cost);
Expand Down Expand Up @@ -232,12 +232,12 @@ mod tests {
let mut testee = CostModel::default();

let known_key = Pubkey::from_str("known11111111111111111111111111111111111111").unwrap();
testee.upsert_instruction_cost(&known_key, &100).unwrap();
testee.upsert_instruction_cost(&known_key, 100).unwrap();
// find cost for known programs
assert_eq!(100, testee.find_instruction_cost(&known_key));

testee
.upsert_instruction_cost(&bpf_loader::id(), &1999)
.upsert_instruction_cost(&bpf_loader::id(), 1999)
.unwrap();
assert_eq!(1999, testee.find_instruction_cost(&bpf_loader::id()));

Expand Down Expand Up @@ -267,7 +267,7 @@ mod tests {

let mut testee = CostModel::default();
testee
.upsert_instruction_cost(&system_program::id(), &expected_cost)
.upsert_instruction_cost(&system_program::id(), expected_cost)
.unwrap();
assert_eq!(
expected_cost,
Expand All @@ -293,7 +293,7 @@ mod tests {

let mut testee = CostModel::default();
testee
.upsert_instruction_cost(&system_program::id(), &program_cost)
.upsert_instruction_cost(&system_program::id(), program_cost)
.unwrap();
assert_eq!(expected_cost, testee.find_transaction_cost(&tx));
}
Expand Down Expand Up @@ -371,7 +371,7 @@ mod tests {
);

// insert instruction cost to table
assert!(cost_model.upsert_instruction_cost(&key1, &cost1).is_ok());
assert!(cost_model.upsert_instruction_cost(&key1, cost1).is_ok());

// now it is known insturction with known cost
assert_eq!(cost1, cost_model.find_instruction_cost(&key1));
Expand All @@ -390,7 +390,7 @@ mod tests {

let mut cost_model = CostModel::default();
cost_model
.upsert_instruction_cost(&system_program::id(), &expected_execution_cost)
.upsert_instruction_cost(&system_program::id(), expected_execution_cost)
.unwrap();
let tx_cost = cost_model.calculate_cost(&tx);
assert_eq!(expected_account_cost, tx_cost.account_access_cost);
Expand All @@ -408,11 +408,11 @@ mod tests {
let mut cost_model = CostModel::default();

// insert instruction cost to table
assert!(cost_model.upsert_instruction_cost(&key1, &cost1).is_ok());
assert!(cost_model.upsert_instruction_cost(&key1, cost1).is_ok());
assert_eq!(cost1, cost_model.find_instruction_cost(&key1));

// update instruction cost
assert!(cost_model.upsert_instruction_cost(&key1, &cost2).is_ok());
assert!(cost_model.upsert_instruction_cost(&key1, cost2).is_ok());
assert_eq!(updated_cost, cost_model.find_instruction_cost(&key1));
}

Expand Down Expand Up @@ -454,8 +454,8 @@ mod tests {
if i == 5 {
thread::spawn(move || {
let mut cost_model = cost_model.write().unwrap();
assert!(cost_model.upsert_instruction_cost(&prog1, &cost1).is_ok());
assert!(cost_model.upsert_instruction_cost(&prog2, &cost2).is_ok());
assert!(cost_model.upsert_instruction_cost(&prog1, cost1).is_ok());
assert!(cost_model.upsert_instruction_cost(&prog2, cost2).is_ok());
})
} else {
thread::spawn(move || {
Expand Down
2 changes: 1 addition & 1 deletion core/src/cost_tracker.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! `cost_tracker` keeps tracking tranasction cost per chained accounts as well as for entire block
//! `cost_tracker` keeps tracking transaction cost per chained accounts as well as for entire block
//! It aggregates `cost_model`, which provides service of calculating transaction cost.
//! The main functions are:
//! - would_transaction_fit(&tx), immutable function to test if `tx` would fit into current block
Expand Down
52 changes: 30 additions & 22 deletions core/src/cost_update_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,26 +135,27 @@ impl CostUpdateService {

fn update_cost_model(cost_model: &RwLock<CostModel>, execute_timings: &ExecuteTimings) -> bool {
let mut dirty = false;
let mut cost_model_mutable = cost_model.write().unwrap();
for (program_id, stats) in &execute_timings.details.per_program_timings {
let cost = stats.0 / stats.1 as u64;
match cost_model_mutable.upsert_instruction_cost(program_id, &cost) {
Ok(c) => {
debug!(
"after replayed into bank, instruction {:?} has averaged cost {}",
program_id, c
);
dirty = true;
}
Err(err) => {
debug!(
{
let mut cost_model_mutable = cost_model.write().unwrap();
for (program_id, tining) in &execute_timings.details.per_program_timings {
let cost = tining.accumulated_us / tining.count as u64;
match cost_model_mutable.upsert_instruction_cost(program_id, cost) {
Ok(c) => {
debug!(
"after replayed into bank, instruction {:?} has averaged cost {}",
program_id, c
);
dirty = true;
}
Err(err) => {
debug!(
"after replayed into bank, instruction {:?} failed to update cost, err: {}",
program_id, err
);
}
}
}
}
drop(cost_model_mutable);
debug!(
"after replayed into bank, updated cost model instruction cost table, current values: {:?}",
cost_model.read().unwrap().get_instruction_cost_table()
Expand Down Expand Up @@ -187,6 +188,7 @@ impl CostUpdateService {
#[cfg(test)]
mod tests {
use super::*;
use solana_runtime::message_processor::ProgramTiming;
use solana_sdk::pubkey::Pubkey;

#[test]
Expand Down Expand Up @@ -219,10 +221,13 @@ mod tests {
let count: u32 = 10;
expected_cost = accumulated_us / count as u64;

execute_timings
.details
.per_program_timings
.insert(program_key_1, (accumulated_us, count));
execute_timings.details.per_program_timings.insert(
program_key_1,
ProgramTiming {
accumulated_us,
count,
},
);
CostUpdateService::update_cost_model(&cost_model, &execute_timings);
assert_eq!(
1,
Expand All @@ -249,10 +254,13 @@ mod tests {
// to expect new cost is Average(new_value, existing_value)
expected_cost = ((accumulated_us / count as u64) + expected_cost) / 2;

execute_timings
.details
.per_program_timings
.insert(program_key_1, (accumulated_us, count));
execute_timings.details.per_program_timings.insert(
program_key_1,
ProgramTiming {
accumulated_us,
count,
},
);
CostUpdateService::update_cost_model(&cost_model, &execute_timings);
assert_eq!(
1,
Expand Down
36 changes: 18 additions & 18 deletions core/src/execute_cost_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,15 @@ impl ExecuteCostTable {
self.table.get(key)
}

pub fn upsert(&mut self, key: &Pubkey, value: &u64) {
pub fn upsert(&mut self, key: &Pubkey, value: u64) {
let need_to_add = self.table.get(key).is_none();
let current_size = self.get_count();
if current_size == self.capacity && need_to_add {
self.prune_to(&((current_size as f64 * PRUNE_RATIO) as usize));
}

let program_cost = self.table.entry(*key).or_insert(*value);
*program_cost = (*program_cost + *value) / 2;
let program_cost = self.table.entry(*key).or_insert(value);
*program_cost = (*program_cost + value) / 2;

let (count, timestamp) = self
.occurrences
Expand Down Expand Up @@ -154,9 +154,9 @@ mod tests {
let key2 = Pubkey::new_unique();
let key3 = Pubkey::new_unique();

testee.upsert(&key1, &1);
testee.upsert(&key2, &2);
testee.upsert(&key3, &3);
testee.upsert(&key1, 1);
testee.upsert(&key2, 2);
testee.upsert(&key3, 3);

testee.prune_to(&(capacity - 1));

Expand All @@ -176,10 +176,10 @@ mod tests {
let key2 = Pubkey::new_unique();
let key3 = Pubkey::new_unique();

testee.upsert(&key1, &1);
testee.upsert(&key1, &1);
testee.upsert(&key2, &2);
testee.upsert(&key3, &3);
testee.upsert(&key1, 1);
testee.upsert(&key1, 1);
testee.upsert(&key2, 2);
testee.upsert(&key3, 3);

testee.prune_to(&(capacity - 1));

Expand All @@ -204,22 +204,22 @@ mod tests {
assert!(testee.get_cost(&key1).is_none());

// insert one record
testee.upsert(&key1, &cost1);
testee.upsert(&key1, cost1);
assert_eq!(1, testee.get_count());
assert_eq!(cost1, testee.get_average());
assert_eq!(cost1, testee.get_mode());
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());

// insert 2nd record
testee.upsert(&key2, &cost2);
testee.upsert(&key2, cost2);
assert_eq!(2, testee.get_count());
assert_eq!((cost1 + cost2) / 2_u64, testee.get_average());
assert_eq!(cost2, testee.get_mode());
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());
assert_eq!(&cost2, testee.get_cost(&key2).unwrap());

// update 1st record
testee.upsert(&key1, &cost2);
testee.upsert(&key1, cost2);
assert_eq!(2, testee.get_count());
assert_eq!(((cost1 + cost2) / 2 + cost2) / 2, testee.get_average());
assert_eq!((cost1 + cost2) / 2, testee.get_mode());
Expand All @@ -243,18 +243,18 @@ mod tests {
let cost4: u64 = 130;

// insert one record
testee.upsert(&key1, &cost1);
testee.upsert(&key1, cost1);
assert_eq!(1, testee.get_count());
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());

// insert 2nd record
testee.upsert(&key2, &cost2);
testee.upsert(&key2, cost2);
assert_eq!(2, testee.get_count());
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());
assert_eq!(&cost2, testee.get_cost(&key2).unwrap());

// insert 3rd record, pushes out the oldest (eg 1st) record
testee.upsert(&key3, &cost3);
testee.upsert(&key3, cost3);
assert_eq!(2, testee.get_count());
assert_eq!((cost2 + cost3) / 2_u64, testee.get_average());
assert_eq!(cost3, testee.get_mode());
Expand All @@ -264,8 +264,8 @@ mod tests {

// update 2nd record, so the 3rd becomes the oldest
// add 4th record, pushes out 3rd key
testee.upsert(&key2, &cost1);
testee.upsert(&key4, &cost4);
testee.upsert(&key2, cost1);
testee.upsert(&key4, cost4);
assert_eq!(((cost1 + cost2) / 2 + cost4) / 2_u64, testee.get_average());
assert_eq!((cost1 + cost2) / 2, testee.get_mode());
assert_eq!(2, testee.get_count());
Expand Down
6 changes: 3 additions & 3 deletions core/src/progress_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,13 +121,13 @@ impl ReplaySlotStats {
.per_program_timings
.iter()
.collect();
per_pubkey_timings.sort_by(|a, b| b.1 .0.cmp(&a.1 .0));
let total: u64 = per_pubkey_timings.iter().map(|a| a.1 .0).sum();
per_pubkey_timings.sort_by(|a, b| b.1.accumulated_us.cmp(&a.1.accumulated_us));
let total: u64 = per_pubkey_timings.iter().map(|a| a.1.accumulated_us).sum();
for (pubkey, time) in per_pubkey_timings.iter().take(5) {
datapoint_info!(
"per_program_timings",
("pubkey", pubkey.to_string(), String),
("execute_us", time.0, i64)
("execute_us", time.accumulated_us, i64)
);
}
datapoint_info!(
Expand Down
16 changes: 11 additions & 5 deletions runtime/src/message_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ impl Executors {
}
}

#[derive(Default, Debug)]
pub struct ProgramTiming {
pub accumulated_us: u64,
pub count: u32,
}

#[derive(Default, Debug)]
pub struct ExecuteDetailsTimings {
pub serialize_us: u64,
Expand All @@ -66,7 +72,7 @@ pub struct ExecuteDetailsTimings {
pub total_account_count: u64,
pub total_data_size: usize,
pub data_size_changed: usize,
pub per_program_timings: HashMap<Pubkey, (u64, u32)>,
pub per_program_timings: HashMap<Pubkey, ProgramTiming>,
}

impl ExecuteDetailsTimings {
Expand All @@ -81,8 +87,8 @@ impl ExecuteDetailsTimings {
self.data_size_changed += other.data_size_changed;
for (id, other) in &other.per_program_timings {
let time_count = self.per_program_timings.entry(*id).or_default();
time_count.0 += other.0;
time_count.1 += other.1;
time_count.accumulated_us += other.accumulated_us;
time_count.count += other.count;
}
}
}
Expand Down Expand Up @@ -1244,8 +1250,8 @@ impl MessageProcessor {

let program_id = instruction.program_id(&message.account_keys);
let time_count = timings.per_program_timings.entry(*program_id).or_default();
time_count.0 += time.as_us();
time_count.1 += 1;
time_count.accumulated_us += time.as_us();
time_count.count += 1;

err?;
}
Expand Down

0 comments on commit e9ace3a

Please sign in to comment.