referrerpolicy=no-referrer-when-downgrade

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