diff --git a/Cargo.dev.toml b/Cargo.dev.toml index 47842fc5d..988e00465 100644 --- a/Cargo.dev.toml +++ b/Cargo.dev.toml @@ -3,8 +3,6 @@ members = [ "asset-registry", "auction", "authority", - "bencher", - "bencher/test", "benchmarking", "currencies", "gradually-update", @@ -24,14 +22,10 @@ members = [ "xcm-support", "unknown-tokens", "build-script-utils", - "weight-gen", - "weight-meter", "payments", "parameters", ] -exclude = ["bencher/test"] - resolver = "2" [profile.dev] diff --git a/Makefile b/Makefile index 3e434d745..f7e5c4565 100644 --- a/Makefile +++ b/Makefile @@ -44,11 +44,9 @@ dev-check: Cargo.toml check dev-check-tests: Cargo.toml cargo check --tests --all - cargo check --tests --features=bench --package=orml-weight-meter --package=orml-bencher-test dev-test: Cargo.toml cargo test --all --features=runtime-benchmarks - cargo test --features=bench --package=orml-weight-meter --package=orml-bencher-test # run benchmarks via Acala node benchmark-all: diff --git a/README.md b/README.md index 70b7f37a2..fb711bdca 100644 --- a/README.md +++ b/README.md @@ -47,14 +47,8 @@ The Open Runtime Module Library (ORML) is a community maintained collection of S - Used by multiple parachains for their XCM token transfer implementation. #### Benchmarking -- [bencher](https://github.com/open-web3-stack/open-runtime-module-library/tree/master/bencher) - - Benchmarking tool using cargo bench for benchmarking - [benchmarking](https://github.com/open-web3-stack/open-runtime-module-library/tree/master/benchmarking) - Fork of frame-benchmarking in Substrate to allow implement runtime specific benchmarks -- [weight-gen](https://github.com/open-web3-stack/open-runtime-module-library/tree/master/weight-gen) - - Weight meter file generation -- [weight-meter](https://github.com/open-web3-stack/open-runtime-module-library/tree/master/weight-meter) - - A low overhead dynamic weight meter ## Example @@ -100,7 +94,7 @@ _In alphabetical order_ - [HydraDX](https://github.com/galacticcouncil/hack.HydraDX-node) - [Interlay and Kintsugi](https://github.com/interlay/interbtc) - [InvArch and Tinkernet](https://github.com/InvArch/InvArch-Node) -- [KodaDot: MetaPrime Network](https://github.com/kodadot/metaprime.network) +- [KodaDot: MetaPrime Network](https://github.com/kodadot/metaprime.network) - [Laminar Chain](https://github.com/laminar-protocol/laminar-chain) - [Libra](https://github.com/atscaletech/libra) - [Listen](https://github.com/listenofficial) diff --git a/bencher/Cargo.toml b/bencher/Cargo.toml deleted file mode 100644 index b1fc20d8f..000000000 --- a/bencher/Cargo.toml +++ /dev/null @@ -1,76 +0,0 @@ -[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.4.1-dev" -authors = ["Laminar Developers "] -edition = "2021" - -[dependencies] -paste = "1.0.7" -build-helper = { version = "0.1.1", optional = true } -cargo_metadata = { version = "0.15.2", optional = true } -tempfile = { version = "3.2.0", optional = true } -toml = { version = "0.5.8", optional = true } -walkdir = { version = "2.3.1", optional = true } -ansi_term = { version = "0.12.1", optional = true } -wasm-gc-api = { version = "0.1.11", optional = true } -rand = {version = "0.8.3", optional = true } -linregress = { version = "0.5.0", optional = true } -parking_lot = { version = "0.12.1", optional = true } -thiserror = { version = "1.0", optional = true } -serde = { version = "1.0.136", optional = true, features = ['derive'] } -serde_json = {version = "1.0.68", optional = true } -hash-db = { version = "0.15.2", default-features = false, optional = true } -bencher-procedural = { path = "bencher-procedural", default-features = false } -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } - -sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-io = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-runtime-interface = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-state-machine = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "polkadot-v1.0.0" } -sc-executor = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "polkadot-v1.0.0" } -sc-executor-common = { git = "https://github.com/paritytech/substrate", optional = true , branch = "polkadot-v1.0.0" } -sc-client-db = { git = "https://github.com/paritytech/substrate", default-features = false, features = ["rocksdb"], optional = true , branch = "polkadot-v1.0.0" } -sp-maybe-compressed-blob = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "polkadot-v1.0.0" } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-externalities = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-storage = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true , branch = "polkadot-v1.0.0" } - -[features] -default = ["std"] -std = [ - "bencher-procedural/std", - "build-helper", - "cargo_metadata", - "tempfile", - "toml", - "walkdir", - "ansi_term", - "wasm-gc-api", - "rand", - "linregress", - "parking_lot", - "thiserror", - "serde/std", - "serde_json/std", - "hash-db/std", - "codec/std", - "sp-core/std", - "sp-std/std", - "sp-io/std", - "sp-runtime-interface/std", - "sp-state-machine/std", - "sc-executor/std", - "sc-executor-common", - "sc-client-db", - "sp-maybe-compressed-blob", - "frame-support/std", - "sp-externalities/std", - "sp-storage/std", -] -bench = [ - "sp-io/disable_panic_handler", -] diff --git a/bencher/bencher-procedural/Cargo.toml b/bencher/bencher-procedural/Cargo.toml deleted file mode 100644 index 4dc7534e1..000000000 --- a/bencher/bencher-procedural/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "bencher-procedural" -version = "0.1.0" -license = "Apache-2.0" -authors = ["Laminar Developers "] -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0.40" -quote = "1.0.20" -syn = { version = "1.0.98", features = ["full"] } - -[features] -default = ["std"] -std = [] diff --git a/bencher/bencher-procedural/src/lib.rs b/bencher/bencher-procedural/src/lib.rs deleted file mode 100644 index 07bc2ae28..000000000 --- a/bencher/bencher-procedural/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -use proc_macro::TokenStream; - -#[proc_macro_attribute] -pub fn benchmarkable(_attr: TokenStream, item: TokenStream) -> TokenStream { - let syn::ItemFn { attrs, vis, sig, block } = syn::parse(item).unwrap(); - (quote::quote! { - #(#attrs)* - #vis #sig { - #[cfg(not(feature = "std"))] - ::orml_bencher::bench::before_block(); - let result = #block; - #[cfg(not(feature = "std"))] - ::orml_bencher::bench::after_block(); - result - } - }) - .into() -} diff --git a/bencher/src/bench_ext.rs b/bencher/src/bench_ext.rs deleted file mode 100644 index 3c94b222c..000000000 --- a/bencher/src/bench_ext.rs +++ /dev/null @@ -1,192 +0,0 @@ -use core::any::{Any, TypeId}; -use sp_core::Hasher; -use sp_externalities::{Extension, ExtensionStore, Externalities, MultiRemovalResults}; -use sp_state_machine::{Backend, Ext}; -use sp_std::sync::Arc; -use sp_storage::{ChildInfo, StateVersion, TrackedStorageKey}; - -use super::tracker::BenchTracker; - -pub struct BenchExt<'a, H, B> -where - H: Hasher, - B: 'a + Backend, -{ - ext: Ext<'a, H, B>, - tracker: Arc, -} - -impl<'a, H, B> BenchExt<'a, H, B> -where - H: Hasher, - B: 'a + Backend, -{ - pub fn new(ext: Ext<'a, H, B>, tracker: Arc) -> Self { - BenchExt { ext, tracker } - } -} - -impl<'a, H, B> Externalities for BenchExt<'a, H, B> -where - H: Hasher, - B: 'a + Backend, - H::Out: Ord + 'static + codec::Codec, -{ - fn set_offchain_storage(&mut self, key: &[u8], value: Option<&[u8]>) { - self.ext.set_offchain_storage(key, value); - } - - fn storage(&self, key: &[u8]) -> Option> { - self.tracker.on_read_storage(key.to_vec()); - self.ext.storage(key) - } - - fn storage_hash(&self, key: &[u8]) -> Option> { - self.tracker.on_read_storage(key.to_vec()); - self.ext.storage_hash(key) - } - - fn child_storage_hash(&self, child_info: &ChildInfo, key: &[u8]) -> Option> { - self.tracker.on_read_child_storage(child_info, key.to_vec()); - self.ext.child_storage_hash(child_info, key) - } - - fn child_storage(&self, child_info: &ChildInfo, key: &[u8]) -> Option> { - self.tracker.on_read_child_storage(child_info, key.to_vec()); - self.ext.child_storage(child_info, key) - } - - fn next_storage_key(&self, key: &[u8]) -> Option> { - self.tracker.on_read_storage(key.to_vec()); - self.ext.next_storage_key(key) - } - - fn next_child_storage_key(&self, child_info: &ChildInfo, key: &[u8]) -> Option> { - self.tracker.on_read_child_storage(child_info, key.to_vec()); - self.ext.next_child_storage_key(child_info, key) - } - - fn kill_child_storage( - &mut self, - child_info: &ChildInfo, - limit: Option, - maybe_cursor: Option<&[u8]>, - ) -> MultiRemovalResults { - self.tracker.on_kill_child_storage(child_info, limit); - self.ext.kill_child_storage(child_info, limit, maybe_cursor) - } - - fn clear_prefix(&mut self, prefix: &[u8], limit: Option, maybe_cursor: Option<&[u8]>) -> MultiRemovalResults { - self.tracker.on_clear_prefix(prefix, limit); - self.ext.clear_prefix(prefix, limit, maybe_cursor) - } - - fn clear_child_prefix( - &mut self, - child_info: &ChildInfo, - prefix: &[u8], - limit: Option, - maybe_cursor: Option<&[u8]>, - ) -> MultiRemovalResults { - self.tracker.on_clear_child_prefix(child_info, prefix, limit); - self.ext.clear_child_prefix(child_info, prefix, limit, maybe_cursor) - } - - fn place_storage(&mut self, key: Vec, value: Option>) { - self.tracker.on_update_storage(key.clone()); - self.ext.place_storage(key, value); - } - - fn place_child_storage(&mut self, child_info: &ChildInfo, key: Vec, value: Option>) { - self.tracker.on_update_child_storage(child_info, key.clone()); - self.ext.place_child_storage(child_info, key, value); - } - - fn storage_root(&mut self, state_version: StateVersion) -> Vec { - self.ext.storage_root(state_version) - } - - fn child_storage_root(&mut self, child_info: &ChildInfo, state_version: StateVersion) -> Vec { - self.ext.child_storage_root(child_info, state_version) - } - - fn storage_append(&mut self, key: Vec, value: Vec) { - self.tracker.on_read_storage(key.clone()); - self.tracker.on_update_storage(key.clone()); - self.ext.storage_append(key, value); - } - - fn storage_start_transaction(&mut self) { - self.ext.storage_start_transaction(); - } - - fn storage_rollback_transaction(&mut self) -> Result<(), ()> { - self.ext.storage_rollback_transaction() - } - - fn storage_commit_transaction(&mut self) -> Result<(), ()> { - self.ext.storage_commit_transaction() - } - - fn storage_index_transaction(&mut self, index: u32, hash: &[u8], size: u32) { - self.ext.storage_index_transaction(index, hash, size); - } - - fn storage_renew_transaction_index(&mut self, index: u32, hash: &[u8]) { - self.ext.storage_renew_transaction_index(index, hash); - } - - fn wipe(&mut self) { - self.ext.wipe(); - } - - fn commit(&mut self) { - self.ext.commit(); - } - - fn read_write_count(&self) -> (u32, u32, u32, u32) { - self.ext.read_write_count() - } - - fn reset_read_write_count(&mut self) { - self.ext.reset_read_write_count(); - } - - fn get_whitelist(&self) -> Vec { - self.ext.get_whitelist() - } - - fn set_whitelist(&mut self, new: Vec) { - self.ext.set_whitelist(new); - } - - fn proof_size(&self) -> Option { - self.ext.proof_size() - } - - fn get_read_and_written_keys(&self) -> Vec<(Vec, u32, u32, bool)> { - self.ext.get_read_and_written_keys() - } -} - -impl<'a, H, B> ExtensionStore for BenchExt<'a, H, B> -where - H: Hasher, - B: 'a + Backend, -{ - fn extension_by_type_id(&mut self, type_id: TypeId) -> Option<&mut dyn Any> { - self.ext.extension_by_type_id(type_id) - } - - fn register_extension_with_type_id( - &mut self, - type_id: TypeId, - extension: Box, - ) -> Result<(), sp_externalities::Error> { - self.ext.register_extension_with_type_id(type_id, extension) - } - - fn deregister_extension_by_type_id(&mut self, type_id: TypeId) -> Result<(), sp_externalities::Error> { - self.ext.deregister_extension_by_type_id(type_id) - } -} diff --git a/bencher/src/bench_runner.rs b/bencher/src/bench_runner.rs deleted file mode 100644 index aa6157775..000000000 --- a/bencher/src/bench_runner.rs +++ /dev/null @@ -1,40 +0,0 @@ -use super::{ - bench_ext::BenchExt, - tracker::{BenchTracker, BenchTrackerExt}, -}; -use frame_support::sp_runtime::traits::Block; -use sc_executor::{WasmExecutionMethod, WasmExecutor, WasmtimeInstantiationStrategy}; -use sc_executor_common::runtime_blob::RuntimeBlob; -use sp_externalities::Extensions; -use sp_state_machine::{Ext, OverlayedChanges, StorageTransactionCache}; -use sp_std::sync::Arc; - -type ComposeHostFunctions = (sp_io::SubstrateHostFunctions, super::bench::HostFunctions); - -/// Run benches -pub fn run(wasm_code: Vec) -> std::result::Result, sc_executor_common::error::Error> { - let mut overlay = OverlayedChanges::default(); - let mut cache = StorageTransactionCache::default(); - let state = sc_client_db::BenchmarkingState::::new(Default::default(), Default::default(), false, true).unwrap(); - - let tracker = Arc::new(BenchTracker::new()); - let tracker_ext = BenchTrackerExt(Arc::clone(&tracker)); - - let mut extensions = Extensions::default(); - extensions.register(tracker_ext); - - let ext = Ext::<_, _>::new(&mut overlay, &mut cache, &state, Some(&mut extensions)); - let mut bench_ext = BenchExt::new(ext, tracker); - - let executor = WasmExecutor::::builder() - .with_execution_method(WasmExecutionMethod::Compiled { - instantiation_strategy: WasmtimeInstantiationStrategy::PoolingCopyOnWrite, - }) - .with_max_runtime_instances(1) - .with_runtime_cache_size(1) - .build(); - - let blob = RuntimeBlob::uncompress_if_needed(&wasm_code[..]).unwrap(); - - executor.uncached_call(blob, &mut bench_ext, false, "run_benches", &[]) -} diff --git a/bencher/src/bencher.rs b/bencher/src/bencher.rs deleted file mode 100644 index 3ac197f2b..000000000 --- a/bencher/src/bencher.rs +++ /dev/null @@ -1,84 +0,0 @@ -use codec::{Decode, Encode}; -use sp_std::prelude::Vec; - -#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)] -pub struct BenchResult { - pub method: Vec, - pub elapses: Vec, - pub keys: Vec, -} - -impl BenchResult { - pub fn with_name(name: &str) -> Self { - Self { - method: name.as_bytes().to_vec(), - ..Default::default() - } - } -} - -#[derive(Default)] -pub struct Bencher { - pub current: BenchResult, - pub results: Vec, -} - -#[inline] -fn black_box(dummy: T) -> T { - let ret = unsafe { sp_std::ptr::read_volatile(&dummy) }; - sp_std::mem::forget(dummy); - ret -} - -#[allow(unused_variables, clippy::let_and_return)] -impl Bencher { - pub fn whitelist(&mut self, key: Vec, read: bool, write: bool) { - #[cfg(not(feature = "std"))] - crate::bench::whitelist(key, read, write); - } - - pub fn before_run(&self) { - #[cfg(not(feature = "std"))] - { - crate::bench::commit_db(); - crate::bench::wipe_db(); - } - } - - pub fn count_clear_prefix(&mut self) { - #[cfg(not(feature = "std"))] - crate::bench::count_clear_prefix(); - } - - pub fn bench(&mut self, mut inner: F) -> T - where - F: FnMut() -> T, - { - #[cfg(not(feature = "std"))] - { - crate::bench::commit_db(); - crate::bench::reset_read_write_count(); - crate::bench::start_timer(); - } - - let ret = black_box(inner()); - - #[cfg(not(feature = "std"))] - { - let elapsed = crate::bench::end_timer().saturating_sub(crate::bench::redundant_time()); - self.current.elapses.push(elapsed); - - crate::bench::commit_db(); - - // changed keys - self.current.keys = crate::bench::read_written_keys(); - } - - ret - } - - pub fn print_warnings(&self, name: &str) { - #[cfg(not(feature = "std"))] - crate::bench::print_warnings(name.encode()); - } -} diff --git a/bencher/src/build_wasm/mod.rs b/bencher/src/build_wasm/mod.rs deleted file mode 100644 index 85d866be2..000000000 --- a/bencher/src/build_wasm/mod.rs +++ /dev/null @@ -1,64 +0,0 @@ -use rand::{distributions::Alphanumeric, thread_rng, Rng}; - -pub mod prerequisites; -pub mod wasm_project; - -/// Environment variable to disable color output of the wasm build. -const WASM_BUILD_NO_COLOR: &str = "WASM_BUILD_NO_COLOR"; - -/// Returns `true` when color output is enabled. -pub fn color_output_enabled() -> bool { - std::env::var(WASM_BUILD_NO_COLOR).is_err() -} - -pub fn build() -> std::io::Result> { - let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let pkg_name = std::env::var("CARGO_PKG_NAME").unwrap(); - - let random = thread_rng() - .sample_iter(&Alphanumeric) - .take(16) - .map(char::from) - .collect::(); - - let mut out_dir = std::path::PathBuf::from(manifest_dir); - out_dir.push(format!("target/release/build/{}-{}/out", pkg_name, random)); - - std::env::set_var("OUT_DIR", out_dir.display().to_string()); - - let mut project_cargo_toml = std::env::current_dir()?; - project_cargo_toml.push("Cargo.toml"); - - let default_rustflags = "-Clink-arg=--export=__heap_base -C link-arg=--import-memory"; - let cargo_cmd = match prerequisites::check() { - Ok(cmd) => cmd, - Err(err_msg) => { - eprintln!("{}", err_msg); - std::process::exit(1); - } - }; - - let (wasm_binary, bloaty) = wasm_project::create_and_compile( - &project_cargo_toml, - default_rustflags, - cargo_cmd, - vec!["bench".to_string()], - None, - ); - - let (wasm_binary, _wasm_binary_bloaty) = if let Some(wasm_binary) = wasm_binary { - ( - wasm_binary.wasm_binary_path_escaped(), - bloaty.wasm_binary_bloaty_path_escaped(), - ) - } else { - ( - bloaty.wasm_binary_bloaty_path_escaped(), - bloaty.wasm_binary_bloaty_path_escaped(), - ) - }; - - let bytes = std::fs::read(wasm_binary)?; - - Ok(bytes.to_vec()) -} diff --git a/bencher/src/build_wasm/prerequisites.rs b/bencher/src/build_wasm/prerequisites.rs deleted file mode 100644 index c1fc8a4fa..000000000 --- a/bencher/src/build_wasm/prerequisites.rs +++ /dev/null @@ -1,297 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use crate::colorize::{color_output_enabled, red_bold, yellow_bold}; -use std::{ - env, fs, - io::BufRead, - path::{Path, PathBuf}, - process::Command, -}; - -/// Environment variable to set the toolchain used to compile the wasm binary. -pub const WASM_BUILD_TOOLCHAIN: &str = "WASM_BUILD_TOOLCHAIN"; - -/// Write to the given `file` if the `content` is different. -pub fn write_file_if_changed(file: impl AsRef, content: impl AsRef) { - if fs::read_to_string(file.as_ref()).ok().as_deref() != Some(content.as_ref()) { - fs::write(file.as_ref(), content.as_ref()) - .unwrap_or_else(|_| panic!("Writing `{}` can not fail!", file.as_ref().display())); - } -} - -/// Copy `src` to `dst` if the `dst` does not exist or is different. -pub fn copy_file_if_changed(src: PathBuf, dst: PathBuf) { - let src_file = fs::read_to_string(&src).ok(); - let dst_file = fs::read_to_string(&dst).ok(); - - if src_file != dst_file { - fs::copy(&src, &dst) - .unwrap_or_else(|_| panic!("Copying `{}` to `{}` can not fail; qed", src.display(), dst.display())); - } -} - -/// Get a cargo command that compiles with nightly -fn get_nightly_cargo() -> CargoCommand { - let env_cargo = CargoCommand::new(&env::var("CARGO").expect("`CARGO` env variable is always set by cargo")); - let default_cargo = CargoCommand::new("cargo"); - let rustup_run_nightly = CargoCommand::new_with_args("rustup", &["run", "nightly", "cargo"]); - let wasm_toolchain = env::var(WASM_BUILD_TOOLCHAIN).ok(); - - // First check if the user requested a specific toolchain - if let Some(cmd) = wasm_toolchain.and_then(|t| get_rustup_nightly(Some(t))) { - cmd - } else if env_cargo.is_nightly() { - env_cargo - } else if default_cargo.is_nightly() { - default_cargo - } else if rustup_run_nightly.is_nightly() { - rustup_run_nightly - } else { - // If no command before provided us with a nightly compiler, we try to search - // one with rustup. If that fails as well, we return the default cargo and let - // the prequisities check fail. - get_rustup_nightly(None).unwrap_or(default_cargo) - } -} - -/// Get a nightly from rustup. If `selected` is `Some(_)`, a `CargoCommand` -/// using the given nightly is returned. -fn get_rustup_nightly(selected: Option) -> Option { - let host = format!("-{}", env::var("HOST").expect("`HOST` is always set by cargo")); - - let version = match selected { - Some(selected) => selected, - None => { - let output = Command::new("rustup").args(["toolchain", "list"]).output().ok()?.stdout; - let lines = output.as_slice().lines(); - - let mut latest_nightly = None; - for line in lines.map_while(Result::ok) { - if line.starts_with("nightly-") && line.ends_with(&host) { - // Rustup prints them sorted - latest_nightly = Some(line.clone()); - } - } - - latest_nightly?.trim_end_matches(&host).into() - } - }; - - Some(CargoCommand::new_with_args("rustup", &["run", &version, "cargo"])) -} - -/// Wraps a specific command which represents a cargo invocation. -#[derive(Debug)] -pub struct CargoCommand { - program: String, - args: Vec, -} - -impl CargoCommand { - fn new(program: &str) -> Self { - CargoCommand { - program: program.into(), - args: Vec::new(), - } - } - - fn new_with_args(program: &str, args: &[&str]) -> Self { - CargoCommand { - program: program.into(), - args: args.iter().map(ToString::to_string).collect(), - } - } - - pub fn command(&self) -> Command { - let mut cmd = Command::new(&self.program); - cmd.args(&self.args); - cmd - } - - /// Check if the supplied cargo command is a nightly version - fn is_nightly(&self) -> bool { - // `RUSTC_BOOTSTRAP` tells a stable compiler to behave like a nightly. So, when - // this env variable is set, we can assume that whatever rust compiler we have, - // it is a nightly compiler. For "more" information, see: - // https://github.com/rust-lang/rust/blob/fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f/src/libsyntax/feature_gate/check.rs#L891 - env::var("RUSTC_BOOTSTRAP").is_ok() - || self - .command() - .arg("--version") - .output() - .map_err(|_| ()) - .and_then(|o| String::from_utf8(o.stdout).map_err(|_| ())) - .unwrap_or_default() - .contains("-nightly") - } -} - -/// Wraps a [`CargoCommand`] and the version of `rustc` the cargo command uses. -pub struct CargoCommandVersioned { - command: CargoCommand, - version: String, -} - -impl CargoCommandVersioned { - fn new(command: CargoCommand, version: String) -> Self { - Self { command, version } - } - - /// Returns the `rustc` version. - pub fn rustc_version(&self) -> &str { - &self.version - } -} - -impl std::ops::Deref for CargoCommandVersioned { - type Target = CargoCommand; - - fn deref(&self) -> &CargoCommand { - &self.command - } -} - -use tempfile::tempdir; - -/// Checks that all prerequisites are installed. -/// -/// Returns the versioned cargo command on success. -pub fn check() -> Result { - let cargo_command = get_nightly_cargo(); - - if !cargo_command.is_nightly() { - return Err(red_bold("Rust nightly not installed, please install it!")); - } - - check_wasm_toolchain_installed(cargo_command) -} - -/// Create the project that will be used to check that the wasm toolchain is -/// installed and to extract the rustc version. -fn create_check_toolchain_project(project_dir: &Path) { - let lib_rs_file = project_dir.join("src/lib.rs"); - let main_rs_file = project_dir.join("src/main.rs"); - let build_rs_file = project_dir.join("build.rs"); - let manifest_path = project_dir.join("Cargo.toml"); - - write_file_if_changed( - manifest_path, - r#" - [package] - name = "wasm-test" - version = "1.0.0" - edition = "2021" - build = "build.rs" - - [lib] - name = "wasm_test" - crate-type = ["cdylib"] - - [workspace] - "#, - ); - write_file_if_changed(lib_rs_file, "pub fn test() {}"); - - // We want to know the rustc version of the rustc that is being used by our - // cargo command. The cargo command is determined by some *very* complex - // algorithm to find the cargo command that supports nightly. - // The best solution would be if there is a `cargo rustc --version` command, - // which sadly doesn't exists. So, the only available way of getting the rustc - // version is to build a project and capture the rustc version in this build - // process. This `build.rs` is exactly doing this. It gets the rustc version by - // calling `rustc --version` and exposing it in the `RUSTC_VERSION` environment - // variable. - write_file_if_changed( - build_rs_file, - r#" - fn main() { - let rustc_cmd = std::env::var("RUSTC").ok().unwrap_or_else(|| "rustc".into()); - - let rustc_version = std::process::Command::new(rustc_cmd) - .arg("--version") - .output() - .ok() - .and_then(|o| String::from_utf8(o.stdout).ok()); - - println!( - "cargo:rustc-env=RUSTC_VERSION={}", - rustc_version.unwrap_or_else(|| "unknown rustc version".into()), - ); - } - "#, - ); - // Just prints the `RURSTC_VERSION` environment variable that is being created - // by the `build.rs` script. - write_file_if_changed( - main_rs_file, - r#" - fn main() { - println!("{}", env!("RUSTC_VERSION")); - } - "#, - ); -} - -fn check_wasm_toolchain_installed(cargo_command: CargoCommand) -> Result { - let temp = tempdir().expect("Creating temp dir does not fail; qed"); - fs::create_dir_all(temp.path().join("src")).expect("Creating src dir does not fail; qed"); - create_check_toolchain_project(temp.path()); - - let err_msg = red_bold("Rust WASM toolchain not installed, please install it!"); - let manifest_path = temp.path().join("Cargo.toml").display().to_string(); - - let mut build_cmd = cargo_command.command(); - build_cmd.args([ - "build", - "--target=wasm32-unknown-unknown", - "--manifest-path", - &manifest_path, - ]); - - if color_output_enabled() { - build_cmd.arg("--color=always"); - } - - let mut run_cmd = cargo_command.command(); - run_cmd.args(["run", "--manifest-path", &manifest_path]); - - build_cmd.output().map_err(|_| err_msg.clone()).and_then(|s| { - if s.status.success() { - let version = run_cmd.output().ok().and_then(|o| String::from_utf8(o.stdout).ok()); - Ok(CargoCommandVersioned::new( - cargo_command, - version.unwrap_or_else(|| "unknown rustc version".into()), - )) - } else { - match String::from_utf8(s.stderr) { - Ok(ref err) if err.contains("linker `rust-lld` not found") => { - Err(red_bold("`rust-lld` not found, please install it!")) - } - Ok(ref err) => Err(format!( - "{}\n\n{}\n{}\n{}{}\n", - err_msg, - yellow_bold("Further error information:"), - yellow_bold(&"-".repeat(60)), - err, - yellow_bold(&"-".repeat(60)), - )), - Err(_) => Err(err_msg), - } - } - }) -} diff --git a/bencher/src/build_wasm/wasm_project.rs b/bencher/src/build_wasm/wasm_project.rs deleted file mode 100644 index 35104568e..000000000 --- a/bencher/src/build_wasm/wasm_project.rs +++ /dev/null @@ -1,593 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#![allow(clippy::option_map_unit_fn)] - -use super::{ - color_output_enabled, - prerequisites::{copy_file_if_changed, write_file_if_changed, CargoCommandVersioned}, -}; - -use std::{ - borrow::ToOwned, - collections::HashSet, - env, fs, - hash::{Hash, Hasher}, - ops::Deref, - path::{Path, PathBuf}, - process, -}; - -use toml::value::Table; - -use cargo_metadata::{Metadata, MetadataCommand}; - -/// Environment variable that tells us to skip building the wasm binary. -const SKIP_BUILD_ENV: &str = "SKIP_WASM_BUILD"; - -/// Environment variable to force a certain build type when building the wasm -/// binary. Expects "debug" or "release" as value. -/// -/// By default the WASM binary uses the same build type as the main cargo build. -const WASM_BUILD_TYPE_ENV: &str = "WASM_BUILD_TYPE"; - -/// Environment variable to extend the `RUSTFLAGS` variable given to the wasm -/// build. -const WASM_BUILD_RUSTFLAGS_ENV: &str = "WASM_BUILD_RUSTFLAGS"; - -/// Environment variable to set the target directory to copy the final wasm -/// binary. -/// -/// The directory needs to be an absolute path. -const WASM_TARGET_DIRECTORY: &str = "WASM_TARGET_DIRECTORY"; - -/// Holds the path to the bloaty WASM binary. -pub struct WasmBinaryBloaty(PathBuf); - -impl WasmBinaryBloaty { - /// Returns the escaped path to the bloaty wasm binary. - pub fn wasm_binary_bloaty_path_escaped(&self) -> String { - self.0.display().to_string().escape_default().to_string() - } -} - -/// Holds the path to the WASM binary. -pub struct WasmBinary(PathBuf); - -impl WasmBinary { - /// Returns the path to the wasm binary. - pub fn wasm_binary_path(&self) -> &Path { - &self.0 - } - - /// Returns the escaped path to the wasm binary. - pub fn wasm_binary_path_escaped(&self) -> String { - self.0.display().to_string().escape_default().to_string() - } -} - -fn crate_metadata(cargo_manifest: &Path) -> Metadata { - let mut cargo_lock = cargo_manifest.to_path_buf(); - cargo_lock.set_file_name("Cargo.lock"); - - let cargo_lock_existed = cargo_lock.exists(); - - let crate_metadata = MetadataCommand::new() - .manifest_path(cargo_manifest) - .exec() - .expect("`cargo metadata` can not fail on project `Cargo.toml`; qed"); - - // If the `Cargo.lock` didn't exist, we need to remove it after - // calling `cargo metadata`. This is required to ensure that we don't change - // the build directory outside of the `target` folder. Commands like - // `cargo publish` require this. - if !cargo_lock_existed { - let _ = fs::remove_file(&cargo_lock); - } - - crate_metadata -} - -/// Creates the WASM project, compiles the WASM binary and compacts the WASM -/// binary. -/// -/// # Returns -/// -/// The path to the compact WASM binary and the bloaty WASM binary. -pub fn create_and_compile( - project_cargo_toml: &Path, - default_rustflags: &str, - cargo_cmd: CargoCommandVersioned, - features_to_enable: Vec, - wasm_binary_name: Option, -) -> (Option, WasmBinaryBloaty) { - let wasm_workspace_root = get_wasm_workspace_root(); - let wasm_workspace = wasm_workspace_root.join("wbuild"); - - let crate_metadata = crate_metadata(project_cargo_toml); - - let project = create_project( - project_cargo_toml, - &wasm_workspace, - &crate_metadata, - crate_metadata.workspace_root.as_ref(), - features_to_enable, - ); - - build_project(&project, default_rustflags, cargo_cmd); - let (wasm_binary, wasm_binary_compressed, bloaty) = - compact_wasm_file(&project, project_cargo_toml, wasm_binary_name); - - wasm_binary - .as_ref() - .map(|wasm_binary| copy_wasm_to_target_directory(project_cargo_toml, wasm_binary)); - - wasm_binary_compressed - .as_ref() - .map(|wasm_binary_compressed| copy_wasm_to_target_directory(project_cargo_toml, wasm_binary_compressed)); - - (wasm_binary_compressed.or(wasm_binary), bloaty) -} - -/// Find the `Cargo.lock` relative to the `OUT_DIR` environment variable. -/// -/// If the `Cargo.lock` cannot be found, we emit a warning and return `None`. -fn find_cargo_lock(cargo_manifest: &Path) -> Option { - fn find_impl(mut path: PathBuf) -> Option { - loop { - if path.join("Cargo.lock").exists() { - return Some(path.join("Cargo.lock")); - } - - if !path.pop() { - return None; - } - } - } - - if let Some(path) = find_impl(build_helper::out_dir()) { - return Some(path); - } - - if let Some(path) = find_impl(cargo_manifest.to_path_buf()) { - return Some(path); - } - - build_helper::warning!( - "Could not find `Cargo.lock` for `{}`, while searching from `{}`.", - cargo_manifest.display(), - build_helper::out_dir().display() - ); - - None -} - -/// Extract the crate name from the given `Cargo.toml`. -fn get_crate_name(cargo_manifest: &Path) -> String { - let cargo_toml: Table = - toml::from_str(&fs::read_to_string(cargo_manifest).expect("File exists as checked before; qed")) - .expect("Cargo manifest is a valid toml file; qed"); - - let package = cargo_toml - .get("package") - .and_then(|t| t.as_table()) - .expect("`package` key exists in valid `Cargo.toml`; qed"); - - package - .get("name") - .and_then(|p| p.as_str()) - .map(ToOwned::to_owned) - .expect("Package name exists; qed") -} - -/// Returns the name for the wasm binary. -fn get_wasm_binary_name(cargo_manifest: &Path) -> String { - get_crate_name(cargo_manifest).replace('-', "_") -} - -/// Returns the root path of the wasm workspace. -fn get_wasm_workspace_root() -> PathBuf { - let mut out_dir = build_helper::out_dir(); - - loop { - match out_dir.parent() { - Some(parent) if out_dir.ends_with("build") => return parent.to_path_buf(), - _ => { - if !out_dir.pop() { - break; - } - } - } - } - - panic!("Could not find target dir in: {}", build_helper::out_dir().display()) -} - -fn create_project_cargo_toml( - wasm_workspace: &Path, - workspace_root_path: &Path, - crate_name: &str, - crate_path: &Path, - wasm_binary: &str, - enabled_features: impl Iterator, -) { - let mut workspace_toml: Table = toml::from_str( - &fs::read_to_string(workspace_root_path.join("Cargo.toml")).expect("Workspace root `Cargo.toml` exists; qed"), - ) - .expect("Workspace root `Cargo.toml` is a valid toml file; qed"); - - let mut wasm_workspace_toml = Table::new(); - - // Add `profile` with release and dev - let mut release_profile = Table::new(); - release_profile.insert("panic".into(), "abort".into()); - release_profile.insert("lto".into(), true.into()); - - let mut dev_profile = Table::new(); - dev_profile.insert("panic".into(), "abort".into()); - - let mut profile = Table::new(); - profile.insert("release".into(), release_profile.into()); - profile.insert("dev".into(), dev_profile.into()); - - wasm_workspace_toml.insert("profile".into(), profile.into()); - - // Add patch section from the project root `Cargo.toml` - if let Some(mut patch) = workspace_toml.remove("patch").and_then(|p| p.try_into::().ok()) { - // Iterate over all patches and make the patch path absolute from the workspace - // root path. - patch - .iter_mut() - .filter_map(|p| { - p.1.as_table_mut() - .map(|t| t.iter_mut().filter_map(|t| t.1.as_table_mut())) - }) - .flatten() - .for_each(|p| { - p.iter_mut().filter(|(k, _)| k == &"path").for_each(|(_, v)| { - if let Some(path) = v.as_str().map(PathBuf::from) { - if path.is_relative() { - *v = workspace_root_path.join(path).display().to_string().into(); - } - } - }) - }); - - wasm_workspace_toml.insert("patch".into(), patch.into()); - } - - let mut package = Table::new(); - package.insert("name".into(), format!("{}-wasm", crate_name).into()); - package.insert("version".into(), "1.0.0".into()); - package.insert("edition".into(), "2021".into()); - - wasm_workspace_toml.insert("package".into(), package.into()); - - let mut lib = Table::new(); - lib.insert("name".into(), wasm_binary.into()); - lib.insert("crate-type".into(), vec!["cdylib".to_string()].into()); - - wasm_workspace_toml.insert("lib".into(), lib.into()); - - let mut dependencies = Table::new(); - - let mut wasm_project = Table::new(); - wasm_project.insert("package".into(), crate_name.into()); - wasm_project.insert("path".into(), crate_path.display().to_string().into()); - wasm_project.insert("default-features".into(), false.into()); - wasm_project.insert("features".into(), enabled_features.collect::>().into()); - - dependencies.insert("wasm-project".into(), wasm_project.into()); - - wasm_workspace_toml.insert("dependencies".into(), dependencies.into()); - - wasm_workspace_toml.insert("workspace".into(), Table::new().into()); - - write_file_if_changed( - wasm_workspace.join("Cargo.toml"), - toml::to_string_pretty(&wasm_workspace_toml).expect("Wasm workspace toml is valid; qed"), - ); -} - -/// Find a package by the given `manifest_path` in the metadata. -/// -/// Panics if the package could not be found. -fn find_package_by_manifest_path<'a>( - manifest_path: &Path, - crate_metadata: &'a cargo_metadata::Metadata, -) -> &'a cargo_metadata::Package { - crate_metadata - .packages - .iter() - .find(|p| p.manifest_path == manifest_path) - .expect("Wasm project exists in its own metadata; qed") -} - -/// Get a list of enabled features for the project. -fn project_enabled_features(cargo_manifest: &Path, crate_metadata: &cargo_metadata::Metadata) -> Vec { - let package = find_package_by_manifest_path(cargo_manifest, crate_metadata); - - let mut enabled_features = package - .features - .keys() - .filter(|f| { - let mut feature_env = f.replace('-', "_"); - feature_env.make_ascii_uppercase(); - - // We don't want to enable the `std`/`default` feature for the wasm build and - // we need to check if the feature is enabled by checking the env variable. - *f != "std" - && *f != "default" - && env::var(format!("CARGO_FEATURE_{}", feature_env)) - .map(|v| v == "1") - .unwrap_or_default() - }) - .cloned() - .collect::>(); - - enabled_features.sort(); - enabled_features -} - -/// Returns if the project has the `runtime-wasm` feature -fn has_runtime_wasm_feature_declared(cargo_manifest: &Path, crate_metadata: &cargo_metadata::Metadata) -> bool { - let package = find_package_by_manifest_path(cargo_manifest, crate_metadata); - - package.features.keys().any(|k| k == "runtime-wasm") -} - -/// Create the project used to build the wasm binary. -/// -/// # Returns -/// -/// The path to the created wasm project. -fn create_project( - project_cargo_toml: &Path, - wasm_workspace: &Path, - crate_metadata: &Metadata, - workspace_root_path: &Path, - features_to_enable: Vec, -) -> PathBuf { - let crate_name = get_crate_name(project_cargo_toml); - let crate_path = project_cargo_toml.parent().expect("Parent path exists; qed"); - let wasm_binary = get_wasm_binary_name(project_cargo_toml); - let wasm_project_folder = wasm_workspace.join(&crate_name); - - fs::create_dir_all(wasm_project_folder.join("src")).expect("Wasm project dir create can not fail; qed"); - - let mut enabled_features = project_enabled_features(project_cargo_toml, crate_metadata); - - if has_runtime_wasm_feature_declared(project_cargo_toml, crate_metadata) { - enabled_features.push("runtime-wasm".into()); - } - - let mut enabled_features = enabled_features.into_iter().collect::>(); - enabled_features.extend(features_to_enable.into_iter()); - - create_project_cargo_toml( - &wasm_project_folder, - workspace_root_path, - &crate_name, - crate_path, - &wasm_binary, - enabled_features.into_iter(), - ); - - write_file_if_changed( - wasm_project_folder.join("src/lib.rs"), - "#![no_std] pub use wasm_project::*;", - ); - - if let Some(crate_lock_file) = find_cargo_lock(project_cargo_toml) { - // Use the `Cargo.lock` of the main project. - copy_file_if_changed(crate_lock_file, wasm_project_folder.join("Cargo.lock")); - } - - wasm_project_folder -} - -/// Returns if the project should be built as a release. -fn is_release_build() -> bool { - if let Ok(var) = env::var(WASM_BUILD_TYPE_ENV) { - match var.as_str() { - "release" => true, - "debug" => false, - var => panic!( - "Unexpected value for `{}` env variable: {}\nOne of the following are expected: `debug` or `release`.", - WASM_BUILD_TYPE_ENV, var, - ), - } - } else { - true - } -} - -/// Build the project to create the WASM binary. -fn build_project(project: &Path, default_rustflags: &str, cargo_cmd: CargoCommandVersioned) { - let manifest_path = project.join("Cargo.toml"); - let mut build_cmd = cargo_cmd.command(); - - let rustflags = format!( - "-C link-arg=--export-table {} {}", - default_rustflags, - env::var(WASM_BUILD_RUSTFLAGS_ENV).unwrap_or_default(), - ); - - build_cmd - .args(["rustc", "--target=wasm32-unknown-unknown"]) - .arg(format!("--manifest-path={}", manifest_path.display())) - .env("RUSTFLAGS", rustflags) - // Unset the `CARGO_TARGET_DIR` to prevent a cargo deadlock (cargo locks a target dir exclusive). - // The runner project is created in `CARGO_TARGET_DIR` and executing it will create a sub target - // directory inside of `CARGO_TARGET_DIR`. - .env_remove("CARGO_TARGET_DIR") - // We don't want to call ourselves recursively - .env(SKIP_BUILD_ENV, ""); - - if color_output_enabled() { - build_cmd.arg("--color=always"); - } - - if is_release_build() { - build_cmd.arg("--release"); - }; - - match build_cmd.status().map(|s| s.success()) { - Ok(true) => {} - // Use `process.exit(1)` to have a clean error output. - _ => process::exit(1), - } -} - -/// Compact the WASM binary using `wasm-gc` and compress it using zstd. -fn compact_wasm_file( - project: &Path, - cargo_manifest: &Path, - wasm_binary_name: Option, -) -> (Option, Option, WasmBinaryBloaty) { - let is_release_build = is_release_build(); - let target = if is_release_build { "release" } else { "debug" }; - let default_wasm_binary_name = get_wasm_binary_name(cargo_manifest); - let wasm_file = project - .join("target/wasm32-unknown-unknown") - .join(target) - .join(format!("{}.wasm", default_wasm_binary_name)); - - let wasm_compact_file = if is_release_build { - let wasm_compact_file = project.join(format!( - "{}.compact.wasm", - wasm_binary_name - .clone() - .unwrap_or_else(|| default_wasm_binary_name.clone()), - )); - wasm_gc::garbage_collect_file(&wasm_file, &wasm_compact_file) - .expect("Failed to compact generated WASM binary."); - Some(WasmBinary(wasm_compact_file)) - } else { - None - }; - - let wasm_compact_compressed_file = wasm_compact_file.as_ref().and_then(|compact_binary| { - let file_name = wasm_binary_name - .clone() - .unwrap_or_else(|| default_wasm_binary_name.clone()); - - let wasm_compact_compressed_file = project.join(format!("{}.compact.compressed.wasm", file_name,)); - - if compress_wasm(&compact_binary.0, &wasm_compact_compressed_file) { - Some(WasmBinary(wasm_compact_compressed_file)) - } else { - None - } - }); - - let bloaty_file_name = if let Some(name) = wasm_binary_name { - format!("{}.wasm", name) - } else { - format!("{}.wasm", default_wasm_binary_name) - }; - - let bloaty_file = project.join(bloaty_file_name); - fs::copy(wasm_file, &bloaty_file).expect("Copying the bloaty file to the project dir."); - - ( - wasm_compact_file, - wasm_compact_compressed_file, - WasmBinaryBloaty(bloaty_file), - ) -} - -fn compress_wasm(wasm_binary_path: &Path, compressed_binary_out_path: &Path) -> bool { - use sp_maybe_compressed_blob::CODE_BLOB_BOMB_LIMIT; - - let data = fs::read(wasm_binary_path).expect("Failed to read WASM binary"); - if let Some(compressed) = sp_maybe_compressed_blob::compress(&data, CODE_BLOB_BOMB_LIMIT) { - fs::write(compressed_binary_out_path, &compressed[..]).expect("Failed to write WASM binary"); - - true - } else { - println!( - "cargo:warning=Writing uncompressed wasm. Exceeded maximum size {}", - CODE_BLOB_BOMB_LIMIT, - ); - - false - } -} - -/// Custom wrapper for a [`cargo_metadata::Package`] to store it in -/// a `HashSet`. -#[derive(Debug)] -struct DeduplicatePackage<'a> { - package: &'a cargo_metadata::Package, - identifier: String, -} - -impl<'a> From<&'a cargo_metadata::Package> for DeduplicatePackage<'a> { - fn from(package: &'a cargo_metadata::Package) -> Self { - Self { - package, - identifier: format!("{}{}{:?}", package.name, package.version, package.source), - } - } -} - -impl<'a> Hash for DeduplicatePackage<'a> { - fn hash(&self, state: &mut H) { - self.identifier.hash(state); - } -} - -impl<'a> PartialEq for DeduplicatePackage<'a> { - fn eq(&self, other: &Self) -> bool { - self.identifier == other.identifier - } -} - -impl<'a> Eq for DeduplicatePackage<'a> {} - -impl<'a> Deref for DeduplicatePackage<'a> { - type Target = cargo_metadata::Package; - - fn deref(&self) -> &Self::Target { - self.package - } -} - -/// Copy the WASM binary to the target directory set in `WASM_TARGET_DIRECTORY` -/// environment variable. If the variable is not set, this is a no-op. -fn copy_wasm_to_target_directory(cargo_manifest: &Path, wasm_binary: &WasmBinary) { - let target_dir = match env::var(WASM_TARGET_DIRECTORY) { - Ok(path) => PathBuf::from(path), - Err(_) => return, - }; - - assert!( - target_dir.is_absolute(), - "Environment variable `{}` with `{}` is not an absolute path!", - WASM_TARGET_DIRECTORY, - target_dir.display() - ); - - fs::create_dir_all(&target_dir).expect("Creates `WASM_TARGET_DIRECTORY`."); - - fs::copy( - wasm_binary.wasm_binary_path(), - target_dir.join(format!("{}.wasm", get_wasm_binary_name(cargo_manifest))), - ) - .expect("Copies WASM binary to `WASM_TARGET_DIRECTORY`."); -} diff --git a/bencher/src/colorize.rs b/bencher/src/colorize.rs deleted file mode 100644 index 98cf73723..000000000 --- a/bencher/src/colorize.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// Environment variable to disable color output of the wasm build. -const WASM_BUILD_NO_COLOR: &str = "WASM_BUILD_NO_COLOR"; - -/// Returns `true` when color output is enabled. -pub fn color_output_enabled() -> bool { - std::env::var(WASM_BUILD_NO_COLOR).is_err() -} - -pub fn red_bold(message: &str) -> String { - if color_output_enabled() { - ansi_term::Color::Red.bold().paint(message).to_string() - } else { - message.into() - } -} - -pub fn yellow_bold(message: &str) -> String { - if color_output_enabled() { - ansi_term::Color::Yellow.bold().paint(message).to_string() - } else { - message.into() - } -} - -pub fn cyan(message: &str) -> String { - if crate::build_wasm::color_output_enabled() { - ansi_term::Color::Cyan.paint(message).to_string() - } else { - message.into() - } -} - -pub fn green_bold(message: &str) -> String { - if crate::build_wasm::color_output_enabled() { - ansi_term::Color::Green.bold().paint(message).to_string() - } else { - message.into() - } -} diff --git a/bencher/src/handler.rs b/bencher/src/handler.rs deleted file mode 100644 index e5291b18f..000000000 --- a/bencher/src/handler.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::{ - colorize::{cyan, green_bold}, - BenchResult, -}; -use codec::Decode; -use frame_support::traits::StorageInfo; -use linregress::{FormulaRegressionBuilder, RegressionDataBuilder}; -use serde::{Deserialize, Serialize}; -use sp_core::hexdisplay::HexDisplay; -use std::io::Write; -use std::time::Duration; - -#[derive(Serialize, Deserialize, Default, Debug, Clone)] -struct BenchData { - pub name: String, - pub weight: u64, - pub reads: u32, - pub writes: u32, - pub comments: Vec, -} - -/// Handle bench results -pub fn handle(output: Vec, storage_infos: Vec) { - println!(); - - let pkg_name = std::env::var("CARGO_PKG_NAME").unwrap_or_default().replace('-', "_"); - - 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(); - - let y: Vec = result.elapses.into_iter().map(|x| x as f64).collect(); - let x: Vec = (0..y.len()).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(); - - let mut total_reads = 0u32; - let mut total_writes = 0u32; - let mut comments = Vec::::new(); - let keys = , u32, u32)> as Decode>::decode(&mut &result.keys[..]).unwrap(); - keys.into_iter().for_each(|(prefix, reads, writes)| { - total_reads += reads; - total_writes += writes; - if let Some(info) = storage_infos.iter().find(|x| x.prefix.eq(&prefix)) { - let pallet = String::from_utf8(info.pallet_name.clone()).unwrap(); - let name = String::from_utf8(info.storage_name.clone()).unwrap(); - comments.push(format!("{}::{} (r: {}, w: {})", pallet, name, reads, writes)); - } else { - comments.push(format!( - "Unknown 0x{} (r: {}, w: {})", - HexDisplay::from(&prefix), - reads, - writes - )); - } - }); - - comments.sort(); - - let intercepted_value = model.parameters()[0] as u64; - - println!( - "{} {:<40} {:>20} storage: {:<20}", - green_bold("Bench"), - cyan(&name), - green_bold(&format!("{:?}", Duration::from_nanos(intercepted_value))), - green_bold(&format!( - "[r: {}, w: {}]", - &total_reads.to_string(), - &total_writes.to_string() - )), - ); - - BenchData { - name, - weight: intercepted_value * 1_000, - reads: total_reads, - writes: total_writes, - comments, - } - }) - .collect(); - - println!(); - - let outdir = std::env::var("CARGO_MANIFEST_DIR").unwrap(); - let json_path = format!("{}/target/{}_bench_data.json", outdir, pkg_name); - let mut writer = std::io::BufWriter::new(std::fs::File::create(std::path::Path::new(&json_path)).unwrap()); - serde_json::to_writer_pretty(&mut writer, &data).unwrap(); - writer.write_all(b"\n").unwrap(); - writer.flush().unwrap(); - - std::io::stdout().lock().write_all(json_path.as_bytes()).unwrap(); -} diff --git a/bencher/src/lib.rs b/bencher/src/lib.rs deleted file mode 100644 index 824248fa6..000000000 --- a/bencher/src/lib.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -#[doc(hidden)] -pub extern crate frame_support; -#[doc(hidden)] -pub extern crate paste; -#[doc(hidden)] -pub extern crate sp_core; -#[doc(hidden)] -pub extern crate sp_io; -#[doc(hidden)] -pub extern crate sp_std; - -mod bencher; -mod macros; -mod utils; - -pub use bencher::*; -pub use utils::*; - -#[cfg(feature = "std")] -pub mod bench_runner; -#[cfg(feature = "std")] -pub mod build_wasm; -#[cfg(feature = "std")] -pub mod handler; - -#[cfg(feature = "std")] -mod bench_ext; -#[cfg(feature = "std")] -mod colorize; -#[cfg(feature = "std")] -mod tracker; - -pub use bencher_procedural::benchmarkable; diff --git a/bencher/src/macros.rs b/bencher/src/macros.rs deleted file mode 100644 index 4945b0046..000000000 --- a/bencher/src/macros.rs +++ /dev/null @@ -1,142 +0,0 @@ -/// Run benches in WASM environment. -/// -/// Update Cargo.toml by adding: -/// ```toml -/// .. -/// [package] -/// name = "your-module" -/// .. -/// [[bench]] -/// name = 'module_benches' -/// harness = false -/// required-features = ['bench'] -/// -/// [features] -/// bench = [ -/// 'orml-bencher/bench' -/// 'orml-weight-meter/bench' -/// ] -/// .. -/// ``` -/// -/// Create a file `benches/module_benches.rs` must be the same as bench name. -/// ```.ignore -/// use your_module::mock::{AllPalletsWithSystem, Block}; -/// orml_bencher::run_benches!(AllPalletsWithSystem, Block); -/// ``` -/// -/// Define benches -/// -/// Create a file `src/benches.rs` -/// ```ignore -/// #!#[cfg(feature = "bench")] -/// -/// use orml_bencher::{Bencher, benches}; -/// use crate::mock::*; -/// -/// fn foo(b: &mut Bencher) { -/// // Run anything before code here -/// let ret = b.bench(|| { -/// // foo must have macro `[orml_weight_meter::weight(..)]` to measure correct redundant info -/// YourModule::foo() -/// }); -/// // Run anything after code here -/// } -/// -/// fn bar(b: &mut Bencher) { -/// // optional. method name is used by default i.e: `bar` -/// b.name("bench_name") -/// .bench(|| { -/// // bar must have macro `[orml_weight_meter::weight(..)]` to measure correct redundant info -/// YourModule::bar(); -/// }); -/// } -/// -/// benches!(foo, bar); // Tests are generated automatically -/// ``` -/// Update `src/lib.rs` -/// ```ignore -/// #[cfg(any(feature = "bench", test))] -/// pub mod mock; /* mock runtime needs to be compiled into wasm */ -/// pub mod benches; -/// ``` -/// -/// Run benchmarking: `cargo bench --features=bench` -#[macro_export] -macro_rules! benches { - ($($method:path),+) => { - #[cfg(feature = "bench")] - $crate::sp_core::wasm_export_functions! { - fn run_benches() -> $crate::sp_std::vec::Vec<$crate::BenchResult> { - $crate::bench::print_info("\nRunning benches ...\n".as_bytes().to_vec()); - let mut bencher = $crate::Bencher::default(); - $( - $crate::bench::init_bench(); - - let name = stringify!($method); - bencher.current = $crate::BenchResult::with_name(name); - - for _ in 0..1_000 { - bencher.before_run(); - $method(&mut bencher); - } - - bencher.print_warnings(name); - - bencher.results.push(bencher.current); - )+ - bencher.results - } - } - - #[cfg(all(feature = "bench", not(feature = "std")))] - #[panic_handler] - #[no_mangle] - fn panic_handler(info: &::core::panic::PanicInfo) -> ! { - let message = $crate::sp_std::alloc::format!("{}", info); - $crate::bench::print_error(message.as_bytes().to_vec()); - unsafe {core::arch::wasm32::unreachable(); } - } - - // Tests - #[cfg(test)] - mod tests { - $( - $crate::paste::item! { - #[test] - fn [] () { - $crate::sp_io::TestExternalities::new_empty().execute_with(|| { - let mut bencher = $crate::Bencher::default(); - super::$method(&mut bencher); - }); - } - } - )+ - } - - } -} - -#[macro_export] -macro_rules! run_benches { - ( - $all_pallets_with_system:ident, - $block:tt - ) => { - #[cfg(all(feature = "std", feature = "bench"))] - pub fn main() -> std::io::Result<()> { - use $crate::frame_support::traits::StorageInfoTrait; - let wasm = $crate::build_wasm::build()?; - let storage_info = $all_pallets_with_system::storage_info(); - match $crate::bench_runner::run::<$block>(wasm) { - Ok(output) => { - $crate::handler::handle(output, storage_info); - } - Err(e) => { - eprintln!("{:?}", e); - } - }; - Ok(()) - } - }; -} diff --git a/bencher/src/tracker.rs b/bencher/src/tracker.rs deleted file mode 100644 index 6dc3c8cb7..000000000 --- a/bencher/src/tracker.rs +++ /dev/null @@ -1,356 +0,0 @@ -use codec::Encode; -use parking_lot::RwLock; -use sp_state_machine::StorageKey; -use sp_storage::ChildInfo; -use std::{collections::HashMap, sync::Arc, time::Instant}; - -#[derive(PartialEq, Eq, Default)] -enum AccessType { - #[default] - None, - Redundant, - Important, - Whitelisted, -} - -impl AccessType { - fn is_important(&self) -> bool { - *self == AccessType::Important - } - fn mark_important(&mut self) { - if *self != AccessType::Whitelisted { - *self = AccessType::Important; - } - } -} - -#[derive(Default)] -struct AccessInfo { - pub read: AccessType, - pub written: AccessType, -} - -impl AccessInfo { - fn read(redundant: bool) -> Self { - let read = if redundant { - AccessType::Redundant - } else { - AccessType::Important - }; - Self { - read, - written: AccessType::None, - } - } - - fn written(redundant: bool) -> Self { - let written = if redundant { - AccessType::Redundant - } else { - AccessType::Important - }; - Self { - read: AccessType::Redundant, - written, - } - } - - fn whitelisted(read: bool, write: bool) -> Self { - Self { - read: if read { - AccessType::Whitelisted - } else { - AccessType::None - }, - written: if write { - AccessType::Whitelisted - } else { - AccessType::None - }, - } - } -} - -#[derive(Default, Debug)] -struct AccessReport { - pub read: u32, - pub written: u32, -} - -#[derive(thiserror::Error, Copy, Clone, Debug)] -pub enum Warning { - #[error("clear prefix without limit, cannot be tracked")] - ClearPrefixWithoutLimit, - #[error("child storage is not supported")] - ChildStorageNotSupported, -} - -pub struct BenchTracker { - instant: RwLock, - depth: RwLock, - redundant: RwLock, - results: RwLock>, - main_keys: RwLock>, - clear_prefixes: RwLock>, - warnings: RwLock>, - whitelisted_keys: RwLock>, - count_clear_prefix: RwLock, -} - -impl BenchTracker { - pub fn new() -> Self { - BenchTracker { - instant: RwLock::new(Instant::now()), - depth: RwLock::new(0), - redundant: RwLock::new(Instant::now()), - results: RwLock::new(Vec::new()), - main_keys: RwLock::new(HashMap::new()), - clear_prefixes: RwLock::new(HashMap::new()), - warnings: RwLock::new(Vec::new()), - whitelisted_keys: RwLock::new(HashMap::new()), - count_clear_prefix: RwLock::new(false), - } - } - - pub fn warnings(&self) -> Vec { - let warnings = &*self.warnings.read(); - warnings.clone() - } - - pub fn instant(&self) { - *self.instant.write() = Instant::now(); - } - - pub fn elapsed(&self) -> u128 { - self.instant.read().elapsed().as_nanos() - } - - pub fn is_redundant(&self) -> bool { - *self.depth.read() > 1 - } - - pub fn on_read_storage(&self, key: StorageKey) { - let redundant = self.is_redundant(); - let main_keys = &mut *self.main_keys.write(); - match main_keys.get_mut(&key) { - Some(info) => { - if redundant { - return; - } - if info.written.is_important() { - return; - } - info.read.mark_important(); - } - None => { - main_keys.insert(key, AccessInfo::read(redundant)); - } - }; - } - - pub fn on_read_child_storage(&self, _child_info: &ChildInfo, _key: StorageKey) { - if self.is_redundant() { - return; - } - self.warn(Warning::ChildStorageNotSupported); - } - - pub fn on_update_storage(&self, key: StorageKey) { - let redundant = self.is_redundant(); - let main_keys = &mut *self.main_keys.write(); - match main_keys.get_mut(&key) { - Some(info) => { - if redundant { - return; - } - info.written.mark_important(); - } - None => { - main_keys.insert(key, AccessInfo::written(redundant)); - } - }; - } - - pub fn on_update_child_storage(&self, _child_info: &ChildInfo, _key: StorageKey) { - if self.is_redundant() { - return; - } - self.warn(Warning::ChildStorageNotSupported); - } - - pub fn on_clear_prefix(&self, prefix: &[u8], limit: Option) { - if self.is_redundant() || !(*self.count_clear_prefix.read()) { - return; - } - if let Some(limit) = limit { - let key = prefix.to_vec(); - let clear_prefixes = &mut *self.clear_prefixes.write(); - match clear_prefixes.get_mut(&key) { - Some(n) => { - *n += limit; - } - None => { - clear_prefixes.insert(key, limit); - } - }; - } else { - self.warn(Warning::ClearPrefixWithoutLimit); - } - } - - pub fn on_clear_child_prefix(&self, _child_info: &ChildInfo, _prefix: &[u8], _limit: Option) { - if self.is_redundant() { - return; - } - self.warn(Warning::ChildStorageNotSupported); - } - - pub fn on_kill_child_storage(&self, _child_info: &ChildInfo, _limit: Option) { - if self.is_redundant() { - return; - } - self.warn(Warning::ChildStorageNotSupported); - } - - /// Get the benchmark summary - pub fn read_written_keys(&self) -> Vec { - let mut summary = HashMap::::new(); - - self.main_keys.read().iter().for_each(|(key, info)| { - let prefix_end = core::cmp::min(32, key.len()); - let prefix = key[0..prefix_end].to_vec(); - if let Some(report) = summary.get_mut(&prefix) { - if info.read.is_important() { - report.read += 1; - } - if info.written.is_important() { - report.written += 1; - } - } else { - let mut report = AccessReport::default(); - if info.read.is_important() { - report.read += 1; - } - if info.written.is_important() { - report.written += 1; - } - if report.read + report.written > 0 { - summary.insert(prefix, report); - } - } - }); - - self.clear_prefixes.read().iter().for_each(|(key, items)| { - let prefix_end = core::cmp::min(32, key.len()); - let prefix = key[0..prefix_end].to_vec(); - if let Some(report) = summary.get_mut(&prefix) { - report.written += items; - } else { - summary.insert( - prefix, - AccessReport { - written: *items, - ..Default::default() - }, - ); - } - }); - - summary - .into_iter() - .map(|(prefix, report)| (prefix, report.read, report.written)) - .collect::>() - .encode() - } - - /// Run before executing the code been benchmarked - pub fn before_block(&self) { - let timestamp = Instant::now(); - - let mut depth = self.depth.write(); - - if *depth == 0 { - *depth = 1; - return; - } - - if *depth == 1 { - *self.redundant.write() = timestamp; - } - - *depth += 1; - } - - /// Run after benchmarking code is executed - pub fn after_block(&self) { - let mut depth = self.depth.write(); - if *depth == 2 { - let redundant = self.redundant.read(); - let elapsed = redundant.elapsed().as_nanos(); - self.results.write().push(elapsed); - } - *depth -= 1; - } - - /// Add a warning to be printed after execution - pub fn warn(&self, warning: Warning) { - let mut warnings = self.warnings.write(); - warnings.push(warning); - } - - /// Redundant elapsed time - pub fn redundant_time(&self) -> u128 { - assert_eq!(*self.depth.read(), 0, "benchmark in progress"); - - let mut elapsed = 0u128; - - self.results.read().iter().for_each(|x| { - elapsed = elapsed.saturating_add(*x); - }); - - elapsed - } - - /// Prepare tracker for next run - pub fn prepare_next_run(&self) { - *self.depth.write() = 0; - self.results.write().clear(); - - self.clear_prefixes.write().clear(); - self.warnings.write().clear(); - - let main_keys = &mut self.main_keys.write(); - main_keys.clear(); - - let keys = self.whitelisted_keys.read(); - for (key, (read, write)) in keys.iter() { - main_keys.insert(key.clone(), AccessInfo::whitelisted(*read, *write)); - } - } - - /// Whitelist keys that don't need to be tracked - pub fn whitelist(&self, key: Vec, read: bool, write: bool) { - let whitelisted = &mut self.whitelisted_keys.write(); - whitelisted.insert(key, (read, write)); - } - - pub fn count_clear_prefix(&self) { - *self.count_clear_prefix.write() = true; - } - - /// Reset for the next benchmark - pub fn reset(&self) { - *self.depth.write() = 0; - *self.redundant.write() = Instant::now(); - self.results.write().clear(); - self.main_keys.write().clear(); - self.clear_prefixes.write().clear(); - self.warnings.write().clear(); - self.whitelisted_keys.write().clear(); - *self.count_clear_prefix.write() = false; - } -} - -sp_externalities::decl_extension! { - pub struct BenchTrackerExt(Arc); -} diff --git a/bencher/src/utils.rs b/bencher/src/utils.rs deleted file mode 100644 index f46f58e17..000000000 --- a/bencher/src/utils.rs +++ /dev/null @@ -1,114 +0,0 @@ -use sp_std::vec::Vec; - -#[cfg(feature = "std")] -use super::colorize::{cyan, red_bold, yellow_bold}; -#[cfg(feature = "std")] -use super::tracker::BenchTrackerExt; -#[cfg(feature = "std")] -use codec::Decode; -#[cfg(feature = "std")] -use sp_externalities::ExternalitiesExt; - -#[sp_runtime_interface::runtime_interface] -pub trait Bench { - fn print_error(message: Vec) { - let msg = String::from_utf8_lossy(&message); - eprintln!("{}", red_bold(&msg)); - } - - fn print_warnings(&mut self, method: Vec) { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - let method_name = ::decode(&mut &method[..]).unwrap(); - tracker.warnings().iter().for_each(|warning| { - println!( - "{} {} {}", - yellow_bold("WARNING:"), - cyan(&method_name), - yellow_bold(&warning.to_string()) - ); - }); - } - - fn print_info(&mut self, message: Vec) { - let msg = String::from_utf8_lossy(&message); - println!("{}", msg); - } - - fn commit_db(&mut self) { - self.commit() - } - - fn wipe_db(&mut self) { - self.wipe() - } - - fn reset_read_write_count(&mut self) { - self.reset_read_write_count() - } - - fn start_timer(&mut self) { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.prepare_next_run(); - tracker.instant(); - } - - fn end_timer(&mut self) -> u128 { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.elapsed() - } - - fn before_block(&mut self) { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.before_block(); - } - - fn after_block(&mut self) { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.after_block(); - } - - fn redundant_time(&mut self) -> u128 { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.redundant_time() - } - - fn read_written_keys(&mut self) -> Vec { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.read_written_keys() - } - - fn whitelist(&mut self, key: Vec, read: bool, write: bool) { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.whitelist(key, read, write); - } - - fn init_bench(&mut self) { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.reset(); - } - - fn count_clear_prefix(&mut self) { - let tracker = &***self - .extension::() - .expect("No `bench_tracker` associated for the current context!"); - tracker.count_clear_prefix(); - } -} diff --git a/bencher/test/Cargo.toml b/bencher/test/Cargo.toml deleted file mode 100644 index 9d8084637..000000000 --- a/bencher/test/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -[package] -name = "orml-bencher-test" -repository = "https://github.com/open-web3-stack/open-runtime-module-library/tree/master/bencher/test" -license = "Apache-2.0" -version = "0.4.1-dev" -authors = ["Laminar Developers "] -edition = "2021" - -[[bench]] -name = "foo" -harness = false -required-features = ["bench"] - -[dependencies] -serde = { version = "1.0.136", optional = true } -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -codec = { package = "parity-scale-codec", version = "3.0.0", features = ["derive"], default-features = false } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -frame-system = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-core = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -sp-std = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -orml-bencher = { path = "..", default-features = false } -orml-weight-meter = { path = "../../weight-meter", default-features = false } - -[dev-dependencies] -sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } - -[features] -default = ["std"] -std = [ - "serde", - "scale-info/std", - "codec/std", - "frame-support/std", - "frame-system/std", - "sp-runtime/std", - "sp-core/std", - "sp-std/std", - "orml-bencher/std", - "orml-weight-meter/std", -] -bench = [ - "orml-bencher/bench", - "orml-weight-meter/bench", -] diff --git a/bencher/test/benches/foo.rs b/bencher/test/benches/foo.rs deleted file mode 100644 index d1a1082c9..000000000 --- a/bencher/test/benches/foo.rs +++ /dev/null @@ -1,2 +0,0 @@ -use orml_bencher_test::mock::{AllPalletsWithSystem, Block}; -orml_bencher::run_benches!(AllPalletsWithSystem, Block); diff --git a/bencher/test/src/benches.rs b/bencher/test/src/benches.rs deleted file mode 100644 index 62ac88231..000000000 --- a/bencher/test/src/benches.rs +++ /dev/null @@ -1,45 +0,0 @@ -#![cfg(feature = "bench")] -#![allow(dead_code)] - -use crate::{mock::*, pallet::*}; -use frame_support::assert_ok; -use orml_bencher::{benches, Bencher}; - -fn set_value(b: &mut Bencher) { - let result = b.bench(|| Test::set_value(RuntimeOrigin::signed(1), 1)); - assert_ok!(result); - assert_eq!(Test::value(), Some(1 + 1)); -} - -fn set_foo(b: &mut Bencher) { - b.bench(|| { - let _ = Test::set_foo(); - }); -} - -fn remove_all_bar(b: &mut Bencher) { - Bar::::insert(1, 1); - b.bench(|| { - Test::remove_all_bar(); - }); -} - -fn remove_all_bar_with_limit(b: &mut Bencher) { - b.count_clear_prefix(); - Bar::::insert(1, 1); - b.bench(|| { - Test::remove_all_bar_with_limit(); - }); -} - -fn whitelist(b: &mut Bencher) { - b.whitelist(Bar::::hashed_key_for(1), true, true); - b.whitelist(Bar::::hashed_key_for(2), true, false); - b.whitelist(Foo::::hashed_key().to_vec(), true, true); - b.whitelist(Value::::hashed_key().to_vec(), true, true); - b.bench(|| { - let _ = Test::set_foo(); - }); -} - -benches!(whitelist, set_value, set_foo, remove_all_bar, remove_all_bar_with_limit); diff --git a/bencher/test/src/lib.rs b/bencher/test/src/lib.rs deleted file mode 100644 index 15646b4ba..000000000 --- a/bencher/test/src/lib.rs +++ /dev/null @@ -1,89 +0,0 @@ -#![cfg_attr(not(feature = "std"), no_std)] - -pub mod benches; -pub mod mock; -mod tests; -mod weights; - -#[frame_support::pallet(dev_mode)] -pub mod pallet { - use crate::weights::ModuleWeights; - use frame_support::{ - dispatch::{DispatchResult, DispatchResultWithPostInfo}, - pallet_prelude::*, - }; - use frame_system::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::hooks] - impl Hooks> for Pallet {} - - #[pallet::pallet] - pub struct Pallet(PhantomData); - - #[pallet::storage] - #[pallet::getter(fn foo)] - pub type Foo = StorageValue<_, u32, OptionQuery>; - - #[pallet::storage] - #[pallet::getter(fn value)] - pub type Value = StorageValue<_, u32, OptionQuery>; - - #[pallet::storage] - #[pallet::getter(fn bar)] - pub type Bar = StorageMap<_, Twox64Concat, u32, u32>; - - #[pallet::call] - impl Pallet { - #[pallet::call_index(0)] - #[pallet::weight(0)] - #[orml_weight_meter::start(ModuleWeights::::set_value().ref_time())] - pub fn set_value(origin: OriginFor, n: u32) -> DispatchResultWithPostInfo { - frame_system::ensure_signed(origin)?; - Value::::get(); - Value::::put(n); - Value::::put(n + 1); - let _ = Self::set_foo(); - Ok(Some(orml_weight_meter::used_weight()).into()) - } - - #[pallet::call_index(1)] - #[pallet::weight(0)] - pub fn dummy(origin: OriginFor, _n: u32) -> DispatchResult { - frame_system::ensure_none(origin)?; - Foo::::put(1); - Ok(()) - } - } - - impl Pallet { - #[orml_weight_meter::weight(ModuleWeights::::set_foo().ref_time())] - pub(crate) fn set_foo() -> frame_support::dispatch::DispatchResult { - Value::::put(2); - - Foo::::put(1); - Foo::::get(); - - Bar::::mutate(1, |v| { - *v = Some(1); - }); - Bar::::insert(1, 1); - - Bar::::insert(2, 2); - Bar::::get(1); - Ok(()) - } - - #[orml_weight_meter::weight(0)] - pub(crate) fn remove_all_bar() { - _ = Bar::::clear(10, None); - } - - #[orml_weight_meter::weight(0)] - pub(crate) fn remove_all_bar_with_limit() { - _ = Bar::::clear(10, None); - } - } -} diff --git a/bencher/test/src/mock.rs b/bencher/test/src/mock.rs deleted file mode 100644 index 49a125804..000000000 --- a/bencher/test/src/mock.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![cfg(any(test, feature = "bench"))] - -use frame_support::pallet_prelude::ConstU32; -use sp_core::H256; -use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, - BuildStorage, MultiSignature, -}; -use sp_std::prelude::*; - -pub type Signature = MultiSignature; -pub type BlockNumber = u64; -pub type AccountId = u32; -pub type Address = sp_runtime::MultiAddress; -pub type Header = sp_runtime::generic::Header; - -pub type SignedExtra = (frame_system::CheckWeight,); - -pub type UncheckedExtrinsic = sp_runtime::generic::UncheckedExtrinsic; - -pub type Block = sp_runtime::generic::Block; - -frame_support::construct_runtime!( - pub enum Runtime { - System: frame_system, - Test: crate::pallet, - } -); - -impl frame_system::Config for Runtime { - type BaseCallFilter = frame_support::traits::Everything; - type BlockWeights = (); - type BlockLength = (); - type DbWeight = (); - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type Hash = H256; - type RuntimeCall = RuntimeCall; - type Hashing = BlakeTwo256; - type AccountId = AccountId; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = (); - type OnNewAccount = (); - type OnKilledAccount = (); - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; -} - -impl crate::pallet::Config for Runtime {} - -#[cfg(test)] -pub struct ExtBuilder; - -#[cfg(test)] -impl Default for ExtBuilder { - fn default() -> Self { - Self {} - } -} - -#[cfg(test)] -impl ExtBuilder { - pub fn build(self) -> sp_io::TestExternalities { - let t = frame_system::GenesisConfig::::default() - .build_storage() - .unwrap(); - - t.into() - } -} diff --git a/bencher/test/src/tests.rs b/bencher/test/src/tests.rs deleted file mode 100644 index b3d9441f4..000000000 --- a/bencher/test/src/tests.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![cfg(test)] - -use super::mock::*; -use super::weights::ModuleWeights; -use frame_support::dispatch::PostDispatchInfo; - -#[test] -fn set_value() { - let weight = ModuleWeights::::set_value() + ModuleWeights::::set_foo(); - ExtBuilder::default().build().execute_with(|| { - assert_eq!( - Test::set_value(RuntimeOrigin::signed(1), 1), - Ok(PostDispatchInfo { - actual_weight: Some(weight), - ..Default::default() - }) - ); - }); -} diff --git a/bencher/test/src/weights.rs b/bencher/test/src/weights.rs deleted file mode 100644 index 100178d15..000000000 --- a/bencher/test/src/weights.rs +++ /dev/null @@ -1,51 +0,0 @@ - - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![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 { - // Storage access info - // - // Test::Bar (r: 0, w: 1) - pub fn whitelist() -> Weight { - Weight::from_parts(5_356_000, 0) - .saturating_add(T::DbWeight::get().writes(1)) - } - // Storage access info - // - // Test::Value (r: 1, w: 1) - // Unknown 0x3a7472616e73616374696f6e5f6c6576656c3a (r: 1, w: 1) - pub fn set_value() -> Weight { - Weight::from_parts(3_919_000, 0) - .saturating_add(T::DbWeight::get().reads(2)) - .saturating_add(T::DbWeight::get().writes(2)) - } - // Storage access info - // - // Test::Bar (r: 1, w: 2) - // Test::Foo (r: 0, w: 1) - // Test::Value (r: 0, w: 1) - pub fn set_foo() -> Weight { - Weight::from_parts(5_133_000, 0) - .saturating_add(T::DbWeight::get().reads(1)) - .saturating_add(T::DbWeight::get().writes(4)) - } - // Storage access info - // - pub fn remove_all_bar() -> Weight { - Weight::from_parts(1_533_000, 0) - } - // Storage access info - // - // Test::Bar (r: 0, w: 10) - pub fn remove_all_bar_with_limit() -> Weight { - Weight::from_parts(1_600_000, 0) - .saturating_add(T::DbWeight::get().writes(10)) - } -} diff --git a/weight-gen/Cargo.toml b/weight-gen/Cargo.toml deleted file mode 100644 index a6162073c..000000000 --- a/weight-gen/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "weight-gen" -description = "CLI for generating weight from bencher output" -license = "Apache-2.0" -version = "0.4.1-dev" -authors = ["Laminar Developers "] -edition = "2021" - -[dependencies] -serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0" -clap = "4.0.9" -handlebars = "4.1.0" - -[features] -default = ["std"] -std = [] diff --git a/weight-gen/src/main.rs b/weight-gen/src/main.rs deleted file mode 100644 index b8f521ca5..000000000 --- a/weight-gen/src/main.rs +++ /dev/null @@ -1,200 +0,0 @@ -use clap::{Arg, Command}; -use serde::{Deserialize, Serialize}; -use std::io::Read; - -#[derive(Serialize, Deserialize, Default, Debug, Clone)] -pub struct BenchData { - pub name: String, - pub weight: u64, - pub reads: u32, - pub writes: u32, - pub comments: Vec, -} - -#[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(); - std::io::stdin() - .read_to_string(&mut buffer) - .expect("Unable to read from stdin"); - - let file_path = buffer - .split_ascii_whitespace() - .last() - .expect("Last line must be JOSN file path."); - let reader = std::fs::File::open(std::path::Path::new(file_path)).unwrap(); - serde_json::from_reader(&reader).ok() -} - -fn main() { - let matches = Command::new("Weight Generator") - .version("1.0") - .author("Laminar Developers ") - .about("Generate rust weight info source file from JSON data generated by ORML bencher") - .arg( - Arg::new("input") - .short('i') - .long("input") - .value_name("PATH") - .help("Input JSON data file") - .num_args(1), - ) - .arg( - Arg::new("template") - .short('t') - .long("template") - .value_name("PATH") - .help("Handlebars template file") - .num_args(1), - ) - .arg( - Arg::new("header") - .long("header") - .value_name("PATH") - .help("Header file path") - .num_args(1), - ) - .arg( - Arg::new("output") - .short('o') - .long("output") - .value_name("PATH") - .help("Output file path") - .num_args(1), - ) - .get_matches(); - - let mut benchmarks: Vec = { - if let Some(input_path) = matches.get_one::("input") { - let reader = std::fs::File::open(std::path::Path::new(&input_path.trim())).unwrap(); - serde_json::from_reader(&reader).expect("Could not parse JSON data") - } else { - parse_stdio().expect("Could not parse JSON data") - } - }; - - // Sort comments - benchmarks.iter_mut().for_each(|x| { - x.comments.sort(); - }); - - 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) = matches.get_one::("header") { - ::std::fs::read_to_string(path).expect("Header file not found") - } 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) = matches.get_one::("template") { - ::std::fs::read_to_string(path).expect("Template file not found") - } else { - String::from(DEFAULT_TEMPLATE) - } - }; - - // Write benchmark to file or print to terminal if output path is not given. - if let Some(path) = matches.get_one::("output") { - 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) - .expect("Unable to render template"); - println!(); - println!("Weights file `{}` was generated.", path); - } 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 deleted file mode 100644 index 814dd60a8..000000000 --- a/weight-gen/src/template.hbs +++ /dev/null @@ -1,29 +0,0 @@ -{{header}} - -#![cfg_attr(rustfmt, rustfmt_skip)] -#![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|}} - // Storage access info - // - {{#each benchmark.comments as |comment|}} - // {{comment}} - {{/each}} - pub fn {{benchmark.name~}} () -> Weight { - Weight::from_parts({{underscore benchmark.weight}}, 0) - {{#if (ne benchmark.reads 0)}} - .saturating_add(T::DbWeight::get().reads({{benchmark.reads}})) - {{/if}} - {{#if (ne benchmark.writes 0)}} - .saturating_add(T::DbWeight::get().writes({{benchmark.writes}})) - {{/if}} - } - {{/each}} -} diff --git a/weight-meter/Cargo.toml b/weight-meter/Cargo.toml deleted file mode 100644 index 06dfe39f9..000000000 --- a/weight-meter/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "orml-weight-meter" -version = "0.4.1-dev" -license = "Apache-2.0" -authors = ["Laminar Developers "] -edition = "2021" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -scale-info = { version = "2.9.0", default-features = false, features = ["derive"] } -frame-support = { git = "https://github.com/paritytech/substrate", default-features = false , branch = "polkadot-v1.0.0" } -weight-meter-procedural = { path = "weight-meter-procedural", default-features = false } - -[dev-dependencies] -serde = "1.0.136" -codec = { package = "parity-scale-codec", version = "3.4.0" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } -sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } -sp-std = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } - -frame-support = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } -frame-system = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } -pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v1.0.0" } - -orml-bencher = { path = "../bencher" } - -[features] -default = ["std"] -std = [ - "scale-info/std", - "frame-support/std", - "weight-meter-procedural/std", -] -bench = [ - "weight-meter-procedural/bench", -] diff --git a/weight-meter/README.md b/weight-meter/README.md deleted file mode 100644 index 26f821e28..000000000 --- a/weight-meter/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Weight Meter - -Include `WeightMeter` into your module Cargo.toml -``` -[dependencies] -orml-weight-meter = { version = "..", default-features = false } - -std = [ - .. - 'orml-weight-meter/std', -] - -``` \ No newline at end of file diff --git a/weight-meter/src/lib.rs b/weight-meter/src/lib.rs deleted file mode 100644 index a1d519a62..000000000 --- a/weight-meter/src/lib.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![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. This only works for methods with `orml_weight_meter::start` and -//! `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(ModuleWeights::::inner_do_something())] -//! ``` -//! -//! 3. Use WeightMeter on your calls by adding macro -//! `#[orml_weight_meter::start(weight)]` or `#[orml_weight_meter::start]` if -//! starts with zero 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(ModuleWeights::::do_something())] -//! 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; - -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; - -extern crate self as orml_weight_meter; - -#[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 -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 deleted file mode 100644 index 952d2239b..000000000 --- a/weight-meter/src/meter_no_std.rs +++ /dev/null @@ -1,40 +0,0 @@ -// TODO: research if there's a better way -#![cfg(not(feature = "std"))] - -use super::{Meter, Weight}; - -static mut METER: Meter = Meter { - used_weight: Weight::zero(), - depth: 0, -}; - -pub fn start(weight: Weight) { - unsafe { - if METER.depth == 0 { - METER.used_weight = weight; - } - METER.depth = METER.depth.saturating_add(1); - } -} - -pub fn using(weight: Weight) { - unsafe { - METER.used_weight = METER.used_weight.saturating_add(weight); - } -} - -pub fn finish() { - unsafe { - METER.depth.checked_sub(1).map_or_else( - || { - debug_assert!(false); - 0 - }, - |v| v, - ); - } -} - -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 deleted file mode 100644 index 7acbb8805..000000000 --- a/weight-meter/src/meter_std.rs +++ /dev/null @@ -1,44 +0,0 @@ -// TODO: research if there's a better way -#![cfg(feature = "std")] - -use super::{Meter, Weight}; -use std::cell::RefCell; - -thread_local! { - static METER: RefCell = RefCell::new(Meter { - used_weight: Weight::zero(), - depth: 0, - }); -} - -/// Start weight meter with base weight -pub fn start(weight: Weight) { - METER.with(|v| { - let mut meter = v.borrow_mut(); - if meter.depth == 0 { - meter.used_weight = weight; - } - meter.depth = meter.depth.saturating_add(1); - }); -} - -/// Increment used weight -pub fn using(weight: Weight) { - METER.with(|v| { - let mut meter = v.borrow_mut(); - meter.used_weight = meter.used_weight.saturating_add(weight); - }) -} - -/// Finish weight meter -pub fn finish() { - METER.with(|v| { - let mut meter = v.borrow_mut(); - meter.depth = meter.depth.saturating_sub(1); - }) -} - -/// Get used weight -pub fn used_weight() -> Weight { - METER.with(|v| v.borrow().used_weight) -} diff --git a/weight-meter/src/mock.rs b/weight-meter/src/mock.rs deleted file mode 100644 index f98c4bfc0..000000000 --- a/weight-meter/src/mock.rs +++ /dev/null @@ -1,224 +0,0 @@ -#[frame_support::pallet(dev_mode)] -pub mod test_module { - use frame_support::{dispatch::DispatchResultWithPostInfo, pallet_prelude::*, weights::Weight}; - use frame_system::pallet_prelude::*; - - #[pallet::config] - pub trait Config: frame_system::Config {} - - #[pallet::pallet] - 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::call_index(0)] - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - pub fn expect_100(origin: OriginFor) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - Self::put_100(); - - Ok(Some(orml_weight_meter::used_weight()).into()) - } - - #[pallet::call_index(1)] - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - 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(Some(orml_weight_meter::used_weight()).into()) - } - - #[pallet::call_index(2)] - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - pub fn expect_max_weight(origin: OriginFor) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - Self::max_weight(); - Self::put_100(); - - Ok(Some(orml_weight_meter::used_weight()).into()) - } - - #[pallet::call_index(3)] - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - pub fn expect_100_or_200(origin: OriginFor, branch: bool) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - if branch { - Self::put_200(); - } else { - Self::put_100(); - } - - Ok(Some(orml_weight_meter::used_weight()).into()) - } - - #[pallet::call_index(4)] - #[pallet::weight(50_000)] - #[orml_weight_meter::start] - pub fn nested_inner_methods(origin: OriginFor) -> DispatchResultWithPostInfo { - ensure_signed(origin)?; - - Self::put_300_nested(); - - Ok(Some(orml_weight_meter::used_weight()).into()) - } - - #[pallet::call_index(5)] - #[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()) - } - } - - 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(Weight::MAX.ref_time())] - fn max_weight() {} - } -} - -use frame_support::sp_runtime::traits::IdentityLookup; -use frame_support::traits::{ConstU128, ConstU32, ConstU64, Everything}; -use sp_runtime::{testing::H256, BuildStorage}; - -type Block = frame_system::mocking::MockBlock; -type Balance = u128; - -impl frame_system::Config for Runtime { - type RuntimeOrigin = RuntimeOrigin; - type Nonce = u64; - type RuntimeCall = RuntimeCall; - type Hash = H256; - type Hashing = ::sp_runtime::traits::BlakeTwo256; - type AccountId = u64; - type Lookup = IdentityLookup; - type Block = Block; - type RuntimeEvent = RuntimeEvent; - type BlockHashCount = ConstU64<250>; - type BlockWeights = (); - type BlockLength = (); - type Version = (); - type PalletInfo = PalletInfo; - type AccountData = pallet_balances::AccountData; - type OnNewAccount = (); - type OnKilledAccount = (); - type DbWeight = (); - type BaseCallFilter = Everything; - type SystemWeightInfo = (); - type SS58Prefix = (); - type OnSetCode = (); - type MaxConsumers = ConstU32<16>; -} - -impl pallet_balances::Config for Runtime { - type Balance = Balance; - type RuntimeEvent = RuntimeEvent; - type DustRemoval = (); - type ExistentialDeposit = ConstU128<1>; - type AccountStore = frame_system::Pallet; - type MaxLocks = (); - type MaxReserves = (); - type ReserveIdentifier = [u8; 8]; - type WeightInfo = (); - type RuntimeHoldReason = RuntimeHoldReason; - type FreezeIdentifier = [u8; 8]; - type MaxHolds = (); - type MaxFreezes = (); -} - -impl test_module::Config for Runtime {} - -frame_support::construct_runtime!( - pub enum Runtime { - System: frame_system, - TestModule: test_module, - Balances: pallet_balances, - } -); - -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 - } -} - -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 deleted file mode 100644 index eb95ce152..000000000 --- a/weight-meter/src/tests.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::mock::*; -use frame_support::{dispatch::PostDispatchInfo, weights::Weight}; - -#[test] -fn used_weight_works() { - new_test_ext().execute_with(|| { - let result: PostDispatchInfo = TestModule::expect_100(RuntimeOrigin::signed(100)).unwrap(); - // Check used weight is correct - assert_eq!(Some(Weight::from_parts(100, 0)), result.actual_weight); - // Check that the method ran correctly - assert_eq!(Some(100), TestModule::something()); - - let result: PostDispatchInfo = TestModule::expect_500(RuntimeOrigin::signed(100)).unwrap(); - assert_eq!(Some(Weight::from_parts(500, 0)), result.actual_weight); - assert_eq!(Some(600), TestModule::something()); - }); -} - -#[test] -fn used_weight_branch_works() { - new_test_ext().execute_with(|| { - let result: PostDispatchInfo = TestModule::expect_100_or_200(RuntimeOrigin::signed(100), false).unwrap(); - // Check used weight is correct - assert_eq!(Some(Weight::from_parts(100, 0)), result.actual_weight); - // Check that the method ran correctly - assert_eq!(Some(100), TestModule::something()); - - let result: PostDispatchInfo = TestModule::expect_100_or_200(RuntimeOrigin::signed(100), true).unwrap(); - // Check used weight is correct - assert_eq!(Some(Weight::from_parts(200, 0)), result.actual_weight); - // Check that the method ran correctly - assert_eq!(Some(300), TestModule::something()); - }); -} - -#[test] -fn used_weight_nested_calls_works() { - new_test_ext().execute_with(|| { - let result: PostDispatchInfo = TestModule::nested_inner_methods(RuntimeOrigin::signed(100)).unwrap(); - // Check used weight is correct - assert_eq!(Some(Weight::from_parts(300, 0)), result.actual_weight); - }); -} - -#[test] -fn exceed_max_weight_works() { - new_test_ext().execute_with(|| { - let result: PostDispatchInfo = TestModule::expect_max_weight(RuntimeOrigin::signed(100)).unwrap(); - // Check used weight is correct - assert_eq!(Some(Weight::from_parts(u64::MAX, 0)), result.actual_weight); - }); -} - -#[test] -fn nested_module_calls_works() { - new_test_ext().execute_with(|| { - let result = TestModule::nested_extrinsic(RuntimeOrigin::signed(0)).unwrap(); - assert_eq!(result.actual_weight, Some(Weight::from_parts(700, 0))); - }); -} diff --git a/weight-meter/weight-meter-procedural/Cargo.toml b/weight-meter/weight-meter-procedural/Cargo.toml deleted file mode 100644 index 697fae79f..000000000 --- a/weight-meter/weight-meter-procedural/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "weight-meter-procedural" -version = "0.1.0" -license = "Apache-2.0" -authors = ["Laminar Developers "] -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0.40" -quote = "1.0.20" -syn = { version = "1.0.98", features = ["full"] } - -[features] -default = ["std"] -std = [] -bench = [] diff --git a/weight-meter/weight-meter-procedural/src/lib.rs b/weight-meter/weight-meter-procedural/src/lib.rs deleted file mode 100644 index 785e72023..000000000 --- a/weight-meter/weight-meter-procedural/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse, Expr, ItemFn}; - -#[proc_macro_attribute] -pub fn start(attr: TokenStream, item: TokenStream) -> TokenStream { - let weight: Expr = if attr.is_empty() { - parse((quote! { 0 }).into()).unwrap() - } else { - parse(attr).unwrap() - }; - let ItemFn { attrs, vis, sig, block } = parse(item).unwrap(); - (quote! { - #(#attrs)* - #[cfg_attr(feature = "bench", ::orml_bencher::benchmarkable)] - #vis #sig { - ::orml_weight_meter::start(frame_support::weights::Weight::from_parts(#weight, 0)); - let result = #block; - ::orml_weight_meter::finish(); - result - } - }) - .into() -} - -#[proc_macro_attribute] -pub fn weight(attr: TokenStream, item: TokenStream) -> TokenStream { - let weight: Expr = parse(attr).unwrap(); - let ItemFn { attrs, vis, sig, block } = parse(item).unwrap(); - (quote! { - #(#attrs)* - #[cfg_attr(feature = "bench", ::orml_bencher::benchmarkable)] - #vis #sig { - ::orml_weight_meter::using(frame_support::weights::Weight::from_parts(#weight, 0)); - #block - } - }) - .into() -}