From e62e1ede2b6669fd07f57fd6a31da5730df7aae1 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Thu, 11 Mar 2021 19:49:48 +0100 Subject: [PATCH 01/42] init weight_meter --- weight-meter/Cargo.toml | 15 ++ weight-meter/README.md | 3 + weight-meter/src/lib.rs | 32 +++++ .../weight-meter-procedural/Cargo.toml | 17 +++ .../weight-meter-procedural/src/lib.rs | 133 ++++++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 weight-meter/Cargo.toml create mode 100644 weight-meter/README.md create mode 100644 weight-meter/src/lib.rs create mode 100644 weight-meter/weight-meter-procedural/Cargo.toml create mode 100644 weight-meter/weight-meter-procedural/src/lib.rs diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml new file mode 100644 index 000000000..b97d2ac09 --- /dev/null +++ b/weight-meter/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "weight-meter" +version = "0.1.0" +license = "Apache-2.0" +authors = ["Laminar Developers "] +edition = "2018" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +weight-meter-procedural = { path = "weight-meter-procedural" } + +[features] +runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] \ No newline at end of file diff --git a/weight-meter/README.md b/weight-meter/README.md new file mode 100644 index 000000000..5ecc3216f --- /dev/null +++ b/weight-meter/README.md @@ -0,0 +1,3 @@ +# Weight Meter + +work in progress... \ No newline at end of file diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs new file mode 100644 index 000000000..1f4097c88 --- /dev/null +++ b/weight-meter/src/lib.rs @@ -0,0 +1,32 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +// TODO: find a better way +static mut USED_WEIGHT: u64 = 0; +static mut NESTED: u64 = 0; + +pub fn using(m: u64) { + unsafe { + USED_WEIGHT = USED_WEIGHT.saturating_add(m); + } +} + +pub fn used_weight() -> u64 { + unsafe { USED_WEIGHT } +} + +pub fn start_with(m: u64) { + unsafe { + if NESTED == 0 { + USED_WEIGHT = m; + } + NESTED = NESTED.saturating_add(1); + } +} + +pub fn end() { + unsafe { + NESTED = NESTED.saturating_sub(1); + } +} + +pub use weight_meter_procedural::*; diff --git a/weight-meter/weight-meter-procedural/Cargo.toml b/weight-meter/weight-meter-procedural/Cargo.toml new file mode 100644 index 000000000..850be7581 --- /dev/null +++ b/weight-meter/weight-meter-procedural/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "weight-meter-procedural" +version = "0.1.0" +license = "Apache-2.0" +authors = ["Laminar Developers "] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.6" +quote = "1.0.3" +syn = { version = "1.0.58", features = ["full"] } + +[features] +runtime-benchmarks = [] \ No newline at end of file diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs new file mode 100644 index 000000000..b6451fd68 --- /dev/null +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -0,0 +1,133 @@ +extern crate proc_macro; +use proc_macro::TokenStream; +use syn::{ItemFn, FnArg, ImplItem, ImplItemMethod, Item, ItemMod, Attribute}; +use quote::{quote, ToTokens}; + +#[proc_macro_attribute] +pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { + let base_weight: syn::Expr = syn::parse(attr).unwrap(); + let ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); + (quote! { + #(#attrs)* + #vis #sig { + weight_meter::start_with(#base_weight); + let result = #block; + weight_meter::end(); + result + } + }).into() +} + + +#[proc_macro_attribute] +pub fn weight(attr: TokenStream, item: TokenStream) -> TokenStream { + let weight: syn::Expr = syn::parse(attr).unwrap(); + let ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); + (quote! { + #(#attrs)* + #vis #sig { + weight_meter::using(#weight); + #block + } + }).into() +} + +#[proc_macro_attribute] +pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream { + #[cfg(feature = "runtime-benchmarks")] // Inject methods if we're benchmarking + { + let mut methods: Vec = vec![]; + + let mut item: ItemMod = syn::parse(input).unwrap(); + let (brace, content) = item.content.clone().unwrap(); + + let method_names = find_methods(&content); + + // Generate methods dynamically + content.iter().for_each(|i| { + if let Item::Impl(x) = i { // implementation + x.items.iter().for_each(|x| { + if let ImplItem::Method(i) = x { // method + let method_name = i.sig.ident.to_string(); + if method_names.contains(&method_name) { + let call_method_name: proc_macro2::TokenStream = i.sig.ident.to_string().parse().unwrap(); + let inject_method: proc_macro2::TokenStream = format!("method_{}", method_name).parse().unwrap(); + let args = i.sig.inputs.clone().into_iter().collect::>(); + let inputs: Vec = i.sig.inputs + .iter() + .map(|x| argument_name(&x)) + .filter(|x| x != &"") + .map(|x| x.parse().unwrap()) + .collect(); + + let method = quote! { + #[pallet::weight(0)] + pub fn #inject_method(_origin: OriginFor, #(#args),*) -> DispatchResultWithPostInfo { + Self::#call_method_name(#(#inputs),*); + Ok(().into()) + } + }; + + let generated_method: ImplItemMethod = syn::parse(method.into()).unwrap(); + methods.push(ImplItem::from(generated_method)); + } + } + }); + } + }); + + // Inject methods into pallet::call impl + let new_content = content.into_iter().map(|item| { + if let Item::Impl(mut item_impl) = item { + if has_attribute(&item_impl.attrs, "pallet::call") { + println!("injected callable methods for inner methods {:?}", method_names); + item_impl.items.append(&mut methods); + } + return Item::from(item_impl); + } else { + item + } + }).collect::>(); + + // update content + item.content = Some((brace, new_content)); + + item.into_token_stream().into() + } + #[cfg(not(feature = "runtime-benchmarks"))] + input +} + +#[cfg(feature = "runtime-benchmarks")] +fn has_attribute(attrs: &Vec, attr: &str) -> bool { + if attrs.is_empty() { return false }; + let attributes = attrs.iter().map(|a| { + a.path.segments.iter().map(|p| p.ident.to_string()).collect::>().join("::") + }).collect::>(); + attributes.contains(&attr.to_string()) +} + +#[cfg(feature = "runtime-benchmarks")] +fn find_methods(content: &Vec) -> Vec { + let mut method_names = vec![]; + content.iter().for_each(|i| { + if let Item::Impl(x) = i { + x.items.iter().for_each(|x| { + if let ImplItem::Method(i) = x { + if has_attribute(&i.attrs, "weight_meter::weight") { + method_names.push(i.sig.ident.to_string()); + } + } + }) + } + }); + method_names +} + +#[cfg(feature = "runtime-benchmarks")] +fn argument_name(x: &FnArg) -> String { + match x { + FnArg::Receiver(_) => "".into(), + FnArg::Typed(a) => a.pat.to_token_stream().to_string(), + } +} \ No newline at end of file From 1ee5d6933ce1cb1fe1762bd5b064ffdfdcd3a29d Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Thu, 11 Mar 2021 22:23:30 +0100 Subject: [PATCH 02/42] update meter static var --- weight-meter/Cargo.toml | 3 +++ weight-meter/src/lib.rs | 43 +++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index b97d2ac09..15ae52344 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -9,7 +9,10 @@ edition = "2018" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +lazy_static = "1.4.0" +sp-std = {version = "3.0.0", default-fearures = false } weight-meter-procedural = { path = "weight-meter-procedural" } [features] +std = ["sp-std/std"] runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] \ No newline at end of file diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 1f4097c88..a9f7066d1 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -1,32 +1,41 @@ +// TODO: research if there's a better way #![cfg_attr(not(feature = "std"), no_std)] -// TODO: find a better way -static mut USED_WEIGHT: u64 = 0; -static mut NESTED: u64 = 0; +#[macro_use] +extern crate lazy_static; + +use sp_std::sync::Mutex; + +pub use weight_meter_procedural::*; + +#[derive(Default)] +struct State { + pub used_weight: u64, + pub nested: usize, +} + +lazy_static! { + static ref STATE: Mutex = Mutex::new(State::default()); +} pub fn using(m: u64) { - unsafe { - USED_WEIGHT = USED_WEIGHT.saturating_add(m); - } + let mut s = STATE.lock().unwrap(); + s.used_weight = s.used_weight.saturating_add(m); } pub fn used_weight() -> u64 { - unsafe { USED_WEIGHT } + STATE.lock().unwrap().used_weight } pub fn start_with(m: u64) { - unsafe { - if NESTED == 0 { - USED_WEIGHT = m; - } - NESTED = NESTED.saturating_add(1); + let mut s = STATE.lock().unwrap(); + if s.nested == 0 { + s.used_weight = m; } + s.nested = s.nested.saturating_add(1); } pub fn end() { - unsafe { - NESTED = NESTED.saturating_sub(1); - } + let mut s = STATE.lock().unwrap(); + s.nested = s.nested.saturating_sub(1); } - -pub use weight_meter_procedural::*; From 9250171e668f7c1018eb27d4fdd5abc0d2793b91 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Thu, 11 Mar 2021 22:26:20 +0100 Subject: [PATCH 03/42] update workspace --- Cargo.dev.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.dev.toml b/Cargo.dev.toml index a38c164db..4b8025012 100644 --- a/Cargo.dev.toml +++ b/Cargo.dev.toml @@ -16,6 +16,7 @@ members = [ "nft", "xtokens", "xcm-support", + "weight-meter", ] resolver = "2" From 8f85cf80962a7b85a4731f618b84d5760d1090fb Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Thu, 11 Mar 2021 22:35:15 +0100 Subject: [PATCH 04/42] fmt --- .../weight-meter-procedural/src/lib.rs | 197 ++++++++++-------- 1 file changed, 108 insertions(+), 89 deletions(-) diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index b6451fd68..633616fc0 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -1,133 +1,152 @@ extern crate proc_macro; use proc_macro::TokenStream; -use syn::{ItemFn, FnArg, ImplItem, ImplItemMethod, Item, ItemMod, Attribute}; use quote::{quote, ToTokens}; +use syn::{Attribute, FnArg, ImplItem, ImplItemMethod, Item, ItemFn, ItemMod}; #[proc_macro_attribute] pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { - let base_weight: syn::Expr = syn::parse(attr).unwrap(); - let ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); - (quote! { + let base_weight: syn::Expr = syn::parse(attr).unwrap(); + let ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); + (quote! { #(#attrs)* #vis #sig { - weight_meter::start_with(#base_weight); + weight_meter::start_with(#base_weight); let result = #block; weight_meter::end(); result } - }).into() + }) + .into() } - #[proc_macro_attribute] pub fn weight(attr: TokenStream, item: TokenStream) -> TokenStream { - let weight: syn::Expr = syn::parse(attr).unwrap(); - let ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); - (quote! { + let weight: syn::Expr = syn::parse(attr).unwrap(); + let ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); + (quote! { #(#attrs)* #vis #sig { - weight_meter::using(#weight); + weight_meter::using(#weight); #block } - }).into() + }) + .into() } #[proc_macro_attribute] pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream { - #[cfg(feature = "runtime-benchmarks")] // Inject methods if we're benchmarking - { - let mut methods: Vec = vec![]; + #[cfg(feature = "runtime-benchmarks")] // Inject methods if we're benchmarking + { + let mut methods: Vec = vec![]; - let mut item: ItemMod = syn::parse(input).unwrap(); - let (brace, content) = item.content.clone().unwrap(); + let mut item: ItemMod = syn::parse(input).unwrap(); + let (brace, content) = item.content.clone().unwrap(); - let method_names = find_methods(&content); + let method_names = find_methods(&content); - // Generate methods dynamically - content.iter().for_each(|i| { - if let Item::Impl(x) = i { // implementation - x.items.iter().for_each(|x| { - if let ImplItem::Method(i) = x { // method - let method_name = i.sig.ident.to_string(); - if method_names.contains(&method_name) { - let call_method_name: proc_macro2::TokenStream = i.sig.ident.to_string().parse().unwrap(); - let inject_method: proc_macro2::TokenStream = format!("method_{}", method_name).parse().unwrap(); - let args = i.sig.inputs.clone().into_iter().collect::>(); - let inputs: Vec = i.sig.inputs - .iter() - .map(|x| argument_name(&x)) - .filter(|x| x != &"") - .map(|x| x.parse().unwrap()) - .collect(); + // Generate methods dynamically + content.iter().for_each(|i| { + if let Item::Impl(x) = i { + // implementation + x.items.iter().for_each(|x| { + if let ImplItem::Method(i) = x { + // method + let method_name = i.sig.ident.to_string(); + if method_names.contains(&method_name) { + let call_method_name: proc_macro2::TokenStream = i.sig.ident.to_string().parse().unwrap(); + let inject_method: proc_macro2::TokenStream = + format!("method_{}", method_name).parse().unwrap(); + let args = i.sig.inputs.clone().into_iter().collect::>(); + let inputs: Vec = i + .sig + .inputs + .iter() + .map(|x| argument_name(&x)) + .filter(|x| x != &"") + .map(|x| x.parse().unwrap()) + .collect(); - let method = quote! { - #[pallet::weight(0)] - pub fn #inject_method(_origin: OriginFor, #(#args),*) -> DispatchResultWithPostInfo { - Self::#call_method_name(#(#inputs),*); - Ok(().into()) - } - }; + let method = quote! { + #[pallet::weight(0)] + pub fn #inject_method(_origin: OriginFor, #(#args),*) -> DispatchResultWithPostInfo { + Self::#call_method_name(#(#inputs),*); + Ok(().into()) + } + }; - let generated_method: ImplItemMethod = syn::parse(method.into()).unwrap(); - methods.push(ImplItem::from(generated_method)); - } - } - }); - } - }); + let generated_method: ImplItemMethod = syn::parse(method.into()).unwrap(); + methods.push(ImplItem::from(generated_method)); + } + } + }); + } + }); - // Inject methods into pallet::call impl - let new_content = content.into_iter().map(|item| { - if let Item::Impl(mut item_impl) = item { - if has_attribute(&item_impl.attrs, "pallet::call") { - println!("injected callable methods for inner methods {:?}", method_names); - item_impl.items.append(&mut methods); - } - return Item::from(item_impl); - } else { - item - } - }).collect::>(); + // Inject methods into pallet::call impl + let new_content = content + .into_iter() + .map(|item| { + if let Item::Impl(mut item_impl) = item { + if has_attribute(&item_impl.attrs, "pallet::call") { + println!("injected callable methods for inner methods {:?}", method_names); + item_impl.items.append(&mut methods); + } + return Item::from(item_impl); + } else { + item + } + }) + .collect::>(); - // update content - item.content = Some((brace, new_content)); + // update content + item.content = Some((brace, new_content)); - item.into_token_stream().into() - } - #[cfg(not(feature = "runtime-benchmarks"))] - input + item.into_token_stream().into() + } + #[cfg(not(feature = "runtime-benchmarks"))] + input } #[cfg(feature = "runtime-benchmarks")] fn has_attribute(attrs: &Vec, attr: &str) -> bool { - if attrs.is_empty() { return false }; - let attributes = attrs.iter().map(|a| { - a.path.segments.iter().map(|p| p.ident.to_string()).collect::>().join("::") - }).collect::>(); - attributes.contains(&attr.to_string()) + if attrs.is_empty() { + return false; + }; + let attributes = attrs + .iter() + .map(|a| { + a.path + .segments + .iter() + .map(|p| p.ident.to_string()) + .collect::>() + .join("::") + }) + .collect::>(); + attributes.contains(&attr.to_string()) } #[cfg(feature = "runtime-benchmarks")] fn find_methods(content: &Vec) -> Vec { - let mut method_names = vec![]; - content.iter().for_each(|i| { - if let Item::Impl(x) = i { - x.items.iter().for_each(|x| { - if let ImplItem::Method(i) = x { - if has_attribute(&i.attrs, "weight_meter::weight") { - method_names.push(i.sig.ident.to_string()); - } - } - }) - } - }); - method_names + let mut method_names = vec![]; + content.iter().for_each(|i| { + if let Item::Impl(x) = i { + x.items.iter().for_each(|x| { + if let ImplItem::Method(i) = x { + if has_attribute(&i.attrs, "weight_meter::weight") { + method_names.push(i.sig.ident.to_string()); + } + } + }) + } + }); + method_names } #[cfg(feature = "runtime-benchmarks")] fn argument_name(x: &FnArg) -> String { - match x { - FnArg::Receiver(_) => "".into(), - FnArg::Typed(a) => a.pat.to_token_stream().to_string(), - } -} \ No newline at end of file + match x { + FnArg::Receiver(_) => "".into(), + FnArg::Typed(a) => a.pat.to_token_stream().to_string(), + } +} From 61615e5caddf63672b5467ddb8ac742491f04de0 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Thu, 11 Mar 2021 22:40:31 +0100 Subject: [PATCH 05/42] clippy allow unused imports --- weight-meter/weight-meter-procedural/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index 633616fc0..a2f5fb323 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports)] + extern crate proc_macro; use proc_macro::TokenStream; use quote::{quote, ToTokens}; From 8b465d9042f82f6d6946e506b118260b4a782880 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Thu, 11 Mar 2021 23:40:39 +0100 Subject: [PATCH 06/42] default std --- weight-meter/Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index 15ae52344..7da2a1b13 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -14,5 +14,6 @@ sp-std = {version = "3.0.0", default-fearures = false } weight-meter-procedural = { path = "weight-meter-procedural" } [features] +default = ["std"] std = ["sp-std/std"] -runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] \ No newline at end of file +runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] From 8e40a045ca5c7f0b01249327090474a59fda97c5 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Fri, 12 Mar 2021 00:47:19 +0100 Subject: [PATCH 07/42] update cargo --- weight-meter/Cargo.toml | 8 +++++--- weight-meter/src/lib.rs | 4 +--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index 7da2a1b13..5601be44f 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -9,11 +9,13 @@ edition = "2018" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -lazy_static = "1.4.0" -sp-std = {version = "3.0.0", default-fearures = false } +lazy_static = { version = "1.4.0", features = ["spin_no_std"] } +sp-std = { version = "3.0.0", default-fearures = false } +sp-io = { version = "3.0.0", default-fearures = false } weight-meter-procedural = { path = "weight-meter-procedural" } + [features] default = ["std"] -std = ["sp-std/std"] +std=["sp-std/std", "sp-io/std"] runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index a9f7066d1..1584517b1 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -1,9 +1,7 @@ // TODO: research if there's a better way #![cfg_attr(not(feature = "std"), no_std)] -#[macro_use] -extern crate lazy_static; - +use lazy_static::lazy_static; use sp_std::sync::Mutex; pub use weight_meter_procedural::*; From 04f659b60db2a8c2b49d092454cbf1acf660c7f5 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Fri, 12 Mar 2021 00:55:41 +0100 Subject: [PATCH 08/42] remove std --- weight-meter/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index 5601be44f..6437aa7b4 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -16,6 +16,4 @@ weight-meter-procedural = { path = "weight-meter-procedural" } [features] -default = ["std"] -std=["sp-std/std", "sp-io/std"] runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] From 8edec36658e9f744e7d1a02902c08e133473b009 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Fri, 12 Mar 2021 01:06:55 +0100 Subject: [PATCH 09/42] revert until fix no_std issue --- weight-meter/Cargo.toml | 4 ---- weight-meter/src/lib.rs | 35 ++++++++++++++--------------------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index 6437aa7b4..12f4e9228 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -9,11 +9,7 @@ edition = "2018" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -lazy_static = { version = "1.4.0", features = ["spin_no_std"] } -sp-std = { version = "3.0.0", default-fearures = false } -sp-io = { version = "3.0.0", default-fearures = false } weight-meter-procedural = { path = "weight-meter-procedural" } - [features] runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 1584517b1..22400388b 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -1,39 +1,32 @@ // TODO: research if there's a better way #![cfg_attr(not(feature = "std"), no_std)] -use lazy_static::lazy_static; -use sp_std::sync::Mutex; - pub use weight_meter_procedural::*; -#[derive(Default)] -struct State { - pub used_weight: u64, - pub nested: usize, -} - -lazy_static! { - static ref STATE: Mutex = Mutex::new(State::default()); -} +static mut USED_WEIGHT: u64 = 0; +static mut NESTED: u64 = 0; pub fn using(m: u64) { - let mut s = STATE.lock().unwrap(); - s.used_weight = s.used_weight.saturating_add(m); + unsafe { + USED_WEIGHT = USED_WEIGHT.saturating_add(m); + } } pub fn used_weight() -> u64 { - STATE.lock().unwrap().used_weight + unsafe { USED_WEIGHT } } pub fn start_with(m: u64) { - let mut s = STATE.lock().unwrap(); - if s.nested == 0 { - s.used_weight = m; + unsafe { + if NESTED == 0 { + USED_WEIGHT = m; + } + NESTED = NESTED.saturating_add(1); } - s.nested = s.nested.saturating_add(1); } pub fn end() { - let mut s = STATE.lock().unwrap(); - s.nested = s.nested.saturating_sub(1); + unsafe { + NESTED = NESTED.saturating_sub(1); + } } From 41136b85a1801a8e60402fb95d3694c4644f2ca8 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Fri, 12 Mar 2021 12:09:43 +0100 Subject: [PATCH 10/42] improvements --- .../weight-meter-procedural/src/lib.rs | 78 ++++++++++--------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index a2f5fb323..fde836ce0 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -2,8 +2,8 @@ extern crate proc_macro; use proc_macro::TokenStream; -use quote::{quote, ToTokens}; -use syn::{Attribute, FnArg, ImplItem, ImplItemMethod, Item, ItemFn, ItemMod}; +use quote::{quote, ToTokens, format_ident}; +use syn::{Attribute, FnArg, Ident, ItemImpl, ImplItem, ImplItemMethod, Item, ItemFn, ItemMod}; #[proc_macro_attribute] pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -44,54 +44,54 @@ pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream let mut item: ItemMod = syn::parse(input).unwrap(); let (brace, content) = item.content.clone().unwrap(); - let method_names = find_methods(&content); - - // Generate methods dynamically - content.iter().for_each(|i| { - if let Item::Impl(x) = i { - // implementation - x.items.iter().for_each(|x| { - if let ImplItem::Method(i) = x { - // method - let method_name = i.sig.ident.to_string(); - if method_names.contains(&method_name) { - let call_method_name: proc_macro2::TokenStream = i.sig.ident.to_string().parse().unwrap(); - let inject_method: proc_macro2::TokenStream = - format!("method_{}", method_name).parse().unwrap(); - let args = i.sig.inputs.clone().into_iter().collect::>(); - let inputs: Vec = i - .sig - .inputs - .iter() + let whitelist = find_methods(&content); + + // Generate callable methods dynamically + content.iter().for_each(|item| { + if let Item::Impl(ItemImpl {items, ..}) = item { + items.iter().for_each(|item_impl| { + if let ImplItem::Method(ImplItemMethod { sig, ..} ) = item_impl { + + let method_name = sig.ident.clone(); + + // generate call method if whitelisted + if whitelist.contains(&method_name) { + let call_method_name = format_ident!("method_{}", method_name); + let args = sig.inputs.clone().into_iter().collect::>(); + let inputs: Vec = sig.inputs.iter() .map(|x| argument_name(&x)) .filter(|x| x != &"") .map(|x| x.parse().unwrap()) .collect(); + // construct call method let method = quote! { #[pallet::weight(0)] - pub fn #inject_method(_origin: OriginFor, #(#args),*) -> DispatchResultWithPostInfo { - Self::#call_method_name(#(#inputs),*); + pub fn #call_method_name(_origin: OriginFor, #(#args),*) -> DispatchResultWithPostInfo { + Self::#method_name(#(#inputs),*); Ok(().into()) } }; - let generated_method: ImplItemMethod = syn::parse(method.into()).unwrap(); - methods.push(ImplItem::from(generated_method)); + let call_method: ImplItemMethod = syn::parse(method.into()).unwrap(); + methods.push(ImplItem::from(call_method)); } } }); } }); - // Inject methods into pallet::call impl + // Inject methods into #[pallet::call] impl let new_content = content .into_iter() .map(|item| { if let Item::Impl(mut item_impl) = item { if has_attribute(&item_impl.attrs, "pallet::call") { - println!("injected callable methods for inner methods {:?}", method_names); item_impl.items.append(&mut methods); + + //// debug + // let method_names = whitelist.iter().map(|x| x.to_string()).collect::>(); + // println!("injected callable methods for inner methods {:?}", method_names); } return Item::from(item_impl); } else { @@ -113,7 +113,7 @@ pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream fn has_attribute(attrs: &Vec, attr: &str) -> bool { if attrs.is_empty() { return false; - }; + } let attributes = attrs .iter() .map(|a| { @@ -128,23 +128,25 @@ fn has_attribute(attrs: &Vec, attr: &str) -> bool { attributes.contains(&attr.to_string()) } +// Find methods with attribute `#[weight_meter::weight]` #[cfg(feature = "runtime-benchmarks")] -fn find_methods(content: &Vec) -> Vec { - let mut method_names = vec![]; - content.iter().for_each(|i| { - if let Item::Impl(x) = i { - x.items.iter().for_each(|x| { - if let ImplItem::Method(i) = x { - if has_attribute(&i.attrs, "weight_meter::weight") { - method_names.push(i.sig.ident.to_string()); +fn find_methods(content: &Vec) -> Vec { + let mut methods = vec![]; + content.iter().for_each(|content| { + if let Item::Impl(item_impl) = content { + item_impl.items.iter().for_each(|item| { + if let ImplItem::Method(ImplItemMethod {attrs, sig, ..}) = item { + if has_attribute(&attrs, "weight_meter::weight") { + methods.push(sig.ident.clone()); } } - }) + }); } }); - method_names + methods } +// Extract name from function argument #[cfg(feature = "runtime-benchmarks")] fn argument_name(x: &FnArg) -> String { match x { From 14850350342e0264e17408fe907ad3be3378e2e9 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Fri, 12 Mar 2021 14:28:00 +0100 Subject: [PATCH 11/42] fmt --- .../weight-meter-procedural/src/lib.rs | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index fde836ce0..590bf284b 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -2,8 +2,8 @@ extern crate proc_macro; use proc_macro::TokenStream; -use quote::{quote, ToTokens, format_ident}; -use syn::{Attribute, FnArg, Ident, ItemImpl, ImplItem, ImplItemMethod, Item, ItemFn, ItemMod}; +use quote::{format_ident, quote, ToTokens}; +use syn::{Attribute, FnArg, Ident, ImplItem, ImplItemMethod, Item, ItemFn, ItemImpl, ItemMod}; #[proc_macro_attribute] pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -48,17 +48,18 @@ pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream // Generate callable methods dynamically content.iter().for_each(|item| { - if let Item::Impl(ItemImpl {items, ..}) = item { + if let Item::Impl(ItemImpl { items, .. }) = item { items.iter().for_each(|item_impl| { - if let ImplItem::Method(ImplItemMethod { sig, ..} ) = item_impl { - + if let ImplItem::Method(ImplItemMethod { sig, .. }) = item_impl { let method_name = sig.ident.clone(); // generate call method if whitelisted if whitelist.contains(&method_name) { let call_method_name = format_ident!("method_{}", method_name); let args = sig.inputs.clone().into_iter().collect::>(); - let inputs: Vec = sig.inputs.iter() + let inputs: Vec = sig + .inputs + .iter() .map(|x| argument_name(&x)) .filter(|x| x != &"") .map(|x| x.parse().unwrap()) @@ -89,9 +90,11 @@ pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream if has_attribute(&item_impl.attrs, "pallet::call") { item_impl.items.append(&mut methods); - //// debug - // let method_names = whitelist.iter().map(|x| x.to_string()).collect::>(); - // println!("injected callable methods for inner methods {:?}", method_names); + // debug + // println!( + // "injected callable methods for inner methods {:?}", + // whitelist.iter().map(|x| x.to_string()).collect::>() + // ); } return Item::from(item_impl); } else { @@ -135,7 +138,7 @@ fn find_methods(content: &Vec) -> Vec { content.iter().for_each(|content| { if let Item::Impl(item_impl) = content { item_impl.items.iter().for_each(|item| { - if let ImplItem::Method(ImplItemMethod {attrs, sig, ..}) = item { + if let ImplItem::Method(ImplItemMethod { attrs, sig, .. }) = item { if has_attribute(&attrs, "weight_meter::weight") { methods.push(sig.ident.clone()); } From 0d6c751ec9096b0ce5643b1f9be29c134729d3f8 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Fri, 12 Mar 2021 20:40:40 +0100 Subject: [PATCH 12/42] update argument extract --- weight-meter/Cargo.toml | 6 ++++- .../weight-meter-procedural/Cargo.toml | 2 ++ .../weight-meter-procedural/src/lib.rs | 25 +++++-------------- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index 12f4e9228..72c50afcf 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -9,7 +9,11 @@ edition = "2018" targets = ["x86_64-unknown-linux-gnu"] [dependencies] -weight-meter-procedural = { path = "weight-meter-procedural" } +weight-meter-procedural = { path = "weight-meter-procedural", default-features = false } [features] +default = ["std"] +std = [ + "weight-meter-procedural/std", +] runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] diff --git a/weight-meter/weight-meter-procedural/Cargo.toml b/weight-meter/weight-meter-procedural/Cargo.toml index 850be7581..c72305821 100644 --- a/weight-meter/weight-meter-procedural/Cargo.toml +++ b/weight-meter/weight-meter-procedural/Cargo.toml @@ -14,4 +14,6 @@ quote = "1.0.3" syn = { version = "1.0.58", features = ["full"] } [features] +default = ["std"] +std = [] runtime-benchmarks = [] \ No newline at end of file diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index 590bf284b..04dd80641 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -1,9 +1,8 @@ #![allow(unused_imports)] -extern crate proc_macro; use proc_macro::TokenStream; use quote::{format_ident, quote, ToTokens}; -use syn::{Attribute, FnArg, Ident, ImplItem, ImplItemMethod, Item, ItemFn, ItemImpl, ItemMod}; +use syn::{Attribute, FnArg, Ident, ImplItem, ImplItemMethod, Item, ItemFn, ItemImpl, ItemMod, Pat}; #[proc_macro_attribute] pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -56,14 +55,8 @@ pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream // generate call method if whitelisted if whitelist.contains(&method_name) { let call_method_name = format_ident!("method_{}", method_name); - let args = sig.inputs.clone().into_iter().collect::>(); - let inputs: Vec = sig - .inputs - .iter() - .map(|x| argument_name(&x)) - .filter(|x| x != &"") - .map(|x| x.parse().unwrap()) - .collect(); + let args = sig.inputs.iter().collect::>(); + let inputs = sig.inputs.iter().map(|x| argument_name(&x)).collect::>(); // construct call method let method = quote! { @@ -89,12 +82,6 @@ pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream if let Item::Impl(mut item_impl) = item { if has_attribute(&item_impl.attrs, "pallet::call") { item_impl.items.append(&mut methods); - - // debug - // println!( - // "injected callable methods for inner methods {:?}", - // whitelist.iter().map(|x| x.to_string()).collect::>() - // ); } return Item::from(item_impl); } else { @@ -151,9 +138,9 @@ fn find_methods(content: &Vec) -> Vec { // Extract name from function argument #[cfg(feature = "runtime-benchmarks")] -fn argument_name(x: &FnArg) -> String { +fn argument_name(x: &FnArg) -> Box { match x { - FnArg::Receiver(_) => "".into(), - FnArg::Typed(a) => a.pat.to_token_stream().to_string(), + FnArg::Receiver(_) => panic!("unexpected argument self"), + FnArg::Typed(ty) => ty.pat.clone(), } } From 135d43d396744524c06a5b0b2d2b08b9377ff95b Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Fri, 12 Mar 2021 20:53:58 +0100 Subject: [PATCH 13/42] package name with orml prefix --- weight-meter/Cargo.toml | 2 +- weight-meter/weight-meter-procedural/src/lib.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index 72c50afcf..2bd65eb76 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "weight-meter" +name = "orml-weight-meter" version = "0.1.0" license = "Apache-2.0" authors = ["Laminar Developers "] diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index 04dd80641..e5c9e9fed 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -11,9 +11,9 @@ pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { (quote! { #(#attrs)* #vis #sig { - weight_meter::start_with(#base_weight); + orml_weight_meter::start_with(#base_weight); let result = #block; - weight_meter::end(); + orml_weight_meter::end(); result } }) @@ -27,7 +27,7 @@ pub fn weight(attr: TokenStream, item: TokenStream) -> TokenStream { (quote! { #(#attrs)* #vis #sig { - weight_meter::using(#weight); + orml_weight_meter::using(#weight); #block } }) @@ -118,7 +118,7 @@ fn has_attribute(attrs: &Vec, attr: &str) -> bool { attributes.contains(&attr.to_string()) } -// Find methods with attribute `#[weight_meter::weight]` +// Find methods with attribute `#[orml_weight_meter::weight]` #[cfg(feature = "runtime-benchmarks")] fn find_methods(content: &Vec) -> Vec { let mut methods = vec![]; @@ -126,7 +126,7 @@ fn find_methods(content: &Vec) -> Vec { if let Item::Impl(item_impl) = content { item_impl.items.iter().for_each(|item| { if let ImplItem::Method(ImplItemMethod { attrs, sig, .. }) = item { - if has_attribute(&attrs, "weight_meter::weight") { + if has_attribute(&attrs, "orml_weight_meter::weight") { methods.push(sig.ident.clone()); } } From c6040e1d2f4248e61a98b0cf42f806fe674b53e8 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Mon, 15 Mar 2021 18:12:17 +0100 Subject: [PATCH 14/42] update meter to be Mutex --- weight-meter/Cargo.toml | 3 ++ weight-meter/src/lib.rs | 48 ++++++++++++------- .../weight-meter-procedural/src/lib.rs | 2 +- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index 2bd65eb76..2265bb15e 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -9,11 +9,14 @@ edition = "2018" targets = ["x86_64-unknown-linux-gnu"] [dependencies] +spin = "0.7.1" +frame-support = { version = "3.0.0", default-features = false } weight-meter-procedural = { path = "weight-meter-procedural", default-features = false } [features] default = ["std"] std = [ + "frame-support/std", "weight-meter-procedural/std", ] runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 22400388b..6a59bf3e3 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -1,32 +1,44 @@ // TODO: research if there's a better way #![cfg_attr(not(feature = "std"), no_std)] +use frame_support::weights::Weight; + pub use weight_meter_procedural::*; -static mut USED_WEIGHT: u64 = 0; -static mut NESTED: u64 = 0; +struct Meter { + used_weight: Weight, + nested: usize, +} + +static METER: spin::Mutex = spin::Mutex::new(Meter { + used_weight: 0, + nested: 0, +}); -pub fn using(m: u64) { - unsafe { - USED_WEIGHT = USED_WEIGHT.saturating_add(m); +pub fn start_with(base: Weight) { + let mut meter = METER.lock(); + if meter.nested == 0 { + meter.used_weight = base; } + meter.nested = meter.nested.saturating_add(1); + drop(meter); } -pub fn used_weight() -> u64 { - unsafe { USED_WEIGHT } +pub fn using(weight: Weight) { + let mut meter = METER.lock(); + meter.used_weight = meter.used_weight.saturating_add(weight); + drop(meter); } -pub fn start_with(m: u64) { - unsafe { - if NESTED == 0 { - USED_WEIGHT = m; - } - NESTED = NESTED.saturating_add(1); - } +pub fn finish() { + let mut meter = METER.lock(); + meter.nested = meter.nested.saturating_sub(1); + drop(meter); } -pub fn end() { - unsafe { - NESTED = NESTED.saturating_sub(1); - } +pub fn used_weight() -> Weight { + let meter = METER.lock(); + let used_weight = meter.used_weight; + drop(meter); + used_weight } diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index e5c9e9fed..53648488b 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -13,7 +13,7 @@ pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { #vis #sig { orml_weight_meter::start_with(#base_weight); let result = #block; - orml_weight_meter::end(); + orml_weight_meter::finish(); result } }) From c8d7d739d9afaaef53daace4e05fdfb2809e36c8 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Mon, 15 Mar 2021 22:52:33 +0100 Subject: [PATCH 15/42] use mutex only in std --- weight-meter/README.md | 45 +++++++++++++++++++++++++++++++- weight-meter/src/lib.rs | 43 +++++++----------------------- weight-meter/src/meter_no_std.rs | 34 ++++++++++++++++++++++++ weight-meter/src/meter_std.rs | 37 ++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 34 deletions(-) create mode 100644 weight-meter/src/meter_no_std.rs create mode 100644 weight-meter/src/meter_std.rs diff --git a/weight-meter/README.md b/weight-meter/README.md index 5ecc3216f..d65320e6e 100644 --- a/weight-meter/README.md +++ b/weight-meter/README.md @@ -1,3 +1,46 @@ # Weight Meter -work in progress... \ No newline at end of file +## How to use WeightMeter +1. Include `WeightMeter` into your module Cargo.toml +``` +orml-weight-meter = { version = "0.1.0", default-features = false } + +std = [ + ... + 'orml-weight-meter/std', +] +runtime-benchmarks = [ + ... + 'orml-weight-meter/runtime-benchmarks', +] + +``` + +2. Add macro attribute on top of the module declaration +``` +#[orml_weight_meter::method_benchmarks] +#[frame_support::pallet] +pub mod module { + use super::*; + ... +``` + +3. Add macro attribute on method you want to benchmark. +``` +#[orml_weight_meter::weight(0)] +fn inner_do_something(something: u32) { + // Update storage. + Something::::put(something); +} +``` +Start with `0` after the weights is generated then it can be replaced with generated weight. Macro will inject callable methods that wraps inner methods. Generated call will start with prefix `method_` followed by method name. This only works for methods with `orml_weight_meter::weight` attribute and only when running benchmarks. + +4. Create benchmarks as we normally do. Just need to use prefix `method_` followed by +method name. +``` +method_inner_do_something { + let caller = whitelisted_caller(); +}: _(frame_system::RawOrigin::Signed(caller), 10) +``` +After running benchmarks we can replace `#[orml_weight_meter::weight(0)]` with + `#[orml_weight_meter::weight(T::WeightInfo::method_inner_do_something())]`. \ No newline at end of file diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 6a59bf3e3..de03b0c0a 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -1,44 +1,21 @@ -// TODO: research if there's a better way #![cfg_attr(not(feature = "std"), no_std)] use frame_support::weights::Weight; -pub use weight_meter_procedural::*; - struct Meter { used_weight: Weight, - nested: usize, + // Deep gets incremented when entering call or a sub-call + // This is used to avoid miscalculation during sub-calls + deep: usize, } -static METER: spin::Mutex = spin::Mutex::new(Meter { - used_weight: 0, - nested: 0, -}); - -pub fn start_with(base: Weight) { - let mut meter = METER.lock(); - if meter.nested == 0 { - meter.used_weight = base; - } - meter.nested = meter.nested.saturating_add(1); - drop(meter); -} +mod meter_no_std; +mod meter_std; -pub fn using(weight: Weight) { - let mut meter = METER.lock(); - meter.used_weight = meter.used_weight.saturating_add(weight); - drop(meter); -} +#[cfg(feature = "std")] +pub use meter_std::*; -pub fn finish() { - let mut meter = METER.lock(); - meter.nested = meter.nested.saturating_sub(1); - drop(meter); -} +#[cfg(not(feature = "std"))] +pub use meter_no_std::*; -pub fn used_weight() -> Weight { - let meter = METER.lock(); - let used_weight = meter.used_weight; - drop(meter); - used_weight -} +pub use weight_meter_procedural::*; diff --git a/weight-meter/src/meter_no_std.rs b/weight-meter/src/meter_no_std.rs new file mode 100644 index 000000000..934885ad7 --- /dev/null +++ b/weight-meter/src/meter_no_std.rs @@ -0,0 +1,34 @@ +// TODO: research if there's a better way +#![cfg(not(feature = "std"))] + +use super::{Meter, Weight}; + +static mut METER: Meter = Meter { + used_weight: 0, + deep: 0, +}; + +pub fn start_with(base: Weight) { + unsafe { + if METER.deep == 0 { + METER.used_weight = base; + } + METER.deep = METER.deep.saturating_add(1); + } +} + +pub fn using(weight: Weight) { + unsafe { + METER.used_weight = METER.used_weight.saturating_add(weight); + } +} + +pub fn finish() { + unsafe { + METER.deep = METER.deep.saturating_sub(1); + } +} + +pub fn used_weight() -> Weight { + unsafe { METER.used_weight } +} diff --git a/weight-meter/src/meter_std.rs b/weight-meter/src/meter_std.rs new file mode 100644 index 000000000..50aba551d --- /dev/null +++ b/weight-meter/src/meter_std.rs @@ -0,0 +1,37 @@ +// TODO: research if there's a better way +#![cfg(feature = "std")] + +use super::{Meter, Weight}; + +static METER: spin::Mutex = spin::Mutex::new(Meter { + used_weight: 0, + deep: 0, +}); + +pub fn start_with(base: Weight) { + let mut meter = METER.lock(); + if meter.deep == 0 { + meter.used_weight = base; + } + meter.deep = meter.deep.saturating_add(1); + drop(meter); +} + +pub fn using(weight: Weight) { + let mut meter = METER.lock(); + meter.used_weight = meter.used_weight.saturating_add(weight); + drop(meter); +} + +pub fn finish() { + let mut meter = METER.lock(); + meter.deep = meter.deep.saturating_sub(1); + drop(meter); +} + +pub fn used_weight() -> Weight { + let meter = METER.lock(); + let used_weight = meter.used_weight; + drop(meter); + used_weight +} From b857553fcdbd8c2d6a93b7717cd938b27fd23d86 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Mon, 15 Mar 2021 23:04:12 +0100 Subject: [PATCH 16/42] update README --- weight-meter/README.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/weight-meter/README.md b/weight-meter/README.md index d65320e6e..df4430282 100644 --- a/weight-meter/README.md +++ b/weight-meter/README.md @@ -33,7 +33,7 @@ fn inner_do_something(something: u32) { Something::::put(something); } ``` -Start with `0` after the weights is generated then it can be replaced with generated weight. Macro will inject callable methods that wraps inner methods. Generated call will start with prefix `method_` followed by method name. This only works for methods with `orml_weight_meter::weight` attribute and only when running benchmarks. +Start with `0` and after the weights is generated then it can be replaced with generated weight. Macro will inject callable methods that wraps inner methods. Generated call will start with prefix `method_` followed by method name. This only works for methods with `orml_weight_meter::weight` attribute and only when running benchmarks. 4. Create benchmarks as we normally do. Just need to use prefix `method_` followed by method name. @@ -43,4 +43,23 @@ method_inner_do_something { }: _(frame_system::RawOrigin::Signed(caller), 10) ``` After running benchmarks we can replace `#[orml_weight_meter::weight(0)]` with - `#[orml_weight_meter::weight(T::WeightInfo::method_inner_do_something())]`. \ No newline at end of file + `#[orml_weight_meter::weight(T::WeightInfo::method_inner_do_something())]`. + +5. Use WeightMeter on your calls by adding macro `#[orml_weight_meter::start_with()]` and at the end use `orml_weight_meter::used_weight()` to get used weight. +``` +#[pallet::call] +impl Pallet { + #[pallet::weight(T::WeightInfo::do_something())] + #[orml_weight_meter::start_with(1_000_000)] + pub fn do_something(origin: OriginFor, something: u32) -> DispatchResultWithPostInfo { + let who = ensure_signed(origin)?; + + Self::inner_do_something(something); + + // Emit an event. + Self::deposit_event(Event::SomethingStored(something, who)); + + Ok(PostDispatchInfo::from(Some(orml_weight_meter::used_weight()))) + } +} +``` From d7a3af09b461709bb96571010204d2dece3b1d7c Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Mon, 15 Mar 2021 23:05:53 +0100 Subject: [PATCH 17/42] update README --- weight-meter/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/weight-meter/README.md b/weight-meter/README.md index df4430282..a89b4f571 100644 --- a/weight-meter/README.md +++ b/weight-meter/README.md @@ -3,6 +3,7 @@ ## How to use WeightMeter 1. Include `WeightMeter` into your module Cargo.toml ``` +[dependencies] orml-weight-meter = { version = "0.1.0", default-features = false } std = [ From c5ab5a4adf233c3de8cf25db824ad17c6dc8253f Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Tue, 16 Mar 2021 11:59:42 +0100 Subject: [PATCH 18/42] update property name --- weight-meter/src/lib.rs | 4 ++-- weight-meter/src/meter_no_std.rs | 8 ++++---- weight-meter/src/meter_std.rs | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index de03b0c0a..f96e6b05d 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -4,9 +4,9 @@ use frame_support::weights::Weight; struct Meter { used_weight: Weight, - // Deep gets incremented when entering call or a sub-call + // Depth gets incremented when entering call or a sub-call // This is used to avoid miscalculation during sub-calls - deep: usize, + depth: u8, } mod meter_no_std; diff --git a/weight-meter/src/meter_no_std.rs b/weight-meter/src/meter_no_std.rs index 934885ad7..3628f0ede 100644 --- a/weight-meter/src/meter_no_std.rs +++ b/weight-meter/src/meter_no_std.rs @@ -5,15 +5,15 @@ use super::{Meter, Weight}; static mut METER: Meter = Meter { used_weight: 0, - deep: 0, + depth: 0, }; pub fn start_with(base: Weight) { unsafe { - if METER.deep == 0 { + if METER.depth == 0 { METER.used_weight = base; } - METER.deep = METER.deep.saturating_add(1); + METER.depth = METER.depth.saturating_add(1); } } @@ -25,7 +25,7 @@ pub fn using(weight: Weight) { pub fn finish() { unsafe { - METER.deep = METER.deep.saturating_sub(1); + METER.depth = METER.depth.saturating_sub(1); } } diff --git a/weight-meter/src/meter_std.rs b/weight-meter/src/meter_std.rs index 50aba551d..0b188de72 100644 --- a/weight-meter/src/meter_std.rs +++ b/weight-meter/src/meter_std.rs @@ -5,15 +5,15 @@ use super::{Meter, Weight}; static METER: spin::Mutex = spin::Mutex::new(Meter { used_weight: 0, - deep: 0, + depth: 0, }); pub fn start_with(base: Weight) { let mut meter = METER.lock(); - if meter.deep == 0 { + if meter.depth == 0 { meter.used_weight = base; } - meter.deep = meter.deep.saturating_add(1); + meter.depth = meter.depth.saturating_add(1); drop(meter); } @@ -25,7 +25,7 @@ pub fn using(weight: Weight) { pub fn finish() { let mut meter = METER.lock(); - meter.deep = meter.deep.saturating_sub(1); + meter.depth = meter.depth.saturating_sub(1); drop(meter); } From 5dadd780d44e5343aebacc2906846808177f7ac9 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Tue, 16 Mar 2021 12:42:10 +0100 Subject: [PATCH 19/42] separate method injector --- .../weight-meter-procedural/src/lib.rs | 123 ++---------------- .../src/method_injector.rs | 107 +++++++++++++++ 2 files changed, 117 insertions(+), 113 deletions(-) create mode 100644 weight-meter/weight-meter-procedural/src/method_injector.rs diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index 53648488b..e65dba4e0 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -1,8 +1,8 @@ -#![allow(unused_imports)] - use proc_macro::TokenStream; -use quote::{format_ident, quote, ToTokens}; -use syn::{Attribute, FnArg, Ident, ImplItem, ImplItemMethod, Item, ItemFn, ItemImpl, ItemMod, Pat}; +use quote::quote; +use syn::ItemFn; + +mod method_injector; #[proc_macro_attribute] pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { @@ -11,9 +11,9 @@ pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { (quote! { #(#attrs)* #vis #sig { - orml_weight_meter::start_with(#base_weight); + ::orml_weight_meter::start_with(#base_weight); let result = #block; - orml_weight_meter::finish(); + ::orml_weight_meter::finish(); result } }) @@ -27,7 +27,7 @@ pub fn weight(attr: TokenStream, item: TokenStream) -> TokenStream { (quote! { #(#attrs)* #vis #sig { - orml_weight_meter::using(#weight); + ::orml_weight_meter::using(#weight); #block } }) @@ -36,111 +36,8 @@ pub fn weight(attr: TokenStream, item: TokenStream) -> TokenStream { #[proc_macro_attribute] pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream { - #[cfg(feature = "runtime-benchmarks")] // Inject methods if we're benchmarking - { - let mut methods: Vec = vec![]; - - let mut item: ItemMod = syn::parse(input).unwrap(); - let (brace, content) = item.content.clone().unwrap(); - - let whitelist = find_methods(&content); - - // Generate callable methods dynamically - content.iter().for_each(|item| { - if let Item::Impl(ItemImpl { items, .. }) = item { - items.iter().for_each(|item_impl| { - if let ImplItem::Method(ImplItemMethod { sig, .. }) = item_impl { - let method_name = sig.ident.clone(); - - // generate call method if whitelisted - if whitelist.contains(&method_name) { - let call_method_name = format_ident!("method_{}", method_name); - let args = sig.inputs.iter().collect::>(); - let inputs = sig.inputs.iter().map(|x| argument_name(&x)).collect::>(); - - // construct call method - let method = quote! { - #[pallet::weight(0)] - pub fn #call_method_name(_origin: OriginFor, #(#args),*) -> DispatchResultWithPostInfo { - Self::#method_name(#(#inputs),*); - Ok(().into()) - } - }; - - let call_method: ImplItemMethod = syn::parse(method.into()).unwrap(); - methods.push(ImplItem::from(call_method)); - } - } - }); - } - }); - - // Inject methods into #[pallet::call] impl - let new_content = content - .into_iter() - .map(|item| { - if let Item::Impl(mut item_impl) = item { - if has_attribute(&item_impl.attrs, "pallet::call") { - item_impl.items.append(&mut methods); - } - return Item::from(item_impl); - } else { - item - } - }) - .collect::>(); - - // update content - item.content = Some((brace, new_content)); - - item.into_token_stream().into() - } + #[cfg(feature = "runtime-benchmarks")] + return method_injector::inject_methods(input); #[cfg(not(feature = "runtime-benchmarks"))] - input -} - -#[cfg(feature = "runtime-benchmarks")] -fn has_attribute(attrs: &Vec, attr: &str) -> bool { - if attrs.is_empty() { - return false; - } - let attributes = attrs - .iter() - .map(|a| { - a.path - .segments - .iter() - .map(|p| p.ident.to_string()) - .collect::>() - .join("::") - }) - .collect::>(); - attributes.contains(&attr.to_string()) -} - -// Find methods with attribute `#[orml_weight_meter::weight]` -#[cfg(feature = "runtime-benchmarks")] -fn find_methods(content: &Vec) -> Vec { - let mut methods = vec![]; - content.iter().for_each(|content| { - if let Item::Impl(item_impl) = content { - item_impl.items.iter().for_each(|item| { - if let ImplItem::Method(ImplItemMethod { attrs, sig, .. }) = item { - if has_attribute(&attrs, "orml_weight_meter::weight") { - methods.push(sig.ident.clone()); - } - } - }); - } - }); - methods -} - -// Extract name from function argument -#[cfg(feature = "runtime-benchmarks")] -fn argument_name(x: &FnArg) -> Box { - match x { - FnArg::Receiver(_) => panic!("unexpected argument self"), - FnArg::Typed(ty) => ty.pat.clone(), - } + return input; } diff --git a/weight-meter/weight-meter-procedural/src/method_injector.rs b/weight-meter/weight-meter-procedural/src/method_injector.rs new file mode 100644 index 000000000..4e986ab64 --- /dev/null +++ b/weight-meter/weight-meter-procedural/src/method_injector.rs @@ -0,0 +1,107 @@ +#![cfg(feature = "runtime-benchmarks")] + +use proc_macro::TokenStream; +use quote::{format_ident, quote, ToTokens}; +use syn::{Attribute, FnArg, Ident, ImplItem, ImplItemMethod, Item, ItemImpl, ItemMod, Pat}; + +pub fn inject_methods(input: TokenStream) -> TokenStream { + let mut methods: Vec = vec![]; + + let mut item: ItemMod = syn::parse(input).unwrap(); + let (brace, content) = item.content.clone().unwrap(); + + let whitelist = find_methods(&content); + + // Generate callable methods dynamically + content.iter().for_each(|item| { + if let Item::Impl(ItemImpl { items, .. }) = item { + items.iter().for_each(|item_impl| { + if let ImplItem::Method(ImplItemMethod { sig, .. }) = item_impl { + let method_name = sig.ident.clone(); + + // generate call method if whitelisted + if whitelist.contains(&method_name) { + let call_method_name = format_ident!("method_{}", method_name); + let args = sig.inputs.iter().collect::>(); + let inputs = sig.inputs.iter().map(|x| argument_name(&x)).collect::>(); + + // construct call method + let method = quote! { + #[pallet::weight(0)] + pub fn #call_method_name(_origin: OriginFor, #(#args),*) -> DispatchResultWithPostInfo { + Self::#method_name(#(#inputs),*); + Ok(().into()) + } + }; + + let call_method: ImplItemMethod = syn::parse(method.into()).unwrap(); + methods.push(ImplItem::from(call_method)); + } + } + }); + } + }); + + // Inject methods into #[pallet::call] impl + let new_content = content + .into_iter() + .map(|item| { + if let Item::Impl(mut item_impl) = item { + if has_attribute(&item_impl.attrs, "pallet::call") { + item_impl.items.append(&mut methods); + } + return Item::from(item_impl); + } else { + item + } + }) + .collect::>(); + + // update content + item.content = Some((brace, new_content)); + + item.into_token_stream().into() +} + +fn has_attribute(attrs: &Vec, attr: &str) -> bool { + if attrs.is_empty() { + return false; + } + let attributes = attrs + .iter() + .map(|a| { + a.path + .segments + .iter() + .map(|p| p.ident.to_string()) + .collect::>() + .join("::") + }) + .collect::>(); + attributes.contains(&attr.to_string()) +} + +// Find methods with attribute `#[orml_weight_meter::weight]` +fn find_methods(content: &Vec) -> Vec { + let mut methods = vec![]; + content.iter().for_each(|content| { + if let Item::Impl(item_impl) = content { + item_impl.items.iter().for_each(|item| { + if let ImplItem::Method(ImplItemMethod { attrs, sig, .. }) = item { + if has_attribute(&attrs, "orml_weight_meter::weight") { + methods.push(sig.ident.clone()); + } + } + }); + } + }); + methods +} + +// Extract name from function argument +fn argument_name(x: &FnArg) -> Box { + match x { + FnArg::Receiver(_) => panic!("unexpected argument self"), + FnArg::Typed(ty) => ty.pat.clone(), + } +} From 46a7969f331e02b69750ecf727c7b7a25242de9c Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Tue, 16 Mar 2021 16:24:09 +0100 Subject: [PATCH 20/42] docs --- weight-meter/README.md | 59 +++---------------------------- weight-meter/src/lib.rs | 66 ++++++++++++++++++++++++++++++++++- weight-meter/src/meter_std.rs | 4 +++ 3 files changed, 74 insertions(+), 55 deletions(-) diff --git a/weight-meter/README.md b/weight-meter/README.md index a89b4f571..6d30487d1 100644 --- a/weight-meter/README.md +++ b/weight-meter/README.md @@ -1,66 +1,17 @@ # Weight Meter -## How to use WeightMeter -1. Include `WeightMeter` into your module Cargo.toml +Include `WeightMeter` into your module Cargo.toml ``` [dependencies] -orml-weight-meter = { version = "0.1.0", default-features = false } +orml-weight-meter = { version = "..", default-features = false } std = [ - ... + .. 'orml-weight-meter/std', ] runtime-benchmarks = [ - ... + .. 'orml-weight-meter/runtime-benchmarks', ] -``` - -2. Add macro attribute on top of the module declaration -``` -#[orml_weight_meter::method_benchmarks] -#[frame_support::pallet] -pub mod module { - use super::*; - ... -``` - -3. Add macro attribute on method you want to benchmark. -``` -#[orml_weight_meter::weight(0)] -fn inner_do_something(something: u32) { - // Update storage. - Something::::put(something); -} -``` -Start with `0` and after the weights is generated then it can be replaced with generated weight. Macro will inject callable methods that wraps inner methods. Generated call will start with prefix `method_` followed by method name. This only works for methods with `orml_weight_meter::weight` attribute and only when running benchmarks. - -4. Create benchmarks as we normally do. Just need to use prefix `method_` followed by -method name. -``` -method_inner_do_something { - let caller = whitelisted_caller(); -}: _(frame_system::RawOrigin::Signed(caller), 10) -``` -After running benchmarks we can replace `#[orml_weight_meter::weight(0)]` with - `#[orml_weight_meter::weight(T::WeightInfo::method_inner_do_something())]`. - -5. Use WeightMeter on your calls by adding macro `#[orml_weight_meter::start_with()]` and at the end use `orml_weight_meter::used_weight()` to get used weight. -``` -#[pallet::call] -impl Pallet { - #[pallet::weight(T::WeightInfo::do_something())] - #[orml_weight_meter::start_with(1_000_000)] - pub fn do_something(origin: OriginFor, something: u32) -> DispatchResultWithPostInfo { - let who = ensure_signed(origin)?; - - Self::inner_do_something(something); - - // Emit an event. - Self::deposit_event(Event::SomethingStored(something, who)); - - Ok(PostDispatchInfo::from(Some(orml_weight_meter::used_weight()))) - } -} -``` +``` \ No newline at end of file diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index f96e6b05d..cb67ef62d 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -18,4 +18,68 @@ pub use meter_std::*; #[cfg(not(feature = "std"))] pub use meter_no_std::*; -pub use weight_meter_procedural::*; +/// Start weight meter with base weight +pub use weight_meter_procedural::start_with; + +/// Measure each methods weight +pub use weight_meter_procedural::weight; + +/// `method_benchmarks` attribute macro let's you benchmark inner methods +/// +/// 1. Add macro attribute on top of the module declaration +/// ```ignore +/// #[orml_weight_meter::method_benchmarks] +/// #[frame_support::pallet] +/// pub mod module { +/// use super::*; +/// .. +/// } +/// ``` +/// +/// 2. Add macro attribute on method you want to benchmark. +/// ```ignore +/// #[orml_weight_meter::weight(0)] +/// fn inner_do_something(something: u32) { +/// // Update storage. +/// Something::::put(something); +/// } +/// ``` +/// Start with `0` and after the weights is generated then it can be replaced +/// with generated weight. Macro will inject callable methods that wraps inner +/// methods. Generated call will start with prefix `method_` followed by method +/// name. This only works for methods with `orml_weight_meter::weight` attribute +/// and only when running benchmarks. +/// +/// 3. Create benchmarks as we normally do. Just need to use prefix `method_` +/// followed by method name. +/// ```ignore +/// method_inner_do_something { +/// let caller = whitelisted_caller(); +/// }: _(frame_system::RawOrigin::Signed(caller), 10) +/// ``` +/// After running benchmarks and weights been generated then we can replace ` +/// ```ignore +/// #[orml_weight_meter::weight(0)] +/// ``` +/// with +/// ```ignore +/// #[orml_weight_meter::weight(T::WeightInfo::method_inner_do_something())] +/// ``` +/// +/// 4. Use WeightMeter on your calls by adding macro +/// `#[orml_weight_meter::start_with()]` and at the end use +/// `orml_weight_meter::used_weight()` to get used weight. ```ignore +/// #[pallet::call] +/// impl Pallet { +/// #[pallet::weight(T::WeightInfo::do_something())] +/// #[orml_weight_meter::start_with(1_000_000)] +/// pub fn do_something(origin: OriginFor, something: u32) -> DispatchResultWithPostInfo { +/// let who = ensure_signed(origin)?; +/// Self::inner_do_something(something); +/// // Emit an event. +/// Self::deposit_event(Event::SomethingStored(something, who)); +/// Ok(PostDispatchInfo::from(Some(orml_weight_meter::used_weight()))) +/// } +/// } +/// ``` +pub use weight_meter_procedural::method_benchmarks; diff --git a/weight-meter/src/meter_std.rs b/weight-meter/src/meter_std.rs index 0b188de72..9622d05cb 100644 --- a/weight-meter/src/meter_std.rs +++ b/weight-meter/src/meter_std.rs @@ -8,6 +8,7 @@ static METER: spin::Mutex = spin::Mutex::new(Meter { depth: 0, }); +/// Start weight meter with base weight pub fn start_with(base: Weight) { let mut meter = METER.lock(); if meter.depth == 0 { @@ -17,18 +18,21 @@ pub fn start_with(base: Weight) { drop(meter); } +/// Increment used weight pub fn using(weight: Weight) { let mut meter = METER.lock(); meter.used_weight = meter.used_weight.saturating_add(weight); drop(meter); } +/// Finish weight meter pub fn finish() { let mut meter = METER.lock(); meter.depth = meter.depth.saturating_sub(1); drop(meter); } +/// Get used weight pub fn used_weight() -> Weight { let meter = METER.lock(); let used_weight = meter.used_weight; From d46f3d4ba2024c06ca721a01ba142e6cbe936df1 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Tue, 16 Mar 2021 19:22:18 +0100 Subject: [PATCH 21/42] fmt --- weight-meter/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index cb67ef62d..80ba24212 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -73,7 +73,8 @@ pub use weight_meter_procedural::weight; /// impl Pallet { /// #[pallet::weight(T::WeightInfo::do_something())] /// #[orml_weight_meter::start_with(1_000_000)] -/// pub fn do_something(origin: OriginFor, something: u32) -> DispatchResultWithPostInfo { +/// pub fn do_something(origin: OriginFor, something: u32) -> +/// DispatchResultWithPostInfo { /// let who = ensure_signed(origin)?; /// Self::inner_do_something(something); /// // Emit an event. From 31166278dfeb662ae967034964e49717f5e0675b Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Tue, 16 Mar 2021 19:51:35 +0100 Subject: [PATCH 22/42] clippy --- weight-meter/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 80ba24212..c63362328 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -31,7 +31,6 @@ pub use weight_meter_procedural::weight; /// #[orml_weight_meter::method_benchmarks] /// #[frame_support::pallet] /// pub mod module { -/// use super::*; /// .. /// } /// ``` @@ -74,7 +73,7 @@ pub use weight_meter_procedural::weight; /// #[pallet::weight(T::WeightInfo::do_something())] /// #[orml_weight_meter::start_with(1_000_000)] /// pub fn do_something(origin: OriginFor, something: u32) -> -/// DispatchResultWithPostInfo { +/// DispatchResultWithPostInfo { /// let who = ensure_signed(origin)?; /// Self::inner_do_something(something); /// // Emit an event. From 9245ede8f8372685b7eab2aa333dc18dc5b21f77 Mon Sep 17 00:00:00 2001 From: brettkolodny Date: Thu, 15 Apr 2021 14:21:52 -0400 Subject: [PATCH 23/42] Orml bencher (#452) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use MultiLocation as xtokens transfer dest type. (#396) * Use MultiLocation as xtokens transfer dest type. * Make clippy happy. * Use xcm-handler to execute XCM locally (#401) * Use cumulus xcm-handler to execute XCM locally. * Add docstring for xtokens config. * Replace XcmError::Undefined usage. (#402) * Replace XcmError::Undefined usage. * make clippy happy * Bump and unify serde versions. (#403) * xtokens and xcm-support documentations (#404) * Add xtokens module docstring. * Add xtokens readme. * Add documentations for xcm-support. * Add xtokens and xcm-support entries in main readme. * Add unit tests for xcm-support. (#405) * Added Minterest to the list of users. (#406) * update step guide link * Handle unknown assets in TransactAsset impl (#409) * Handle unknown assets in TransactAsset impl. * More documentations. * Clean code. * Renaming. * Should try to deposit known asset first. * Return error if no UnknownAsset impl. * Make clippy happy. * Fix description and repo link. (#410) * Unknown tokens pallet (#411) * Impl unknown tokens pallet. * Fix workspace pallet path. * Make clippy happy. * Clippy, be happy. * Unit tests. * Remove nonces from oracle pallet. (#413) * refactor rewards (#412) * Bump rococo v1 dependencies (#418) * Fix mocks. * Replace deprecated. * Update orml-unknown-tokens unit tests. (#421) * add build-script-utils from Substrate (#422) * Update README.md (#420) * Update README.md * Update README.md * Bump impl-trait-for-tuples to 0.2.1 (#424) * update Cargo.toml (#429) * bencher init commit * split into files * clean deps * add docs * use frame_benchmarking apis * add macro bencher_use to export stuff for bench_runner * * generate weights file * refactor * improvements * CLI Options (#446) * Added command line options for output, headers, and templates * Fixed options to conform to standard cli * Added weight-gen cli * fixed dependencies * Replaced unwraps with expects (#449) * Orml bencher (#451) * add Handler (#431) * remove disable-tokens-by-owner (#434) * Cross-chain transfer rework (#432) * Reserve chain trait. * Rework cross-chain transfer. * Remove relay chain balance convert. * Add 'Parse' trait. * Change transfer_multiasset fn signature. * Add transfer dispatchable call. * Update doc. * Use xcm-simulator to mock network. * Send relay chain asset to sibling unit test. * Move location traits into orml-traits. * Add MultiNativeAsset filter for is reserve check. * More unit tests. * Failing edge case unit tests. * Handle zero amount asset case. * Fix mocks. * Renaming. * Update currency adapter to work with new xtokens impl (#436) * Xcm support implementations rework. * Update xtokens mock. * Use CurrencyId convert. (#437) * Use CurrencyId convert. * Apply review suggestions. * Update xtokens docs. (#438) * Update xtokens docs. * Fix typo. * Update imbalances impl. * Don't deposit failure event in orml-unknown-tokens. (#440) * Don't deposit failure event in orml-unknown-tokens. * Patch substrate/polkadot/cumulus. * Fix patch. * Update README.md (#441) Include Zeitgeist into "Projects using ORML" section * Add PoV size in benchmarking. (#442) * Bump cumulus ref in cargo patch. (#443) * fix missing features (#444) * fix missing features * test with benchmarks * update auction weight (#445) * Bump dependencies. (#448) * Replaced unwraps with expects Co-authored-by: Xiliang Chen Co-authored-by: Shaun Wang Co-authored-by: Harald Heckmann Co-authored-by: wangjj9219 <183318287@qq.com> Co-authored-by: Shaun Wang Co-authored-by: dzianis.ramanouski Co-authored-by: Bette <42193328+bette7@users.noreply.github.com> Co-authored-by: wangjj9219 <183318287@qq.com> Co-authored-by: Xiliang Chen Co-authored-by: transxask <68648225+transxask@users.noreply.github.com> Co-authored-by: Aaro Perämaa Co-authored-by: Ermal Kaleci Co-authored-by: Harald Heckmann --- Cargo.dev.toml | 4 +- bencher/Cargo.toml | 40 ++++++++ bencher/src/bench_runner.rs | 39 ++++++++ bencher/src/handler.rs | 54 +++++++++++ bencher/src/lib.rs | 28 ++++++ bencher/src/macros.rs | 160 +++++++++++++++++++++++++++++++ bencher/src/template.hbs | 23 +++++ weight-gen/Cargo.toml | 20 ++++ weight-gen/src/main.rs | 181 ++++++++++++++++++++++++++++++++++++ weight-gen/src/template.hbs | 23 +++++ 10 files changed, 571 insertions(+), 1 deletion(-) create mode 100644 bencher/Cargo.toml create mode 100644 bencher/src/bench_runner.rs create mode 100644 bencher/src/handler.rs create mode 100644 bencher/src/lib.rs create mode 100644 bencher/src/macros.rs create mode 100644 bencher/src/template.hbs create mode 100644 weight-gen/Cargo.toml create mode 100644 weight-gen/src/main.rs create mode 100644 weight-gen/src/template.hbs diff --git a/Cargo.dev.toml b/Cargo.dev.toml index 4b8025012..9ace6b2bd 100644 --- a/Cargo.dev.toml +++ b/Cargo.dev.toml @@ -16,7 +16,9 @@ members = [ "nft", "xtokens", "xcm-support", - "weight-meter", + "unknown-tokens", + "build-script-utils", + "weight-meter", ] resolver = "2" diff --git a/bencher/Cargo.toml b/bencher/Cargo.toml new file mode 100644 index 000000000..0942cc850 --- /dev/null +++ b/bencher/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "orml-bencher" +description = "Provide macro to benchmark pallets." +repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/bencher" +license = "Apache-2.0" +version = "0.1.0" +authors = ["Laminar Developers "] +edition = "2018" + +[dependencies] +linregress = { version = "0.4.0", optional = true } +handlebars = {version = "3.5.2", optional = true } +serde = { features = ['derive'], optional = true, version = "1.0.119" } +serde_json = "1.0" +codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"], default-features = false } +sp-core = { version = "3.0.0", default-features = false } +sp-std = { version = "3.0.0", default-features = false } +sp-io = { version = "3.0.0", default-features = false } +sp-runtime-interface = { version = "3.0.0", default-features = false } +sp-state-machine = { version = "0.9.0", default-features = false, optional = true } +sc-executor = { version = "0.9.0", default-features = false, optional = true } +sc-client-db = { version = "0.9.0", default-features = false, features = ["with-kvdb-rocksdb"], optional = true } +frame-benchmarking = { version = "3.1.0", default-features = false } + +[features] +default = ["std"] +std = [ + "linregress", + "handlebars", + "serde/std", + "codec/std", + "sp-core/std", + "sp-std/std", + "sp-io/std", + "sp-runtime-interface/std", + "sp-state-machine/std", + "sc-executor/std", + "sc-client-db", + "frame-benchmarking/std", +] diff --git a/bencher/src/bench_runner.rs b/bencher/src/bench_runner.rs new file mode 100644 index 000000000..6f0d49075 --- /dev/null +++ b/bencher/src/bench_runner.rs @@ -0,0 +1,39 @@ +use frame_benchmarking::{ + benchmarking, + frame_support::sp_runtime::traits::{Block, NumberFor}, +}; +use sc_client_db::BenchmarkingState; +use sc_executor::{sp_wasm_interface::HostFunctions, WasmExecutionMethod, WasmExecutor}; +use sp_core::traits::{CallInWasm, MissingHostFunctions}; +use sp_io::SubstrateHostFunctions; +use sp_state_machine::{Ext, OverlayedChanges, StorageTransactionCache}; + +/// Run benches +pub fn run(wasm_code: Vec) -> Vec { + let mut overlay = OverlayedChanges::default(); + let mut cache = StorageTransactionCache::default(); + let state = BenchmarkingState::::new(Default::default(), Default::default()).unwrap(); + let mut ext = Ext::<_, NumberFor, _>::new(&mut overlay, &mut cache, &state, None, None); + + let mut host_functions = benchmarking::HostFunctions::host_functions(); + host_functions.append(&mut SubstrateHostFunctions::host_functions()); + + let executor = WasmExecutor::new( + WasmExecutionMethod::Compiled, + Default::default(), + host_functions, + 1, + None, + ); + + executor + .call_in_wasm( + &wasm_code[..], + None, + "run_benches", + &[], + &mut ext, + MissingHostFunctions::Disallow, + ) + .unwrap() +} diff --git a/bencher/src/handler.rs b/bencher/src/handler.rs new file mode 100644 index 000000000..8533d2db1 --- /dev/null +++ b/bencher/src/handler.rs @@ -0,0 +1,54 @@ +use crate::BenchResult; +use codec::Decode; +use linregress::{FormulaRegressionBuilder, RegressionDataBuilder}; +use serde::{Deserialize, Serialize}; +use std::io::Write; + +#[derive(Serialize, Deserialize, Default, Debug, Clone)] +struct BenchData { + pub name: String, + pub base_weight: u64, + pub base_reads: u32, + pub base_writes: u32, +} + +/// Handle bench results +pub fn handle(output: Vec) { + let results = as Decode>::decode(&mut &output[..]).unwrap(); + let data: Vec = results + .into_iter() + .map(|result| { + let name = String::from_utf8_lossy(&result.method).to_string(); + + eprintln!("{:#?}", result); + + let y: Vec = result.elapses.into_iter().map(|x| x as f64).collect(); + let x: Vec = (0..y.len()).into_iter().map(|x| x as f64).collect(); + let data = vec![("Y", y), ("X", x)]; + let data = RegressionDataBuilder::new().build_from(data).unwrap(); + let formula = "Y ~ X"; + + let model = FormulaRegressionBuilder::new() + .data(&data) + .formula(formula) + .fit() + .unwrap(); + + BenchData { + name, + base_weight: model.parameters.intercept_value as u64 * 1_000, + base_reads: result.reads, + base_writes: result.writes, + } + }) + .collect(); + + if let Ok(json) = serde_json::to_string(&data) { + let stdout = ::std::io::stdout(); + let mut handle = stdout.lock(); + + handle.write_all(&json.as_bytes()).unwrap(); + } else { + eprintln!("Could not write benchdata to JSON"); + } +} diff --git a/bencher/src/lib.rs b/bencher/src/lib.rs new file mode 100644 index 000000000..2ef25f776 --- /dev/null +++ b/bencher/src/lib.rs @@ -0,0 +1,28 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +#[doc(hidden)] +pub extern crate frame_benchmarking; +#[doc(hidden)] +pub extern crate sp_core; +#[doc(hidden)] +pub extern crate sp_std; + +use codec::{Decode, Encode}; +use sp_std::prelude::Vec; + +#[derive(Encode, Decode, Default, Clone, PartialEq, Debug)] +pub struct BenchResult { + pub method: Vec, + pub elapses: Vec, + pub reads: u32, + pub repeat_reads: u32, + pub writes: u32, + pub repeat_writes: u32, +} + +mod macros; + +#[cfg(feature = "std")] +pub mod bench_runner; +#[cfg(feature = "std")] +pub mod handler; diff --git a/bencher/src/macros.rs b/bencher/src/macros.rs new file mode 100644 index 000000000..0175ef40c --- /dev/null +++ b/bencher/src/macros.rs @@ -0,0 +1,160 @@ +/// Run benches in WASM environment. +/// +/// Configure your module to build the mock runtime into wasm code. +/// Create a `build.rs` like you do with your runtime. +/// ```.ignore +/// use substrate_wasm_builder::WasmBuilder; +/// fn main() { +/// WasmBuilder::new() +/// .with_current_project() +/// .export_heap_base() +/// .import_memory() +/// .build() +/// } +/// ``` +/// +/// Update mock runtime to be build into wasm code. +/// ```.ignore +/// #![cfg_attr(not(feature = "std"), no_std)] +/// +/// #[cfg(feature = "std")] +/// include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); +/// +/// #[cfg(feature = "std")] +/// pub fn wasm_binary_unwrap() -> &'static [u8] { WASM_BINARY.unwrap() } +/// .. +/// ``` +/// +/// Create a file `bench_runner.rs` with following code: +/// ```.ignore +/// orml_bencher::run_benches!(my_module::benches); +/// ``` +/// +/// Update Cargo.toml by adding: +/// ```toml +/// .. +/// [package] +/// name = "my-module" +/// .. +/// build = 'build.rs' +/// +/// [build-dependencies] +/// substrate-wasm-builder = '4.0.0' +/// +/// [[bench]] +/// name = 'benches' +/// harness = false +/// path = 'bench_runner.rs' +/// required-features = ['bench'] +/// +/// [features] +/// bench = [] +/// .. +/// ``` +/// +/// Run bench with features bench: `cargo bench --features=bench` +#[cfg(feature = "std")] +#[macro_export] +macro_rules! run_benches { + ($benches:path) => { + use $benches::{wasm_binary_unwrap, Block}; + pub fn main() { + let output = $crate::bench_runner::run::(wasm_binary_unwrap().to_vec()); + $crate::handler::handle(output); + } + }; +} + +/// Define benches +/// +/// Create a file `src/benches.rs`: +/// ```.ignore +/// #![cfg_attr(not(feature = "std"), no_std)] +/// #![allow(dead_code)] +/// +/// #[cfg(feature = "std")] // Re-export for bench_runner +/// pub use crate::mock::{Block, wasm_binary_unwrap}; +/// +/// use crate::mock::YourModule; +/// +/// fn foo(b: &mut Bencher) { +/// b.bench("foo", || { +/// YourModule::foo(); +/// }); +/// } +/// +/// fn bar(b: &mut Bencher) { +/// b.bench("bar", || { +/// YourModule::bar(); +/// }); +/// } +/// +/// orml_bencher::bench!(foo, bar); +/// ``` +/// Update `src/lib.rs`: +/// ```.ignore +/// #[cfg(any(feature = "bench", test))] +/// pub mod mock; /* mock runtime needs to be compiled into wasm */ +/// #[cfg(feature = "bench")] +/// pub mod benches; +/// ``` +#[macro_export] +macro_rules! bench { + ( + $($method:path),+ + ) => { + use $crate::BenchResult; + use $crate::sp_std::{cmp::max, prelude::Vec}; + use $crate::frame_benchmarking::{benchmarking, BenchmarkResults}; + + #[derive(Default, Clone, PartialEq, Debug)] + struct Bencher { + pub results: Vec, + } + + impl Bencher { + pub fn bench(&mut self, name: &str, block: fn() -> ()) { + // Warm up the DB + benchmarking::commit_db(); + benchmarking::wipe_db(); + + let mut result = BenchResult { + method: name.as_bytes().to_vec(), + ..Default::default() + }; + + for _ in 0..50 { + benchmarking::commit_db(); + benchmarking::reset_read_write_count(); + + let start_time = benchmarking::current_time(); + block(); + let end_time = benchmarking::current_time(); + let elasped = end_time - start_time; + result.elapses.push(elasped); + + benchmarking::commit_db(); + let (reads, repeat_reads, writes, repeat_writes) = benchmarking::read_write_count(); + + result.reads = max(result.reads, reads); + result.repeat_reads = max(result.repeat_reads, repeat_reads); + result.writes = max(result.writes, writes); + result.repeat_writes = max(result.repeat_writes, repeat_writes); + + benchmarking::wipe_db(); + } + self.results.push(result); + } + } + + $crate::sp_core::wasm_export_functions! { + fn run_benches() -> Vec { + let mut bencher = Bencher::default(); + $( + $method(&mut bencher); + )+ + bencher.results + } + } + } +} diff --git a/bencher/src/template.hbs b/bencher/src/template.hbs new file mode 100644 index 000000000..470b00c25 --- /dev/null +++ b/bencher/src/template.hbs @@ -0,0 +1,23 @@ +{{header}} + +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(dead_code)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +pub struct ModuleWeights(PhantomData); +impl ModuleWeights { + {{~#each benchmarks as |benchmark|}} + pub fn {{benchmark.name~}} () -> Weight { + ({{underscore benchmark.base_weight}} as Weight) + {{~#if (ne benchmark.base_reads "0")}} + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) + {{~/if}} + {{~#if (ne benchmark.base_writes "0")}} + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) + {{~/if}} + } + {{~/each}} +} diff --git a/weight-gen/Cargo.toml b/weight-gen/Cargo.toml new file mode 100644 index 000000000..81f68bd1a --- /dev/null +++ b/weight-gen/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "weight-gen" +description = "CLI for generating weight from bencher output" +license = "Apache-2.0" +version = "0.1.0" +authors = ["Laminar Developers "] +edition = "2018" + +[dependencies] +serde = { features = ['derive'], optional = true, version = "1.0.119" } +serde_json = "1.0" +clap = "3.0.0-beta.2" +handlebars = {version = "3.5.2", optional = true } + +[features] +default = ["std"] +std = [ + "handlebars", + "serde/std", +] \ No newline at end of file diff --git a/weight-gen/src/main.rs b/weight-gen/src/main.rs new file mode 100644 index 000000000..3cdf1052b --- /dev/null +++ b/weight-gen/src/main.rs @@ -0,0 +1,181 @@ +use clap::{AppSettings, Clap}; +use serde::{Deserialize, Serialize}; +use std::io::Read; + +#[derive(Clap)] +#[clap(version = "01.0", author = "Laminar Developers ")] +#[clap(setting = AppSettings::ColoredHelp)] +struct Opts { + input: Option, + #[clap(short, long)] + template: Option, + #[clap(short, long)] + header: Option, + #[clap(short, long)] + out: Option, +} + +#[cfg(feature = "std")] +#[derive(Serialize, Deserialize, Default, Debug, Clone)] +pub struct BenchData { + pub name: String, + pub base_weight: u64, + pub base_reads: u32, + pub base_writes: u32, +} + +#[derive(Serialize, Default, Debug, Clone)] +struct TemplateData { + pub header: String, + pub benchmarks: Vec, +} + +// A Handlebars helper to add an underscore after every 3rd character, +// i.e. a separator for large numbers. +#[derive(Clone, Copy)] +struct UnderscoreHelper; +impl handlebars::HelperDef for UnderscoreHelper { + fn call<'reg: 'rc, 'rc>( + &self, + h: &handlebars::Helper, + _: &handlebars::Handlebars, + _: &handlebars::Context, + _rc: &mut handlebars::RenderContext, + out: &mut dyn handlebars::Output, + ) -> handlebars::HelperResult { + use handlebars::JsonRender; + let param = h.param(0).expect("Unable to retrieve param from handlebars helper"); + let underscore_param = underscore(param.value().render()); + out.write(&underscore_param)?; + Ok(()) + } +} + +// Add an underscore after every 3rd character, i.e. a separator for large +// numbers. +fn underscore(i: Number) -> String +where + Number: std::string::ToString, +{ + let mut s = String::new(); + let i_str = i.to_string(); + let a = i_str.chars().rev().enumerate(); + for (idx, val) in a { + if idx != 0 && idx % 3 == 0 { + s.insert(0, '_'); + } + s.insert(0, val); + } + s +} + +// A helper to join a string of vectors. +#[derive(Clone, Copy)] +struct JoinHelper; +impl handlebars::HelperDef for JoinHelper { + fn call<'reg: 'rc, 'rc>( + &self, + h: &handlebars::Helper, + _: &handlebars::Handlebars, + _: &handlebars::Context, + _rc: &mut handlebars::RenderContext, + out: &mut dyn handlebars::Output, + ) -> handlebars::HelperResult { + use handlebars::JsonRender; + let param = h.param(0).expect("Unable to retrieve param from handlebars helper"); + let value = param.value(); + let joined = if value.is_array() { + value + .as_array() + .unwrap() + .iter() + .map(|v| v.render()) + .collect::>() + .join(" ") + } else { + value.render() + }; + out.write(&joined)?; + Ok(()) + } +} + +fn parse_stdio() -> Option> { + let mut buffer = String::new(); + let stdin = std::io::stdin(); + let mut handle = stdin.lock(); + + handle.read_to_string(&mut buffer).expect("Unable to read from stdin"); + + let lines: Vec<&str> = buffer.split("\n").collect(); + for line in lines { + let json = serde_json::from_str(line); + + if let Ok(data) = json { + return Some(data); + } + } + + None +} + +fn main() { + let opts: Opts = Opts::parse(); + + let benchmarks: Vec = { + if let Some(data) = opts.input { + serde_json::from_str(&data).expect("Could not parse JSON data") + } else { + parse_stdio().expect("Could not parse JSON data") + } + }; + + let mut handlebars = handlebars::Handlebars::new(); + handlebars.register_helper("underscore", Box::new(UnderscoreHelper)); + handlebars.register_helper("join", Box::new(JoinHelper)); + // Don't HTML escape any characters. + handlebars.register_escape_fn(|s| -> String { s.to_string() }); + + // Use empty header if a header path is not given. + let header = { + if let Some(path) = opts.header { + let header_string = ::std::fs::read_to_string(&path).expect(&format!("Header file not found at {}", &path)); + + header_string + } else { + String::from("") + } + }; + + let hbs_data = TemplateData { header, benchmarks }; + + const DEFAULT_TEMPLATE: &str = include_str!("./template.hbs"); + + // Use default template if template path is not given. + let template = { + if let Some(path) = opts.template { + let template_string = + ::std::fs::read_to_string(&path).expect(&format!("Template file not found at {}", &path)); + + template_string + } else { + String::from(DEFAULT_TEMPLATE) + } + }; + + // Write benchmark to file or print to terminal if output path is not given. + if let Some(path) = opts.out { + let mut output_file = + ::std::fs::File::create(&path).expect(&format!("Could not create output file at {}", &path)); + + handlebars + .render_template_to_write(&template, &hbs_data, &mut output_file) + .expect("Unable to render template"); + } else { + let template_string = handlebars + .render_template(&template, &hbs_data) + .expect("Unable to render template"); + + println!("{}", template_string); + } +} diff --git a/weight-gen/src/template.hbs b/weight-gen/src/template.hbs new file mode 100644 index 000000000..470b00c25 --- /dev/null +++ b/weight-gen/src/template.hbs @@ -0,0 +1,23 @@ +{{header}} + +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(dead_code)] + +use frame_support::{traits::Get, weights::Weight}; +use sp_std::marker::PhantomData; + +pub struct ModuleWeights(PhantomData); +impl ModuleWeights { + {{~#each benchmarks as |benchmark|}} + pub fn {{benchmark.name~}} () -> Weight { + ({{underscore benchmark.base_weight}} as Weight) + {{~#if (ne benchmark.base_reads "0")}} + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) + {{~/if}} + {{~#if (ne benchmark.base_writes "0")}} + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) + {{~/if}} + } + {{~/each}} +} From 2c253faf41aa5259242443fff08439959ed9f10b Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Fri, 16 Apr 2021 20:10:09 +0200 Subject: [PATCH 24/42] fix bencher dependencies --- bencher/Cargo.toml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bencher/Cargo.toml b/bencher/Cargo.toml index 0942cc850..5ff55205b 100644 --- a/bencher/Cargo.toml +++ b/bencher/Cargo.toml @@ -13,14 +13,14 @@ handlebars = {version = "3.5.2", optional = true } serde = { features = ['derive'], optional = true, version = "1.0.119" } serde_json = "1.0" codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"], default-features = false } -sp-core = { version = "3.0.0", default-features = false } -sp-std = { version = "3.0.0", default-features = false } -sp-io = { version = "3.0.0", default-features = false } -sp-runtime-interface = { version = "3.0.0", default-features = false } -sp-state-machine = { version = "0.9.0", default-features = false, optional = true } -sc-executor = { version = "0.9.0", default-features = false, optional = true } -sc-client-db = { version = "0.9.0", default-features = false, features = ["with-kvdb-rocksdb"], optional = true } -frame-benchmarking = { version = "3.1.0", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } +sp-runtime-interface = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false, optional = true } +sc-executor = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false, features = ["wasmtime"], optional = true } +sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false, features = ["with-kvdb-rocksdb"], optional = true } +frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } [features] default = ["std"] From 4d21e02a1bb3442e9039b0aa45a6349b70eeade8 Mon Sep 17 00:00:00 2001 From: brettkolodny Date: Wed, 21 Apr 2021 16:22:22 -0400 Subject: [PATCH 25/42] Weight meter (#459) * Added argument to BenchmarkingState --- Cargo.dev.toml | 2 ++ bencher/src/bench_runner.rs | 2 +- bencher/src/template.hbs | 23 ----------------------- 3 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 bencher/src/template.hbs diff --git a/Cargo.dev.toml b/Cargo.dev.toml index 9ace6b2bd..a0ea1d79e 100644 --- a/Cargo.dev.toml +++ b/Cargo.dev.toml @@ -4,6 +4,7 @@ cargo-features = ["resolver"] members = [ "auction", "authority", + "bencher", "benchmarking", "currencies", "gradually-update", @@ -18,6 +19,7 @@ members = [ "xcm-support", "unknown-tokens", "build-script-utils", + "weight-gen", "weight-meter", ] resolver = "2" diff --git a/bencher/src/bench_runner.rs b/bencher/src/bench_runner.rs index 6f0d49075..26fabc066 100644 --- a/bencher/src/bench_runner.rs +++ b/bencher/src/bench_runner.rs @@ -12,7 +12,7 @@ use sp_state_machine::{Ext, OverlayedChanges, StorageTransactionCache}; pub fn run(wasm_code: Vec) -> Vec { let mut overlay = OverlayedChanges::default(); let mut cache = StorageTransactionCache::default(); - let state = BenchmarkingState::::new(Default::default(), Default::default()).unwrap(); + let state = BenchmarkingState::::new(Default::default(), Default::default(), false).unwrap(); let mut ext = Ext::<_, NumberFor, _>::new(&mut overlay, &mut cache, &state, None, None); let mut host_functions = benchmarking::HostFunctions::host_functions(); diff --git a/bencher/src/template.hbs b/bencher/src/template.hbs deleted file mode 100644 index 470b00c25..000000000 --- a/bencher/src/template.hbs +++ /dev/null @@ -1,23 +0,0 @@ -{{header}} - -#![allow(unused_parens)] -#![allow(unused_imports)] -#![allow(dead_code)] - -use frame_support::{traits::Get, weights::Weight}; -use sp_std::marker::PhantomData; - -pub struct ModuleWeights(PhantomData); -impl ModuleWeights { - {{~#each benchmarks as |benchmark|}} - pub fn {{benchmark.name~}} () -> Weight { - ({{underscore benchmark.base_weight}} as Weight) - {{~#if (ne benchmark.base_reads "0")}} - .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}} as Weight)) - {{~/if}} - {{~#if (ne benchmark.base_writes "0")}} - .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}} as Weight)) - {{~/if}} - } - {{~/each}} -} From db799bc56642a5677d1d93f3ec283ab6ae61c403 Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Thu, 22 Apr 2021 11:26:56 +1200 Subject: [PATCH 26/42] fix --- bencher/src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bencher/src/macros.rs b/bencher/src/macros.rs index 0175ef40c..f6548136a 100644 --- a/bencher/src/macros.rs +++ b/bencher/src/macros.rs @@ -113,7 +113,7 @@ macro_rules! bench { } impl Bencher { - pub fn bench(&mut self, name: &str, block: fn() -> ()) { + pub fn bench ()>(&mut self, name: &str, block: F) { // Warm up the DB benchmarking::commit_db(); benchmarking::wipe_db(); From 7dc337e5d39deab8f1de53e245853034e18c272a Mon Sep 17 00:00:00 2001 From: brettkolodny Date: Thu, 22 Apr 2021 16:14:51 -0400 Subject: [PATCH 27/42] Updated frame-support version (#461) --- weight-meter/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index 2265bb15e..e9e527744 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -10,7 +10,7 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] spin = "0.7.1" -frame-support = { version = "3.0.0", default-features = false } +frame-support = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } weight-meter-procedural = { path = "weight-meter-procedural", default-features = false } [features] From b516ee16441f6f0ef270836d2765286e232f2b9d Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Wed, 5 May 2021 14:44:34 -0400 Subject: [PATCH 28/42] clippy --- weight-gen/src/main.rs | 13 ++++--------- weight-meter/src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/weight-gen/src/main.rs b/weight-gen/src/main.rs index 3cdf1052b..820726a6b 100644 --- a/weight-gen/src/main.rs +++ b/weight-gen/src/main.rs @@ -107,7 +107,7 @@ fn parse_stdio() -> Option> { handle.read_to_string(&mut buffer).expect("Unable to read from stdin"); - let lines: Vec<&str> = buffer.split("\n").collect(); + let lines: Vec<&str> = buffer.split('\n').collect(); for line in lines { let json = serde_json::from_str(line); @@ -139,9 +139,7 @@ fn main() { // Use empty header if a header path is not given. let header = { if let Some(path) = opts.header { - let header_string = ::std::fs::read_to_string(&path).expect(&format!("Header file not found at {}", &path)); - - header_string + ::std::fs::read_to_string(&path).expect("Header file not found") } else { String::from("") } @@ -154,10 +152,7 @@ fn main() { // Use default template if template path is not given. let template = { if let Some(path) = opts.template { - let template_string = - ::std::fs::read_to_string(&path).expect(&format!("Template file not found at {}", &path)); - - template_string + ::std::fs::read_to_string(&path).expect("Template file not found") } else { String::from(DEFAULT_TEMPLATE) } @@ -166,7 +161,7 @@ fn main() { // Write benchmark to file or print to terminal if output path is not given. if let Some(path) = opts.out { let mut output_file = - ::std::fs::File::create(&path).expect(&format!("Could not create output file at {}", &path)); + ::std::fs::File::create(&path).expect("Could not create output file at {}"); handlebars .render_template_to_write(&template, &hbs_data, &mut output_file) diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index c63362328..d0df9c2a2 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -73,7 +73,7 @@ pub use weight_meter_procedural::weight; /// #[pallet::weight(T::WeightInfo::do_something())] /// #[orml_weight_meter::start_with(1_000_000)] /// pub fn do_something(origin: OriginFor, something: u32) -> -/// DispatchResultWithPostInfo { +/// DispatchResultWithPostInfo { /// let who = ensure_signed(origin)?; /// Self::inner_do_something(something); /// // Emit an event. From 89db2f79bfc07252a5b8cb8fb459755c1cfe63e5 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Wed, 5 May 2021 15:04:24 -0400 Subject: [PATCH 29/42] fmt --- weight-gen/src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/weight-gen/src/main.rs b/weight-gen/src/main.rs index 820726a6b..cedbecd0d 100644 --- a/weight-gen/src/main.rs +++ b/weight-gen/src/main.rs @@ -160,8 +160,7 @@ fn main() { // Write benchmark to file or print to terminal if output path is not given. if let Some(path) = opts.out { - let mut output_file = - ::std::fs::File::create(&path).expect("Could not create output file at {}"); + let mut output_file = ::std::fs::File::create(&path).expect("Could not create output file"); handlebars .render_template_to_write(&template, &hbs_data, &mut output_file) From 7a9a4e8940513e9bd2d0309c5372104e6f3dcd48 Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Thu, 6 May 2021 09:32:56 +1200 Subject: [PATCH 30/42] fix --- Cargo.dev.toml | 3 ++- weight-gen/Cargo.toml | 9 +++------ weight-gen/src/main.rs | 1 - 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/Cargo.dev.toml b/Cargo.dev.toml index 0662f5567..176890e6e 100644 --- a/Cargo.dev.toml +++ b/Cargo.dev.toml @@ -22,7 +22,7 @@ members = [ # "unknown-tokens", "build-script-utils", "weight-gen", - "weight-meter", + "weight-meter", ] resolver = "2" @@ -78,6 +78,7 @@ sp-timestamp = { git = "https://github.com/paritytech//substrate", rev = "2be8fc sp-session = { git = "https://github.com/paritytech//substrate", rev = "2be8fcc4236d32786c62f6f27a98e7fe7e550807" } sp-blockchain = { git = "https://github.com/paritytech//substrate", rev = "2be8fcc4236d32786c62f6f27a98e7fe7e550807" } sp-transaction-pool = { git = "https://github.com/paritytech//substrate", rev = "2be8fcc4236d32786c62f6f27a98e7fe7e550807" } +sc-client-db = { git = "https://github.com/paritytech//substrate", rev = "2be8fcc4236d32786c62f6f27a98e7fe7e550807" } # [patch.'https://github.com/paritytech/cumulus'] # cumulus-primitives-core = { git = "https://github.com/paritytech//cumulus", rev = "da4c3bac6e9584e65740ef5db4dbd2c31c1a91db" } diff --git a/weight-gen/Cargo.toml b/weight-gen/Cargo.toml index 81f68bd1a..efbe23025 100644 --- a/weight-gen/Cargo.toml +++ b/weight-gen/Cargo.toml @@ -7,14 +7,11 @@ authors = ["Laminar Developers "] edition = "2018" [dependencies] -serde = { features = ['derive'], optional = true, version = "1.0.119" } +serde = { version = "1.0.119", features = ['derive'] } serde_json = "1.0" clap = "3.0.0-beta.2" -handlebars = {version = "3.5.2", optional = true } +handlebars = { version = "3.5.2" } [features] default = ["std"] -std = [ - "handlebars", - "serde/std", -] \ No newline at end of file +std = [] diff --git a/weight-gen/src/main.rs b/weight-gen/src/main.rs index cedbecd0d..1b9cff753 100644 --- a/weight-gen/src/main.rs +++ b/weight-gen/src/main.rs @@ -15,7 +15,6 @@ struct Opts { out: Option, } -#[cfg(feature = "std")] #[derive(Serialize, Deserialize, Default, Debug, Clone)] pub struct BenchData { pub name: String, From 161d4c02a28d0ab58a4f2ffbd2f72c5a6a666f48 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Wed, 5 May 2021 19:07:31 -0400 Subject: [PATCH 31/42] switched to thread_local --- weight-meter/src/meter_std.rs | 43 +++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/weight-meter/src/meter_std.rs b/weight-meter/src/meter_std.rs index 9622d05cb..78e80eddb 100644 --- a/weight-meter/src/meter_std.rs +++ b/weight-meter/src/meter_std.rs @@ -2,40 +2,43 @@ #![cfg(feature = "std")] use super::{Meter, Weight}; +use std::cell::RefCell; -static METER: spin::Mutex = spin::Mutex::new(Meter { - used_weight: 0, - depth: 0, -}); +thread_local! { + static METER: RefCell = RefCell::new(Meter { + used_weight: 0, + depth: 0, + }); +} /// Start weight meter with base weight pub fn start_with(base: Weight) { - let mut meter = METER.lock(); - if meter.depth == 0 { - meter.used_weight = base; - } - meter.depth = meter.depth.saturating_add(1); - drop(meter); + METER.with(|v| { + let mut meter = v.borrow_mut(); + if meter.depth == 0 { + meter.used_weight = base; + } + meter.depth = meter.depth.saturating_add(1); + }); } /// Increment used weight pub fn using(weight: Weight) { - let mut meter = METER.lock(); - meter.used_weight = meter.used_weight.saturating_add(weight); - drop(meter); + METER.with(|v| { + let mut meter = v.borrow_mut(); + meter.used_weight = meter.used_weight.saturating_add(weight); + }) } /// Finish weight meter pub fn finish() { - let mut meter = METER.lock(); - meter.depth = meter.depth.saturating_sub(1); - drop(meter); + METER.with(|v| { + let mut meter = v.borrow_mut(); + meter.depth = meter.depth.saturating_sub(1); + }) } /// Get used weight pub fn used_weight() -> Weight { - let meter = METER.lock(); - let used_weight = meter.used_weight; - drop(meter); - used_weight + METER.with(|v| v.borrow().used_weight) } From d0b1bfaf9ed8dcaedc0e6e48af417c38ba23537a Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Wed, 5 May 2021 22:32:59 -0400 Subject: [PATCH 32/42] Added checked add --- weight-meter/src/meter_no_std.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/weight-meter/src/meter_no_std.rs b/weight-meter/src/meter_no_std.rs index 3628f0ede..7e2a9be83 100644 --- a/weight-meter/src/meter_no_std.rs +++ b/weight-meter/src/meter_no_std.rs @@ -25,7 +25,13 @@ pub fn using(weight: Weight) { pub fn finish() { unsafe { - METER.depth = METER.depth.saturating_sub(1); + METER.depth.checked_sub(1).map_or_else( + || { + debug_assert!(false); + 0 + }, + |v| v, + ); } } From 70155766431481820720aa6262bdff8d05a93d20 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Thu, 6 May 2021 17:37:44 -0400 Subject: [PATCH 33/42] corrected versions --- bencher/Cargo.toml | 2 +- weight-gen/Cargo.toml | 2 +- weight-meter/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bencher/Cargo.toml b/bencher/Cargo.toml index 5ff55205b..b68c9f9e6 100644 --- a/bencher/Cargo.toml +++ b/bencher/Cargo.toml @@ -3,7 +3,7 @@ name = "orml-bencher" description = "Provide macro to benchmark pallets." repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/bencher" license = "Apache-2.0" -version = "0.1.0" +version = "0.4.1-dev" authors = ["Laminar Developers "] edition = "2018" diff --git a/weight-gen/Cargo.toml b/weight-gen/Cargo.toml index efbe23025..e82e7bf36 100644 --- a/weight-gen/Cargo.toml +++ b/weight-gen/Cargo.toml @@ -2,7 +2,7 @@ name = "weight-gen" description = "CLI for generating weight from bencher output" license = "Apache-2.0" -version = "0.1.0" +version = "0.4.1-dev" authors = ["Laminar Developers "] edition = "2018" diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index e9e527744..f7a91dc17 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "orml-weight-meter" -version = "0.1.0" +version = "0.4.1-dev" license = "Apache-2.0" authors = ["Laminar Developers "] edition = "2018" From 24eb2d85a43fcb5e8f20213464d58ee19edbb277 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Mon, 10 May 2021 14:44:39 -0400 Subject: [PATCH 34/42] weight_meter tests --- weight-meter/Cargo.toml | 11 ++ weight-meter/src/lib.rs | 9 ++ weight-meter/src/mock.rs | 279 ++++++++++++++++++++++++++++++++++++++ weight-meter/src/tests.rs | 91 +++++++++++++ 4 files changed, 390 insertions(+) create mode 100644 weight-meter/src/mock.rs create mode 100644 weight-meter/src/tests.rs diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index f7a91dc17..c6832150e 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -13,6 +13,17 @@ spin = "0.7.1" frame-support = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } weight-meter-procedural = { path = "weight-meter-procedural", default-features = false } +[dev-dependencies] +serde = { version = "1.0.124" } +codec = { package = "parity-scale-codec", version = "2.0.0" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } +sp-std = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } + +frame-support = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1"} +frame-system = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1" } + [features] default = ["std"] std = [ diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index d0df9c2a2..613f75352 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -2,6 +2,9 @@ use frame_support::weights::Weight; +// For use in mock file +extern crate self as orml_weight_meter; + struct Meter { used_weight: Weight, // Depth gets incremented when entering call or a sub-call @@ -12,6 +15,12 @@ struct Meter { mod meter_no_std; mod meter_std; +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + #[cfg(feature = "std")] pub use meter_std::*; diff --git a/weight-meter/src/mock.rs b/weight-meter/src/mock.rs new file mode 100644 index 000000000..c9c03b884 --- /dev/null +++ b/weight-meter/src/mock.rs @@ -0,0 +1,279 @@ +#[frame_support::pallet] +pub mod test_module { + use frame_support::weights::PostDispatchInfo; + use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; + use frame_system::pallet_prelude::*; + use orml_weight_meter; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + #[pallet::generate_store(pub(super) trait Store)] + pub struct Pallet(PhantomData); + + #[pallet::hooks] + impl Hooks for Pallet {} + + #[pallet::storage] + #[pallet::getter(fn something)] + pub type Something = StorageValue<_, u32>; + + #[pallet::call] + impl Pallet { + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(0)] + pub fn expect_100(origin: OriginFor) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + Self::put_100(); + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(0)] + pub fn expect_500(origin: OriginFor) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + Self::put_100(); + Self::put_100(); + Self::put_100(); + Self::put_100(); + Self::put_100(); + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(0)] + pub fn expect_max_weight(origin: OriginFor) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + Self::max_weight(); + Self::put_100(); + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(0)] + pub fn expect_100_or_200(origin: OriginFor, branch: bool) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + if branch { + Self::put_200(); + } else { + Self::put_100(); + } + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(0)] + pub fn nested_inner_methods(origin: OriginFor) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + Self::put_300_nested(); + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(200)] + pub fn start_with_200(origin: OriginFor) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(200)] + pub fn start_with_200_add_100(origin: OriginFor) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + Self::put_100(); + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(200)] + pub fn start_with_200_branch(origin: OriginFor, branch: bool) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + if branch { + Self::put_200(); + } else { + Self::put_100(); + } + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start_with(u64::MAX)] + pub fn start_with_max_weight(origin: OriginFor) -> DispatchResultWithPostInfo { + ensure_signed(origin)?; + + Self::put_100(); + + Ok(PostDispatchInfo { + actual_weight: Some(orml_weight_meter::used_weight()), + pays_fee: Pays::Yes, + }) + } + } + + impl Pallet { + #[orml_weight_meter::weight(100)] + fn put_100() { + let something = Self::something(); + + if let Some(v) = something { + Something::::put(v.checked_add(100).unwrap()); + } else { + Something::::put(100); + } + } + + #[orml_weight_meter::weight(200)] + fn put_200() { + let something = Self::something(); + + if let Some(v) = something { + Something::::put(v.checked_add(200).unwrap()); + } else { + Something::::put(100); + } + } + + #[orml_weight_meter::weight(200)] + fn put_300_nested() { + Self::put_100(); + } + + #[orml_weight_meter::weight(u64::MAX)] + fn max_weight() { + return; + } + } +} + +use frame_support::sp_runtime::traits::IdentityLookup; +use sp_runtime::testing::{Header, H256}; + +pub type BlockNumber = u64; + +frame_support::parameter_types! { + pub const BlockHashCount: u64 = 250; +} + +type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; +type Block = frame_system::mocking::MockBlock; +type Balance = u128; + +impl frame_system::Config for Runtime { + type Origin = Origin; + type Index = u64; + type BlockNumber = BlockNumber; + type Call = Call; + type Hash = H256; + type Hashing = ::sp_runtime::traits::BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = Event; + type BlockHashCount = BlockHashCount; + type BlockWeights = (); + type BlockLength = (); + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type DbWeight = (); + type BaseCallFilter = (); + type SystemWeightInfo = (); + type SS58Prefix = (); + type OnSetCode = (); +} + +frame_support::parameter_types! { + pub const ExistentialDeposit: u64 = 1; +} + +impl pallet_balances::Config for Runtime { + type Balance = Balance; + type Event = Event; + type DustRemoval = (); + type ExistentialDeposit = ExistentialDeposit; + type AccountStore = frame_system::Pallet; + type MaxLocks = (); + type WeightInfo = (); +} + +impl test_module::Config for Runtime {} + +frame_support::construct_runtime!( + pub enum Runtime where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + System: frame_system::{Pallet, Call, Storage, Config, Event}, + TestModule: test_module::{Pallet, Call, Storage}, + Balances: pallet_balances::{Pallet, Call, Storage, Config, Event}, + } +); + +pub struct ExtBuilder(); + +impl Default for ExtBuilder { + fn default() -> Self { + Self() + } +} + +impl ExtBuilder { + pub fn build(self) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::default() + .build_storage::() + .unwrap(); + + pallet_balances::GenesisConfig:: { + balances: vec![(100, 100_000)], + } + .assimilate_storage(&mut t) + .unwrap(); + + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext + } +} diff --git a/weight-meter/src/tests.rs b/weight-meter/src/tests.rs new file mode 100644 index 000000000..7c38763f1 --- /dev/null +++ b/weight-meter/src/tests.rs @@ -0,0 +1,91 @@ +use crate::mock::*; +use frame_support::weights::PostDispatchInfo; + +#[test] +fn used_weight_works() { + ExtBuilder::default().build().execute_with(|| { + let result: PostDispatchInfo = TestModule::expect_100(Origin::signed(100)).unwrap(); + // Check used weight is correct + assert_eq!(Some(100), result.actual_weight); + // Check that the method ran correctly + assert_eq!(Some(100), TestModule::something()); + + let result: PostDispatchInfo = TestModule::expect_500(Origin::signed(100)).unwrap(); + assert_eq!(Some(500), result.actual_weight); + assert_eq!(Some(600), TestModule::something()); + }); +} + +#[test] +fn used_weight_branch_works() { + ExtBuilder::default().build().execute_with(|| { + let result: PostDispatchInfo = TestModule::expect_100_or_200(Origin::signed(100), false).unwrap(); + // Check used weight is correct + assert_eq!(Some(100), result.actual_weight); + // Check that the method ran correctly + assert_eq!(Some(100), TestModule::something()); + + let result: PostDispatchInfo = TestModule::expect_100_or_200(Origin::signed(100), true).unwrap(); + // Check used weight is correct + assert_eq!(Some(200), result.actual_weight); + // Check that the method ran correctly + assert_eq!(Some(300), TestModule::something()); + }); +} + +#[test] +fn used_weight_nested_calls_works() { + ExtBuilder::default().build().execute_with(|| { + let result: PostDispatchInfo = TestModule::nested_inner_methods(Origin::signed(100)).unwrap(); + // Check used weight is correct + assert_eq!(Some(300), result.actual_weight); + }); +} + +#[test] +fn exceed_max_weight_works() { + ExtBuilder::default().build().execute_with(|| { + let result: PostDispatchInfo = TestModule::expect_max_weight(Origin::signed(100)).unwrap(); + // Check used weight is correct + assert_eq!(Some(u64::MAX), result.actual_weight); + }); +} + +#[test] +fn start_with_works() { + ExtBuilder::default().build().execute_with(|| { + let result: PostDispatchInfo = TestModule::start_with_200(Origin::signed(100)).unwrap(); + // Check used weight is correct + assert_eq!(Some(200), result.actual_weight); + // Check that the method ran correctly + assert_eq!(None, TestModule::something()); + + let result: PostDispatchInfo = TestModule::start_with_200_add_100(Origin::signed(100)).unwrap(); + // Check used weight is correct + assert_eq!(Some(300), result.actual_weight); + // Check that the method ran correctly + assert_eq!(Some(100), TestModule::something()); + }); +} + +#[test] +fn start_with_branch_works() { + ExtBuilder::default().build().execute_with(|| { + let result: PostDispatchInfo = TestModule::start_with_200_branch(Origin::signed(100), false).unwrap(); + // Check used weight is correct + assert_eq!(Some(300), result.actual_weight); + + let result: PostDispatchInfo = TestModule::start_with_200_branch(Origin::signed(100), true).unwrap(); + // Check used weight is correct + assert_eq!(Some(400), result.actual_weight); + }); +} + +#[test] +fn start_with_max_weight_works() { + ExtBuilder::default().build().execute_with(|| { + let result: PostDispatchInfo = TestModule::start_with_max_weight(Origin::signed(100)).unwrap(); + // Check used weight is correct + assert_eq!(Some(u64::MAX), result.actual_weight); + }); +} From 1f25e71934e5c107161b73aa9381796483b9c627 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Tue, 11 May 2021 19:16:36 -0400 Subject: [PATCH 35/42] Removed starting weight --- weight-meter/src/lib.rs | 2 +- weight-meter/src/meter_no_std.rs | 4 +- weight-meter/src/meter_std.rs | 4 +- weight-meter/src/mock.rs | 18 ++++----- weight-meter/src/tests.rs | 39 ------------------- .../weight-meter-procedural/src/lib.rs | 5 +-- 6 files changed, 16 insertions(+), 56 deletions(-) diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 613f75352..6f2d8918a 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -28,7 +28,7 @@ pub use meter_std::*; pub use meter_no_std::*; /// Start weight meter with base weight -pub use weight_meter_procedural::start_with; +pub use weight_meter_procedural::start; /// Measure each methods weight pub use weight_meter_procedural::weight; diff --git a/weight-meter/src/meter_no_std.rs b/weight-meter/src/meter_no_std.rs index 7e2a9be83..32b129363 100644 --- a/weight-meter/src/meter_no_std.rs +++ b/weight-meter/src/meter_no_std.rs @@ -8,10 +8,10 @@ static mut METER: Meter = Meter { depth: 0, }; -pub fn start_with(base: Weight) { +pub fn start() { unsafe { if METER.depth == 0 { - METER.used_weight = base; + METER.used_weight = 0; } METER.depth = METER.depth.saturating_add(1); } diff --git a/weight-meter/src/meter_std.rs b/weight-meter/src/meter_std.rs index 78e80eddb..e30985423 100644 --- a/weight-meter/src/meter_std.rs +++ b/weight-meter/src/meter_std.rs @@ -12,11 +12,11 @@ thread_local! { } /// Start weight meter with base weight -pub fn start_with(base: Weight) { +pub fn start_with() { METER.with(|v| { let mut meter = v.borrow_mut(); if meter.depth == 0 { - meter.used_weight = base; + meter.used_weight = 0; } meter.depth = meter.depth.saturating_add(1); }); diff --git a/weight-meter/src/mock.rs b/weight-meter/src/mock.rs index c9c03b884..950a2a195 100644 --- a/weight-meter/src/mock.rs +++ b/weight-meter/src/mock.rs @@ -22,7 +22,7 @@ pub mod test_module { #[pallet::call] impl Pallet { #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(0)] + #[orml_weight_meter::start] pub fn expect_100(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_signed(origin)?; @@ -35,7 +35,7 @@ pub mod test_module { } #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(0)] + #[orml_weight_meter::start] pub fn expect_500(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_signed(origin)?; @@ -52,7 +52,7 @@ pub mod test_module { } #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(0)] + #[orml_weight_meter::start] pub fn expect_max_weight(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_signed(origin)?; @@ -66,7 +66,7 @@ pub mod test_module { } #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(0)] + #[orml_weight_meter::start] pub fn expect_100_or_200(origin: OriginFor, branch: bool) -> DispatchResultWithPostInfo { ensure_signed(origin)?; @@ -83,7 +83,7 @@ pub mod test_module { } #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(0)] + #[orml_weight_meter::start] pub fn nested_inner_methods(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_signed(origin)?; @@ -96,7 +96,7 @@ pub mod test_module { } #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(200)] + #[orml_weight_meter::start] pub fn start_with_200(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_signed(origin)?; @@ -107,7 +107,7 @@ pub mod test_module { } #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(200)] + #[orml_weight_meter::start] pub fn start_with_200_add_100(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_signed(origin)?; @@ -120,7 +120,7 @@ pub mod test_module { } #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(200)] + #[orml_weight_meter::start] pub fn start_with_200_branch(origin: OriginFor, branch: bool) -> DispatchResultWithPostInfo { ensure_signed(origin)?; @@ -137,7 +137,7 @@ pub mod test_module { } #[pallet::weight(50_000)] - #[orml_weight_meter::start_with(u64::MAX)] + #[orml_weight_meter::start] pub fn start_with_max_weight(origin: OriginFor) -> DispatchResultWithPostInfo { ensure_signed(origin)?; diff --git a/weight-meter/src/tests.rs b/weight-meter/src/tests.rs index 7c38763f1..f509b08dc 100644 --- a/weight-meter/src/tests.rs +++ b/weight-meter/src/tests.rs @@ -50,42 +50,3 @@ fn exceed_max_weight_works() { assert_eq!(Some(u64::MAX), result.actual_weight); }); } - -#[test] -fn start_with_works() { - ExtBuilder::default().build().execute_with(|| { - let result: PostDispatchInfo = TestModule::start_with_200(Origin::signed(100)).unwrap(); - // Check used weight is correct - assert_eq!(Some(200), result.actual_weight); - // Check that the method ran correctly - assert_eq!(None, TestModule::something()); - - let result: PostDispatchInfo = TestModule::start_with_200_add_100(Origin::signed(100)).unwrap(); - // Check used weight is correct - assert_eq!(Some(300), result.actual_weight); - // Check that the method ran correctly - assert_eq!(Some(100), TestModule::something()); - }); -} - -#[test] -fn start_with_branch_works() { - ExtBuilder::default().build().execute_with(|| { - let result: PostDispatchInfo = TestModule::start_with_200_branch(Origin::signed(100), false).unwrap(); - // Check used weight is correct - assert_eq!(Some(300), result.actual_weight); - - let result: PostDispatchInfo = TestModule::start_with_200_branch(Origin::signed(100), true).unwrap(); - // Check used weight is correct - assert_eq!(Some(400), result.actual_weight); - }); -} - -#[test] -fn start_with_max_weight_works() { - ExtBuilder::default().build().execute_with(|| { - let result: PostDispatchInfo = TestModule::start_with_max_weight(Origin::signed(100)).unwrap(); - // Check used weight is correct - assert_eq!(Some(u64::MAX), result.actual_weight); - }); -} diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index e65dba4e0..15af8f310 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -5,13 +5,12 @@ use syn::ItemFn; mod method_injector; #[proc_macro_attribute] -pub fn start_with(attr: TokenStream, item: TokenStream) -> TokenStream { - let base_weight: syn::Expr = syn::parse(attr).unwrap(); +pub fn start(_attr: TokenStream, item: TokenStream) -> TokenStream { let ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); (quote! { #(#attrs)* #vis #sig { - ::orml_weight_meter::start_with(#base_weight); + ::orml_weight_meter::start_with(); let result = #block; ::orml_weight_meter::finish(); result From 21e3ed412b32882f2d2ef279b6451d9c4035f301 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Tue, 11 May 2021 19:27:45 -0400 Subject: [PATCH 36/42] Removed method_benchmark/updated inner docs --- weight-meter/src/lib.rs | 97 ++++++++----------- .../weight-meter-procedural/src/lib.rs | 8 -- 2 files changed, 40 insertions(+), 65 deletions(-) diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 6f2d8918a..86c974742 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -1,50 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::weights::Weight; - -// For use in mock file -extern crate self as orml_weight_meter; - -struct Meter { - used_weight: Weight, - // Depth gets incremented when entering call or a sub-call - // This is used to avoid miscalculation during sub-calls - depth: u8, -} - -mod meter_no_std; -mod meter_std; - -#[cfg(test)] -mod mock; - -#[cfg(test)] -mod tests; - -#[cfg(feature = "std")] -pub use meter_std::*; - -#[cfg(not(feature = "std"))] -pub use meter_no_std::*; - -/// Start weight meter with base weight -pub use weight_meter_procedural::start; - -/// Measure each methods weight -pub use weight_meter_procedural::weight; - -/// `method_benchmarks` attribute macro let's you benchmark inner methods -/// -/// 1. Add macro attribute on top of the module declaration -/// ```ignore -/// #[orml_weight_meter::method_benchmarks] -/// #[frame_support::pallet] -/// pub mod module { -/// .. -/// } -/// ``` -/// -/// 2. Add macro attribute on method you want to benchmark. +//! 1. Add macro attribute on method you want to benchmark. /// ```ignore /// #[orml_weight_meter::weight(0)] /// fn inner_do_something(something: u32) { @@ -58,14 +14,9 @@ pub use weight_meter_procedural::weight; /// name. This only works for methods with `orml_weight_meter::weight` attribute /// and only when running benchmarks. /// -/// 3. Create benchmarks as we normally do. Just need to use prefix `method_` -/// followed by method name. -/// ```ignore -/// method_inner_do_something { -/// let caller = whitelisted_caller(); -/// }: _(frame_system::RawOrigin::Signed(caller), 10) -/// ``` -/// After running benchmarks and weights been generated then we can replace ` +/// 2. Create benchmarks using orml_bencher and generate the weights with +/// orml_weight_gen +/// After running the benchmarks and the weights have been generated then we can replace /// ```ignore /// #[orml_weight_meter::weight(0)] /// ``` @@ -74,13 +25,13 @@ pub use weight_meter_procedural::weight; /// #[orml_weight_meter::weight(T::WeightInfo::method_inner_do_something())] /// ``` /// -/// 4. Use WeightMeter on your calls by adding macro -/// `#[orml_weight_meter::start_with()]` and at the end use +/// 3. Use WeightMeter on your calls by adding macro +/// `#[orml_weight_meter::start]` and at the end use /// `orml_weight_meter::used_weight()` to get used weight. ```ignore /// #[pallet::call] /// impl Pallet { /// #[pallet::weight(T::WeightInfo::do_something())] -/// #[orml_weight_meter::start_with(1_000_000)] +/// #[orml_weight_meter::start] /// pub fn do_something(origin: OriginFor, something: u32) -> /// DispatchResultWithPostInfo { /// let who = ensure_signed(origin)?; @@ -91,4 +42,36 @@ pub use weight_meter_procedural::weight; /// } /// } /// ``` -pub use weight_meter_procedural::method_benchmarks; + +use frame_support::weights::Weight; + +// For use in mock file +extern crate self as orml_weight_meter; + +struct Meter { + used_weight: Weight, + // Depth gets incremented when entering call or a sub-call + // This is used to avoid miscalculation during sub-calls + depth: u8, +} + +mod meter_no_std; +mod meter_std; + +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "std")] +pub use meter_std::*; + +#[cfg(not(feature = "std"))] +pub use meter_no_std::*; + +/// Start weight meter with base weight +pub use weight_meter_procedural::start; + +/// Measure each methods weight +pub use weight_meter_procedural::weight; diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index 15af8f310..2bf423eb6 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -32,11 +32,3 @@ pub fn weight(attr: TokenStream, item: TokenStream) -> TokenStream { }) .into() } - -#[proc_macro_attribute] -pub fn method_benchmarks(_attr: TokenStream, input: TokenStream) -> TokenStream { - #[cfg(feature = "runtime-benchmarks")] - return method_injector::inject_methods(input); - #[cfg(not(feature = "runtime-benchmarks"))] - return input; -} From 4ac388e7e4123a97f9d6682cbda92a7d0ef5ed29 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Tue, 11 May 2021 20:30:59 -0400 Subject: [PATCH 37/42] clippy and fmt --- weight-meter/src/lib.rs | 84 +++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 86c974742..59a5bb5ea 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -1,47 +1,49 @@ #![cfg_attr(not(feature = "std"), no_std)] //! 1. Add macro attribute on method you want to benchmark. -/// ```ignore -/// #[orml_weight_meter::weight(0)] -/// fn inner_do_something(something: u32) { -/// // Update storage. -/// Something::::put(something); -/// } -/// ``` -/// Start with `0` and after the weights is generated then it can be replaced -/// with generated weight. Macro will inject callable methods that wraps inner -/// methods. Generated call will start with prefix `method_` followed by method -/// name. This only works for methods with `orml_weight_meter::weight` attribute -/// and only when running benchmarks. -/// -/// 2. Create benchmarks using orml_bencher and generate the weights with -/// orml_weight_gen -/// After running the benchmarks and the weights have been generated then we can replace -/// ```ignore -/// #[orml_weight_meter::weight(0)] -/// ``` -/// with -/// ```ignore -/// #[orml_weight_meter::weight(T::WeightInfo::method_inner_do_something())] -/// ``` -/// -/// 3. Use WeightMeter on your calls by adding macro -/// `#[orml_weight_meter::start]` and at the end use -/// `orml_weight_meter::used_weight()` to get used weight. ```ignore -/// #[pallet::call] -/// impl Pallet { -/// #[pallet::weight(T::WeightInfo::do_something())] -/// #[orml_weight_meter::start] -/// pub fn do_something(origin: OriginFor, something: u32) -> -/// DispatchResultWithPostInfo { -/// let who = ensure_signed(origin)?; -/// Self::inner_do_something(something); -/// // Emit an event. -/// Self::deposit_event(Event::SomethingStored(something, who)); -/// Ok(PostDispatchInfo::from(Some(orml_weight_meter::used_weight()))) -/// } -/// } -/// ``` +//! ```ignore +//! #[orml_weight_meter::weight(0)] +//! fn inner_do_something(something: u32) { +//! // Update storage. +//! Something::::put(something); +//! } +//! ``` +//! Start with `0` and after the weights is generated then it can be replaced +//! with generated weight. Macro will inject callable methods that wraps inner +//! methods. Generated call will start with prefix `method_` followed by method +//! name. This only works for methods with `orml_weight_meter::weight` attribute +//! and only when running benchmarks. +//! +//! 2. Create benchmarks using orml_bencher and generate the weights with +//! orml_weight_gen +//! After running the benchmarks and the weights have been generated then we can +//! replace +//! ```ignore +//! #[orml_weight_meter::weight(0)] +//! ``` +//! with +//!```ignore +//! #[orml_weight_meter::weight(T::WeightInfo::method_inner_do_something())] +//! ``` +//! +//! 3. Use WeightMeter on your calls by adding macro +//! `#[orml_weight_meter::start]` and at the end use +//! `orml_weight_meter::used_weight()` to get used weight. +//!```ignore +//! #[pallet::call] +//! impl Pallet { +//! #[pallet::weight(T::WeightInfo::do_something())] +//! #[orml_weight_meter::start] +//! pub fn do_something(origin: OriginFor, something: u32) -> +//! DispatchResultWithPostInfo { +//! let who = ensure_signed(origin)?; +//! Self::inner_do_something(something); +//! // Emit an event. +//! Self::deposit_event(Event::SomethingStored(something, who)); +//! Ok(PostDispatchInfo::from(Some(orml_weight_meter::used_weight()))) +//! } +//! } +//! ``` use frame_support::weights::Weight; From a19888dbafb6673abcf71c8f8c78b830ec595db2 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Fri, 14 May 2021 16:16:12 -0400 Subject: [PATCH 38/42] changed start_with to start --- weight-meter/src/meter_std.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weight-meter/src/meter_std.rs b/weight-meter/src/meter_std.rs index e30985423..1e6c4687e 100644 --- a/weight-meter/src/meter_std.rs +++ b/weight-meter/src/meter_std.rs @@ -12,7 +12,7 @@ thread_local! { } /// Start weight meter with base weight -pub fn start_with() { +pub fn start() { METER.with(|v| { let mut meter = v.borrow_mut(); if meter.depth == 0 { From 6f029fad1bf0322fc5ff70181381d961a3e032d0 Mon Sep 17 00:00:00 2001 From: Brett Kolodny Date: Fri, 14 May 2021 16:22:58 -0400 Subject: [PATCH 39/42] Changed start_with to start in macro --- weight-meter/weight-meter-procedural/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index 2bf423eb6..4a5eecd23 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -10,7 +10,7 @@ pub fn start(_attr: TokenStream, item: TokenStream) -> TokenStream { (quote! { #(#attrs)* #vis #sig { - ::orml_weight_meter::start_with(); + ::orml_weight_meter::start(); let result = #block; ::orml_weight_meter::finish(); result From ec787cbd076230bd3229bf98dad13ff4b007dbf9 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Mon, 17 May 2021 12:10:09 +0200 Subject: [PATCH 40/42] cleanup --- weight-meter/Cargo.toml | 1 - weight-meter/README.md | 4 - weight-meter/src/lib.rs | 2 +- weight-meter/src/mock.rs | 54 --------- .../weight-meter-procedural/Cargo.toml | 3 +- .../weight-meter-procedural/src/lib.rs | 2 - .../src/method_injector.rs | 107 ------------------ 7 files changed, 2 insertions(+), 171 deletions(-) delete mode 100644 weight-meter/weight-meter-procedural/src/method_injector.rs diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml index c6832150e..7ae22ae33 100644 --- a/weight-meter/Cargo.toml +++ b/weight-meter/Cargo.toml @@ -30,4 +30,3 @@ std = [ "frame-support/std", "weight-meter-procedural/std", ] -runtime-benchmarks = ["weight-meter-procedural/runtime-benchmarks"] diff --git a/weight-meter/README.md b/weight-meter/README.md index 6d30487d1..26f821e28 100644 --- a/weight-meter/README.md +++ b/weight-meter/README.md @@ -9,9 +9,5 @@ std = [ .. 'orml-weight-meter/std', ] -runtime-benchmarks = [ - .. - 'orml-weight-meter/runtime-benchmarks', -] ``` \ No newline at end of file diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index 59a5bb5ea..fce5db764 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -72,7 +72,7 @@ pub use meter_std::*; #[cfg(not(feature = "std"))] pub use meter_no_std::*; -/// Start weight meter with base weight +/// Start weight meter pub use weight_meter_procedural::start; /// Measure each methods weight diff --git a/weight-meter/src/mock.rs b/weight-meter/src/mock.rs index 950a2a195..b91b24a02 100644 --- a/weight-meter/src/mock.rs +++ b/weight-meter/src/mock.rs @@ -94,60 +94,6 @@ pub mod test_module { pays_fee: Pays::Yes, }) } - - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - pub fn start_with_200(origin: OriginFor) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) - } - - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - pub fn start_with_200_add_100(origin: OriginFor) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - Self::put_100(); - - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) - } - - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - pub fn start_with_200_branch(origin: OriginFor, branch: bool) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - if branch { - Self::put_200(); - } else { - Self::put_100(); - } - - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) - } - - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - pub fn start_with_max_weight(origin: OriginFor) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - Self::put_100(); - - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) - } } impl Pallet { diff --git a/weight-meter/weight-meter-procedural/Cargo.toml b/weight-meter/weight-meter-procedural/Cargo.toml index c72305821..05554eea1 100644 --- a/weight-meter/weight-meter-procedural/Cargo.toml +++ b/weight-meter/weight-meter-procedural/Cargo.toml @@ -15,5 +15,4 @@ syn = { version = "1.0.58", features = ["full"] } [features] default = ["std"] -std = [] -runtime-benchmarks = [] \ No newline at end of file +std = [] \ No newline at end of file diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs index 4a5eecd23..87f5f753c 100644 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ b/weight-meter/weight-meter-procedural/src/lib.rs @@ -2,8 +2,6 @@ use proc_macro::TokenStream; use quote::quote; use syn::ItemFn; -mod method_injector; - #[proc_macro_attribute] pub fn start(_attr: TokenStream, item: TokenStream) -> TokenStream { let ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); diff --git a/weight-meter/weight-meter-procedural/src/method_injector.rs b/weight-meter/weight-meter-procedural/src/method_injector.rs deleted file mode 100644 index 4e986ab64..000000000 --- a/weight-meter/weight-meter-procedural/src/method_injector.rs +++ /dev/null @@ -1,107 +0,0 @@ -#![cfg(feature = "runtime-benchmarks")] - -use proc_macro::TokenStream; -use quote::{format_ident, quote, ToTokens}; -use syn::{Attribute, FnArg, Ident, ImplItem, ImplItemMethod, Item, ItemImpl, ItemMod, Pat}; - -pub fn inject_methods(input: TokenStream) -> TokenStream { - let mut methods: Vec = vec![]; - - let mut item: ItemMod = syn::parse(input).unwrap(); - let (brace, content) = item.content.clone().unwrap(); - - let whitelist = find_methods(&content); - - // Generate callable methods dynamically - content.iter().for_each(|item| { - if let Item::Impl(ItemImpl { items, .. }) = item { - items.iter().for_each(|item_impl| { - if let ImplItem::Method(ImplItemMethod { sig, .. }) = item_impl { - let method_name = sig.ident.clone(); - - // generate call method if whitelisted - if whitelist.contains(&method_name) { - let call_method_name = format_ident!("method_{}", method_name); - let args = sig.inputs.iter().collect::>(); - let inputs = sig.inputs.iter().map(|x| argument_name(&x)).collect::>(); - - // construct call method - let method = quote! { - #[pallet::weight(0)] - pub fn #call_method_name(_origin: OriginFor, #(#args),*) -> DispatchResultWithPostInfo { - Self::#method_name(#(#inputs),*); - Ok(().into()) - } - }; - - let call_method: ImplItemMethod = syn::parse(method.into()).unwrap(); - methods.push(ImplItem::from(call_method)); - } - } - }); - } - }); - - // Inject methods into #[pallet::call] impl - let new_content = content - .into_iter() - .map(|item| { - if let Item::Impl(mut item_impl) = item { - if has_attribute(&item_impl.attrs, "pallet::call") { - item_impl.items.append(&mut methods); - } - return Item::from(item_impl); - } else { - item - } - }) - .collect::>(); - - // update content - item.content = Some((brace, new_content)); - - item.into_token_stream().into() -} - -fn has_attribute(attrs: &Vec, attr: &str) -> bool { - if attrs.is_empty() { - return false; - } - let attributes = attrs - .iter() - .map(|a| { - a.path - .segments - .iter() - .map(|p| p.ident.to_string()) - .collect::>() - .join("::") - }) - .collect::>(); - attributes.contains(&attr.to_string()) -} - -// Find methods with attribute `#[orml_weight_meter::weight]` -fn find_methods(content: &Vec) -> Vec { - let mut methods = vec![]; - content.iter().for_each(|content| { - if let Item::Impl(item_impl) = content { - item_impl.items.iter().for_each(|item| { - if let ImplItem::Method(ImplItemMethod { attrs, sig, .. }) = item { - if has_attribute(&attrs, "orml_weight_meter::weight") { - methods.push(sig.ident.clone()); - } - } - }); - } - }); - methods -} - -// Extract name from function argument -fn argument_name(x: &FnArg) -> Box { - match x { - FnArg::Receiver(_) => panic!("unexpected argument self"), - FnArg::Typed(ty) => ty.pat.clone(), - } -} From 223046a80da8dee8bb2a9964cf0df0c918962236 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Mon, 17 May 2021 18:47:59 +0200 Subject: [PATCH 41/42] refactor --- weight-meter/src/lib.rs | 7 ++--- weight-meter/src/mock.rs | 54 +++++++++++++++++++++------------------ weight-meter/src/tests.rs | 16 +++++++++--- 3 files changed, 45 insertions(+), 32 deletions(-) diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs index fce5db764..cfdc45d12 100644 --- a/weight-meter/src/lib.rs +++ b/weight-meter/src/lib.rs @@ -47,9 +47,6 @@ use frame_support::weights::Weight; -// For use in mock file -extern crate self as orml_weight_meter; - struct Meter { used_weight: Weight, // Depth gets incremented when entering call or a sub-call @@ -60,6 +57,10 @@ struct Meter { mod meter_no_std; mod meter_std; +// For use in mock file +#[cfg(test)] +extern crate self as orml_weight_meter; + #[cfg(test)] mod mock; diff --git a/weight-meter/src/mock.rs b/weight-meter/src/mock.rs index b91b24a02..ecc10e796 100644 --- a/weight-meter/src/mock.rs +++ b/weight-meter/src/mock.rs @@ -1,9 +1,7 @@ #[frame_support::pallet] pub mod test_module { - use frame_support::weights::PostDispatchInfo; - use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*}; + use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*, weights::Weight}; use frame_system::pallet_prelude::*; - use orml_weight_meter; #[pallet::config] pub trait Config: frame_system::Config {} @@ -28,10 +26,7 @@ pub mod test_module { Self::put_100(); - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) + Ok(Some(orml_weight_meter::used_weight()).into()) } #[pallet::weight(50_000)] @@ -45,10 +40,7 @@ pub mod test_module { Self::put_100(); Self::put_100(); - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) + Ok(Some(orml_weight_meter::used_weight()).into()) } #[pallet::weight(50_000)] @@ -59,10 +51,7 @@ pub mod test_module { Self::max_weight(); Self::put_100(); - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) + Ok(Some(orml_weight_meter::used_weight()).into()) } #[pallet::weight(50_000)] @@ -76,10 +65,7 @@ pub mod test_module { Self::put_100(); } - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) + Ok(Some(orml_weight_meter::used_weight()).into()) } #[pallet::weight(50_000)] @@ -89,10 +75,24 @@ pub mod test_module { Self::put_300_nested(); - Ok(PostDispatchInfo { - actual_weight: Some(orml_weight_meter::used_weight()), - pays_fee: Pays::Yes, - }) + Ok(Some(orml_weight_meter::used_weight()).into()) + } + + #[pallet::weight(50_000)] + #[orml_weight_meter::start] + pub fn nested_extrinsic(origin: OriginFor) -> DispatchResultWithPostInfo { + ensure_signed(origin.clone())?; + + // some module call + Self::put_300_nested(); + + // call extrinsic method + Self::expect_100(origin)?; + + // some module call + Self::put_300_nested(); + + Ok(Some(orml_weight_meter::used_weight()).into()) } } @@ -124,7 +124,7 @@ pub mod test_module { Self::put_100(); } - #[orml_weight_meter::weight(u64::MAX)] + #[orml_weight_meter::weight(Weight::MAX)] fn max_weight() { return; } @@ -137,7 +137,7 @@ use sp_runtime::testing::{Header, H256}; pub type BlockNumber = u64; frame_support::parameter_types! { - pub const BlockHashCount: u64 = 250; + pub const BlockHashCount: u64 = 250; } type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; @@ -223,3 +223,7 @@ impl ExtBuilder { ext } } + +pub fn new_test_ext() -> sp_io::TestExternalities { + ExtBuilder::default().build() +} diff --git a/weight-meter/src/tests.rs b/weight-meter/src/tests.rs index f509b08dc..8d4c1bae3 100644 --- a/weight-meter/src/tests.rs +++ b/weight-meter/src/tests.rs @@ -3,7 +3,7 @@ use frame_support::weights::PostDispatchInfo; #[test] fn used_weight_works() { - ExtBuilder::default().build().execute_with(|| { + new_test_ext().execute_with(|| { let result: PostDispatchInfo = TestModule::expect_100(Origin::signed(100)).unwrap(); // Check used weight is correct assert_eq!(Some(100), result.actual_weight); @@ -18,7 +18,7 @@ fn used_weight_works() { #[test] fn used_weight_branch_works() { - ExtBuilder::default().build().execute_with(|| { + new_test_ext().execute_with(|| { let result: PostDispatchInfo = TestModule::expect_100_or_200(Origin::signed(100), false).unwrap(); // Check used weight is correct assert_eq!(Some(100), result.actual_weight); @@ -35,7 +35,7 @@ fn used_weight_branch_works() { #[test] fn used_weight_nested_calls_works() { - ExtBuilder::default().build().execute_with(|| { + new_test_ext().execute_with(|| { let result: PostDispatchInfo = TestModule::nested_inner_methods(Origin::signed(100)).unwrap(); // Check used weight is correct assert_eq!(Some(300), result.actual_weight); @@ -44,9 +44,17 @@ fn used_weight_nested_calls_works() { #[test] fn exceed_max_weight_works() { - ExtBuilder::default().build().execute_with(|| { + new_test_ext().execute_with(|| { let result: PostDispatchInfo = TestModule::expect_max_weight(Origin::signed(100)).unwrap(); // Check used weight is correct assert_eq!(Some(u64::MAX), result.actual_weight); }); } + +#[test] +fn nested_module_calls_works() { + new_test_ext().execute_with(|| { + let result = TestModule::nested_extrinsic(Origin::signed(0)).unwrap(); + assert_eq!(result.actual_weight, Some(700)); + }); +} From 529a79c23fe36f05b34d45380d9534abea5f9a88 Mon Sep 17 00:00:00 2001 From: Ermal Kaleci Date: Tue, 18 May 2021 00:10:02 +0200 Subject: [PATCH 42/42] fix clippy --- Cargo.dev.toml | 1 + bencher/Cargo.toml | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.dev.toml b/Cargo.dev.toml index 5f890844c..1b3b68b5b 100644 --- a/Cargo.dev.toml +++ b/Cargo.dev.toml @@ -70,6 +70,7 @@ sp-authority-discovery = { git = "https://github.com/paritytech//substrate", rev sc-executor-common = { git = "https://github.com/paritytech//substrate", rev = "3f110196163b5ec03bac5ee188d60bedf3ebd91d" } sc-executor-wasmi = { git = "https://github.com/paritytech//substrate", rev = "3f110196163b5ec03bac5ee188d60bedf3ebd91d" } sc-executor = { git = "https://github.com/paritytech//substrate", rev = "3f110196163b5ec03bac5ee188d60bedf3ebd91d" } +sc-client-db = { git = "https://github.com/paritytech//substrate", rev = "3f110196163b5ec03bac5ee188d60bedf3ebd91d" } sc-client-api = { git = "https://github.com/paritytech//substrate", rev = "3f110196163b5ec03bac5ee188d60bedf3ebd91d" } sp-tasks = { git = "https://github.com/paritytech//substrate", rev = "3f110196163b5ec03bac5ee188d60bedf3ebd91d" } sp-authorship = { git = "https://github.com/paritytech//substrate", rev = "3f110196163b5ec03bac5ee188d60bedf3ebd91d" } diff --git a/bencher/Cargo.toml b/bencher/Cargo.toml index b68c9f9e6..5c8eeba26 100644 --- a/bencher/Cargo.toml +++ b/bencher/Cargo.toml @@ -9,9 +9,8 @@ edition = "2018" [dependencies] linregress = { version = "0.4.0", optional = true } -handlebars = {version = "3.5.2", optional = true } -serde = { features = ['derive'], optional = true, version = "1.0.119" } -serde_json = "1.0" +serde = { version = "1.0.119", optional = true, features = ['derive'] } +serde_json = {version = "1.0.64", optional = true } codec = { package = "parity-scale-codec", version = "2.0.0", features = ["derive"], default-features = false } sp-core = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "rococo-v1", default-features = false } @@ -26,8 +25,8 @@ frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = default = ["std"] std = [ "linregress", - "handlebars", "serde/std", + "serde_json/std", "codec/std", "sp-core/std", "sp-std/std",