diff --git a/benches/benches/block_target_gas.rs b/benches/benches/block_target_gas.rs index 33d73bc4e31..d14daee0f55 100644 --- a/benches/benches/block_target_gas.rs +++ b/benches/benches/block_target_gas.rs @@ -83,7 +83,6 @@ mod block_target_gas_set; #[global_allocator] static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -const STATE_SIZE: u64 = 10_000_000; const TARGET_BLOCK_GAS_LIMIT: u64 = 1_000_000; const BASE: u64 = 100_000; @@ -100,7 +99,7 @@ impl SanityBenchmarkRunnerBuilder { /// Creates a factory for benchmarks that share a service with a contract, `contract_id`, pre- /// deployed. pub fn new_shared(contract_id: ContractId) -> SharedSanityBenchmarkFactory { - let state_size = get_state_size(); + let state_size = crate::utils::get_state_size(); let (service, rt) = service_with_contract_id(state_size, contract_id); let rng = rand::rngs::StdRng::seed_from_u64(2322u64); SharedSanityBenchmarkFactory { @@ -251,7 +250,9 @@ fn run( else { panic!("The execution should fails with out of gas") }; - assert!(reason.contains("OutOfGas")); + if !reason.contains("OutOfGas") { + panic!("The test failed because of {}", reason); + } } }) }); @@ -344,19 +345,6 @@ fn service_with_contract_id( (service, rt) } -fn get_state_size() -> u64 { - // Override state size if the env var is set - let state_size = std::env::var_os("STATE_SIZE") - .map(|value| { - let value = value.to_str().unwrap(); - let value = value.parse::().unwrap(); - println!("Overriding state size with {}", value); - value - }) - .unwrap_or(STATE_SIZE); - state_size -} - // Runs benchmark for `script` with prepared `service` and specified contract (by `contract_id`) which should be // included in service. // Also include additional inputs and outputs in transaction diff --git a/benches/benches/block_target_gas_set/crypto.rs b/benches/benches/block_target_gas_set/crypto.rs index ca00b3d31ee..84ba98fb5ad 100644 --- a/benches/benches/block_target_gas_set/crypto.rs +++ b/benches/benches/block_target_gas_set/crypto.rs @@ -97,14 +97,14 @@ pub fn run_crypto(group: &mut BenchmarkGroup) { .collect(), ); - let message = fuel_core_types::fuel_crypto::Message::new(b"foo"); + let message = Message::new(b"foo"); let ed19_secret = ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng {}); let ed19_signature = ed19_secret.sign(&*message); run( "crypto/ed19 opcode", group, - [ + vec![ op::gtf_args(0x20, 0x00, GTFArgs::ScriptData), op::addi( 0x21, @@ -122,13 +122,9 @@ pub fn run_crypto(group: &mut BenchmarkGroup) { ed19_signature.to_bytes().len().try_into().unwrap(), ), op::addi(0x22, 0x21, message.as_ref().len().try_into().unwrap()), - op::movi(0x10, ed25519_dalek::PUBLIC_KEY_LENGTH.try_into().unwrap()), - op::aloc(0x10), - op::move_(0x11, RegId::HP), op::ed19(0x20, 0x21, 0x22), op::jmpb(RegId::ZERO, 0), - ] - .to_vec(), + ], ed19_secret .verifying_key() .to_bytes() diff --git a/benches/benches/block_target_gas_set/default_gas_costs.rs b/benches/benches/block_target_gas_set/default_gas_costs.rs index 7431bbeaa6d..cd72bc31e6e 100644 --- a/benches/benches/block_target_gas_set/default_gas_costs.rs +++ b/benches/benches/block_target_gas_set/default_gas_costs.rs @@ -1,171 +1,171 @@ use super::*; pub fn default_gas_costs() -> GasCostsValues { GasCostsValues { - add: 1, - addi: 1, + add: 2, + addi: 2, aloc: 1, - and: 1, - andi: 1, - bal: 26, + and: 2, + andi: 2, + bal: 328, bhei: 1, - bhsh: 1, - burn: 27286, - cb: 1, - cfei: 1, + bhsh: 2, + burn: 27738, + cb: 2, + cfei: 2, cfsi: 1, - croo: 37, - div: 1, - divi: 1, - eck1: 3351, - ecr1: 46061, - ed19: 3163, - eq: 1, - exp: 1, - expi: 1, + croo: 40, + div: 2, + divi: 2, + eck1: 3107, + ecr1: 42738, + ed19: 2897, + eq: 2, + exp: 2, + expi: 2, flag: 1, - gm: 1, - gt: 1, - gtf: 1, - ji: 1, - jmp: 1, - jne: 1, - jnei: 1, - jnzi: 1, + gm: 2, + gt: 2, + gtf: 2, + ji: 2, + jmp: 2, + jne: 2, + jnei: 2, + jnzi: 2, jmpf: 1, jmpb: 1, jnzf: 1, jnzb: 1, jnef: 1, jneb: 1, - lb: 1, - log: 92, - lt: 1, - lw: 1, - mint: 25370, - mlog: 1, + lb: 2, + log: 87, + lt: 2, + lw: 2, + mint: 25515, + mlog: 2, vm_initialization: 1, - modi: 1, - mod_op: 1, - movi: 1, + modi: 2, + mod_op: 2, + movi: 2, mroo: 4, - mul: 1, - muli: 1, - mldv: 3, + mul: 2, + muli: 2, + mldv: 4, noop: 1, not: 1, - or: 1, - ori: 1, - poph: 1, - popl: 1, - pshh: 1, - pshl: 1, + or: 2, + ori: 2, + poph: 3, + popl: 3, + pshh: 3, + pshl: 3, move_op: 1, - ret: 135, - sb: 1, - sll: 1, - slli: 1, - srl: 1, - srli: 1, - srw: 237, - sub: 1, - subi: 1, - sw: 1, - sww: 27313, - time: 1, - tr: 38459, - tro: 26269, - wdcm: 1, - wqcm: 2, - wdop: 2, - wqop: 2, - wdml: 2, - wqml: 3, - wddv: 4, + ret: 127, + sb: 2, + sll: 2, + slli: 2, + srl: 2, + srli: 2, + srw: 224, + sub: 2, + subi: 2, + sw: 2, + sww: 26247, + time: 76, + tr: 38925, + tro: 26756, + wdcm: 2, + wqcm: 3, + wdop: 3, + wqop: 3, + wdml: 3, + wqml: 4, + wddv: 5, wqdv: 6, wdmd: 10, - wqmd: 16, - wdam: 8, + wqmd: 17, + wdam: 9, wqam: 10, - wdmm: 9, - wqmm: 9, - xor: 1, - xori: 1, + wdmm: 10, + wqmm: 10, + xor: 2, + xori: 2, call: DependentCost::LightOperation { - base: 1171, - units_per_gas: 47, + base: 17510, + units_per_gas: 5, }, ccp: DependentCost::LightOperation { - base: 39, - units_per_gas: 65, + base: 54, + units_per_gas: 21, }, csiz: DependentCost::LightOperation { - base: 49, - units_per_gas: 214, + base: 58, + units_per_gas: 212, }, k256: DependentCost::LightOperation { - base: 277, - units_per_gas: 3, + base: 259, + units_per_gas: 4, }, ldc: DependentCost::LightOperation { - base: 37, - units_per_gas: 63, + base: 42, + units_per_gas: 65, }, logd: DependentCost::LightOperation { - base: 444, + base: 413, units_per_gas: 3, }, mcl: DependentCost::LightOperation { - base: 1, - units_per_gas: 500, + base: 2, + units_per_gas: 568, }, mcli: DependentCost::LightOperation { - base: 1, - units_per_gas: 500, + base: 3, + units_per_gas: 568, }, mcp: DependentCost::LightOperation { - base: 2, - units_per_gas: 493, + base: 3, + units_per_gas: 470, }, mcpi: DependentCost::LightOperation { - base: 4, - units_per_gas: 1023, + base: 6, + units_per_gas: 682, }, meq: DependentCost::LightOperation { - base: 2, - units_per_gas: 1111, + base: 10, + units_per_gas: 1161, }, - rvrt: 136, + rvrt: 127, s256: DependentCost::LightOperation { - base: 44, + base: 42, units_per_gas: 3, }, scwq: DependentCost::HeavyOperation { - base: 28687, - gas_per_unit: 27036, + base: 27337, + gas_per_unit: 25552, }, smo: DependentCost::LightOperation { - base: 58089, + base: 55851, units_per_gas: 1, }, - srwq: DependentCost::LightOperation { - base: 121, - units_per_gas: 1, + srwq: DependentCost::HeavyOperation { + base: 501, + gas_per_unit: 22, }, swwq: DependentCost::HeavyOperation { - base: 26790, - gas_per_unit: 25451, + base: 25619, + gas_per_unit: 24002, }, contract_root: DependentCost::LightOperation { - base: 44, + base: 43, units_per_gas: 2, }, state_root: DependentCost::HeavyOperation { - base: 347, - gas_per_unit: 176, + base: 324, + gas_per_unit: 164, }, new_storage_per_byte: 1, retd: DependentCost::LightOperation { - base: 466, + base: 434, units_per_gas: 3, }, } diff --git a/benches/benches/block_target_gas_set/memory.rs b/benches/benches/block_target_gas_set/memory.rs index 4ded8689652..8c31790d4ea 100644 --- a/benches/benches/block_target_gas_set/memory.rs +++ b/benches/benches/block_target_gas_set/memory.rs @@ -28,12 +28,7 @@ pub fn run_memory(group: &mut BenchmarkGroup) { run( "memory/aloc opcode", group, - [ - op::movi(0x10, 1000), - op::aloc(0x10), - op::jmpb(RegId::ZERO, 0), - ] - .to_vec(), + [op::movi(0x10, 0), op::aloc(0x10), op::jmpb(RegId::ZERO, 0)].to_vec(), vec![], ); diff --git a/benches/benches/utils.rs b/benches/benches/utils.rs index fdd8d03ebba..f2af0e21f01 100644 --- a/benches/benches/utils.rs +++ b/benches/benches/utils.rs @@ -12,6 +12,21 @@ use fuel_core_types::{ }, }; +pub const STATE_SIZE: u64 = 10_000_000; + +pub fn get_state_size() -> u64 { + // Override state size if the env var is set + let state_size = std::env::var_os("STATE_SIZE") + .map(|value| { + let value = value.to_str().unwrap(); + let value = value.parse::().unwrap(); + println!("Overriding state size with {}", value); + value + }) + .unwrap_or(STATE_SIZE); + state_size +} + /// Allocates a byte array from heap and initializes it. Then points `reg` to it. fn aloc_bytearray(reg: u8, v: [u8; S]) -> Vec { let mut ops = vec![op::movi(reg, S as u32), op::aloc(reg)]; diff --git a/benches/benches/vm.rs b/benches/benches/vm.rs index 9d1217e02fd..e9d4a5982fb 100644 --- a/benches/benches/vm.rs +++ b/benches/benches/vm.rs @@ -38,8 +38,11 @@ where let mut total = core::time::Duration::ZERO; for _ in 0..iters { let original_db = vm.as_mut().database_mut().clone(); - let database_tx = original_db.transaction().as_ref().clone(); - *vm.as_mut().database_mut() = database_tx; + // Simulates the block production/validation with three levels of database transaction. + let block_database_tx = original_db.transaction().as_ref().clone(); + let tx_database_tx = block_database_tx.transaction().as_ref().clone(); + let vm_tx_database_tx = tx_database_tx.transaction().as_ref().clone(); + *vm.as_mut().database_mut() = vm_tx_database_tx; let start = black_box(clock.raw()); match instruction { @@ -65,12 +68,12 @@ where fn vm(c: &mut Criterion) { alu::run(c); - blockchain::run(c); crypto::run(c); flow::run(c); mem::run(c); contract_root(c); state_root(c); + blockchain::run(c); } criterion_group!(benches, vm); diff --git a/benches/benches/vm_set/alu.rs b/benches/benches/vm_set/alu.rs index 2cb5d63fe92..8e93f7db566 100644 --- a/benches/benches/vm_set/alu.rs +++ b/benches/benches/vm_set/alu.rs @@ -37,7 +37,8 @@ pub fn run(c: &mut Criterion) { run_group_ref( &mut c.benchmark_group("aloc"), "aloc", - VmBench::new(op::aloc(0x10)), + VmBench::new(op::aloc(0x10)) + .with_prepare_script(vec![op::movi(0x10, (1 << 18) - 1)]), ); run_group_ref( diff --git a/benches/benches/vm_set/blockchain.rs b/benches/benches/vm_set/blockchain.rs index a716f4d46d6..a72920c5f2c 100644 --- a/benches/benches/vm_set/blockchain.rs +++ b/benches/benches/vm_set/blockchain.rs @@ -11,6 +11,7 @@ use criterion::{ }; use fuel_core::{ database::vm_database::VmDatabase, + service::Config, state::rocks_db::{ RocksDb, ShallowTempDir, @@ -18,6 +19,7 @@ use fuel_core::{ }; use fuel_core_benches::*; use fuel_core_types::{ + blockchain::header::ConsensusHeader, fuel_asm::{ op, GTFArgs, @@ -31,6 +33,7 @@ use fuel_core_types::{ }, fuel_types::*, fuel_vm::consts::*, + tai64::Tai64, }; use rand::{ rngs::StdRng, @@ -45,40 +48,49 @@ pub struct BenchDb { } impl BenchDb { - const STATE_SIZE: u64 = 10_000_000; - fn new(contract_id: &ContractId) -> anyhow::Result { + use fuel_core::database::vm_database::IncreaseStorageKey; let tmp_dir = ShallowTempDir::new(); let db = Arc::new(RocksDb::default_open(tmp_dir.path(), None).unwrap()); let mut storage_key = primitive_types::U256::zero(); let mut key_bytes = Bytes32::zeroed(); + let state_size = crate::utils::get_state_size(); + let mut database = Database::new(db); database.init_contract_state( contract_id, - (0..Self::STATE_SIZE).map(|_| { - use fuel_core::database::vm_database::IncreaseStorageKey; + (0..state_size).map(|_| { storage_key.to_big_endian(key_bytes.as_mut()); storage_key.increase().unwrap(); (key_bytes, key_bytes) }), )?; + + let mut storage_key = primitive_types::U256::zero(); + let mut sub_id = Bytes32::zeroed(); database.init_contract_balances( contract_id, - (0..Self::STATE_SIZE).map(|k| { - let key = k / 2; - let mut sub_id = Bytes32::zeroed(); - sub_id.as_mut()[..8].copy_from_slice(&key.to_be_bytes()); + (0..state_size).map(|k| { + storage_key.to_big_endian(sub_id.as_mut()); let asset = if k % 2 == 0 { VmBench::CONTRACT.asset_id(&sub_id) } else { - AssetId::new(*sub_id) + let asset_id = AssetId::new(*sub_id); + storage_key.increase().unwrap(); + asset_id }; - (asset, key + 1_000) + (asset, k / 2 + 1_000) }), )?; + // Adds a genesis block to the database. + fuel_core::service::genesis::maybe_initialize_state( + &Config::local_node(), + &database, + ) + .expect("Should init with genesis block"); database.clone().flush()?; Ok(Self { @@ -89,7 +101,13 @@ impl BenchDb { /// Creates a `VmDatabase` instance. fn to_vm_database(&self) -> VmDatabase { - VmDatabase::default_from_database(self.db.clone()) + let header = ConsensusHeader { + prev_root: Default::default(), + height: 1.into(), + time: Tai64::UNIX_EPOCH, + generated: (), + }; + VmDatabase::new(self.db.clone(), &header, ContractId::zeroed()) } } @@ -107,7 +125,7 @@ pub fn run(c: &mut Criterion) { l.sort_unstable(); linear.extend(l); - let asset: AssetId = rng.gen(); + let asset = AssetId::zeroed(); let contract: ContractId = VmBench::CONTRACT; let db = BenchDb::new(&contract).expect("Unable to fill contract storage"); @@ -115,7 +133,8 @@ pub fn run(c: &mut Criterion) { run_group_ref( &mut c.benchmark_group("bal"), "bal", - VmBench::new(op::bal(0x10, 0x10, 0x11)) + VmBench::new(op::bal(0x13, 0x10, 0x11)) + .with_db(db.to_vm_database()) .with_data(asset.iter().chain(contract.iter()).copied().collect()) .with_prepare_script(vec![ op::gtf_args(0x10, 0x00, GTFArgs::ScriptData), @@ -126,7 +145,7 @@ pub fn run(c: &mut Criterion) { { let mut start_key = Bytes32::zeroed(); - // The checkpoint was initialized with entries starting `0..Self::STATE_SIZE`. + // The checkpoint was initialized with entries starting `0..STATE_SIZE`. // We want to write new entry to the database, so the starting key is far. start_key.as_mut()[0] = 255; let data = start_key.iter().copied().collect::>(); @@ -195,7 +214,7 @@ pub fn run(c: &mut Criterion) { for i in linear_short.clone() { let mut start_key = Bytes32::zeroed(); - // The checkpoint was initialized with entries starting `0..Self::STATE_SIZE`. + // The checkpoint was initialized with entries starting `0..STATE_SIZE`. // We want to write new entries to the database, so the starting key is far. start_key.as_mut()[0] = 255; let data = start_key.iter().copied().collect::>(); @@ -231,10 +250,11 @@ pub fn run(c: &mut Criterion) { rng.fill_bytes(&mut code); - let code = ContractCode::from(code); - let id = code.id; + let mut code = ContractCode::from(code); + code.id = VmBench::CONTRACT; - let data = id + let data = code + .id .iter() .copied() .chain((0 as Word).to_be_bytes().iter().copied()) @@ -272,10 +292,11 @@ pub fn run(c: &mut Criterion) { rng.fill_bytes(&mut code); - let code = ContractCode::from(code); - let id = code.id; + let mut code = ContractCode::from(code); + code.id = VmBench::CONTRACT; - let data = id + let data = code + .id .iter() .copied() .chain((0 as Word).to_be_bytes().iter().copied()) @@ -309,14 +330,15 @@ pub fn run(c: &mut Criterion) { let mut ccp = c.benchmark_group("ccp"); for i in linear.clone() { - let mut code = vec![0u8; i as usize]; + let mut code = vec![op::noop(); i as usize].into_iter().collect::>(); rng.fill_bytes(&mut code); - let code = ContractCode::from(code); - let id = code.id; + let mut code = ContractCode::from(code); + code.id = VmBench::CONTRACT; - let data = id + let data = code + .id .iter() .copied() .chain((0 as Word).to_be_bytes().iter().copied()) @@ -360,10 +382,10 @@ pub fn run(c: &mut Criterion) { rng.fill_bytes(&mut code); - let code = ContractCode::from(code); - let id = code.id; + let mut code = ContractCode::from(code); + code.id = VmBench::CONTRACT; - let data = id.iter().copied().collect(); + let data = code.id.iter().copied().collect(); let prepare_script = vec![op::gtf_args(0x10, 0x00, GTFArgs::ScriptData)]; @@ -430,6 +452,7 @@ pub fn run(c: &mut Criterion) { ]), ); + // tr { let mut input = VmBench::contract_using_db( rng, @@ -443,6 +466,7 @@ pub fn run(c: &mut Criterion) { run_group_ref(&mut c.benchmark_group("tr"), "tr", input); } + // tro { let mut input = VmBench::contract_using_db( rng, @@ -512,49 +536,52 @@ pub fn run(c: &mut Criterion) { VmBench::contract(rng, op::gm(0x10, 1)).unwrap(), ); - let mut smo = c.benchmark_group("smo"); + // smo + { + let mut smo = c.benchmark_group("smo"); + + for i in linear.clone() { + let mut input = VmBench::contract_using_db( + rng, + db.to_vm_database(), + op::smo(0x15, 0x16, 0x17, 0x18), + ) + .expect("failed to prepare contract"); + input.post_call.extend(vec![ + op::gtf_args(0x15, 0x00, GTFArgs::ScriptData), + // Offset 32 + 8 + 8 + 32 + op::addi(0x15, 0x15, 32 + 8 + 8 + 32), // target address pointer + op::addi(0x16, 0x15, 32), // data ppinter + op::movi(0x17, i.try_into().unwrap()), // data length + op::movi(0x18, 10), // coins to send + ]); + input.data.extend( + Address::new([1u8; 32]) + .iter() + .copied() + .chain(vec![2u8; i as usize]), + ); + let predicate = op::ret(RegId::ONE).to_bytes().to_vec(); + let owner = Input::predicate_owner(&predicate); + let coin_input = Input::coin_predicate( + Default::default(), + owner, + Word::MAX, + AssetId::zeroed(), + Default::default(), + Default::default(), + Default::default(), + predicate, + vec![], + ); + input.inputs.push(coin_input); + smo.throughput(Throughput::Bytes(i)); + run_group_ref(&mut smo, format!("{i}"), input); + } - for i in linear.clone() { - let mut input = VmBench::contract_using_db( - rng, - db.to_vm_database(), - op::smo(0x15, 0x16, 0x17, 0x18), - ) - .expect("failed to prepare contract"); - input.post_call.extend(vec![ - op::gtf_args(0x15, 0x00, GTFArgs::ScriptData), - // Offset 32 + 8 + 8 + 32 - op::addi(0x15, 0x15, 32 + 8 + 8 + 32), // target address pointer - op::addi(0x16, 0x15, 32), // data ppinter - op::movi(0x17, i.try_into().unwrap()), // data length - op::movi(0x18, 10), // coins to send - ]); - input.data.extend( - Address::new([1u8; 32]) - .iter() - .copied() - .chain(vec![2u8; i as usize]), - ); - let predicate = op::ret(RegId::ONE).to_bytes().to_vec(); - let owner = Input::predicate_owner(&predicate); - let coin_input = Input::coin_predicate( - Default::default(), - owner, - Word::MAX, - AssetId::zeroed(), - Default::default(), - Default::default(), - Default::default(), - predicate, - vec![], - ); - input.inputs.push(coin_input); - smo.throughput(Throughput::Bytes(i)); - run_group_ref(&mut smo, format!("{i}"), input); + smo.finish(); } - smo.finish(); - { let mut srwq = c.benchmark_group("srwq"); @@ -571,10 +598,19 @@ pub fn run(c: &mut Criterion) { op::addi(0x15, 0x15, 1), op::aloc(0x15), op::move_(0x14, RegId::HP), + op::gtf_args(0x27, 0x00, GTFArgs::ScriptData), + op::addi(0x27, 0x27, ContractId::LEN.try_into().unwrap()), + op::addi(0x27, 0x27, WORD_SIZE.try_into().unwrap()), + op::addi(0x27, 0x27, WORD_SIZE.try_into().unwrap()), + op::addi(0x27, 0x27, AssetId::LEN.try_into().unwrap()), ]; - let mut bench = VmBench::contract(rng, op::srwq(0x14, 0x11, 0x27, 0x16)) - .expect("failed to prepare contract") - .with_post_call(post_call); + let mut bench = VmBench::contract_using_db( + rng, + db.to_vm_database(), + op::srwq(0x14, 0x11, 0x27, 0x16), + ) + .expect("failed to prepare contract") + .with_post_call(post_call); bench.data.extend(data); srwq.throughput(Throughput::Bytes(i)); run_group_ref(&mut srwq, format!("{i}"), bench); @@ -583,9 +619,14 @@ pub fn run(c: &mut Criterion) { srwq.finish(); } - run_group_ref( - &mut c.benchmark_group("time"), - "time", - VmBench::new(op::time(0x11, 0x10)).with_prepare_script(vec![op::movi(0x10, 0)]), - ); + // time + { + run_group_ref( + &mut c.benchmark_group("time"), + "time", + VmBench::new(op::time(0x11, 0x10)) + .with_db(db.to_vm_database()) + .with_prepare_script(vec![op::movi(0x10, 0)]), + ); + } } diff --git a/benches/benches/vm_set/mem.rs b/benches/benches/vm_set/mem.rs index 695bb3c8719..9d20bcc200b 100644 --- a/benches/benches/vm_set/mem.rs +++ b/benches/benches/vm_set/mem.rs @@ -164,13 +164,15 @@ pub fn run(c: &mut Criterion) { run_group_ref( &mut c.benchmark_group("pshh"), "pshh", - VmBench::new(op::pshh(full_mask)), + VmBench::new(op::pshh(full_mask)) + .with_prepare_script(vec![op::pshh(full_mask); 10000]), ); // pshl run_group_ref( &mut c.benchmark_group("pshl"), "pshl", - VmBench::new(op::pshl(full_mask)), + VmBench::new(op::pshl(full_mask)) + .with_prepare_script(vec![op::pshl(full_mask); 10000]), ); }