diff --git a/core/src/costs.rs b/core/src/costs.rs index 58c6dae5629..1fcec7b2a97 100644 --- a/core/src/costs.rs +++ b/core/src/costs.rs @@ -502,6 +502,21 @@ impl SyscallCosts { } } +/// Memory pages costs. +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct PagesCosts { + /// Loading from storage and moving it in program memory cost. + pub load_page_data: CostOf, + /// Uploading page data to storage cost. + pub upload_page_data: CostOf, + /// Memory grow cost. + pub mem_grow: CostOf, + /// Memory grow per page cost. + pub mem_grow_per_page: CostOf, + /// Parachain read heuristic cost. + pub parachain_read_heuristic: CostOf, +} + /// Memory pages lazy access costs. #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct LazyPagesCosts { @@ -521,6 +536,15 @@ pub struct LazyPagesCosts { pub load_page_storage_data: CostOf, } +/// IO costs. +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct IoCosts { + /// Consts for common pages. + pub common: PagesCosts, + /// Consts for lazy pages. + pub lazy_pages: LazyPagesCosts, +} + /// Holding in storages rent costs. #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct RentCosts { diff --git a/core/src/gas_metering/schedule.rs b/core/src/gas_metering/schedule.rs index 92db5a65ec1..6734e136fbc 100644 --- a/core/src/gas_metering/schedule.rs +++ b/core/src/gas_metering/schedule.rs @@ -1193,6 +1193,27 @@ impl From for SyscallCosts { } } +impl From for IoCosts { + fn from(val: MemoryWeights) -> Self { + Self { + common: PagesCosts::from(val.clone()), + lazy_pages: LazyPagesCosts::from(val), + } + } +} + +impl From for PagesCosts { + fn from(val: MemoryWeights) -> Self { + Self { + load_page_data: val.load_page_data.ref_time().into(), + upload_page_data: val.upload_page_data.ref_time().into(), + mem_grow: val.mem_grow.ref_time().into(), + mem_grow_per_page: val.mem_grow_per_page.ref_time().into(), + parachain_read_heuristic: val.parachain_read_heuristic.ref_time().into(), + } + } +} + impl From for LazyPagesCosts { fn from(val: MemoryWeights) -> Self { Self { diff --git a/pallets/gear/src/schedule.rs b/pallets/gear/src/schedule.rs index 6be4e52b349..83ac65cfa1d 100644 --- a/pallets/gear/src/schedule.rs +++ b/pallets/gear/src/schedule.rs @@ -24,7 +24,10 @@ use common::scheduler::SchedulingCostsPerBlock; use frame_support::{traits::Get, weights::Weight}; use gear_core::{ code::MAX_WASM_PAGES_AMOUNT, - costs::{ExtCosts, InstantiationCosts, LazyPagesCosts, ProcessCosts, RentCosts, SyscallCosts}, + costs::{ + ExtCosts, InstantiationCosts, IoCosts, LazyPagesCosts, PagesCosts, ProcessCosts, RentCosts, + SyscallCosts, + }, message, pages::{GearPage, WasmPage}, }; @@ -1301,6 +1304,27 @@ impl Default for MemoryWeights { } } +impl From> for IoCosts { + fn from(val: MemoryWeights) -> Self { + Self { + common: PagesCosts::from(val.clone()), + lazy_pages: LazyPagesCosts::from(val), + } + } +} + +impl From> for PagesCosts { + fn from(val: MemoryWeights) -> Self { + Self { + load_page_data: val.load_page_data.ref_time().into(), + upload_page_data: val.upload_page_data.ref_time().into(), + mem_grow: val.mem_grow.ref_time().into(), + mem_grow_per_page: val.mem_grow_per_page.ref_time().into(), + parachain_read_heuristic: val.parachain_read_heuristic.ref_time().into(), + } + } +} + impl From> for LazyPagesCosts { fn from(val: MemoryWeights) -> Self { Self { diff --git a/runtime/common/src/lib.rs b/runtime/common/src/lib.rs index e2af6d0630d..01e9e8d0d6a 100644 --- a/runtime/common/src/lib.rs +++ b/runtime/common/src/lib.rs @@ -20,7 +20,6 @@ mod apis; pub mod constants; -pub mod weights; use sp_runtime::traits::Get; diff --git a/runtime/common/src/weights.rs b/runtime/common/src/weights.rs deleted file mode 100644 index 74e167b6ad8..00000000000 --- a/runtime/common/src/weights.rs +++ /dev/null @@ -1,308 +0,0 @@ -use gear_core::{ - costs::{CostOf, LazyPagesCosts}, - pages::GearPagesAmount, -}; -use pallet_gear::{InstructionWeights, MemoryWeights, SyscallWeights}; - -const INSTRUCTIONS_SPREAD: u8 = 50; -const SYSCALL_SPREAD: u8 = 10; -const PAGES_SPREAD: u8 = 10; - -#[track_caller] -fn check_spreading(weight: u64, expected: u64, spread: u8) { - let left = expected - expected * spread as u64 / 100; - let right = expected + expected * spread as u64 / 100; - - assert!( - left <= weight && weight <= right, - "Weight is {weight} ps. Expected weight is {expected} ps. {spread}% spread interval: [{left} ps, {right} ps]" - ); -} - -#[track_caller] -fn check_instruction_weight(weight: u32, expected: u32) { - check_spreading(weight.into(), expected.into(), INSTRUCTIONS_SPREAD); -} - -#[track_caller] -fn check_syscall_weight(weight: u64, expected: u64) { - check_spreading(weight, expected, SYSCALL_SPREAD); -} - -#[track_caller] -fn check_pages_weight(weight: u64, expected: u64) { - check_spreading(weight, expected, PAGES_SPREAD); -} - -/// Check that the weights of instructions are within the expected range -pub fn check_instructions_weights( - weights: InstructionWeights, - expected: InstructionWeights, -) { - check_instruction_weight(weights.i64const, expected.i64const); - check_instruction_weight(weights.i64load, expected.i64load); - check_instruction_weight(weights.i32load, expected.i32load); - check_instruction_weight(weights.i64store, expected.i64store); - check_instruction_weight(weights.i32store, expected.i32store); - check_instruction_weight(weights.select, expected.select); - check_instruction_weight(weights.r#if, expected.r#if); - check_instruction_weight(weights.br, expected.br); - check_instruction_weight(weights.br_if, expected.br_if); - check_instruction_weight(weights.br_table, expected.br_table); - check_instruction_weight(weights.br_table_per_entry, expected.br_table_per_entry); - check_instruction_weight(weights.call, expected.call); - check_instruction_weight(weights.call_indirect, expected.call_indirect); - check_instruction_weight( - weights.call_indirect_per_param, - expected.call_indirect_per_param, - ); - check_instruction_weight(weights.call_per_local, expected.call_per_local); - check_instruction_weight(weights.local_get, expected.local_get); - check_instruction_weight(weights.local_set, expected.local_set); - check_instruction_weight(weights.local_tee, expected.local_tee); - check_instruction_weight(weights.global_get, expected.global_get); - check_instruction_weight(weights.global_set, expected.global_set); - check_instruction_weight(weights.memory_current, expected.memory_current); - check_instruction_weight(weights.i64clz, expected.i64clz); - check_instruction_weight(weights.i32clz, expected.i32clz); - check_instruction_weight(weights.i64ctz, expected.i64ctz); - check_instruction_weight(weights.i32ctz, expected.i32ctz); - check_instruction_weight(weights.i64popcnt, expected.i64popcnt); - check_instruction_weight(weights.i32popcnt, expected.i32popcnt); - check_instruction_weight(weights.i64eqz, expected.i64eqz); - check_instruction_weight(weights.i32eqz, expected.i32eqz); - check_instruction_weight(weights.i32extend8s, expected.i32extend8s); - check_instruction_weight(weights.i32extend16s, expected.i32extend16s); - check_instruction_weight(weights.i64extend8s, expected.i64extend8s); - check_instruction_weight(weights.i64extend16s, expected.i64extend16s); - check_instruction_weight(weights.i64extend32s, expected.i64extend32s); - check_instruction_weight(weights.i64extendsi32, expected.i64extendsi32); - check_instruction_weight(weights.i64extendui32, expected.i64extendui32); - check_instruction_weight(weights.i32wrapi64, expected.i32wrapi64); - check_instruction_weight(weights.i64eq, expected.i64eq); - check_instruction_weight(weights.i32eq, expected.i32eq); - check_instruction_weight(weights.i64ne, expected.i64ne); - check_instruction_weight(weights.i32ne, expected.i32ne); - check_instruction_weight(weights.i64lts, expected.i64lts); - check_instruction_weight(weights.i32lts, expected.i32lts); - check_instruction_weight(weights.i64ltu, expected.i64ltu); - check_instruction_weight(weights.i32ltu, expected.i32ltu); - check_instruction_weight(weights.i64gts, expected.i64gts); - check_instruction_weight(weights.i32gts, expected.i32gts); - check_instruction_weight(weights.i64gtu, expected.i64gtu); - check_instruction_weight(weights.i32gtu, expected.i32gtu); - check_instruction_weight(weights.i64les, expected.i64les); - check_instruction_weight(weights.i32les, expected.i32les); - check_instruction_weight(weights.i64leu, expected.i64leu); - check_instruction_weight(weights.i32leu, expected.i32leu); - check_instruction_weight(weights.i64ges, expected.i64ges); - check_instruction_weight(weights.i32ges, expected.i32ges); - check_instruction_weight(weights.i64geu, expected.i64geu); - check_instruction_weight(weights.i32geu, expected.i32geu); - check_instruction_weight(weights.i64add, expected.i64add); - check_instruction_weight(weights.i32add, expected.i32add); - check_instruction_weight(weights.i64sub, expected.i64sub); - check_instruction_weight(weights.i32sub, expected.i32sub); - check_instruction_weight(weights.i64mul, expected.i64mul); - check_instruction_weight(weights.i32mul, expected.i32mul); - check_instruction_weight(weights.i64divs, expected.i64divs); - check_instruction_weight(weights.i32divs, expected.i32divs); - check_instruction_weight(weights.i64divu, expected.i64divu); - check_instruction_weight(weights.i32divu, expected.i32divu); - check_instruction_weight(weights.i64rems, expected.i64rems); - check_instruction_weight(weights.i32rems, expected.i32rems); - check_instruction_weight(weights.i64remu, expected.i64remu); - check_instruction_weight(weights.i32remu, expected.i32remu); - check_instruction_weight(weights.i64and, expected.i64and); - check_instruction_weight(weights.i32and, expected.i32and); - check_instruction_weight(weights.i64or, expected.i64or); - check_instruction_weight(weights.i32or, expected.i32or); - check_instruction_weight(weights.i64xor, expected.i64xor); - check_instruction_weight(weights.i32xor, expected.i32xor); - check_instruction_weight(weights.i64shl, expected.i64shl); - check_instruction_weight(weights.i32shl, expected.i32shl); - check_instruction_weight(weights.i64shrs, expected.i64shrs); - check_instruction_weight(weights.i32shrs, expected.i32shrs); - check_instruction_weight(weights.i64shru, expected.i64shru); - check_instruction_weight(weights.i32shru, expected.i32shru); - check_instruction_weight(weights.i64rotl, expected.i64rotl); - check_instruction_weight(weights.i32rotl, expected.i32rotl); - check_instruction_weight(weights.i64rotr, expected.i64rotr); - check_instruction_weight(weights.i32rotr, expected.i32rotr); -} - -/// Check that the weights of syscalls are within the expected range -pub fn check_syscall_weights( - weights: SyscallWeights, - expected: SyscallWeights, -) { - macro_rules! check { - ($inst_name:ident) => { - check_syscall_weight( - weights.$inst_name.ref_time(), - expected.$inst_name.ref_time(), - ); - }; - } - - check!(alloc); - check!(free); - check!(free_range); - check!(free_range_per_page); - check!(gr_reserve_gas); - check!(gr_unreserve_gas); - check!(gr_system_reserve_gas); - check!(gr_gas_available); - check!(gr_message_id); - check!(gr_program_id); - check!(gr_source); - check!(gr_value); - check!(gr_value_available); - check!(gr_size); - check!(gr_read); - check!(gr_read_per_byte); - check!(gr_env_vars); - check!(gr_block_height); - check!(gr_block_timestamp); - check!(gr_random); - check!(gr_reply_deposit); - check!(gr_send); - check!(gr_send_per_byte); - check!(gr_send_wgas); - check!(gr_send_wgas_per_byte); - check!(gr_send_init); - check!(gr_send_push); - check!(gr_send_push_per_byte); - check!(gr_send_commit); - check!(gr_send_commit_wgas); - check!(gr_reservation_send); - check!(gr_reservation_send_per_byte); - check!(gr_reservation_send_commit); - check!(gr_reply_commit); - check!(gr_reply_commit_wgas); - check!(gr_reservation_reply); - check!(gr_reservation_reply_per_byte); - check!(gr_reservation_reply_commit); - check!(gr_reply_push); - check!(gr_reply); - check!(gr_reply_per_byte); - check!(gr_reply_wgas); - check!(gr_reply_wgas_per_byte); - check!(gr_reply_push_per_byte); - check!(gr_reply_to); - check!(gr_signal_code); - check!(gr_signal_from); - check!(gr_reply_input); - check!(gr_reply_input_wgas); - check!(gr_reply_push_input); - check!(gr_reply_push_input_per_byte); - check!(gr_send_input); - check!(gr_send_input_wgas); - check!(gr_send_push_input); - check!(gr_send_push_input_per_byte); - check!(gr_debug); - check!(gr_debug_per_byte); - check!(gr_reply_code); - check!(gr_exit); - check!(gr_leave); - check!(gr_wait); - check!(gr_wait_for); - check!(gr_wait_up_to); - check!(gr_wake); - check!(gr_create_program); - check!(gr_create_program_payload_per_byte); - check!(gr_create_program_salt_per_byte); - check!(gr_create_program_wgas); - check!(gr_create_program_wgas_payload_per_byte); - check!(gr_create_program_wgas_salt_per_byte); -} - -/// Check that the lazy-pages costs are within the expected range -pub fn check_lazy_pages_costs( - lazy_pages_costs: LazyPagesCosts, - expected_lazy_pages_costs: LazyPagesCosts, -) { - check_pages_weight( - lazy_pages_costs.signal_read.cost_for_one(), - expected_lazy_pages_costs.signal_read.cost_for_one(), - ); - check_pages_weight( - lazy_pages_costs.signal_write.cost_for_one(), - expected_lazy_pages_costs.signal_write.cost_for_one(), - ); - check_pages_weight( - lazy_pages_costs.signal_write_after_read.cost_for_one(), - expected_lazy_pages_costs - .signal_write_after_read - .cost_for_one(), - ); - check_pages_weight( - lazy_pages_costs.host_func_read.cost_for_one(), - expected_lazy_pages_costs.host_func_read.cost_for_one(), - ); - check_pages_weight( - lazy_pages_costs.host_func_write.cost_for_one(), - expected_lazy_pages_costs.host_func_write.cost_for_one(), - ); - check_pages_weight( - lazy_pages_costs.host_func_write_after_read.cost_for_one(), - expected_lazy_pages_costs - .host_func_write_after_read - .cost_for_one(), - ); - check_pages_weight( - lazy_pages_costs.load_page_storage_data.cost_for_one(), - expected_lazy_pages_costs - .load_page_storage_data - .cost_for_one(), - ); -} - -/// Memory pages access costs. -pub struct PagesCosts { - pub load_page_data: CostOf, - pub upload_page_data: CostOf, - pub mem_grow: CostOf, - pub mem_grow_per_page: CostOf, - pub parachain_read_heuristic: CostOf, -} - -impl From> for PagesCosts { - fn from(val: MemoryWeights) -> Self { - Self { - load_page_data: val.load_page_data.ref_time().into(), - upload_page_data: val.upload_page_data.ref_time().into(), - mem_grow: val.mem_grow.ref_time().into(), - mem_grow_per_page: val.mem_grow_per_page.ref_time().into(), - parachain_read_heuristic: val.parachain_read_heuristic.ref_time().into(), - } - } -} - -/// Check that the pages costs are within the expected range -pub fn check_pages_costs(page_costs: PagesCosts, expected_page_costs: PagesCosts) { - check_pages_weight( - page_costs.load_page_data.cost_for_one(), - expected_page_costs.load_page_data.cost_for_one(), - ); - - check_pages_weight( - page_costs.upload_page_data.cost_for_one(), - expected_page_costs.upload_page_data.cost_for_one(), - ); - - check_pages_weight( - page_costs.mem_grow.cost_for_one(), - expected_page_costs.mem_grow.cost_for_one(), - ); - - check_pages_weight( - page_costs.mem_grow_per_page.cost_for_one(), - expected_page_costs.mem_grow_per_page.cost_for_one(), - ); - - check_pages_weight( - page_costs.parachain_read_heuristic.cost_for_one(), - expected_page_costs.parachain_read_heuristic.cost_for_one(), - ); -} diff --git a/runtime/vara/src/tests.rs b/runtime/vara/src/tests/mod.rs similarity index 86% rename from runtime/vara/src/tests.rs rename to runtime/vara/src/tests/mod.rs index 2f31c0c25ba..6b7604ca8fc 100644 --- a/runtime/vara/src/tests.rs +++ b/runtime/vara/src/tests/mod.rs @@ -16,19 +16,24 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +//! Weight tests for the runtime. + use super::*; use crate::Runtime; -use frame_support::{dispatch::GetDispatchInfo, traits::StorageInstance}; + +use frame_support::dispatch::GetDispatchInfo; use frame_system::limits::WeightsPerClass; -use gear_core::costs::LazyPagesCosts; +use gear_core::costs::{IoCosts, LazyPagesCosts, PagesCosts}; use pallet_gear::{InstructionWeights, MemoryWeights, SyscallWeights}; use pallet_staking::WeightInfo as _; -use runtime_common::weights::{ - check_instructions_weights, check_lazy_pages_costs, check_pages_costs, check_syscall_weights, - PagesCosts, -}; use sp_runtime::AccountId32; +#[cfg(feature = "dev")] +use frame_support::traits::StorageInstance; + +mod utils; +use utils::*; + #[cfg(feature = "dev")] #[test] fn bridge_storages_have_correct_prefixes() { @@ -224,7 +229,10 @@ fn instruction_weights_heuristics_test() { i32rotr: 300, }; - check_instructions_weights(weights, expected_weights); + let result = check_instructions_weights(weights, expected_weights); + + assert!(result.is_ok(), "{:#?}", result.err().unwrap()); + assert_eq!(result.unwrap(), expected_instructions_weights_count()); } #[test] @@ -305,12 +313,15 @@ fn syscall_weights_test() { _phantom: Default::default(), }; - check_syscall_weights(weights, expected); + let result = check_syscall_weights(weights, expected); + + assert!(result.is_ok(), "{:#?}", result.err().unwrap()); + assert_eq!(result.unwrap(), expected_syscall_weights_count()); } #[test] fn page_costs_heuristic_test() { - let page_costs: PagesCosts = MemoryWeights::::default().into(); + let io_costs: IoCosts = MemoryWeights::::default().into(); let expected_page_costs = PagesCosts { load_page_data: 10_000_000.into(), @@ -320,12 +331,15 @@ fn page_costs_heuristic_test() { parachain_read_heuristic: 0.into(), }; - check_pages_costs(page_costs, expected_page_costs); + let result = check_pages_costs(io_costs.common, expected_page_costs); + + assert!(result.is_ok(), "{:#?}", result.err().unwrap()); + assert_eq!(result.unwrap(), expected_pages_costs_count()); } #[test] fn lazy_page_costs_heuristic_test() { - let lazy_pages_costs: LazyPagesCosts = MemoryWeights::::default().into(); + let io_costs: IoCosts = MemoryWeights::::default().into(); let expected_lazy_pages_costs = LazyPagesCosts { signal_read: 28_000_000.into(), @@ -337,21 +351,31 @@ fn lazy_page_costs_heuristic_test() { load_page_storage_data: 10_000_000.into(), }; - check_lazy_pages_costs(lazy_pages_costs, expected_lazy_pages_costs); + let result = check_lazy_pages_costs(io_costs.lazy_pages, expected_lazy_pages_costs); + + assert!(result.is_ok(), "{:#?}", result.err().unwrap()); + assert_eq!(result.unwrap(), expected_lazy_pages_costs_count()); } /// Check that it is not possible to write/change memory pages too cheaply, /// because this may cause runtime heap memory overflow. #[test] fn write_is_not_too_cheap() { - let costs: LazyPagesCosts = MemoryWeights::::default().into(); + let costs: IoCosts = MemoryWeights::::default().into(); let cheapest_write = u64::MAX - .min(costs.signal_write.cost_for_one()) - .min(costs.signal_read.cost_for_one() + costs.signal_write_after_read.cost_for_one()) - .min(costs.host_func_write.cost_for_one()) - .min(costs.host_func_read.cost_for_one() + costs.host_func_write_after_read.cost_for_one()); + .min(costs.lazy_pages.signal_write.cost_for_one()) + .min( + costs.lazy_pages.signal_read.cost_for_one() + + costs.lazy_pages.signal_write_after_read.cost_for_one(), + ) + .min(costs.lazy_pages.host_func_write.cost_for_one()) + .min( + costs.lazy_pages.host_func_read.cost_for_one() + + costs.lazy_pages.host_func_write_after_read.cost_for_one(), + ); let block_max_gas = 3 * 10 ^ 12; // 3 seconds let runtime_heap_size_in_wasm_pages = 0x4000; // 1GB + assert!((block_max_gas / cheapest_write) < runtime_heap_size_in_wasm_pages); } diff --git a/runtime/vara/src/tests/utils.rs b/runtime/vara/src/tests/utils.rs new file mode 100644 index 00000000000..c40a88e200f --- /dev/null +++ b/runtime/vara/src/tests/utils.rs @@ -0,0 +1,545 @@ +// This file is part of Gear. + +// Copyright (C) 2021-2024 Gear Technologies Inc. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use super::*; +use crate::Runtime; + +use gear_core::costs::{IoCosts, LazyPagesCosts, PagesCosts}; +use pallet_gear::{InstructionWeights, MemoryWeights, SyscallWeights}; + +const INSTRUCTIONS_SPREAD: u8 = 50; +const SYSCALL_SPREAD: u8 = 10; +const PAGES_SPREAD: u8 = 10; + +/// Structure to hold weight expectation +pub(super) struct WeightExpectation { + weight: u64, + expected: u64, + spread: u8, + name: &'static str, +} + +impl WeightExpectation { + pub(super) fn new(weight: u64, expected: u64, spread: u8, name: &'static str) -> Self { + Self { + weight, + expected, + spread, + name, + } + } + + pub(super) fn check(&self) -> Result<(), String> { + let left = self.expected - self.expected * self.spread as u64 / 100; + let right = self.expected + self.expected * self.spread as u64 / 100; + + if left > self.weight || self.weight > right { + return Err(format!("Instruction [{}]. Weight is {} ps. Expected weight is {} ps. {}% spread interval: [{left} ps, {right} ps]", self.name, self.weight, self.expected, self.spread)); + } + + Ok(()) + } +} + +pub(super) fn check_expectations(expectations: &[WeightExpectation]) -> Result> { + let errors = expectations + .iter() + .filter_map(|expectation| { + if let Err(err) = expectation.check() { + Some(err) + } else { + None + } + }) + .collect::>(); + + if errors.is_empty() { + Ok(expectations.iter().count()) + } else { + Err(errors) + } +} + +pub(super) fn expected_instructions_weights_count() -> usize { + let InstructionWeights { + i64const: _, + i64load: _, + i32load: _, + i64store: _, + i32store: _, + select: _, + r#if: _, + br: _, + br_if: _, + br_table: _, + br_table_per_entry: _, + call: _, + call_indirect: _, + call_indirect_per_param: _, + call_per_local: _, + local_get: _, + local_set: _, + local_tee: _, + global_get: _, + global_set: _, + memory_current: _, + i64clz: _, + i32clz: _, + i64ctz: _, + i32ctz: _, + i64popcnt: _, + i32popcnt: _, + i64eqz: _, + i32eqz: _, + i32extend8s: _, + i32extend16s: _, + i64extend8s: _, + i64extend16s: _, + i64extend32s: _, + i64extendsi32: _, + i64extendui32: _, + i32wrapi64: _, + i64eq: _, + i32eq: _, + i64ne: _, + i32ne: _, + i64lts: _, + i32lts: _, + i64ltu: _, + i32ltu: _, + i64gts: _, + i32gts: _, + i64gtu: _, + i32gtu: _, + i64les: _, + i32les: _, + i64leu: _, + i32leu: _, + i64ges: _, + i32ges: _, + i64geu: _, + i32geu: _, + i64add: _, + i32add: _, + i64sub: _, + i32sub: _, + i64mul: _, + i32mul: _, + i64divs: _, + i32divs: _, + i64divu: _, + i32divu: _, + i64rems: _, + i32rems: _, + i64remu: _, + i32remu: _, + i64and: _, + i32and: _, + i64or: _, + i32or: _, + i64xor: _, + i32xor: _, + i64shl: _, + i32shl: _, + i64shrs: _, + i32shrs: _, + i64shru: _, + i32shru: _, + i64rotl: _, + i32rotl: _, + i64rotr: _, + i32rotr: _, + version: _, + _phantom: _, + } = InstructionWeights::::default(); + + // total number of instructions + 87 +} + +pub(super) fn expected_syscall_weights_count() -> usize { + let SyscallWeights { + alloc: _, + free: _, + free_range: _, + free_range_per_page: _, + gr_reserve_gas: _, + gr_unreserve_gas: _, + gr_system_reserve_gas: _, + gr_gas_available: _, + gr_message_id: _, + gr_program_id: _, + gr_source: _, + gr_value: _, + gr_value_available: _, + gr_size: _, + gr_read: _, + gr_read_per_byte: _, + gr_env_vars: _, + gr_block_height: _, + gr_block_timestamp: _, + gr_random: _, + gr_reply_deposit: _, + gr_send: _, + gr_send_per_byte: _, + gr_send_wgas: _, + gr_send_wgas_per_byte: _, + gr_send_init: _, + gr_send_push: _, + gr_send_push_per_byte: _, + gr_send_commit: _, + gr_send_commit_wgas: _, + gr_reservation_send: _, + gr_reservation_send_per_byte: _, + gr_reservation_send_commit: _, + gr_reply_commit: _, + gr_reply_commit_wgas: _, + gr_reservation_reply: _, + gr_reservation_reply_per_byte: _, + gr_reservation_reply_commit: _, + gr_reply_push: _, + gr_reply: _, + gr_reply_per_byte: _, + gr_reply_wgas: _, + gr_reply_wgas_per_byte: _, + gr_reply_push_per_byte: _, + gr_reply_to: _, + gr_signal_code: _, + gr_signal_from: _, + gr_reply_input: _, + gr_reply_input_wgas: _, + gr_reply_push_input: _, + gr_reply_push_input_per_byte: _, + gr_send_input: _, + gr_send_input_wgas: _, + gr_send_push_input: _, + gr_send_push_input_per_byte: _, + gr_debug: _, + gr_debug_per_byte: _, + gr_reply_code: _, + gr_exit: _, + gr_leave: _, + gr_wait: _, + gr_wait_for: _, + gr_wait_up_to: _, + gr_wake: _, + gr_create_program: _, + gr_create_program_payload_per_byte: _, + gr_create_program_salt_per_byte: _, + gr_create_program_wgas: _, + gr_create_program_wgas_payload_per_byte: _, + gr_create_program_wgas_salt_per_byte: _, + _phantom: __phantom, + } = SyscallWeights::::default(); + + // total number of syscalls + 70 +} + +pub(super) fn expected_pages_costs_count() -> usize { + let IoCosts { + lazy_pages: _, + common: + PagesCosts { + load_page_data: _, + upload_page_data: _, + mem_grow: _, + mem_grow_per_page: _, + parachain_read_heuristic: _, + }, + } = MemoryWeights::::default().into(); + + // total number of lazy pages costs + 5 +} + +pub(super) fn expected_lazy_pages_costs_count() -> usize { + let IoCosts { + common: _, + lazy_pages: + LazyPagesCosts { + signal_read: _, + signal_write: _, + signal_write_after_read: _, + host_func_read: _, + host_func_write: _, + host_func_write_after_read: _, + load_page_storage_data: _, + }, + } = MemoryWeights::::default().into(); + + // total number of lazy pages costs + 7 +} + +/// Check that the weights of instructions are within the expected range +pub(super) fn check_instructions_weights( + weights: InstructionWeights, + expected: InstructionWeights, +) -> Result> { + macro_rules! expectation { + ($inst_name:ident) => { + WeightExpectation::new( + weights.$inst_name.into(), + expected.$inst_name.into(), + INSTRUCTIONS_SPREAD, + stringify!($inst_name), + ) + }; + } + + let expectations = vec![ + expectation!(i64const), + expectation!(i64load), + expectation!(i32load), + expectation!(i64store), + expectation!(i32store), + expectation!(select), + expectation!(r#if), + expectation!(br), + expectation!(br_if), + expectation!(br_table), + expectation!(br_table_per_entry), + expectation!(call), + expectation!(call_indirect), + expectation!(call_indirect_per_param), + expectation!(call_per_local), + expectation!(local_get), + expectation!(local_set), + expectation!(local_tee), + expectation!(global_get), + expectation!(global_set), + expectation!(memory_current), + expectation!(i64clz), + expectation!(i32clz), + expectation!(i64ctz), + expectation!(i32ctz), + expectation!(i64popcnt), + expectation!(i32popcnt), + expectation!(i64eqz), + expectation!(i32eqz), + expectation!(i32extend8s), + expectation!(i32extend16s), + expectation!(i64extend8s), + expectation!(i64extend16s), + expectation!(i64extend32s), + expectation!(i64extendsi32), + expectation!(i64extendui32), + expectation!(i32wrapi64), + expectation!(i64eq), + expectation!(i32eq), + expectation!(i64ne), + expectation!(i32ne), + expectation!(i64lts), + expectation!(i32lts), + expectation!(i64ltu), + expectation!(i32ltu), + expectation!(i64gts), + expectation!(i32gts), + expectation!(i64gtu), + expectation!(i32gtu), + expectation!(i64les), + expectation!(i32les), + expectation!(i64leu), + expectation!(i32leu), + expectation!(i64ges), + expectation!(i32ges), + expectation!(i64geu), + expectation!(i32geu), + expectation!(i64add), + expectation!(i32add), + expectation!(i64sub), + expectation!(i32sub), + expectation!(i64mul), + expectation!(i32mul), + expectation!(i64divs), + expectation!(i32divs), + expectation!(i64divu), + expectation!(i32divu), + expectation!(i64rems), + expectation!(i32rems), + expectation!(i64remu), + expectation!(i32remu), + expectation!(i64and), + expectation!(i32and), + expectation!(i64or), + expectation!(i32or), + expectation!(i64xor), + expectation!(i32xor), + expectation!(i64shl), + expectation!(i32shl), + expectation!(i64shrs), + expectation!(i32shrs), + expectation!(i64shru), + expectation!(i32shru), + expectation!(i64rotl), + expectation!(i32rotl), + expectation!(i64rotr), + expectation!(i32rotr), + ]; + + check_expectations(&expectations) +} + +/// Check that the weights of syscalls are within the expected range +pub(super) fn check_syscall_weights( + weights: SyscallWeights, + expected: SyscallWeights, +) -> Result> { + macro_rules! expectation { + ($inst_name:ident) => { + WeightExpectation::new( + weights.$inst_name.ref_time(), + expected.$inst_name.ref_time(), + SYSCALL_SPREAD, + stringify!($inst_name), + ) + }; + } + + let expectations = vec![ + expectation!(alloc), + expectation!(free), + expectation!(free_range), + expectation!(free_range_per_page), + expectation!(gr_reserve_gas), + expectation!(gr_unreserve_gas), + expectation!(gr_system_reserve_gas), + expectation!(gr_gas_available), + expectation!(gr_message_id), + expectation!(gr_program_id), + expectation!(gr_source), + expectation!(gr_value), + expectation!(gr_value_available), + expectation!(gr_size), + expectation!(gr_read), + expectation!(gr_read_per_byte), + expectation!(gr_env_vars), + expectation!(gr_block_height), + expectation!(gr_block_timestamp), + expectation!(gr_random), + expectation!(gr_reply_deposit), + expectation!(gr_send), + expectation!(gr_send_per_byte), + expectation!(gr_send_wgas), + expectation!(gr_send_wgas_per_byte), + expectation!(gr_send_init), + expectation!(gr_send_push), + expectation!(gr_send_push_per_byte), + expectation!(gr_send_commit), + expectation!(gr_send_commit_wgas), + expectation!(gr_reservation_send), + expectation!(gr_reservation_send_per_byte), + expectation!(gr_reservation_send_commit), + expectation!(gr_reply_commit), + expectation!(gr_reply_commit_wgas), + expectation!(gr_reservation_reply), + expectation!(gr_reservation_reply_per_byte), + expectation!(gr_reservation_reply_commit), + expectation!(gr_reply_push), + expectation!(gr_reply), + expectation!(gr_reply_per_byte), + expectation!(gr_reply_wgas), + expectation!(gr_reply_wgas_per_byte), + expectation!(gr_reply_push_per_byte), + expectation!(gr_reply_to), + expectation!(gr_signal_code), + expectation!(gr_signal_from), + expectation!(gr_reply_input), + expectation!(gr_reply_input_wgas), + expectation!(gr_reply_push_input), + expectation!(gr_reply_push_input_per_byte), + expectation!(gr_send_input), + expectation!(gr_send_input_wgas), + expectation!(gr_send_push_input), + expectation!(gr_send_push_input_per_byte), + expectation!(gr_debug), + expectation!(gr_debug_per_byte), + expectation!(gr_reply_code), + expectation!(gr_exit), + expectation!(gr_leave), + expectation!(gr_wait), + expectation!(gr_wait_for), + expectation!(gr_wait_up_to), + expectation!(gr_wake), + expectation!(gr_create_program), + expectation!(gr_create_program_payload_per_byte), + expectation!(gr_create_program_salt_per_byte), + expectation!(gr_create_program_wgas), + expectation!(gr_create_program_wgas_payload_per_byte), + expectation!(gr_create_program_wgas_salt_per_byte), + ]; + + check_expectations(&expectations) +} + +/// Check that the lazy-pages costs are within the expected range +pub(super) fn check_lazy_pages_costs( + lazy_pages_costs: LazyPagesCosts, + expected_lazy_pages_costs: LazyPagesCosts, +) -> Result> { + macro_rules! expectation { + ($inst_name:ident) => { + WeightExpectation::new( + lazy_pages_costs.$inst_name.cost_for_one(), + expected_lazy_pages_costs.$inst_name.cost_for_one(), + PAGES_SPREAD, + stringify!($inst_name), + ) + }; + } + + let expectations = vec![ + expectation!(signal_read), + expectation!(signal_write), + expectation!(signal_write_after_read), + expectation!(host_func_read), + expectation!(host_func_write), + expectation!(host_func_write_after_read), + expectation!(load_page_storage_data), + ]; + + check_expectations(&expectations) +} + +/// Check that the pages costs are within the expected range +pub(super) fn check_pages_costs( + page_costs: PagesCosts, + expected_page_costs: PagesCosts, +) -> Result> { + macro_rules! expectation { + ($inst_name:ident) => { + WeightExpectation::new( + page_costs.$inst_name.cost_for_one(), + expected_page_costs.$inst_name.cost_for_one(), + PAGES_SPREAD, + stringify!($inst_name), + ) + }; + } + + let expectations = vec![ + expectation!(load_page_data), + expectation!(upload_page_data), + expectation!(mem_grow), + expectation!(mem_grow_per_page), + expectation!(parachain_read_heuristic), + ]; + + check_expectations(&expectations) +} diff --git a/utils/weight-diff/src/main.rs b/utils/weight-diff/src/main.rs index 51f4056d94d..684e01a3104 100644 --- a/utils/weight-diff/src/main.rs +++ b/utils/weight-diff/src/main.rs @@ -308,6 +308,8 @@ const TYPE_LIST: &[&str] = &[ "MemoryCosts", "RentCosts", "InstantiationCosts", + "IoCosts", + "PagesCosts", "LazyPagesCosts", ];