mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 01:41:09 +00:00
Fix benchmarks! macro for non dispatchable code (#5100)
* Init allowing non dispatchable closure to be benchmarked. * Remove example, add it in timestamp * Fix nits. * Move test to example. * Update frame/example/src/lib.rs Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com> * Update frame/example/src/lib.rs Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com> * Apply review suggestion: move test to benchmarking crate. * Update frame/benchmarking/src/lib.rs Co-Authored-By: Bastian Köcher <bkchr@users.noreply.github.com> * Remove unused imports. Co-authored-by: Shawn Tabrizi <shawntabrizi@gmail.com> Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> Co-authored-by: Benjamin Kampmann <ben.kampmann@googlemail.com>
This commit is contained in:
Generated
+3
@@ -1456,6 +1456,8 @@ dependencies = [
|
||||
name = "frame-benchmarking"
|
||||
version = "2.0.0-alpha.3"
|
||||
dependencies = [
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"parity-scale-codec",
|
||||
"sp-api",
|
||||
"sp-io",
|
||||
@@ -4119,6 +4121,7 @@ dependencies = [
|
||||
name = "pallet-example"
|
||||
version = "2.0.0-alpha.3"
|
||||
dependencies = [
|
||||
"frame-benchmarking",
|
||||
"frame-support",
|
||||
"frame-system",
|
||||
"pallet-balances",
|
||||
|
||||
@@ -15,7 +15,17 @@ sp-runtime-interface = { version = "2.0.0-alpha.2", path = "../../primitives/run
|
||||
sp-runtime = { version = "2.0.0-alpha.2", path = "../../primitives/runtime", default-features = false }
|
||||
sp-std = { version = "2.0.0-alpha.2", path = "../../primitives/std", default-features = false }
|
||||
sp-io = { path = "../../primitives/io", default-features = false, version = "2.0.0-alpha.2" }
|
||||
frame-support = { version = "2.0.0-alpha.2", default-features = false, path = "../support" }
|
||||
frame-system = { version = "2.0.0-alpha.2", default-features = false, path = "../system" }
|
||||
|
||||
[features]
|
||||
default = [ "std" ]
|
||||
std = [ "sp-runtime-interface/std", "sp-runtime/std", "sp-api/std", "codec/std", "sp-std/std" ]
|
||||
std = [
|
||||
"codec/std",
|
||||
"sp-runtime-interface/std",
|
||||
"sp-runtime/std",
|
||||
"sp-api/std",
|
||||
"sp-std/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
]
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
mod tests;
|
||||
mod utils;
|
||||
pub use utils::*;
|
||||
#[doc(hidden)]
|
||||
@@ -82,15 +83,14 @@ pub use sp_io::storage::root as storage_root;
|
||||
/// foo {
|
||||
/// let caller = account::<T>(b"caller", 0, benchmarks_seed);
|
||||
/// let l = ...;
|
||||
/// } _(Origin::Signed(caller), vec![0u8; l])
|
||||
/// }: _(Origin::Signed(caller), vec![0u8; l])
|
||||
///
|
||||
/// // second dispatchable: bar; this is a root dispatchable and accepts a `u8` vector of size
|
||||
/// // `l`. We don't want it preininitialised like before so we override using the `=> ()`
|
||||
/// // notation.
|
||||
/// // `l`. We don't want it preininitialised like before so we override using the `=> ()` notation.
|
||||
/// // In this case, we explicitly name the call using `bar` instead of `_`.
|
||||
/// bar {
|
||||
/// let l = _ .. _ => ();
|
||||
/// } bar(Origin::Root, vec![0u8; l])
|
||||
/// }: bar(Origin::Root, vec![0u8; l])
|
||||
///
|
||||
/// // third dispatchable: baz; this is a user dispatchable. It isn't dependent on length like the
|
||||
/// // other two but has its own complexity `c` that needs setting up. It uses `caller` (in the
|
||||
@@ -100,13 +100,13 @@ pub use sp_io::storage::root as storage_root;
|
||||
/// baz1 {
|
||||
/// let caller = account::<T>(b"caller", 0, benchmarks_seed);
|
||||
/// let c = 0 .. 10 => setup_c(&caller, c);
|
||||
/// } baz(Origin::Signed(caller))
|
||||
/// }: baz(Origin::Signed(caller))
|
||||
///
|
||||
/// // this is a second benchmark of the baz dispatchable with a different setup.
|
||||
/// baz2 {
|
||||
/// let caller = account::<T>(b"caller", 0, benchmarks_seed);
|
||||
/// let c = 0 .. 10 => setup_c_in_some_other_way(&caller, c);
|
||||
/// } baz(Origin::Signed(caller))
|
||||
/// }: baz(Origin::Signed(caller))
|
||||
///
|
||||
/// // this is benchmarking some code that is not a dispatchable.
|
||||
/// populate_a_set {
|
||||
@@ -115,7 +115,7 @@ pub use sp_io::storage::root as storage_root;
|
||||
/// for i in 0..x {
|
||||
/// m.insert(i);
|
||||
/// }
|
||||
/// } { m.into_iter().collect::<BTreeSet>() }
|
||||
/// }: { m.into_iter().collect::<BTreeSet>() }
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
@@ -134,97 +134,6 @@ macro_rules! benchmarks {
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_benchmark {
|
||||
(
|
||||
$( $name:ident ),*
|
||||
) => {
|
||||
impl<T: Trait> $crate::Benchmarking<$crate::BenchmarkResults> for Module<T> {
|
||||
fn run_benchmark(
|
||||
extrinsic: Vec<u8>,
|
||||
lowest_range_values: Vec<u32>,
|
||||
highest_range_values: Vec<u32>,
|
||||
steps: Vec<u32>,
|
||||
repeat: u32,
|
||||
) -> Result<Vec<$crate::BenchmarkResults>, &'static str> {
|
||||
// Map the input to the selected benchmark.
|
||||
let extrinsic = sp_std::str::from_utf8(extrinsic.as_slice())
|
||||
.map_err(|_| "Could not find extrinsic")?;
|
||||
let selected_benchmark = match extrinsic {
|
||||
$( stringify!($name) => SelectedBenchmark::$name, )*
|
||||
_ => return Err("Could not find extrinsic."),
|
||||
};
|
||||
|
||||
// Warm up the DB
|
||||
$crate::benchmarking::commit_db();
|
||||
$crate::benchmarking::wipe_db();
|
||||
|
||||
let components = <SelectedBenchmark as $crate::BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::components(&selected_benchmark);
|
||||
let mut results: Vec<$crate::BenchmarkResults> = Vec::new();
|
||||
|
||||
// Default number of steps for a component.
|
||||
let mut prev_steps = 10;
|
||||
|
||||
// Select the component we will be benchmarking. Each component will be benchmarked.
|
||||
for (idx, (name, low, high)) in components.iter().enumerate() {
|
||||
// Get the number of steps for this component.
|
||||
let steps = steps.get(idx).cloned().unwrap_or(prev_steps);
|
||||
prev_steps = steps;
|
||||
|
||||
let lowest = lowest_range_values.get(idx).cloned().unwrap_or(*low);
|
||||
let highest = highest_range_values.get(idx).cloned().unwrap_or(*high);
|
||||
|
||||
let diff = highest - lowest;
|
||||
|
||||
// Create up to `STEPS` steps for that component between high and low.
|
||||
let step_size = (diff / steps).max(1);
|
||||
let num_of_steps = diff / step_size + 1;
|
||||
|
||||
for s in 0..num_of_steps {
|
||||
// This is the value we will be testing for component `name`
|
||||
let component_value = lowest + step_size * s;
|
||||
|
||||
// Select the max value for all the other components.
|
||||
let c: Vec<($crate::BenchmarkParameter, u32)> = components.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, (n, l, h))|
|
||||
if n == name {
|
||||
(*n, component_value)
|
||||
} else {
|
||||
(*n, *highest_range_values.get(idx).unwrap_or(h))
|
||||
}
|
||||
)
|
||||
.collect();
|
||||
|
||||
// Run the benchmark `repeat` times.
|
||||
for _ in 0..repeat {
|
||||
// Set up the externalities environment for the setup we want to benchmark.
|
||||
let (call, caller) = <SelectedBenchmark as $crate::BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>>>::instance(&selected_benchmark, &c)?;
|
||||
// Commit the externalities to the database, flushing the DB cache.
|
||||
// This will enable worst case scenario for reading from the database.
|
||||
$crate::benchmarking::commit_db();
|
||||
// Time the extrinsic logic.
|
||||
let start_extrinsic = $crate::benchmarking::current_time();
|
||||
call.dispatch(caller.into())?;
|
||||
let finish_extrinsic = $crate::benchmarking::current_time();
|
||||
let elapsed_extrinsic = finish_extrinsic - start_extrinsic;
|
||||
// Time the storage root recalculation.
|
||||
let start_storage_root = $crate::benchmarking::current_time();
|
||||
$crate::storage_root();
|
||||
let finish_storage_root = $crate::benchmarking::current_time();
|
||||
let elapsed_storage_root = finish_storage_root - start_storage_root;
|
||||
results.push((c.clone(), elapsed_extrinsic, elapsed_storage_root));
|
||||
// Wipe the DB back to the genesis state.
|
||||
$crate::benchmarking::wipe_db();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(results);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[allow(missing_docs)]
|
||||
macro_rules! benchmarks_iter {
|
||||
@@ -247,14 +156,16 @@ macro_rules! benchmarks_iter {
|
||||
$( $rest:tt )*
|
||||
) => {
|
||||
$crate::benchmarks_iter! {
|
||||
{ $( $common )* } ( $( $names )* ) $name { $( $code )* }: { Ok((crate::Call::<T>::$dispatch($($arg),*), $origin)) } $( $rest )*
|
||||
{ $( $common )* } ( $( $names )* ) $name { $( $code )* }: {
|
||||
Call::<T>::$dispatch($($arg),*).dispatch($origin.into())?;
|
||||
} $( $rest )*
|
||||
}
|
||||
};
|
||||
// iteration arm:
|
||||
(
|
||||
{ $( $common:tt )* }
|
||||
( $( $names:ident )* )
|
||||
$name:ident { $( $code:tt )* }: { $eval:expr }
|
||||
$name:ident { $( $code:tt )* }: $eval:block
|
||||
$( $rest:tt )*
|
||||
) => {
|
||||
$crate::benchmark_backend! {
|
||||
@@ -277,7 +188,7 @@ macro_rules! benchmark_backend {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( PRE { $( $pre_parsed:tt )* } )*
|
||||
} { $eval:expr } {
|
||||
} { $eval:block } {
|
||||
let $pre_id:tt : $pre_ty:ty = $pre_ex:expr;
|
||||
$( $rest:tt )*
|
||||
} ) => {
|
||||
@@ -292,7 +203,7 @@ macro_rules! benchmark_backend {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
} { $eval:block } {
|
||||
let $param:ident in ( $param_from:expr ) .. $param_to:expr => $param_instancer:expr;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
@@ -308,7 +219,7 @@ macro_rules! benchmark_backend {
|
||||
$( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
} { $eval:block } {
|
||||
let $param:ident in ...;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
@@ -331,7 +242,7 @@ macro_rules! benchmark_backend {
|
||||
$( { $common:ident , $common_from:tt , $common_to:expr , $common_instancer:expr } )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
} { $eval:block } {
|
||||
let $param:ident in _ .. _ => $param_instancer:expr ;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
@@ -354,7 +265,7 @@ macro_rules! benchmark_backend {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
} { $eval:block } {
|
||||
let $param:ident in $param_from:tt .. $param_to:expr => $param_instancer:expr ;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
@@ -370,7 +281,7 @@ macro_rules! benchmark_backend {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
} { $eval:block } {
|
||||
let $param:ident in $param_from:tt .. $param_to:expr;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
@@ -386,7 +297,7 @@ macro_rules! benchmark_backend {
|
||||
$( $common:tt )*
|
||||
} {
|
||||
$( $parsed:tt )*
|
||||
} { $eval:expr } {
|
||||
} { $eval:block } {
|
||||
let $pre_id:tt = $pre_ex:expr;
|
||||
$( $rest:tt )*
|
||||
}) => {
|
||||
@@ -403,11 +314,11 @@ macro_rules! benchmark_backend {
|
||||
} {
|
||||
$( PRE { $pre_id:tt , $pre_ty:ty , $pre_ex:expr } )*
|
||||
$( PARAM { $param:ident , $param_from:expr , $param_to:expr , $param_instancer:expr } )*
|
||||
} { $eval:expr } { $( $post:tt )* } ) => {
|
||||
} { $eval:block } { $( $post:tt )* } ) => {
|
||||
#[allow(non_camel_case_types)]
|
||||
struct $name;
|
||||
#[allow(unused_variables)]
|
||||
impl<T: Trait> $crate::BenchmarkingSetup<T, crate::Call<T>, RawOrigin<T::AccountId>> for $name {
|
||||
impl<T: Trait> $crate::BenchmarkingSetup<T> for $name {
|
||||
fn components(&self) -> Vec<($crate::BenchmarkParameter, u32, u32)> {
|
||||
vec! [
|
||||
$(
|
||||
@@ -417,7 +328,7 @@ macro_rules! benchmark_backend {
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[($crate::BenchmarkParameter, u32)])
|
||||
-> Result<(crate::Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
-> Result<Box<dyn FnOnce() -> Result<(), &'static str>>, &'static str>
|
||||
{
|
||||
$(
|
||||
let $common = $common_from;
|
||||
@@ -431,7 +342,8 @@ macro_rules! benchmark_backend {
|
||||
)*
|
||||
$( $param_instancer ; )*
|
||||
$( $post )*
|
||||
$eval
|
||||
|
||||
Ok(Box::new(move || -> Result<(), &'static str> { $eval; Ok(()) }))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,28 +375,116 @@ macro_rules! selected_benchmark {
|
||||
}
|
||||
|
||||
// Allow us to select a benchmark from the list of available benchmarks.
|
||||
impl<T: Trait> $crate::BenchmarkingSetup<T, Call<T>, RawOrigin<T::AccountId>> for SelectedBenchmark {
|
||||
impl<T: Trait> $crate::BenchmarkingSetup<T> for SelectedBenchmark {
|
||||
fn components(&self) -> Vec<($crate::BenchmarkParameter, u32, u32)> {
|
||||
match self {
|
||||
$( Self::$bench => <$bench as $crate::BenchmarkingSetup<
|
||||
T,
|
||||
Call<T>,
|
||||
RawOrigin<T::AccountId>,
|
||||
>>::components(&$bench), )*
|
||||
$( Self::$bench => <$bench as $crate::BenchmarkingSetup<T>>::components(&$bench), )*
|
||||
}
|
||||
}
|
||||
|
||||
fn instance(&self, components: &[($crate::BenchmarkParameter, u32)])
|
||||
-> Result<(Call<T>, RawOrigin<T::AccountId>), &'static str>
|
||||
-> Result<Box<dyn FnOnce() -> Result<(), &'static str>>, &'static str>
|
||||
{
|
||||
match self {
|
||||
$( Self::$bench => <$bench as $crate::BenchmarkingSetup<
|
||||
T,
|
||||
Call<T>,
|
||||
RawOrigin<T::AccountId>,
|
||||
>>::instance(&$bench, components), )*
|
||||
$( Self::$bench => <$bench as $crate::BenchmarkingSetup<T>>::instance(&$bench, components), )*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_benchmark {
|
||||
(
|
||||
$( $name:ident ),*
|
||||
) => {
|
||||
impl<T: Trait> $crate::Benchmarking<$crate::BenchmarkResults> for Module<T> {
|
||||
fn run_benchmark(
|
||||
extrinsic: Vec<u8>,
|
||||
lowest_range_values: Vec<u32>,
|
||||
highest_range_values: Vec<u32>,
|
||||
steps: Vec<u32>,
|
||||
repeat: u32,
|
||||
) -> Result<Vec<$crate::BenchmarkResults>, &'static str> {
|
||||
// Map the input to the selected benchmark.
|
||||
let extrinsic = sp_std::str::from_utf8(extrinsic.as_slice())
|
||||
.map_err(|_| "`extrinsic` is not a valid utf8 string!")?;
|
||||
let selected_benchmark = match extrinsic {
|
||||
$( stringify!($name) => SelectedBenchmark::$name, )*
|
||||
_ => return Err("Could not find extrinsic."),
|
||||
};
|
||||
|
||||
// Warm up the DB
|
||||
$crate::benchmarking::commit_db();
|
||||
$crate::benchmarking::wipe_db();
|
||||
|
||||
let components = <SelectedBenchmark as $crate::BenchmarkingSetup<T>>::components(&selected_benchmark);
|
||||
let mut results: Vec<$crate::BenchmarkResults> = Vec::new();
|
||||
|
||||
// Default number of steps for a component.
|
||||
let mut prev_steps = 10;
|
||||
|
||||
// Select the component we will be benchmarking. Each component will be benchmarked.
|
||||
for (idx, (name, low, high)) in components.iter().enumerate() {
|
||||
// Get the number of steps for this component.
|
||||
let steps = steps.get(idx).cloned().unwrap_or(prev_steps);
|
||||
prev_steps = steps;
|
||||
|
||||
let lowest = lowest_range_values.get(idx).cloned().unwrap_or(*low);
|
||||
let highest = highest_range_values.get(idx).cloned().unwrap_or(*high);
|
||||
|
||||
let diff = highest - lowest;
|
||||
|
||||
// Create up to `STEPS` steps for that component between high and low.
|
||||
let step_size = (diff / steps).max(1);
|
||||
let num_of_steps = diff / step_size + 1;
|
||||
|
||||
for s in 0..num_of_steps {
|
||||
// This is the value we will be testing for component `name`
|
||||
let component_value = lowest + step_size * s;
|
||||
|
||||
// Select the max value for all the other components.
|
||||
let c: Vec<($crate::BenchmarkParameter, u32)> = components.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, (n, _, h))|
|
||||
if n == name {
|
||||
(*n, component_value)
|
||||
} else {
|
||||
(*n, *highest_range_values.get(idx).unwrap_or(h))
|
||||
}
|
||||
)
|
||||
.collect();
|
||||
|
||||
// Run the benchmark `repeat` times.
|
||||
for _ in 0..repeat {
|
||||
// Set up the externalities environment for the setup we want to benchmark.
|
||||
let closure_to_benchmark = <SelectedBenchmark as $crate::BenchmarkingSetup<T>>::instance(&selected_benchmark, &c)?;
|
||||
|
||||
// Commit the externalities to the database, flushing the DB cache.
|
||||
// This will enable worst case scenario for reading from the database.
|
||||
$crate::benchmarking::commit_db();
|
||||
|
||||
// Time the extrinsic logic.
|
||||
let start_extrinsic = $crate::benchmarking::current_time();
|
||||
closure_to_benchmark()?;
|
||||
let finish_extrinsic = $crate::benchmarking::current_time();
|
||||
let elapsed_extrinsic = finish_extrinsic - start_extrinsic;
|
||||
|
||||
// Time the storage root recalculation.
|
||||
let start_storage_root = $crate::benchmarking::current_time();
|
||||
$crate::storage_root();
|
||||
let finish_storage_root = $crate::benchmarking::current_time();
|
||||
let elapsed_storage_root = finish_storage_root - start_storage_root;
|
||||
|
||||
results.push((c.clone(), elapsed_extrinsic, elapsed_storage_root));
|
||||
|
||||
// Wipe the DB back to the genesis state.
|
||||
$crate::benchmarking::wipe_db();
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(results);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright 2020 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Substrate 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.
|
||||
|
||||
// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Tests for the module.
|
||||
|
||||
#![cfg(test)]
|
||||
|
||||
use super::*;
|
||||
use codec::Decode;
|
||||
use sp_std::prelude::*;
|
||||
use sp_runtime::{
|
||||
traits::{Dispatchable, BlakeTwo256, IdentityLookup},
|
||||
testing::{H256, Header},
|
||||
};
|
||||
use frame_support::{dispatch::DispatchResult, decl_module, impl_outer_origin};
|
||||
use frame_system::{RawOrigin, ensure_signed, ensure_none};
|
||||
|
||||
decl_module! {
|
||||
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
|
||||
fn dummy(origin, _n: u32) -> DispatchResult {
|
||||
let _sender = ensure_signed(origin)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn other_dummy(origin, _n: u32) -> DispatchResult {
|
||||
let _sender = ensure_none(origin)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_outer_origin! {
|
||||
pub enum Origin for Test where system = frame_system {}
|
||||
}
|
||||
|
||||
pub trait Trait {
|
||||
type Event;
|
||||
type BlockNumber;
|
||||
type AccountId: 'static + Default + Decode;
|
||||
type Origin: From<frame_system::RawOrigin<Self::AccountId>> + Into<Result<RawOrigin<Self::AccountId>, Self::Origin>>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct Test;
|
||||
|
||||
impl frame_system::Trait for Test {
|
||||
type Origin = Origin;
|
||||
type Index = u64;
|
||||
type BlockNumber = u64;
|
||||
type Hash = H256;
|
||||
type Call = ();
|
||||
type Hashing = BlakeTwo256;
|
||||
type AccountId = u64;
|
||||
type Lookup = IdentityLookup<Self::AccountId>;
|
||||
type Header = Header;
|
||||
type Event = ();
|
||||
type BlockHashCount = ();
|
||||
type MaximumBlockWeight = ();
|
||||
type MaximumBlockLength = ();
|
||||
type AvailableBlockRatio = ();
|
||||
type Version = ();
|
||||
type ModuleToIndex = ();
|
||||
type AccountData = ();
|
||||
type OnNewAccount = ();
|
||||
type OnKilledAccount = ();
|
||||
}
|
||||
|
||||
impl Trait for Test {
|
||||
type Event = ();
|
||||
type BlockNumber = u32;
|
||||
type Origin = Origin;
|
||||
type AccountId = u64;
|
||||
}
|
||||
|
||||
// This function basically just builds a genesis storage key/value store according to
|
||||
// our desired mockup.
|
||||
fn new_test_ext() -> sp_io::TestExternalities {
|
||||
frame_system::GenesisConfig::default().build_storage::<Test>().unwrap().into()
|
||||
}
|
||||
|
||||
benchmarks!{
|
||||
_ {
|
||||
// Define a common range for `b`.
|
||||
let b in 1 .. 1000 => ();
|
||||
}
|
||||
|
||||
dummy {
|
||||
let b in ...;
|
||||
let caller = account("caller", 0, 0);
|
||||
}: _ (RawOrigin::Signed(caller), b.into())
|
||||
|
||||
other_name {
|
||||
let b in ...;
|
||||
let caller = account("caller", 0, 0);
|
||||
}: other_dummy (RawOrigin::Signed(caller), b.into())
|
||||
|
||||
sort_vector {
|
||||
let x in 0 .. 10000;
|
||||
let mut m = Vec::<u32>::new();
|
||||
for i in 0..x {
|
||||
m.push(i);
|
||||
}
|
||||
}: {
|
||||
m.sort();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn benchmarks_macro_works() {
|
||||
// Check benchmark creation for `dummy`.
|
||||
let selected_benchmark = SelectedBenchmark::dummy;
|
||||
|
||||
let components = <SelectedBenchmark as BenchmarkingSetup<Test>>::components(&selected_benchmark);
|
||||
assert_eq!(components, vec![(BenchmarkParameter::b, 1, 1000)]);
|
||||
|
||||
let closure = <SelectedBenchmark as BenchmarkingSetup<Test>>::instance(
|
||||
&selected_benchmark,
|
||||
&[(BenchmarkParameter::b, 1)],
|
||||
).expect("failed to create closure");
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(closure(), Ok(()));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn benchmarks_macro_rename_works() {
|
||||
// Check benchmark creation for `other_dummy`.
|
||||
let selected_benchmark = SelectedBenchmark::other_name;
|
||||
let components = <SelectedBenchmark as BenchmarkingSetup<Test>>::components(&selected_benchmark);
|
||||
assert_eq!(components, vec![(BenchmarkParameter::b, 1, 1000)]);
|
||||
|
||||
let closure = <SelectedBenchmark as BenchmarkingSetup<Test>>::instance(
|
||||
&selected_benchmark,
|
||||
&[(BenchmarkParameter::b, 1)],
|
||||
).expect("failed to create closure");
|
||||
|
||||
new_test_ext().execute_with(|| {
|
||||
assert_eq!(closure(), Err("Bad origin"));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn benchmarks_macro_works_for_non_dispatchable() {
|
||||
let selected_benchmark = SelectedBenchmark::sort_vector;
|
||||
|
||||
let components = <SelectedBenchmark as BenchmarkingSetup<Test>>::components(&selected_benchmark);
|
||||
assert_eq!(components, vec![(BenchmarkParameter::x, 0, 10000)]);
|
||||
|
||||
let closure = <SelectedBenchmark as BenchmarkingSetup<Test>>::instance(
|
||||
&selected_benchmark,
|
||||
&[(BenchmarkParameter::x, 1)],
|
||||
).expect("failed to create closure");
|
||||
|
||||
assert_eq!(closure(), Ok(()));
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Interfaces, types and utils for benchmarking a FRAME runtime.
|
||||
|
||||
use codec::{Encode, Decode};
|
||||
use sp_std::vec::Vec;
|
||||
use sp_std::{vec::Vec, prelude::Box};
|
||||
use sp_io::hashing::blake2_256;
|
||||
use sp_runtime::RuntimeString;
|
||||
|
||||
@@ -93,12 +93,12 @@ pub trait Benchmarking<T> {
|
||||
}
|
||||
|
||||
/// The required setup for creating a benchmark.
|
||||
pub trait BenchmarkingSetup<T, Call, RawOrigin> {
|
||||
pub trait BenchmarkingSetup<T> {
|
||||
/// Return the components and their ranges which should be tested in this benchmark.
|
||||
fn components(&self) -> Vec<(BenchmarkParameter, u32, u32)>;
|
||||
|
||||
/// Set up the storage, and prepare a call and caller to test in a single run of the benchmark.
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)]) -> Result<(Call, RawOrigin), &'static str>;
|
||||
/// Set up the storage, and prepare a closure to test in a single run of the benchmark.
|
||||
fn instance(&self, components: &[(BenchmarkParameter, u32)]) -> Result<Box<dyn FnOnce() -> Result<(), &'static str>>, &'static str>;
|
||||
}
|
||||
|
||||
/// Grab an account, seeded by a name and index.
|
||||
|
||||
@@ -11,6 +11,7 @@ description = "FRAME example pallet"
|
||||
[dependencies]
|
||||
serde = { version = "1.0.101", optional = true }
|
||||
codec = { package = "parity-scale-codec", version = "1.2.0", default-features = false }
|
||||
frame-benchmarking = { version = "2.0.0-alpha.2", default-features = false, path = "../benchmarking" }
|
||||
frame-support = { version = "2.0.0-alpha.2", default-features = false, path = "../support" }
|
||||
frame-system = { version = "2.0.0-alpha.2", default-features = false, path = "../system" }
|
||||
pallet-balances = { version = "2.0.0-alpha.2", default-features = false, path = "../balances" }
|
||||
@@ -27,6 +28,7 @@ std = [
|
||||
"serde",
|
||||
"codec/std",
|
||||
"sp-runtime/std",
|
||||
"frame-benchmarking/std",
|
||||
"frame-support/std",
|
||||
"frame-system/std",
|
||||
"pallet-balances/std",
|
||||
|
||||
@@ -258,10 +258,12 @@ use frame_support::{
|
||||
dispatch::DispatchResult, decl_module, decl_storage, decl_event,
|
||||
weights::{SimpleDispatchInfo, DispatchInfo, DispatchClass, ClassifyDispatch, WeighData, Weight, PaysFee},
|
||||
};
|
||||
use frame_system::{self as system, ensure_signed, ensure_root};
|
||||
use sp_std::prelude::*;
|
||||
use frame_benchmarking::{benchmarks, account};
|
||||
use frame_system::{self as system, ensure_signed, ensure_root, RawOrigin};
|
||||
use codec::{Encode, Decode};
|
||||
use sp_runtime::{
|
||||
traits::{SignedExtension, Bounded, SaturatedConversion},
|
||||
traits::{SignedExtension, Bounded, SaturatedConversion, Dispatchable},
|
||||
transaction_validity::{
|
||||
ValidTransaction, TransactionValidityError, InvalidTransaction, TransactionValidity,
|
||||
},
|
||||
@@ -642,6 +644,42 @@ impl<T: Trait + Send + Sync> SignedExtension for WatchDummy<T> {
|
||||
}
|
||||
}
|
||||
|
||||
benchmarks!{
|
||||
_ {
|
||||
// Define a common range for `b`.
|
||||
let b in 1 .. 1000 => ();
|
||||
}
|
||||
|
||||
// This will measure the execution time of `accumulate_dummy` for b in [1..1000] range.
|
||||
accumulate_dummy {
|
||||
let b in ...;
|
||||
let caller = account("caller", 0, 0);
|
||||
}: _ (RawOrigin::Signed(caller), b.into())
|
||||
|
||||
// This will measure the execution time of `set_dummy` for b in [1..1000] range.
|
||||
set_dummy {
|
||||
let b in ...;
|
||||
let caller = account("caller", 0, 0);
|
||||
}: set_dummy (RawOrigin::Signed(caller), b.into())
|
||||
|
||||
// This will measure the execution time of `set_dummy` for b in [1..10] range.
|
||||
another_set_dummy {
|
||||
let b in 1 .. 10;
|
||||
let caller = account("caller", 0, 0);
|
||||
}: set_dummy (RawOrigin::Signed(caller), b.into())
|
||||
|
||||
// This will measure the execution time of sorting a vector.
|
||||
sort_vector {
|
||||
let x in 0 .. 10000;
|
||||
let mut m = Vec::<u32>::new();
|
||||
for i in 0..x {
|
||||
m.push(i);
|
||||
}
|
||||
}: {
|
||||
m.sort();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user