Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v1.17: Combine builtin and BPF compute cost in cost model (backport of #29) #270

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions core/src/banking_stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,7 @@ pub struct BatchedTransactionCostDetails {
pub batched_signature_cost: u64,
pub batched_write_lock_cost: u64,
pub batched_data_bytes_cost: u64,
pub batched_builtins_execute_cost: u64,
pub batched_bpf_execute_cost: u64,
pub batched_programs_execute_cost: u64,
}

#[derive(Debug, Default)]
Expand Down
15 changes: 8 additions & 7 deletions core/src/banking_stage/consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1263,16 +1263,17 @@ mod tests {
assert_eq!(retryable_transaction_indexes, vec![1]);

let expected_block_cost = if !apply_cost_tracker_during_replay_enabled {
let actual_bpf_execution_cost = match commit_transactions_result.get(0).unwrap() {
CommitTransactionDetails::Committed { compute_units } => *compute_units,
CommitTransactionDetails::NotCommitted => {
unreachable!()
}
};
let actual_programs_execution_cost =
match commit_transactions_result.first().unwrap() {
CommitTransactionDetails::Committed { compute_units } => *compute_units,
CommitTransactionDetails::NotCommitted => {
unreachable!()
}
};

let mut cost = CostModel::calculate_cost(&transactions[0], &bank.feature_set);
if let TransactionCost::Transaction(ref mut usage_cost) = cost {
usage_cost.bpf_execution_cost = actual_bpf_execution_cost;
usage_cost.programs_execution_cost = actual_programs_execution_cost;
}

block_cost + cost.sum()
Expand Down
61 changes: 19 additions & 42 deletions core/src/banking_stage/qos_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,14 +236,10 @@ impl QosService {
batched_transaction_details.costs.batched_data_bytes_cost,
Ordering::Relaxed,
);
self.metrics.stats.estimated_builtins_execute_cu.fetch_add(
self.metrics.stats.estimated_programs_execute_cu.fetch_add(
batched_transaction_details
.costs
.batched_builtins_execute_cost,
Ordering::Relaxed,
);
self.metrics.stats.estimated_bpf_execute_cu.fetch_add(
batched_transaction_details.costs.batched_bpf_execute_cost,
.batched_programs_execute_cost,
Ordering::Relaxed,
);

Expand Down Expand Up @@ -297,7 +293,7 @@ impl QosService {
pub fn accumulate_actual_execute_cu(&self, units: u64) {
self.metrics
.stats
.actual_bpf_execute_cu
.actual_programs_execute_cu
.fetch_add(units, Ordering::Relaxed);
}

Expand Down Expand Up @@ -331,12 +327,8 @@ impl QosService {
saturating_add_assign!(
batched_transaction_details
.costs
.batched_builtins_execute_cost,
cost.builtins_execution_cost()
);
saturating_add_assign!(
batched_transaction_details.costs.batched_bpf_execute_cost,
cost.bpf_execution_cost()
.batched_programs_execute_cost,
cost.programs_execution_cost()
);
}
Err(transaction_error) => match transaction_error {
Expand Down Expand Up @@ -427,14 +419,11 @@ struct QosServiceMetricsStats {
/// accumulated estimated instructino data Compute Units to be packed into block
estimated_data_bytes_cu: AtomicU64,

/// accumulated estimated builtin programs Compute Units to be packed into block
estimated_builtins_execute_cu: AtomicU64,

/// accumulated estimated SBF program Compute Units to be packed into block
estimated_bpf_execute_cu: AtomicU64,
/// accumulated estimated program Compute Units to be packed into block
estimated_programs_execute_cu: AtomicU64,

/// accumulated actual program Compute Units that have been packed into block
actual_bpf_execute_cu: AtomicU64,
actual_programs_execute_cu: AtomicU64,

/// accumulated actual program execute micro-sec that have been packed into block
actual_execute_time_us: AtomicU64,
Expand Down Expand Up @@ -515,24 +504,19 @@ impl QosServiceMetrics {
i64
),
(
"estimated_builtins_execute_cu",
"estimated_programs_execute_cu",
self.stats
.estimated_builtins_execute_cu
.estimated_programs_execute_cu
.swap(0, Ordering::Relaxed),
i64
),
(
"estimated_bpf_execute_cu",
"actual_programs_execute_cu",
self.stats
.estimated_bpf_execute_cu
.actual_programs_execute_cu
.swap(0, Ordering::Relaxed),
i64
),
(
"actual_bpf_execute_cu",
self.stats.actual_bpf_execute_cu.swap(0, Ordering::Relaxed),
i64
),
(
"actual_execute_time_us",
self.stats.actual_execute_time_us.swap(0, Ordering::Relaxed),
Expand Down Expand Up @@ -735,7 +719,7 @@ mod tests {
let commited_status: Vec<CommitTransactionDetails> = qos_cost_results
.iter()
.map(|tx_cost| CommitTransactionDetails::Committed {
compute_units: tx_cost.as_ref().unwrap().bpf_execution_cost()
compute_units: tx_cost.as_ref().unwrap().programs_execution_cost()
+ execute_units_adjustment,
})
.collect();
Expand Down Expand Up @@ -862,7 +846,7 @@ mod tests {
CommitTransactionDetails::NotCommitted
} else {
CommitTransactionDetails::Committed {
compute_units: tx_cost.as_ref().unwrap().bpf_execution_cost()
compute_units: tx_cost.as_ref().unwrap().programs_execution_cost()
+ execute_units_adjustment,
}
}
Expand Down Expand Up @@ -898,8 +882,7 @@ mod tests {
let signature_cost = 1;
let write_lock_cost = 2;
let data_bytes_cost = 3;
let builtins_execution_cost = 4;
let bpf_execution_cost = 10;
let programs_execution_cost = 10;
let num_txs = 4;

let tx_cost_results: Vec<_> = (0..num_txs)
Expand All @@ -909,8 +892,7 @@ mod tests {
signature_cost,
write_lock_cost,
data_bytes_cost,
builtins_execution_cost,
bpf_execution_cost,
programs_execution_cost,
..UsageCostDetails::default()
}))
} else {
Expand All @@ -922,8 +904,7 @@ mod tests {
let expected_signatures = signature_cost * (num_txs / 2);
let expected_write_locks = write_lock_cost * (num_txs / 2);
let expected_data_bytes = data_bytes_cost * (num_txs / 2);
let expected_builtins_execution_costs = builtins_execution_cost * (num_txs / 2);
let expected_bpf_execution_costs = bpf_execution_cost * (num_txs / 2);
let expected_programs_execution_costs = programs_execution_cost * (num_txs / 2);
let batched_transaction_details =
QosService::accumulate_batched_transaction_costs(tx_cost_results.iter());
assert_eq!(
Expand All @@ -939,14 +920,10 @@ mod tests {
batched_transaction_details.costs.batched_data_bytes_cost
);
assert_eq!(
expected_builtins_execution_costs,
expected_programs_execution_costs,
batched_transaction_details
.costs
.batched_builtins_execute_cost
);
assert_eq!(
expected_bpf_execution_costs,
batched_transaction_details.costs.batched_bpf_execute_cost
.batched_programs_execute_cost
);
}
}
103 changes: 64 additions & 39 deletions cost-model/src/cost_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,21 +118,25 @@ impl CostModel {
transaction: &SanitizedTransaction,
feature_set: &FeatureSet,
) {
let mut builtin_costs = 0u64;
let mut bpf_costs = 0u64;
let mut programs_execution_costs = 0u64;
let mut loaded_accounts_data_size_cost = 0u64;
let mut data_bytes_len_total = 0u64;
let mut compute_unit_limit_is_set = false;
let mut has_user_space_instructions = false;

for (program_id, instruction) in transaction.message().program_instructions_iter() {
// to keep the same behavior, look for builtin first
if let Some(builtin_cost) = BUILT_IN_INSTRUCTION_COSTS.get(program_id) {
builtin_costs = builtin_costs.saturating_add(*builtin_cost);
} else {
bpf_costs = bpf_costs
.saturating_add(u64::from(DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT))
.min(u64::from(MAX_COMPUTE_UNIT_LIMIT));
}
let ix_execution_cost =
if let Some(builtin_cost) = BUILT_IN_INSTRUCTION_COSTS.get(program_id) {
*builtin_cost
} else {
has_user_space_instructions = true;
u64::from(DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT)
};

programs_execution_costs = programs_execution_costs
.saturating_add(ix_execution_cost)
.min(u64::from(MAX_COMPUTE_UNIT_LIMIT));

data_bytes_len_total =
data_bytes_len_total.saturating_add(instruction.data.len() as u64);

Expand Down Expand Up @@ -163,8 +167,8 @@ impl CostModel {
// 'compute_unit_limit_is_set' flag, because compute_budget does not distinguish
// builtin and bpf instructions when calculating default compute-unit-limit. (see
// compute_budget.rs test `test_process_mixed_instructions_without_compute_budget`)
if bpf_costs > 0 && compute_unit_limit_is_set {
bpf_costs = compute_budget.compute_unit_limit
if has_user_space_instructions && compute_unit_limit_is_set {
programs_execution_costs = compute_budget.compute_unit_limit;
}

if feature_set
Expand All @@ -175,13 +179,11 @@ impl CostModel {
}
}
Err(_) => {
builtin_costs = 0;
bpf_costs = 0;
programs_execution_costs = 0;
}
}

tx_cost.builtins_execution_cost = builtin_costs;
tx_cost.bpf_execution_cost = bpf_costs;
tx_cost.programs_execution_cost = programs_execution_costs;
tx_cost.loaded_accounts_data_size_cost = loaded_accounts_data_size_cost;
tx_cost.data_bytes_cost = data_bytes_len_total / INSTRUCTION_DATA_BYTES_COST;
}
Expand Down Expand Up @@ -333,8 +335,7 @@ mod tests {
&simple_transaction,
&FeatureSet::all_enabled(),
);
assert_eq!(*expected_execution_cost, tx_cost.builtins_execution_cost);
assert_eq!(0, tx_cost.bpf_execution_cost);
assert_eq!(*expected_execution_cost, tx_cost.programs_execution_cost);
assert_eq!(3, tx_cost.data_bytes_cost);
}

Expand Down Expand Up @@ -362,8 +363,10 @@ mod tests {
&token_transaction,
&FeatureSet::all_enabled(),
);
assert_eq!(0, tx_cost.builtins_execution_cost);
assert_eq!(200_000, tx_cost.bpf_execution_cost);
assert_eq!(
DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64,
tx_cost.programs_execution_cost
);
assert_eq!(0, tx_cost.data_bytes_cost);
}

Expand Down Expand Up @@ -399,13 +402,8 @@ mod tests {
&token_transaction,
&FeatureSet::all_enabled(),
);
assert_eq!(
*BUILT_IN_INSTRUCTION_COSTS
.get(&compute_budget::id())
.unwrap(),
tx_cost.builtins_execution_cost
);
assert_eq!(12_345, tx_cost.bpf_execution_cost);
// If cu-limit is specified, that would the cost for all programs
assert_eq!(12_345, tx_cost.programs_execution_cost);
assert_eq!(1, tx_cost.data_bytes_cost);
}

Expand Down Expand Up @@ -449,8 +447,7 @@ mod tests {
&token_transaction,
&FeatureSet::all_enabled(),
);
assert_eq!(0, tx_cost.builtins_execution_cost);
assert_eq!(0, tx_cost.bpf_execution_cost);
assert_eq!(0, tx_cost.programs_execution_cost);
}

#[test]
Expand All @@ -477,8 +474,7 @@ mod tests {

let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(&mut tx_cost, &tx, &FeatureSet::all_enabled());
assert_eq!(expected_cost, tx_cost.builtins_execution_cost);
assert_eq!(0, tx_cost.bpf_execution_cost);
assert_eq!(expected_cost, tx_cost.programs_execution_cost);
assert_eq!(6, tx_cost.data_bytes_cost);
}

Expand Down Expand Up @@ -509,8 +505,7 @@ mod tests {
let expected_cost = DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT as u64 * 2;
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(&mut tx_cost, &tx, &FeatureSet::all_enabled());
assert_eq!(0, tx_cost.builtins_execution_cost);
assert_eq!(expected_cost, tx_cost.bpf_execution_cost);
assert_eq!(expected_cost, tx_cost.programs_execution_cost);
assert_eq!(0, tx_cost.data_bytes_cost);
}

Expand Down Expand Up @@ -569,7 +564,7 @@ mod tests {

let tx_cost = CostModel::calculate_cost(&tx, &FeatureSet::all_enabled());
assert_eq!(expected_account_cost, tx_cost.write_lock_cost());
assert_eq!(*expected_execution_cost, tx_cost.builtins_execution_cost());
assert_eq!(*expected_execution_cost, tx_cost.programs_execution_cost());
assert_eq!(2, tx_cost.writable_accounts().len());
assert_eq!(
expected_loaded_accounts_data_size_cost,
Expand Down Expand Up @@ -598,7 +593,7 @@ mod tests {

let tx_cost = CostModel::calculate_cost(&tx, &feature_set);
assert_eq!(expected_account_cost, tx_cost.write_lock_cost());
assert_eq!(*expected_execution_cost, tx_cost.builtins_execution_cost());
assert_eq!(*expected_execution_cost, tx_cost.programs_execution_cost());
assert_eq!(2, tx_cost.writable_accounts().len());
assert_eq!(
expected_loaded_accounts_data_size_cost,
Expand Down Expand Up @@ -637,7 +632,7 @@ mod tests {

let tx_cost = CostModel::calculate_cost(&tx, &feature_set);
assert_eq!(expected_account_cost, tx_cost.write_lock_cost());
assert_eq!(expected_execution_cost, tx_cost.builtins_execution_cost());
assert_eq!(expected_execution_cost, tx_cost.programs_execution_cost());
assert_eq!(2, tx_cost.writable_accounts().len());
assert_eq!(
expected_loaded_accounts_data_size_cost,
Expand Down Expand Up @@ -670,7 +665,7 @@ mod tests {

let tx_cost = CostModel::calculate_cost(&tx, &feature_set);
assert_eq!(expected_account_cost, tx_cost.write_lock_cost());
assert_eq!(expected_execution_cost, tx_cost.builtins_execution_cost());
assert_eq!(expected_execution_cost, tx_cost.programs_execution_cost());
assert_eq!(2, tx_cost.writable_accounts().len());
assert_eq!(
expected_loaded_accounts_data_size_cost,
Expand Down Expand Up @@ -737,7 +732,37 @@ mod tests {
let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(&mut tx_cost, &transaction, &FeatureSet::all_enabled());

assert_eq!(expected_builtin_cost, tx_cost.builtins_execution_cost);
assert_eq!(expected_bpf_cost as u64, tx_cost.bpf_execution_cost);
assert_eq!(
expected_builtin_cost + expected_bpf_cost as u64,
tx_cost.programs_execution_cost
);
}

#[test]
fn test_transaction_cost_with_mix_instruction_with_cu_limit() {
let (mint_keypair, start_hash) = test_setup();

let transaction =
SanitizedTransaction::from_transaction_for_tests(Transaction::new_signed_with_payer(
&[
system_instruction::transfer(&mint_keypair.pubkey(), &Pubkey::new_unique(), 2),
ComputeBudgetInstruction::set_compute_unit_limit(12_345),
],
Some(&mint_keypair.pubkey()),
&[&mint_keypair],
start_hash,
));
// transaction has one builtin instruction, and one ComputeBudget::compute_unit_limit
let expected_cost = *BUILT_IN_INSTRUCTION_COSTS
.get(&solana_system_program::id())
.unwrap()
+ BUILT_IN_INSTRUCTION_COSTS
.get(&compute_budget::id())
.unwrap();

let mut tx_cost = UsageCostDetails::default();
CostModel::get_transaction_cost(&mut tx_cost, &transaction, &FeatureSet::all_enabled());

assert_eq!(expected_cost, tx_cost.programs_execution_cost);
}
}
Loading
Loading