From 5d297ccf96a0bfb12d269f8c4508ac762385810e Mon Sep 17 00:00:00 2001 From: Tao Zhu <82401714+taozhu-chicago@users.noreply.github.com> Date: Thu, 29 Jul 2021 17:19:36 -0500 Subject: [PATCH] Cost model uses compute_unit to replace microsecond as cost unit (#18934) * wip - cost_update_services to log both us and cu for each instruction to determine possible ratio * replace microsecond with compute_unit as cost unit --- core/src/cost_model.rs | 21 ++++++++++++++------- core/src/cost_update_service.rs | 13 ++++++++----- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/core/src/cost_model.rs b/core/src/cost_model.rs index 50660cd075e081..d72690aa03bc0e 100644 --- a/core/src/cost_model.rs +++ b/core/src/cost_model.rs @@ -12,19 +12,26 @@ use log::*; use solana_sdk::{pubkey::Pubkey, sanitized_transaction::SanitizedTransaction}; use std::collections::HashMap; -// Guestimated from mainnet-beta data, sigver averages 1us, average read 7us and average write 25us +// 07-27-2021, compute_unit to microsecond conversion ratio collected from mainnet-beta +// differs between instructions. Some bpf instruction has much higher CU/US ratio +// (eg 7vxeyaXGLqcp66fFShqUdHxdacp4k4kwUpRSSeoZLCZ4 has average ratio 135), others +// have lower ratio (eg 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin has an average ratio 14). +// With this, I am guestimating the flat_fee for sigver and account read/write +// as following. This can be adjusted when needed. const SIGVER_COST: u64 = 1; -const NON_SIGNED_READONLY_ACCOUNT_ACCESS_COST: u64 = 7; -const NON_SIGNED_WRITABLE_ACCOUNT_ACCESS_COST: u64 = 25; +const NON_SIGNED_READONLY_ACCOUNT_ACCESS_COST: u64 = 1; +const NON_SIGNED_WRITABLE_ACCOUNT_ACCESS_COST: u64 = 2; const SIGNED_READONLY_ACCOUNT_ACCESS_COST: u64 = SIGVER_COST + NON_SIGNED_READONLY_ACCOUNT_ACCESS_COST; const SIGNED_WRITABLE_ACCOUNT_ACCESS_COST: u64 = SIGVER_COST + NON_SIGNED_WRITABLE_ACCOUNT_ACCESS_COST; -// Sampled from mainnet-beta, the instruction execution timings stats are (in us): -// min=194, max=62164, avg=8214.49, med=2243 -pub const ACCOUNT_MAX_COST: u64 = 100_000_000; -pub const BLOCK_MAX_COST: u64 = 2_500_000_000; +// 07-27-2021, cost model limit is set to "worst case scenario", which is the +// max compute unit it can execute. From mainnet-beta, the max CU of instruction +// is 3753, round up to 4_000. Say we allows max 50_000 instruction per writable i +// account, and 1_000_000 instruction per block. It comes to following limits: +pub const ACCOUNT_MAX_COST: u64 = 200_000_000; +pub const BLOCK_MAX_COST: u64 = 4_000_000_000; const MAX_WRITABLE_ACCOUNTS: usize = 256; diff --git a/core/src/cost_update_service.rs b/core/src/cost_update_service.rs index f3b8cb278deaea..96e002c5dfd51d 100644 --- a/core/src/cost_update_service.rs +++ b/core/src/cost_update_service.rs @@ -137,9 +137,12 @@ impl CostUpdateService { let mut dirty = false; { 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) { + for (program_id, timing) in &execute_timings.details.per_program_timings { + if timing.count < 1 { + continue; + } + let units = timing.accumulated_units / timing.count as u64; + match cost_model_mutable.upsert_instruction_cost(program_id, units) { Ok(c) => { debug!( "after replayed into bank, instruction {:?} has averaged cost {}", @@ -220,7 +223,7 @@ mod tests { let accumulated_us: u64 = 1000; let accumulated_units: u64 = 100; let count: u32 = 10; - expected_cost = accumulated_us / count as u64; + expected_cost = accumulated_units / count as u64; execute_timings.details.per_program_timings.insert( program_key_1, @@ -255,7 +258,7 @@ mod tests { let accumulated_units: u64 = 200; let count: u32 = 10; // to expect new cost is Average(new_value, existing_value) - expected_cost = ((accumulated_us / count as u64) + expected_cost) / 2; + expected_cost = ((accumulated_units / count as u64) + expected_cost) / 2; execute_timings.details.per_program_timings.insert( program_key_1,