diff --git a/.snippets/code/develop/parachains/testing/benchmarking/benchmark-output.html b/.snippets/code/develop/parachains/testing/benchmarking/benchmark-output.html index 2e1abec86..518644c44 100644 --- a/.snippets/code/develop/parachains/testing/benchmarking/benchmark-output.html +++ b/.snippets/code/develop/parachains/testing/benchmarking/benchmark-output.html @@ -1,14 +1,14 @@
- ./target/release/INSERT_NODE_BINARY_NAME benchmark pallet \ --runtime INSERT_PATH_TO_WASM_RUNTIME \ --pallet INSERT_PALLET_NAME \ --extrinsic '*' \ --steps 20 \ --repeat 10 \ --output weights.rs - 2024-10-28 11:07:25 Loading WASM from ./target/release/wbuild/educhain-runtime/educhain_runtime.wasm - 2024-10-28 11:07:26 Could not find genesis preset 'development'. Falling back to default. - 2024-10-28 11:07:26 assembling new collators for new session 0 at #0 - 2024-10-28 11:07:26 assembling new collators for new session 1 at #0 - 2024-10-28 11:07:26 Loading WASM from ./target/release/wbuild/educhain-runtime/educhain_runtime.wasm - Pallet: "pallet_parachain_template", Extrinsic: "do_something", Lowest values: [], Highest values: [], Steps: 20, Repeat: 10 + frame-omni-bencher v1 benchmark pallet \ + --runtime INSERT_PATH_TO_WASM_RUNTIME \ + --pallet "INSERT_NAME_OF_PALLET" \ + --extrinsic "" \ + --template ./frame-weight-template.hbs \ + --output ./weights.rs + ... + 2025-01-15T16:41:33.557045Z INFO polkadot_sdk_frame::benchmark::pallet: [ 0 % ] Starting benchmark: pallet_parachain_template::do_something + 2025-01-15T16:41:33.564644Z INFO polkadot_sdk_frame::benchmark::pallet: [ 50 % ] Starting benchmark: pallet_parachain_template::cause_error ... Created file: "weights.rs" - 2024-10-28 11:07:27 [ 0 % ] Starting benchmark: pallet_parachain_template::do_something - I2024-10-28 11:07:27 [ 50 % ] Starting benchmark: pallet_parachain_template::cause_error
diff --git a/.snippets/code/develop/parachains/testing/benchmarking/runtime-cargo.toml b/.snippets/code/develop/parachains/testing/benchmarking/runtime-cargo.toml new file mode 100644 index 000000000..769c28783 --- /dev/null +++ b/.snippets/code/develop/parachains/testing/benchmarking/runtime-cargo.toml @@ -0,0 +1,4 @@ +runtime-benchmarks = [ + # ... + "pallet_parachain_template/runtime-benchmarks", +] diff --git a/.snippets/code/develop/parachains/testing/benchmarking/runtime-pallet-config.rs b/.snippets/code/develop/parachains/testing/benchmarking/runtime-pallet-config.rs new file mode 100644 index 000000000..c3500b054 --- /dev/null +++ b/.snippets/code/develop/parachains/testing/benchmarking/runtime-pallet-config.rs @@ -0,0 +1,5 @@ +// Configure pallet. +impl pallet_parachain_template::Config for Runtime { + // ... + type WeightInfo = pallet_parachain_template::weights::SubstrateWeight; +} \ No newline at end of file diff --git a/.snippets/code/develop/parachains/testing/benchmarking/weight-config.rs b/.snippets/code/develop/parachains/testing/benchmarking/weight-config.rs index 2fdd7fe7d..5bd8b2cb5 100644 --- a/.snippets/code/develop/parachains/testing/benchmarking/weight-config.rs +++ b/.snippets/code/develop/parachains/testing/benchmarking/weight-config.rs @@ -1,8 +1,10 @@ +pub mod weights; use crate::weights::WeightInfo; /// Configure the pallet by specifying the parameters and types on which it depends. #[pallet::config] pub trait Config: frame_system::Config { + // ... /// A type representing the weights required by the dispatchables of this pallet. type WeightInfo: WeightInfo; } \ No newline at end of file diff --git a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/Cargo.toml b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/Cargo.toml index b1db64bf8..7babd6bc5 100644 --- a/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/Cargo.toml +++ b/.snippets/code/tutorials/polkadot-sdk/parachains/zero-to-hero/build-custom-pallet/Cargo.toml @@ -24,14 +24,14 @@ pallet-balances = { workspace = true, default-features = false } [features] default = ["std"] std = [ - "codec/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", - "sp-runtime/std", - "sp-core/std", - "sp-io/std", - "pallet-balances/std", + "codec/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", + "sp-runtime/std", + "sp-core/std", + "sp-io/std", + "pallet-balances/std", ] [lints] diff --git a/develop/parachains/testing/benchmarking.md b/develop/parachains/testing/benchmarking.md index 3c03e792a..fb53fa83e 100644 --- a/develop/parachains/testing/benchmarking.md +++ b/develop/parachains/testing/benchmarking.md @@ -50,6 +50,11 @@ The benchmarking tool runs multiple iterations to model worst-case execution tim ### Prepare Your Environment +Install the [`frame-omni-bencher`](https://crates.io/crates/frame-omni-bencher){target=\_blank} command-line tool: +```bash +cargo install frame-omni-bencher +``` + Before writing benchmark tests, you need to ensure the `frame-benchmarking` crate is included in your pallet's `Cargo.toml` similar to the following: ```toml title="Cargo.toml" @@ -94,24 +99,31 @@ In your benchmarking tests, employ these best practices: - **Use the `#[extrinsic_call]` macro** - this macro is used when calling the extrinsic itself and is a required part of a benchmarking function. See the [`extrinsic_call Rust docs](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html#extrinsic_call-and-block){target=_blank} for more details - **Validate extrinsic behavior** - the `assert_eq` expression ensures that the extrinsic is working properly within the benchmark context +Add the `benchmarking` module to your pallet. In the pallet `lib.rs` file add the following: +```rust +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +``` + ### Add Benchmarks to Runtime Before running the benchmarking tool, you must integrate benchmarks with your runtime as follows: -1. Create a `benchmarks.rs` file. This file should contain the following macro, which registers all pallets for benchmarking, as well as their respective configurations: +1. Navigate to your `runtime/src` directory and check if a `benchmarks.rs` file exists. If not, create one. This file will contain the macro that registers all pallets for benchmarking along with their respective configurations: ```rust title="benchmarks.rs" --8<-- 'code/develop/parachains/testing/benchmarking/frame-benchmark-macro.rs' ``` - For example, to register a pallet named `pallet_parachain_template` for benchmarking, add it as follows: + + For example, to add a new pallet named `pallet_parachain_template` for benchmarking, include it in the macro as shown: ```rust title="benchmarks.rs" hl_lines="3" --8<-- 'code/develop/parachains/testing/benchmarking/frame-benchmark-macro.rs::3' ); ``` !!!warning "Updating `define_benchmarks!` macro is required" - If the pallet isn't included in the `define_benchmarks!` macro, the CLI cannot access and benchmark it later. + Any pallet that needs to be benchmarked must be included in the `define_benchmarks!` macro. The CLI will only be able to access and benchmark pallets that are registered here. -2. Navigate to the runtime's `lib.rs` file and add the import for `benchmarks.rs` as follows: +2. Check your runtime's `lib.rs` file to ensure the `benchmarks` module is imported. The import should look like this: ```rust title="lib.rs" #[cfg(feature = "runtime-benchmarks")] @@ -120,52 +132,74 @@ Before running the benchmarking tool, you must integrate benchmarks with your ru The `runtime-benchmarks` feature gate ensures benchmark tests are isolated from production runtime code. +3. Enable runtime benchmarking for your pallet in `runtime/Cargo.toml`: + ```toml + --8<-- 'code/develop/parachains/testing/benchmarking/runtime-cargo.toml' + ``` + ### Run Benchmarks You can now compile your runtime with the `runtime-benchmarks` feature flag. This feature flag is crucial as the benchmarking tool will look for this feature being enabled to know when it should run benchmark tests. Follow these steps to compile the runtime with benchmarking enabled: -1. Run `build` with the feature flag included +1. Run `build` with the feature flag included: ```bash cargo build --features runtime-benchmarks --release ``` -2. Once compiled, run the benchmarking tool to measure extrinsic weights +2. Create a `weights.rs` file in your pallet's `src/` directory. This file will store the auto-generated weight calculations: +```bash +touch weights.rs +``` - ```sh - ./target/release/INSERT_NODE_BINARY_NAME benchmark pallet \ +3. Before running the benchmarking tool, you'll need a template file that defines how weight information should be formatted. Download the official template from the Polkadot SDK repository and save it in your project folders for future use: +```bash +curl https://raw.githubusercontent.com/paritytech/polkadot-sdk/refs/tags/polkadot-stable2412/substrate/.maintain/frame-weight-template.hbs \ +--output ./pallets/benchmarking/frame-weight-template.hbs +``` + +4. Run the benchmarking tool to measure extrinsic weights: + + ```bash + frame-omni-bencher v1 benchmark pallet \ --runtime INSERT_PATH_TO_WASM_RUNTIME \ --pallet INSERT_NAME_OF_PALLET \ - --extrinsic '*' \ - --steps 20 \ - --repeat 10 \ + --extrinsic "" \ + --template ./frame-weight-template.hbs \ --output weights.rs ``` !!! info "Flag definitions" - `--runtime` - the path to your runtime's Wasm - `--pallet` - the name of the pallet you wish to benchmark. This pallet must be configured in your runtime and defined in `define_benchmarks` - - `--extrinsic` - which extrinsic to test. Using `'*'` implies all extrinsics will be benchmarked + - `--extrinsic` - which extrinsic to test. Using `""` implies all extrinsics will be benchmarked + - `--template` - defines how weight information should be formatted - `--output` - where the output of the auto-generated weights will reside -The generated `weights.rs` file contains weight annotations for your extrinsics, ready to be added to your pallet. The output should be similar to the following. Some output is omitted for brevity: +The generated `weights.rs` file contains weight annotations for your extrinsics, ready to be added to your pallet. The output should be similar to the following. Some output is omitted for brevity: --8<-- 'code/develop/parachains/testing/benchmarking/benchmark-output.html' #### Add Benchmark Weights to Pallet -Once the `weights.rs` is generated, you may add the generated weights to your pallet. It is common that `weights.rs` become part of your pallet's root in `src/`: +Once the `weights.rs` is generated, you need to integrate it with your pallet. This involves two steps: importing the `weights` module and the `WeightInfo` trait, and adding it to your pallet's `Config` trait. Here's how to set this up: ```rust --8<-- 'code/develop/parachains/testing/benchmarking/weight-config.rs' ``` -After which, you may add this to the `#[pallet::weight]` annotation in the extrinsic via the `Config`: +After which, you must add this to the `#[pallet::weight]` annotation in all the extrinsics via the `Config`: ```rust hl_lines="2" --8<-- 'code/develop/parachains/testing/benchmarking/dispatchable-pallet-weight.rs' ``` +Finally, configure the actual weight values in your runtime. In `runtime/src/config/mod.rs`, add: + +```rust +--8<-- 'code/develop/parachains/testing/benchmarking/runtime-pallet-config.rs' +``` + ## Where to Go Next - View the Rust Docs for a more comprehensive, low-level view of the [FRAME V2 Benchmarking Suite](https://paritytech.github.io/polkadot-sdk/master/frame_benchmarking/v2/index.html){target=_blank}