owned this note
owned this note
Published
Linked with GitHub
# Benchmarking and Weights for a New Pallet
Note these instructions are for a pallet authored into Substrate's `frame` path, and don't work for externally authored pallets yet.
## Write the initial `benchmarks.rs`
Copy the following text into a new file `benchmarking.rs`, prepended with whatever licence you want:
```rust
//! Benchmarks for Whatever Pallet
#![cfg(feature = "runtime-benchmarks")]
use sp_std::prelude::*;
use super::*;
use sp_runtime::traits::Bounded;
use frame_system::RawOrigin;
use frame_benchmarking::{benchmarks, whitelisted_caller, impl_benchmark_test_suite};
use crate::Pallet as Whatever;
const SEED: u32 = 0;
benchmarks! {
}
impl_benchmark_test_suite!(
Whatever,
crate::mock::new_test_ext(),
crate::mock::Test,
);
```
## Introduce benchmarking code blocks
Inside the `benchmarks!` macro, introduce a block like this for each dispatchable:
```rust
example {
let x in 0..42;
let caller: T::AccountId = whitelisted_caller();
let arg = vec![1u32; x];
}: _(RawOrigin::Signed(caller.clone()), arg)
verify {
assert_eq!(1, 1);
}
```
Introduce `let ... in ...` lines for each complexity factor your dispatchable has.
## Integrate benchmarks into your pallet
### Ensure that your pallet is integrated into `node`
Note this step may already be done as part of your usual pallet authoring process.
- Ensure that `bin/node/cli/src/chain_spec.rs` includes your pallet's config if needed. **_Note: This is only needed if your pallet has a `GenesisConfig`._**
- In `bin/node/runtime/src/lib.rs`:
- Ensure that `Runtime` struct has an `impl` for your pallet's `Config`.
- Ensure that `construct_runtime!` macro has a line for your pallet.
- Ensure that `fn dispatch_benchmark` has a `add_benchmark!` macro invocation for your pallet.
- In `bin/node/runtime/Cargo.toml`:
- Ensure that your pallet is included as a dependency.
- Ensure that your pallet imitates the enabling of the `std` feature.
- Ensure that your pallet imitates the enabling of the `runtime-benchmarks` feature. **Don't forget this or you'll get weird build errors!**
### Enable benchmarks in your pallet
- In your pallet's `lib.rs`, ensure you have a `pub mod benchmarking;` line at the top.
- In your pallet's `Cargo.toml`, ensure you pass `runtime-benchmarks` feature down to `sp-runtime`, `frame-support` and `frame-system` crates, and use it to enable the `runtime-benchmarks` crate:
```
runtime-benchmarks = [
"frame-benchmarking",
"sp-runtime/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
]
```
## Testing benchmarks
Just use `cargo test`, but with all features enabled:
```bash
cargo test -p pallet-what-ever --all-features
```
## Generating your trait and evaluating benchmarks
This step creates or updates your pallet's `weights.rs`.
This step is run to generate your pallet's `Weights` trait, for use in your pallet's `#[pallet::weight]` tags. It should also be re-run to incorporate changes to the complexities of functions or new dispatchables.
```bash
cd bin/node/cli
cargo build --release --features=runtime-benchmarks
../../../target/release/substrate benchmark \
--chain dev \
--steps 5 \
--repeat 2 \
--pallet pallet_what_ever \
--extrinsic "*" \
--raw --execution=wasm \
--wasm-execution=compiled \
--output ../../../frame/what-ever/src/weights.rs \
--template ../../../.maintain/frame-weight-template.hbs
```
Replace `what_ever` & `what-ever` with your pallet's name (e.g. `gilt`, `elections_phragmen` & `elections-phragmen`).
## Incorporate weight formulae
In your pallet's `lib.rs`:
- Introduce `pub mod weights;` at the top.
- Introduce `pub use crate::weights::WeightInfo;` to expose the `WeightInfo` trait from your pallet.
- Introduce a `WeightInfo` type into the `Config` trait:
```rust
pub trait Config: frame_system::Config {
// ...
/// Information on runtime weights.
type WeightInfo: WeightInfo;
}
```
- For each of your dispatchables, introduce an appropriate weights line to determine the weight using the configured `WeightInfo` type, e.g.:
```rust
#[pallet::weight(T::WeightInfo::example(x.len()))]
fn example(origin: OriginFor<T>, arg: Vec<u32>) {
//...
}
```
### Define the `WeightInfo` type in `Config` trait impls
Additionally, you'll need to define the `WeightInfo` trait in both your pallet's tests mockup `mock.rs` and the Substrate `node`'s runtime.
In your pallet's `Config` trait impl in `mock.rs`, introduce the line:
```
type WeightInfo = ();
```
In your pallet's `Config` trait impl in `bin/node/runtime/src/lib.rs`, introduce the line:
```
type WeightInfo = pallet_what_ever::weights::SubstrateWeight<Runtime>;
```
## Integrating into other runtimes
When integrating into other runtimes, you'll want to use that runtime's custom overarching `WeightInfo`.
Ensure that the runtime's `fn dispatch_benchmark` has a `add_benchmark!` macro invocation for your pallet.
Initially, just use the `()` as the `WeightInfo` type for your pallet. E.g.:
```
impl pallet_what_ever::Config for Runtime {
type Event = Event;
//...
type WeightInfo = ();
}
```
Run the benchmarks for the runtime as usual. This will require you building your node's CLI with `--features runtime-benchmarks` and then running with the appropriate CLI options as above. E.g. for Kusama:
```
cargo run --release --features=runtime-benchmarks -- benchmark \
--chain=kusama-dev \
--steps=50 \
--repeat=20 \
--pallet=pallet_what_ever \
--extrinsic=* \
--execution=wasm \
--wasm-execution=compiled \
--heap-pages=4096 \
--header=./file_header.txt \
--output=./runtime/kusama/src/weights/
```
Reference hardware should really be used. E.g. on the Polkadot CI to benchmark for Kusama, issue a comment:
```
/benchmark runtime kusama pallet_what_ever
```
One you have the new file, you'll want to integrate it into your runtime. First go into the runtime's weights `mod.rs` and include the `pub mod` line to use the new weight file.
E.g. for Kusama, go into `runtime/kusama/src/weights/mod.rs` and add to the list of `pub mod` lines:
```
pub mod pallet_what_ever;
```
Once that's done, you can switch the pallet's config trait impl to use the real weights:
```
impl pallet_what_ever::Config for Runtime {
type Event = Event;
//...
type WeightInfo = weights::pallet_what_ever::WeightInfo<Runtime>;
}
```
That's it!