cost model nits (#18528)
This commit is contained in:
parent
761de8b1a3
commit
e9ace3a0d5
|
@ -92,7 +92,7 @@ impl CostModel {
|
||||||
|
|
||||||
pub fn initialize_cost_table(&mut self, cost_table: &[(Pubkey, u64)]) {
|
pub fn initialize_cost_table(&mut self, cost_table: &[(Pubkey, u64)]) {
|
||||||
for (program_id, cost) in cost_table {
|
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) => {
|
Ok(c) => {
|
||||||
debug!(
|
debug!(
|
||||||
"initiating cost table, instruction {:?} has cost {}",
|
"initiating cost table, instruction {:?} has cost {}",
|
||||||
|
@ -147,7 +147,7 @@ impl CostModel {
|
||||||
pub fn upsert_instruction_cost(
|
pub fn upsert_instruction_cost(
|
||||||
&mut self,
|
&mut self,
|
||||||
program_key: &Pubkey,
|
program_key: &Pubkey,
|
||||||
cost: &u64,
|
cost: u64,
|
||||||
) -> Result<u64, &'static str> {
|
) -> Result<u64, &'static str> {
|
||||||
self.instruction_execution_cost_table
|
self.instruction_execution_cost_table
|
||||||
.upsert(program_key, cost);
|
.upsert(program_key, cost);
|
||||||
|
@ -232,12 +232,12 @@ mod tests {
|
||||||
let mut testee = CostModel::default();
|
let mut testee = CostModel::default();
|
||||||
|
|
||||||
let known_key = Pubkey::from_str("known11111111111111111111111111111111111111").unwrap();
|
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
|
// find cost for known programs
|
||||||
assert_eq!(100, testee.find_instruction_cost(&known_key));
|
assert_eq!(100, testee.find_instruction_cost(&known_key));
|
||||||
|
|
||||||
testee
|
testee
|
||||||
.upsert_instruction_cost(&bpf_loader::id(), &1999)
|
.upsert_instruction_cost(&bpf_loader::id(), 1999)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(1999, testee.find_instruction_cost(&bpf_loader::id()));
|
assert_eq!(1999, testee.find_instruction_cost(&bpf_loader::id()));
|
||||||
|
|
||||||
|
@ -267,7 +267,7 @@ mod tests {
|
||||||
|
|
||||||
let mut testee = CostModel::default();
|
let mut testee = CostModel::default();
|
||||||
testee
|
testee
|
||||||
.upsert_instruction_cost(&system_program::id(), &expected_cost)
|
.upsert_instruction_cost(&system_program::id(), expected_cost)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected_cost,
|
expected_cost,
|
||||||
|
@ -293,7 +293,7 @@ mod tests {
|
||||||
|
|
||||||
let mut testee = CostModel::default();
|
let mut testee = CostModel::default();
|
||||||
testee
|
testee
|
||||||
.upsert_instruction_cost(&system_program::id(), &program_cost)
|
.upsert_instruction_cost(&system_program::id(), program_cost)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(expected_cost, testee.find_transaction_cost(&tx));
|
assert_eq!(expected_cost, testee.find_transaction_cost(&tx));
|
||||||
}
|
}
|
||||||
|
@ -371,7 +371,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
// insert instruction cost to table
|
// 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
|
// now it is known insturction with known cost
|
||||||
assert_eq!(cost1, cost_model.find_instruction_cost(&key1));
|
assert_eq!(cost1, cost_model.find_instruction_cost(&key1));
|
||||||
|
@ -390,7 +390,7 @@ mod tests {
|
||||||
|
|
||||||
let mut cost_model = CostModel::default();
|
let mut cost_model = CostModel::default();
|
||||||
cost_model
|
cost_model
|
||||||
.upsert_instruction_cost(&system_program::id(), &expected_execution_cost)
|
.upsert_instruction_cost(&system_program::id(), expected_execution_cost)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let tx_cost = cost_model.calculate_cost(&tx);
|
let tx_cost = cost_model.calculate_cost(&tx);
|
||||||
assert_eq!(expected_account_cost, tx_cost.account_access_cost);
|
assert_eq!(expected_account_cost, tx_cost.account_access_cost);
|
||||||
|
@ -408,11 +408,11 @@ mod tests {
|
||||||
let mut cost_model = CostModel::default();
|
let mut cost_model = CostModel::default();
|
||||||
|
|
||||||
// insert instruction cost to table
|
// 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));
|
assert_eq!(cost1, cost_model.find_instruction_cost(&key1));
|
||||||
|
|
||||||
// update instruction cost
|
// 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));
|
assert_eq!(updated_cost, cost_model.find_instruction_cost(&key1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,8 +454,8 @@ mod tests {
|
||||||
if i == 5 {
|
if i == 5 {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
let mut cost_model = cost_model.write().unwrap();
|
let mut cost_model = cost_model.write().unwrap();
|
||||||
assert!(cost_model.upsert_instruction_cost(&prog1, &cost1).is_ok());
|
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(&prog2, cost2).is_ok());
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
|
|
|
@ -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.
|
//! It aggregates `cost_model`, which provides service of calculating transaction cost.
|
||||||
//! The main functions are:
|
//! The main functions are:
|
||||||
//! - would_transaction_fit(&tx), immutable function to test if `tx` would fit into current block
|
//! - would_transaction_fit(&tx), immutable function to test if `tx` would fit into current block
|
||||||
|
|
|
@ -135,26 +135,27 @@ impl CostUpdateService {
|
||||||
|
|
||||||
fn update_cost_model(cost_model: &RwLock<CostModel>, execute_timings: &ExecuteTimings) -> bool {
|
fn update_cost_model(cost_model: &RwLock<CostModel>, execute_timings: &ExecuteTimings) -> bool {
|
||||||
let mut dirty = false;
|
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 mut cost_model_mutable = cost_model.write().unwrap();
|
||||||
let cost = stats.0 / stats.1 as u64;
|
for (program_id, tining) in &execute_timings.details.per_program_timings {
|
||||||
match cost_model_mutable.upsert_instruction_cost(program_id, &cost) {
|
let cost = tining.accumulated_us / tining.count as u64;
|
||||||
Ok(c) => {
|
match cost_model_mutable.upsert_instruction_cost(program_id, cost) {
|
||||||
debug!(
|
Ok(c) => {
|
||||||
"after replayed into bank, instruction {:?} has averaged cost {}",
|
debug!(
|
||||||
program_id, c
|
"after replayed into bank, instruction {:?} has averaged cost {}",
|
||||||
);
|
program_id, c
|
||||||
dirty = true;
|
);
|
||||||
}
|
dirty = true;
|
||||||
Err(err) => {
|
}
|
||||||
debug!(
|
Err(err) => {
|
||||||
|
debug!(
|
||||||
"after replayed into bank, instruction {:?} failed to update cost, err: {}",
|
"after replayed into bank, instruction {:?} failed to update cost, err: {}",
|
||||||
program_id, err
|
program_id, err
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(cost_model_mutable);
|
|
||||||
debug!(
|
debug!(
|
||||||
"after replayed into bank, updated cost model instruction cost table, current values: {:?}",
|
"after replayed into bank, updated cost model instruction cost table, current values: {:?}",
|
||||||
cost_model.read().unwrap().get_instruction_cost_table()
|
cost_model.read().unwrap().get_instruction_cost_table()
|
||||||
|
@ -187,6 +188,7 @@ impl CostUpdateService {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use solana_runtime::message_processor::ProgramTiming;
|
||||||
use solana_sdk::pubkey::Pubkey;
|
use solana_sdk::pubkey::Pubkey;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -219,10 +221,13 @@ mod tests {
|
||||||
let count: u32 = 10;
|
let count: u32 = 10;
|
||||||
expected_cost = accumulated_us / count as u64;
|
expected_cost = accumulated_us / count as u64;
|
||||||
|
|
||||||
execute_timings
|
execute_timings.details.per_program_timings.insert(
|
||||||
.details
|
program_key_1,
|
||||||
.per_program_timings
|
ProgramTiming {
|
||||||
.insert(program_key_1, (accumulated_us, count));
|
accumulated_us,
|
||||||
|
count,
|
||||||
|
},
|
||||||
|
);
|
||||||
CostUpdateService::update_cost_model(&cost_model, &execute_timings);
|
CostUpdateService::update_cost_model(&cost_model, &execute_timings);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
1,
|
1,
|
||||||
|
@ -249,10 +254,13 @@ mod tests {
|
||||||
// to expect new cost is Average(new_value, existing_value)
|
// to expect new cost is Average(new_value, existing_value)
|
||||||
expected_cost = ((accumulated_us / count as u64) + expected_cost) / 2;
|
expected_cost = ((accumulated_us / count as u64) + expected_cost) / 2;
|
||||||
|
|
||||||
execute_timings
|
execute_timings.details.per_program_timings.insert(
|
||||||
.details
|
program_key_1,
|
||||||
.per_program_timings
|
ProgramTiming {
|
||||||
.insert(program_key_1, (accumulated_us, count));
|
accumulated_us,
|
||||||
|
count,
|
||||||
|
},
|
||||||
|
);
|
||||||
CostUpdateService::update_cost_model(&cost_model, &execute_timings);
|
CostUpdateService::update_cost_model(&cost_model, &execute_timings);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
1,
|
1,
|
||||||
|
|
|
@ -78,15 +78,15 @@ impl ExecuteCostTable {
|
||||||
self.table.get(key)
|
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 need_to_add = self.table.get(key).is_none();
|
||||||
let current_size = self.get_count();
|
let current_size = self.get_count();
|
||||||
if current_size == self.capacity && need_to_add {
|
if current_size == self.capacity && need_to_add {
|
||||||
self.prune_to(&((current_size as f64 * PRUNE_RATIO) as usize));
|
self.prune_to(&((current_size as f64 * PRUNE_RATIO) as usize));
|
||||||
}
|
}
|
||||||
|
|
||||||
let program_cost = self.table.entry(*key).or_insert(*value);
|
let program_cost = self.table.entry(*key).or_insert(value);
|
||||||
*program_cost = (*program_cost + *value) / 2;
|
*program_cost = (*program_cost + value) / 2;
|
||||||
|
|
||||||
let (count, timestamp) = self
|
let (count, timestamp) = self
|
||||||
.occurrences
|
.occurrences
|
||||||
|
@ -154,9 +154,9 @@ mod tests {
|
||||||
let key2 = Pubkey::new_unique();
|
let key2 = Pubkey::new_unique();
|
||||||
let key3 = Pubkey::new_unique();
|
let key3 = Pubkey::new_unique();
|
||||||
|
|
||||||
testee.upsert(&key1, &1);
|
testee.upsert(&key1, 1);
|
||||||
testee.upsert(&key2, &2);
|
testee.upsert(&key2, 2);
|
||||||
testee.upsert(&key3, &3);
|
testee.upsert(&key3, 3);
|
||||||
|
|
||||||
testee.prune_to(&(capacity - 1));
|
testee.prune_to(&(capacity - 1));
|
||||||
|
|
||||||
|
@ -176,10 +176,10 @@ mod tests {
|
||||||
let key2 = Pubkey::new_unique();
|
let key2 = Pubkey::new_unique();
|
||||||
let key3 = Pubkey::new_unique();
|
let key3 = Pubkey::new_unique();
|
||||||
|
|
||||||
testee.upsert(&key1, &1);
|
testee.upsert(&key1, 1);
|
||||||
testee.upsert(&key1, &1);
|
testee.upsert(&key1, 1);
|
||||||
testee.upsert(&key2, &2);
|
testee.upsert(&key2, 2);
|
||||||
testee.upsert(&key3, &3);
|
testee.upsert(&key3, 3);
|
||||||
|
|
||||||
testee.prune_to(&(capacity - 1));
|
testee.prune_to(&(capacity - 1));
|
||||||
|
|
||||||
|
@ -204,14 +204,14 @@ mod tests {
|
||||||
assert!(testee.get_cost(&key1).is_none());
|
assert!(testee.get_cost(&key1).is_none());
|
||||||
|
|
||||||
// insert one record
|
// insert one record
|
||||||
testee.upsert(&key1, &cost1);
|
testee.upsert(&key1, cost1);
|
||||||
assert_eq!(1, testee.get_count());
|
assert_eq!(1, testee.get_count());
|
||||||
assert_eq!(cost1, testee.get_average());
|
assert_eq!(cost1, testee.get_average());
|
||||||
assert_eq!(cost1, testee.get_mode());
|
assert_eq!(cost1, testee.get_mode());
|
||||||
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());
|
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());
|
||||||
|
|
||||||
// insert 2nd record
|
// insert 2nd record
|
||||||
testee.upsert(&key2, &cost2);
|
testee.upsert(&key2, cost2);
|
||||||
assert_eq!(2, testee.get_count());
|
assert_eq!(2, testee.get_count());
|
||||||
assert_eq!((cost1 + cost2) / 2_u64, testee.get_average());
|
assert_eq!((cost1 + cost2) / 2_u64, testee.get_average());
|
||||||
assert_eq!(cost2, testee.get_mode());
|
assert_eq!(cost2, testee.get_mode());
|
||||||
|
@ -219,7 +219,7 @@ mod tests {
|
||||||
assert_eq!(&cost2, testee.get_cost(&key2).unwrap());
|
assert_eq!(&cost2, testee.get_cost(&key2).unwrap());
|
||||||
|
|
||||||
// update 1st record
|
// update 1st record
|
||||||
testee.upsert(&key1, &cost2);
|
testee.upsert(&key1, cost2);
|
||||||
assert_eq!(2, testee.get_count());
|
assert_eq!(2, testee.get_count());
|
||||||
assert_eq!(((cost1 + cost2) / 2 + cost2) / 2, testee.get_average());
|
assert_eq!(((cost1 + cost2) / 2 + cost2) / 2, testee.get_average());
|
||||||
assert_eq!((cost1 + cost2) / 2, testee.get_mode());
|
assert_eq!((cost1 + cost2) / 2, testee.get_mode());
|
||||||
|
@ -243,18 +243,18 @@ mod tests {
|
||||||
let cost4: u64 = 130;
|
let cost4: u64 = 130;
|
||||||
|
|
||||||
// insert one record
|
// insert one record
|
||||||
testee.upsert(&key1, &cost1);
|
testee.upsert(&key1, cost1);
|
||||||
assert_eq!(1, testee.get_count());
|
assert_eq!(1, testee.get_count());
|
||||||
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());
|
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());
|
||||||
|
|
||||||
// insert 2nd record
|
// insert 2nd record
|
||||||
testee.upsert(&key2, &cost2);
|
testee.upsert(&key2, cost2);
|
||||||
assert_eq!(2, testee.get_count());
|
assert_eq!(2, testee.get_count());
|
||||||
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());
|
assert_eq!(&cost1, testee.get_cost(&key1).unwrap());
|
||||||
assert_eq!(&cost2, testee.get_cost(&key2).unwrap());
|
assert_eq!(&cost2, testee.get_cost(&key2).unwrap());
|
||||||
|
|
||||||
// insert 3rd record, pushes out the oldest (eg 1st) record
|
// 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!(2, testee.get_count());
|
||||||
assert_eq!((cost2 + cost3) / 2_u64, testee.get_average());
|
assert_eq!((cost2 + cost3) / 2_u64, testee.get_average());
|
||||||
assert_eq!(cost3, testee.get_mode());
|
assert_eq!(cost3, testee.get_mode());
|
||||||
|
@ -264,8 +264,8 @@ mod tests {
|
||||||
|
|
||||||
// update 2nd record, so the 3rd becomes the oldest
|
// update 2nd record, so the 3rd becomes the oldest
|
||||||
// add 4th record, pushes out 3rd key
|
// add 4th record, pushes out 3rd key
|
||||||
testee.upsert(&key2, &cost1);
|
testee.upsert(&key2, cost1);
|
||||||
testee.upsert(&key4, &cost4);
|
testee.upsert(&key4, cost4);
|
||||||
assert_eq!(((cost1 + cost2) / 2 + cost4) / 2_u64, testee.get_average());
|
assert_eq!(((cost1 + cost2) / 2 + cost4) / 2_u64, testee.get_average());
|
||||||
assert_eq!((cost1 + cost2) / 2, testee.get_mode());
|
assert_eq!((cost1 + cost2) / 2, testee.get_mode());
|
||||||
assert_eq!(2, testee.get_count());
|
assert_eq!(2, testee.get_count());
|
||||||
|
|
|
@ -121,13 +121,13 @@ impl ReplaySlotStats {
|
||||||
.per_program_timings
|
.per_program_timings
|
||||||
.iter()
|
.iter()
|
||||||
.collect();
|
.collect();
|
||||||
per_pubkey_timings.sort_by(|a, b| b.1 .0.cmp(&a.1 .0));
|
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 .0).sum();
|
let total: u64 = per_pubkey_timings.iter().map(|a| a.1.accumulated_us).sum();
|
||||||
for (pubkey, time) in per_pubkey_timings.iter().take(5) {
|
for (pubkey, time) in per_pubkey_timings.iter().take(5) {
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
"per_program_timings",
|
"per_program_timings",
|
||||||
("pubkey", pubkey.to_string(), String),
|
("pubkey", pubkey.to_string(), String),
|
||||||
("execute_us", time.0, i64)
|
("execute_us", time.accumulated_us, i64)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
datapoint_info!(
|
datapoint_info!(
|
||||||
|
|
|
@ -56,6 +56,12 @@ impl Executors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct ProgramTiming {
|
||||||
|
pub accumulated_us: u64,
|
||||||
|
pub count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ExecuteDetailsTimings {
|
pub struct ExecuteDetailsTimings {
|
||||||
pub serialize_us: u64,
|
pub serialize_us: u64,
|
||||||
|
@ -66,7 +72,7 @@ pub struct ExecuteDetailsTimings {
|
||||||
pub total_account_count: u64,
|
pub total_account_count: u64,
|
||||||
pub total_data_size: usize,
|
pub total_data_size: usize,
|
||||||
pub data_size_changed: usize,
|
pub data_size_changed: usize,
|
||||||
pub per_program_timings: HashMap<Pubkey, (u64, u32)>,
|
pub per_program_timings: HashMap<Pubkey, ProgramTiming>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecuteDetailsTimings {
|
impl ExecuteDetailsTimings {
|
||||||
|
@ -81,8 +87,8 @@ impl ExecuteDetailsTimings {
|
||||||
self.data_size_changed += other.data_size_changed;
|
self.data_size_changed += other.data_size_changed;
|
||||||
for (id, other) in &other.per_program_timings {
|
for (id, other) in &other.per_program_timings {
|
||||||
let time_count = self.per_program_timings.entry(*id).or_default();
|
let time_count = self.per_program_timings.entry(*id).or_default();
|
||||||
time_count.0 += other.0;
|
time_count.accumulated_us += other.accumulated_us;
|
||||||
time_count.1 += other.1;
|
time_count.count += other.count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1244,8 +1250,8 @@ impl MessageProcessor {
|
||||||
|
|
||||||
let program_id = instruction.program_id(&message.account_keys);
|
let program_id = instruction.program_id(&message.account_keys);
|
||||||
let time_count = timings.per_program_timings.entry(*program_id).or_default();
|
let time_count = timings.per_program_timings.entry(*program_id).or_default();
|
||||||
time_count.0 += time.as_us();
|
time_count.accumulated_us += time.as_us();
|
||||||
time_count.1 += 1;
|
time_count.count += 1;
|
||||||
|
|
||||||
err?;
|
err?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue