mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 17:57:56 +00:00
Add initial contract macro benchmarks (#9600)
* Add erc20 benchmarks * Fix typos Co-authored-by: Michael Müller <michi@parity.io> * Fix compilation issue on case sensitive fs Co-authored-by: Michael Müller <michi@parity.io>
This commit is contained in:
committed by
GitHub
parent
61941f2806
commit
13f3e25ebb
@@ -26,14 +26,12 @@
|
||||
|
||||
use crate::Config;
|
||||
use frame_support::traits::Get;
|
||||
use pwasm_utils::{
|
||||
parity_wasm::{
|
||||
builder,
|
||||
elements::{
|
||||
self, BlockType, CustomSection, FuncBody, Instruction, Instructions, Section, ValueType,
|
||||
},
|
||||
use pwasm_utils::parity_wasm::{
|
||||
builder,
|
||||
elements::{
|
||||
self, BlockType, CustomSection, External, FuncBody, Instruction, Instructions, Module,
|
||||
Section, ValueType,
|
||||
},
|
||||
stack_height::inject_limiter,
|
||||
};
|
||||
use sp_core::crypto::UncheckedFrom;
|
||||
use sp_runtime::traits::Hash;
|
||||
@@ -241,9 +239,8 @@ where
|
||||
|
||||
let mut code = contract.build();
|
||||
|
||||
// Inject stack height metering
|
||||
if def.inject_stack_metering {
|
||||
code = inject_limiter(code, T::Schedule::get().limits.stack_height).unwrap();
|
||||
code = inject_stack_metering::<T>(code);
|
||||
}
|
||||
|
||||
let code = code.to_bytes().unwrap();
|
||||
@@ -257,6 +254,34 @@ where
|
||||
T: Config,
|
||||
T::AccountId: UncheckedFrom<T::Hash> + AsRef<[u8]>,
|
||||
{
|
||||
/// Uses the supplied wasm module and instruments it when requested.
|
||||
pub fn instrumented(code: &[u8], inject_gas: bool, inject_stack: bool) -> Self {
|
||||
let module = {
|
||||
let mut module = Module::from_bytes(code).unwrap();
|
||||
if inject_gas {
|
||||
module = inject_gas_metering::<T>(module);
|
||||
}
|
||||
if inject_stack {
|
||||
module = inject_stack_metering::<T>(module);
|
||||
}
|
||||
module
|
||||
};
|
||||
let limits = module
|
||||
.import_section()
|
||||
.unwrap()
|
||||
.entries()
|
||||
.iter()
|
||||
.find_map(|e| if let External::Memory(mem) = e.external() { Some(mem) } else { None })
|
||||
.unwrap()
|
||||
.limits()
|
||||
.clone();
|
||||
let code = module.to_bytes().unwrap();
|
||||
let hash = T::Hashing::hash(&code);
|
||||
let memory =
|
||||
ImportedMemory { min_pages: limits.initial(), max_pages: limits.maximum().unwrap() };
|
||||
Self { code, hash, memory: Some(memory) }
|
||||
}
|
||||
|
||||
/// Creates a wasm module with an empty `call` and `deploy` function and nothing else.
|
||||
pub fn dummy() -> Self {
|
||||
ModuleDefinition::default().into()
|
||||
@@ -519,3 +544,14 @@ where
|
||||
{
|
||||
T::Schedule::get().limits.memory_pages
|
||||
}
|
||||
|
||||
fn inject_gas_metering<T: Config>(module: Module) -> Module {
|
||||
let schedule = T::Schedule::get();
|
||||
let gas_rules = schedule.rules(&module);
|
||||
pwasm_utils::inject_gas_counter(module, &gas_rules, "seal0").unwrap()
|
||||
}
|
||||
|
||||
fn inject_stack_metering<T: Config>(module: Module) -> Module {
|
||||
let height = T::Schedule::get().limits.stack_height;
|
||||
pwasm_utils::stack_height::inject_limiter(module, height).unwrap()
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ use self::{
|
||||
sandbox::Sandbox,
|
||||
};
|
||||
use crate::{
|
||||
exec::StorageKey,
|
||||
exec::{AccountIdOf, StorageKey},
|
||||
rent::Rent,
|
||||
schedule::{API_BENCHMARK_BATCH_SIZE, INSTR_BENCHMARK_BATCH_SIZE},
|
||||
storage::Storage,
|
||||
@@ -124,9 +124,9 @@ where
|
||||
.saturating_mul(<BalanceOf<T>>::from(storage_size) / 2u32.into())
|
||||
.saturating_add(T::DepositPerContract::get());
|
||||
|
||||
(storage_size, endowment)
|
||||
(Some(storage_size), endowment)
|
||||
},
|
||||
Endow::Max => (0u32.into(), Endow::max::<T>()),
|
||||
Endow::Max => (None, Endow::max::<T>()),
|
||||
};
|
||||
T::Currency::make_free_balance_be(&caller, caller_funding::<T>());
|
||||
let salt = vec![0xff];
|
||||
@@ -158,7 +158,9 @@ where
|
||||
};
|
||||
|
||||
let mut contract = result.alive_info()?;
|
||||
contract.storage_size = storage_size;
|
||||
if let Some(size) = storage_size {
|
||||
contract.storage_size = size;
|
||||
}
|
||||
ContractInfoOf::<T>::insert(&result.account_id, ContractInfo::Alive(contract));
|
||||
|
||||
Ok(result)
|
||||
@@ -278,6 +280,24 @@ fn caller_funding<T: Config>() -> BalanceOf<T> {
|
||||
BalanceOf::<T>::max_value() / 2u32.into()
|
||||
}
|
||||
|
||||
/// Load the specified contract file from disk by including it into the runtime.
|
||||
///
|
||||
/// We need to load a different version of ink! contracts when the benchmark is run as
|
||||
/// a test. This is because ink! contracts depend on the sizes of types that are defined
|
||||
/// differently in the test environment. Solang is more lax in that regard.
|
||||
macro_rules! load_benchmark {
|
||||
($name:expr) => {{
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
include_bytes!(concat!("../../benchmarks/", $name, ".wasm"))
|
||||
}
|
||||
#[cfg(test)]
|
||||
{
|
||||
include_bytes!(concat!("../../benchmarks/", $name, "_test.wasm"))
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
benchmarks! {
|
||||
where_clause { where
|
||||
T::AccountId: UncheckedFrom<T::Hash>,
|
||||
@@ -2536,6 +2556,88 @@ benchmarks! {
|
||||
#[cfg(not(feature = "std"))]
|
||||
return Err("Run this bench with a native runtime in order to see the schedule.");
|
||||
}: {}
|
||||
|
||||
// Execute one erc20 transfer using the ink! erc20 example contract.
|
||||
//
|
||||
// `g` is used to enable gas instrumentation to compare the performance impact of
|
||||
// that instrumentation at runtime.
|
||||
#[extra]
|
||||
ink_erc20_transfer {
|
||||
let g in 0 .. 1;
|
||||
let gas_metering = if g == 0 { false } else { true };
|
||||
let code = load_benchmark!("ink_erc20");
|
||||
let data = {
|
||||
let new: ([u8; 4], BalanceOf<T>) = ([0x9b, 0xae, 0x9d, 0x5e], 1000u32.into());
|
||||
new.encode()
|
||||
};
|
||||
let instance = Contract::<T>::new(
|
||||
WasmModule::instrumented(code, gas_metering, true), data, Endow::Max,
|
||||
)?;
|
||||
let data = {
|
||||
let transfer: ([u8; 4], AccountIdOf<T>, BalanceOf<T>) = (
|
||||
[0x84, 0xa1, 0x5d, 0xa1],
|
||||
account::<T::AccountId>("receiver", 0, 0),
|
||||
1u32.into(),
|
||||
);
|
||||
transfer.encode()
|
||||
};
|
||||
}: {
|
||||
<Contracts<T>>::bare_call(
|
||||
instance.caller,
|
||||
instance.account_id,
|
||||
0u32.into(),
|
||||
Weight::MAX,
|
||||
data,
|
||||
false,
|
||||
)
|
||||
.result?;
|
||||
}
|
||||
|
||||
// Execute one erc20 transfer using the open zeppelin erc20 contract compiled with solang.
|
||||
//
|
||||
// `g` is used to enable gas instrumentation to compare the performance impact of
|
||||
// that instrumentation at runtime.
|
||||
#[extra]
|
||||
solang_erc20_transfer {
|
||||
let g in 0 .. 1;
|
||||
let gas_metering = if g == 0 { false } else { true };
|
||||
let code = include_bytes!("../../benchmarks/solang_erc20.wasm");
|
||||
let caller = account::<T::AccountId>("instantiator", 0, 0);
|
||||
let mut balance = [0u8; 32];
|
||||
balance[0] = 100;
|
||||
let data = {
|
||||
let new: ([u8; 4], &str, &str, [u8; 32], AccountIdOf<T>) = (
|
||||
[0xa6, 0xf1, 0xf5, 0xe1],
|
||||
"KSM",
|
||||
"K",
|
||||
balance,
|
||||
caller.clone(),
|
||||
);
|
||||
new.encode()
|
||||
};
|
||||
let instance = Contract::<T>::with_caller(
|
||||
caller, WasmModule::instrumented(code, gas_metering, true), data, Endow::Max,
|
||||
)?;
|
||||
balance[0] = 1;
|
||||
let data = {
|
||||
let transfer: ([u8; 4], AccountIdOf<T>, [u8; 32]) = (
|
||||
[0x6a, 0x46, 0x73, 0x94],
|
||||
account::<T::AccountId>("receiver", 0, 0),
|
||||
balance,
|
||||
);
|
||||
transfer.encode()
|
||||
};
|
||||
}: {
|
||||
<Contracts<T>>::bare_call(
|
||||
instance.caller,
|
||||
instance.account_id,
|
||||
0u32.into(),
|
||||
Weight::MAX,
|
||||
data,
|
||||
false,
|
||||
)
|
||||
.result?;
|
||||
}
|
||||
}
|
||||
|
||||
impl_benchmark_test_suite!(
|
||||
|
||||
Reference in New Issue
Block a user