frame_benchmarking/lib.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Macro for benchmarking a FRAME runtime.
19
20#![cfg_attr(not(feature = "std"), no_std)]
21
22extern crate alloc;
23
24#[cfg(feature = "std")]
25mod analysis;
26#[cfg(test)]
27mod tests;
28#[cfg(test)]
29mod tests_instance;
30mod utils;
31
32pub mod baseline;
33pub mod v1;
34
35/// Private exports that are being used by macros.
36///
37/// The exports are not stable and should not be relied on.
38#[doc(hidden)]
39pub mod __private {
40 pub use alloc::{boxed::Box, str, vec, vec::Vec};
41 pub use codec;
42 pub use frame_support::{storage, traits};
43 pub use log;
44 pub use paste;
45 pub use sp_core::defer;
46 pub use sp_io::storage::root as storage_root;
47 pub use sp_runtime::{traits::Zero, StateVersion};
48 pub use sp_storage::{well_known_keys, TrackedStorageKey};
49}
50
51#[cfg(feature = "std")]
52pub use analysis::{Analysis, AnalysisChoice, BenchmarkSelector};
53pub use utils::*;
54pub use v1::*;
55
56/// Contains macros, structs, and traits associated with v2 of the pallet benchmarking syntax.
57///
58/// The [`v2::benchmarks`] and [`v2::instance_benchmarks`] macros can be used to designate a
59/// module as a benchmarking module that can contain benchmarks and benchmark tests. The
60/// `#[benchmarks]` variant will set up a regular, non-instance benchmarking module, and the
61/// `#[instance_benchmarks]` variant will set up the module in instance benchmarking mode.
62///
63/// Benchmarking modules should be gated behind a `#[cfg(feature = "runtime-benchmarks")]`
64/// feature gate to ensure benchmarking code that is only compiled when the
65/// `runtime-benchmarks` feature is enabled is not referenced.
66///
67/// The following is the general syntax for a benchmarks (or instance benchmarks) module:
68///
69/// ## General Syntax
70///
71/// ```ignore
72/// #![cfg(feature = "runtime-benchmarks")]
73///
74/// use super::{mock_helpers::*, Pallet as MyPallet};
75/// use frame_benchmarking::v2::*;
76///
77/// #[benchmarks]
78/// mod benchmarks {
79/// use super::*;
80///
81/// #[benchmark]
82/// fn bench_name_1(x: Linear<7, 1_000>, y: Linear<1_000, 100_0000>) {
83/// // setup code
84/// let z = x + y;
85/// let caller = whitelisted_caller();
86///
87/// #[extrinsic_call]
88/// extrinsic_name(SystemOrigin::Signed(caller), other, arguments);
89///
90/// // verification code
91/// assert_eq!(MyPallet::<T>::my_var(), z);
92/// }
93///
94/// #[benchmark]
95/// fn bench_name_2() {
96/// // setup code
97/// let caller = whitelisted_caller();
98///
99/// #[block]
100/// {
101/// something(some, thing);
102/// my_extrinsic(RawOrigin::Signed(caller), some, argument);
103/// something_else(foo, bar);
104/// }
105///
106/// // verification code
107/// assert_eq!(MyPallet::<T>::something(), 37);
108/// }
109/// }
110/// ```
111///
112/// ## Benchmark Definitions
113///
114/// Within a `#[benchmarks]` or `#[instance_benchmarks]` module, you can define individual
115/// benchmarks using the `#[benchmark]` attribute, as shown in the example above.
116///
117/// The `#[benchmark]` attribute expects a function definition with a blank return type (or a
118/// return type compatible with `Result<(), BenchmarkError>`, as discussed below) and zero or
119/// more arguments whose names are valid [BenchmarkParameter](`crate::BenchmarkParameter`)
120/// parameters, such as `x`, `y`, `a`, `b`, etc., and whose param types must implement
121/// [ParamRange](`v2::ParamRange`). At the moment the only valid type that implements
122/// [ParamRange](`v2::ParamRange`) is [Linear](`v2::Linear`).
123///
124/// The valid syntax for defining a [Linear](`v2::Linear`) is `Linear<A, B>` where `A`, and `B`
125/// are valid integer literals (that fit in a `u32`), such that `B` >= `A`.
126///
127/// Anywhere within a benchmark function you may use the generic `T: Config` parameter as well
128/// as `I` in the case of an `#[instance_benchmarks]` module. You should not add these to the
129/// function signature as this will be handled automatically for you based on whether this is a
130/// `#[benchmarks]` or `#[instance_benchmarks]` module and whatever [where clause](#where-clause)
131/// you have defined for the module. You should not manually add any generics to the
132/// signature of your benchmark function.
133///
134/// Also note that the `// setup code` and `// verification code` comments shown above are not
135/// required and are included simply for demonstration purposes.
136///
137/// ### `#[extrinsic_call]` and `#[block]`
138///
139/// Within the benchmark function body, either an `#[extrinsic_call]` or a `#[block]`
140/// annotation is required. These attributes should be attached to a block (shown in
141/// `bench_name_2` above) or a one-line function call (shown in `bench_name_1` above, in `syn`
142/// parlance this should be an `ExprCall`), respectively.
143///
144/// The `#[block]` syntax is broad and will benchmark any code contained within the block the
145/// attribute is attached to. If `#[block]` is attached to something other than a block, a
146/// compiler error will be emitted.
147///
148/// The one-line `#[extrinsic_call]` syntax must consist of a function call to an extrinsic,
149/// where the first argument is the origin. If `#[extrinsic_call]` is attached to an item that
150/// doesn't meet these requirements, a compiler error will be emitted.
151///
152/// As a short-hand, you may substitute the name of the extrinsic call with `_`, such as the
153/// following:
154///
155/// ```ignore
156/// #[extrinsic_call]
157/// _(RawOrigin::Signed(whitelisted_caller()), 0u32.into(), 0);
158/// ```
159///
160/// The underscore will be substituted with the name of the benchmark (i.e. the name of the
161/// function in the benchmark function definition).
162///
163/// In case of a `force_origin` where you want to elevate the privileges of the provided origin,
164/// this is the general syntax:
165/// ```ignore
166/// #[extrinsic_call]
167/// _(force_origin as T::RuntimeOrigin, 0u32.into(), 0);
168/// ```
169///
170/// Regardless of whether `#[extrinsic_call]` or `#[block]` is used, this attribute also serves
171/// the purpose of designating the boundary between the setup code portion of the benchmark
172/// (everything before the `#[extrinsic_call]` or `#[block]` attribute) and the verification
173/// stage (everything after the item that the `#[extrinsic_call]` or `#[block]` attribute is
174/// attached to). The setup code section should contain any code that needs to execute before
175/// the measured portion of the benchmark executes. The verification section is where you can
176/// perform assertions to verify that the extrinsic call (or whatever is happening in your
177/// block, if you used the `#[block]` syntax) executed successfully.
178///
179/// Note that neither `#[extrinsic_call]` nor `#[block]` are real attribute macros and are
180/// instead consumed by the outer macro pattern as part of the enclosing benchmark function
181/// definition. This is why we are able to use `#[extrinsic_call]` and `#[block]` within a
182/// function definition even though this behavior has not been stabilized
183/// yet—`#[extrinsic_call]` and `#[block]` are parsed and consumed as part of the benchmark
184/// definition parsing code, so they never expand as their own attribute macros.
185///
186/// ### Optional Attributes
187///
188/// The keywords `extra` and `skip_meta` can be provided as optional arguments to the
189/// `#[benchmark]` attribute, i.e. `#[benchmark(extra, skip_meta)]`. Including either of these
190/// will enable the `extra` or `skip_meta` option, respectively. These options enable the same
191/// behavior they did in the old benchmarking syntax in `frame_benchmarking`, namely:
192///
193/// #### `extra`
194///
195/// Specifies that this benchmark should not normally run. To run benchmarks marked with
196/// `extra`, you will need to invoke the `frame-benchmarking-cli` with `--extra`.
197///
198/// #### `skip_meta`
199///
200/// Specifies that the benchmarking framework should not analyze the storage keys that the
201/// benchmarked code read or wrote. This useful to suppress the prints in the form of unknown
202/// 0x… in case a storage key that does not have metadata. Note that this skips the analysis of
203/// all accesses, not just ones without metadata.
204///
205/// ## Where Clause
206///
207/// Some pallets require a where clause specifying constraints on their generics to make
208/// writing benchmarks feasible. To accommodate this situation, you can provide such a where
209/// clause as the (only) argument to the `#[benchmarks]` or `#[instance_benchmarks]` attribute
210/// macros. Below is an example of this taken from the `message-queue` pallet.
211///
212/// ```ignore
213/// #[benchmarks(
214/// where
215/// <<T as Config>::MessageProcessor as ProcessMessage>::Origin: From<u32> + PartialEq,
216/// <T as Config>::Size: From<u32>,
217/// )]
218/// mod benchmarks {
219/// use super::*;
220/// // ...
221/// }
222/// ```
223///
224/// ## Benchmark Tests
225///
226/// Benchmark tests can be generated using the old syntax in `frame_benchmarking`,
227/// including the `frame_benchmarking::impl_benchmark_test_suite` macro.
228///
229/// An example is shown below (taken from the `message-queue` pallet's `benchmarking` module):
230/// ```ignore
231/// #[benchmarks]
232/// mod benchmarks {
233/// use super::*;
234/// // ...
235/// impl_benchmark_test_suite!(
236/// MessageQueue,
237/// crate::mock::new_test_ext::<crate::integration_test::Test>(),
238/// crate::integration_test::Test
239/// );
240/// }
241/// ```
242///
243/// ## Benchmark Function Generation
244///
245/// The benchmark function definition that you provide is used to automatically create a number
246/// of impls and structs required by the benchmarking engine. Additionally, a benchmark
247/// function is also generated that resembles the function definition you provide, with a few
248/// modifications:
249/// 1. The function name is transformed from i.e. `original_name` to `_original_name` so as not to
250/// collide with the struct `original_name` that is created for some of the benchmarking engine
251/// impls.
252/// 2. Appropriate `T: Config` and `I` (if this is an instance benchmark) generics are added to the
253/// function automatically during expansion, so you should not add these manually on your
254/// function definition (but you may make use of `T` and `I` anywhere within your benchmark
255/// function, in any of the three sections (setup, call, verification).
256/// 3. Arguments such as `u: Linear<10, 100>` are converted to `u: u32` to make the function
257/// directly callable.
258/// 4. A `verify: bool` param is added as the last argument. Specifying `true` will result in the
259/// verification section of your function executing, while a value of `false` will skip
260/// verification.
261/// 5. If you specify a return type on the function definition, it must conform to the [rules
262/// below](#support-for-result-benchmarkerror-and-the--operator), and the last statement of the
263/// function definition must resolve to something compatible with `Result<(), BenchmarkError>`.
264///
265/// The reason we generate an actual function as part of the expansion is to allow the compiler
266/// to enforce several constraints that would otherwise be difficult to enforce and to reduce
267/// developer confusion (especially regarding the use of the `?` operator, as covered below).
268///
269/// Note that any attributes, comments, and doc comments attached to your benchmark function
270/// definition are also carried over onto the resulting benchmark function and the struct for
271/// that benchmark. As a result you should be careful about what attributes you attach here as
272/// they will be replicated in multiple places.
273///
274/// ### Support for `Result<(), BenchmarkError>` and the `?` operator
275///
276/// You may optionally specify `Result<(), BenchmarkError>` as the return type of your
277/// benchmark function definition. If you do so, you must return a compatible `Result<(),
278/// BenchmarkError>` as the *last statement* of your benchmark function definition. You may
279/// also use the `?` operator throughout your benchmark function definition if you choose to
280/// follow this route. See the example below:
281///
282/// ```ignore
283/// #![cfg(feature = "runtime-benchmarks")]
284///
285/// use super::{mock_helpers::*, Pallet as MyPallet};
286/// use frame_benchmarking::v2::*;
287///
288/// #[benchmarks]
289/// mod benchmarks {
290/// use super::*;
291///
292/// #[benchmark]
293/// fn bench_name(x: Linear<5, 25>) -> Result<(), BenchmarkError> {
294/// // setup code
295/// let z = x + 4;
296/// let caller = whitelisted_caller();
297///
298/// // note we can make use of the ? operator here because of the return type
299/// something(z)?;
300///
301/// #[extrinsic_call]
302/// extrinsic_name(SystemOrigin::Signed(caller), other, arguments);
303///
304/// // verification code
305/// assert_eq!(MyPallet::<T>::my_var(), z);
306///
307/// // we must return a valid `Result<(), BenchmarkError>` as the last line of our benchmark
308/// // function definition. This line is not included as part of the verification code that
309/// // appears above it.
310/// Ok(())
311/// }
312/// }
313/// ```
314///
315/// ## Migrate from v1 to v2
316///
317/// To migrate your code from benchmarking v1 to benchmarking v2, you may follow these
318/// steps:
319/// 1. Change the import from `frame_benchmarking::v1::` to `frame_benchmarking::v2::*`, or
320/// `frame::benchmarking::prelude::*` under the umbrella crate;
321/// 2. Move the code inside the v1 `benchmarks! { ... }` block to the v2 benchmarks module `mod
322/// benchmarks { ... }` under the benchmarks macro (`#[benchmarks]` for a regular module, or
323/// `#[instance_benchmarks]` to set up the module in instance benchmarking mode);
324/// 3. Turn each v1 benchmark into a function inside the v2 benchmarks module with the same name,
325/// having either a blank return type or a return type compatible with `Result<(),
326/// BenchmarkError>`. For instance, `foo { ... }` can become `fn foo() -> Result<(),
327/// BenchmarkError>`. More in detail:
328/// 1. Move all the v1 complexity parameters as [ParamRange](`v2::ParamRange`) arguments to the
329/// v2 function, and their setup code to the body of the function. For instance, `let y in 0
330/// .. 10 => setup(y)?;` from v1 will give a `y: Linear<0, 10>` argument to the corresponding
331/// function in v2, while `setup(y)?;` will be moved to the body of the function;
332/// 2. Move all the v1 setup code to the body of the v2 function;
333/// 3. Move the benchmarked code to the body of the v2 function under the appropriate macro
334/// attribute: `#[extrinsic_call]` for extrinsic pallet calls and `#[block]` for blocks of
335/// code;
336/// 4. Move the v1 verify code block to the body of the v2 function, after the
337/// `#[extrinsic_call]` or `#[block]` attribute.
338/// 5. If the function returns a `Result<(), BenchmarkError>`, end with `Ok(())`.
339///
340/// As for tests, the code is the same as v1 (see [Benchmark Tests](#benchmark-tests)).
341///
342/// As an example migration, the following v1 code
343///
344/// ```ignore
345/// #![cfg(feature = "runtime-benchmarks")]
346///
347/// use frame_benchmarking::v1::*;
348///
349/// benchmarks! {
350///
351/// // first dispatchable: this is a user dispatchable and operates on a `u8` vector of
352/// // size `l`
353/// foo {
354/// let caller = funded_account::<T>(b"caller", 0);
355/// let l in 1 .. 10_000 => initialize_l(l);
356/// }: {
357/// _(RuntimeOrigin::Signed(caller), vec![0u8; l])
358/// } verify {
359/// assert_last_event::<T>(Event::FooExecuted { result: Ok(()) }.into());
360/// }
361/// }
362/// ```
363///
364/// would become the following v2 code:
365///
366/// ```ignore
367/// #![cfg(feature = "runtime-benchmarks")]
368///
369/// use frame_benchmarking::v2::*;
370///
371/// #[benchmarks]
372/// mod benchmarks {
373/// use super::*;
374///
375/// // first dispatchable: foo; this is a user dispatchable and operates on a `u8` vector of
376/// // size `l`
377/// #[benchmark]
378/// fn foo(l: Linear<1 .. 10_000>) -> Result<(), BenchmarkError> {
379/// let caller = funded_account::<T>(b"caller", 0);
380/// initialize_l(l);
381///
382/// #[extrinsic_call]
383/// _(RuntimeOrigin::Signed(caller), vec![0u8; l]);
384///
385/// // Everything onwards will be treated as test.
386/// assert_last_event::<T>(Event::FooExecuted { result: Ok(()) }.into());
387/// Ok(())
388/// }
389/// }
390/// ```
391pub mod v2 {
392 pub use super::*;
393 pub use frame_support_procedural::{
394 benchmark, benchmarks, block, extrinsic_call, instance_benchmarks,
395 };
396
397 // Used in #[benchmark] implementation to ensure that benchmark function arguments
398 // implement [`ParamRange`].
399 #[doc(hidden)]
400 pub use static_assertions::{assert_impl_all, assert_type_eq_all};
401
402 /// Used by the new benchmarking code to specify that a benchmarking variable is linear
403 /// over some specified range, i.e. `Linear<0, 1_000>` means that the corresponding variable
404 /// is allowed to range from `0` to `1000`, inclusive.
405 ///
406 /// See [`v2`] for more info.
407 pub struct Linear<const A: u32, const B: u32>;
408
409 /// Trait that must be implemented by all structs that can be used as parameter range types
410 /// in the new benchmarking code (i.e. `Linear<0, 1_000>`). Right now there is just
411 /// [`Linear`] but this could later be extended to support additional non-linear parameter
412 /// ranges.
413 ///
414 /// See [`v2`] for more info.
415 pub trait ParamRange {
416 /// Represents the (inclusive) starting number of this `ParamRange`.
417 fn start(&self) -> u32;
418
419 /// Represents the (inclusive) ending number of this `ParamRange`.
420 fn end(&self) -> u32;
421 }
422
423 impl<const A: u32, const B: u32> ParamRange for Linear<A, B> {
424 fn start(&self) -> u32 {
425 A
426 }
427
428 fn end(&self) -> u32 {
429 B
430 }
431 }
432}