1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
// This file is part of Substrate.

// Copyright (C) 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.

//! Macro for benchmarking a FRAME runtime.

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(feature = "std")]
mod analysis;
#[cfg(test)]
mod tests;
#[cfg(test)]
mod tests_instance;
mod utils;

pub mod baseline;
pub mod v1;

/// Private exports that are being used by macros.
///
/// The exports are not stable and should not be relied on.
#[doc(hidden)]
pub mod __private {
	pub use codec;
	pub use frame_support::{storage, traits};
	pub use log;
	pub use paste;
	pub use sp_core::defer;
	pub use sp_io::storage::root as storage_root;
	pub use sp_runtime::{traits::Zero, StateVersion};
	pub use sp_std::{self, boxed::Box, str, vec, vec::Vec};
	pub use sp_storage::{well_known_keys, TrackedStorageKey};
}

#[cfg(feature = "std")]
pub use analysis::{Analysis, AnalysisChoice, BenchmarkSelector};
pub use utils::*;
pub use v1::*;

/// Contains macros, structs, and traits associated with v2 of the pallet benchmarking syntax.
///
/// The [`v2::benchmarks`] and [`v2::instance_benchmarks`] macros can be used to designate a
/// module as a benchmarking module that can contain benchmarks and benchmark tests. The
/// `#[benchmarks]` variant will set up a regular, non-instance benchmarking module, and the
/// `#[instance_benchmarks]` variant will set up the module in instance benchmarking mode.
///
/// Benchmarking modules should be gated behind a `#[cfg(feature = "runtime-benchmarks")]`
/// feature gate to ensure benchmarking code that is only compiled when the
/// `runtime-benchmarks` feature is enabled is not referenced.
///
/// The following is the general syntax for a benchmarks (or instance benchmarks) module:
///
/// ## General Syntax
///
/// ```ignore
/// #![cfg(feature = "runtime-benchmarks")]
///
/// use super::{mock_helpers::*, Pallet as MyPallet};
/// use frame_benchmarking::v2::*;
///
/// #[benchmarks]
/// mod benchmarks {
/// 	use super::*;
///
/// 	#[benchmark]
/// 	fn bench_name_1(x: Linear<7, 1_000>, y: Linear<1_000, 100_0000>) {
/// 		// setup code
/// 		let z = x + y;
/// 		let caller = whitelisted_caller();
///
/// 		#[extrinsic_call]
/// 		extrinsic_name(SystemOrigin::Signed(caller), other, arguments);
///
/// 		// verification code
/// 		assert_eq!(MyPallet::<T>::my_var(), z);
/// 	}
///
/// 	#[benchmark]
/// 	fn bench_name_2() {
/// 		// setup code
/// 		let caller = whitelisted_caller();
///
/// 		#[block]
/// 		{
/// 			something(some, thing);
/// 			my_extrinsic(RawOrigin::Signed(caller), some, argument);
/// 			something_else(foo, bar);
/// 		}
///
/// 		// verification code
/// 		assert_eq!(MyPallet::<T>::something(), 37);
/// 	}
/// }
/// ```
///
/// ## Benchmark Definitions
///
/// Within a `#[benchmarks]` or `#[instance_benchmarks]` module, you can define individual
/// benchmarks using the `#[benchmark]` attribute, as shown in the example above.
///
/// The `#[benchmark]` attribute expects a function definition with a blank return type (or a
/// return type compatible with `Result<(), BenchmarkError>`, as discussed below) and zero or
/// more arguments whose names are valid [BenchmarkParameter](`crate::BenchmarkParameter`)
/// parameters, such as `x`, `y`, `a`, `b`, etc., and whose param types must implement
/// [ParamRange](`v2::ParamRange`). At the moment the only valid type that implements
/// [ParamRange](`v2::ParamRange`) is [Linear](`v2::Linear`).
///
/// The valid syntax for defining a [Linear](`v2::Linear`) is `Linear<A, B>` where `A`, and `B`
/// are valid integer literals (that fit in a `u32`), such that `B` >= `A`.
///
/// Anywhere within a benchmark function you may use the generic `T: Config` parameter as well
/// as `I` in the case of an `#[instance_benchmarks]` module. You should not add these to the
/// function signature as this will be handled automatically for you based on whether this is a
/// `#[benchmarks]` or `#[instance_benchmarks]` module and whatever [where clause](#where-clause)
/// you have defined for the module. You should not manually add any generics to the
/// signature of your benchmark function.
///
/// Also note that the `// setup code` and `// verification code` comments shown above are not
/// required and are included simply for demonstration purposes.
///
/// ### `#[extrinsic_call]` and `#[block]`
///
/// Within the benchmark function body, either an `#[extrinsic_call]` or a `#[block]`
/// annotation is required. These attributes should be attached to a block (shown in
/// `bench_name_2` above) or a one-line function call (shown in `bench_name_1` above, in `syn`
/// parlance this should be an `ExprCall`), respectively.
///
/// The `#[block]` syntax is broad and will benchmark any code contained within the block the
/// attribute is attached to. If `#[block]` is attached to something other than a block, a
/// compiler error will be emitted.
///
/// The one-line `#[extrinsic_call]` syntax must consist of a function call to an extrinsic,
/// where the first argument is the origin. If `#[extrinsic_call]` is attached to an item that
/// doesn't meet these requirements, a compiler error will be emitted.
///
/// As a short-hand, you may substitute the name of the extrinsic call with `_`, such as the
/// following:
///
/// ```ignore
/// #[extrinsic_call]
/// _(RawOrigin::Signed(whitelisted_caller()), 0u32.into(), 0);
/// ```
///
/// The underscore will be substituted with the name of the benchmark  (i.e. the name of the
/// function in the benchmark function definition).
///
/// In case of a `force_origin` where you want to elevate the privileges of the provided origin,
/// this is the general syntax:
/// ```ignore
/// #[extrinsic_call]
/// _(force_origin as T::RuntimeOrigin, 0u32.into(), 0);
/// ```
///
/// Regardless of whether `#[extrinsic_call]` or `#[block]` is used, this attribute also serves
/// the purpose of designating the boundary between the setup code portion of the benchmark
/// (everything before the `#[extrinsic_call]` or `#[block]` attribute) and the verification
/// stage (everything after the item that the `#[extrinsic_call]` or `#[block]` attribute is
/// attached to). The setup code section should contain any code that needs to execute before
/// the measured portion of the benchmark executes. The verification section is where you can
/// perform assertions to verify that the extrinsic call (or whatever is happening in your
/// block, if you used the `#[block]` syntax) executed successfully.
///
/// Note that neither `#[extrinsic_call]` nor `#[block]` are real attribute macros and are
/// instead consumed by the outer macro pattern as part of the enclosing benchmark function
/// definition. This is why we are able to use `#[extrinsic_call]` and `#[block]` within a
/// function definition even though this behavior has not been stabilized
/// yet—`#[extrinsic_call]` and `#[block]` are parsed and consumed as part of the benchmark
/// definition parsing code, so they never expand as their own attribute macros.
///
/// ### Optional Attributes
///
/// The keywords `extra` and `skip_meta` can be provided as optional arguments to the
/// `#[benchmark]` attribute, i.e. `#[benchmark(extra, skip_meta)]`. Including either of these
/// will enable the `extra` or `skip_meta` option, respectively. These options enable the same
/// behavior they did in the old benchmarking syntax in `frame_benchmarking`, namely:
///
/// #### `extra`
///
/// Specifies that this benchmark should not normally run. To run benchmarks marked with
/// `extra`, you will need to invoke the `frame-benchmarking-cli` with `--extra`.
///
/// #### `skip_meta`
///
/// Specifies that the benchmarking framework should not analyze the storage keys that the
/// benchmarked code read or wrote. This useful to suppress the prints in the form of unknown
/// 0x… in case a storage key that does not have metadata. Note that this skips the analysis of
/// all accesses, not just ones without metadata.
///
/// ## Where Clause
///
/// Some pallets require a where clause specifying constraints on their generics to make
/// writing benchmarks feasible. To accomodate this situation, you can provide such a where
/// clause as the (only) argument to the `#[benchmarks]` or `#[instance_benchmarks]` attribute
/// macros. Below is an example of this taken from the `message-queue` pallet.
///
/// ```ignore
/// #[benchmarks(
/// 	where
/// 		<<T as Config>::MessageProcessor as ProcessMessage>::Origin: From<u32> + PartialEq,
/// 		<T as Config>::Size: From<u32>,
/// )]
/// mod benchmarks {
/// 	use super::*;
/// 	// ...
/// }
/// ```
///
/// ## Benchmark Tests
///
/// Benchmark tests can be generated using the old syntax in `frame_benchmarking`,
/// including the `frame_benchmarking::impl_benchmark_test_suite` macro.
///
/// An example is shown below (taken from the `message-queue` pallet's `benchmarking` module):
/// ```ignore
/// #[benchmarks]
/// mod benchmarks {
/// 	use super::*;
/// 	// ...
/// 	impl_benchmark_test_suite!(
/// 		MessageQueue,
/// 		crate::mock::new_test_ext::<crate::integration_test::Test>(),
/// 		crate::integration_test::Test
/// 	);
/// }
/// ```
///
/// ## Benchmark Function Generation
///
/// The benchmark function definition that you provide is used to automatically create a number
/// of impls and structs required by the benchmarking engine. Additionally, a benchmark
/// function is also generated that resembles the function definition you provide, with a few
/// modifications:
/// 1. The function name is transformed from i.e. `original_name` to `_original_name` so as not to
///    collide with the struct `original_name` that is created for some of the benchmarking engine
///    impls.
/// 2. Appropriate `T: Config` and `I` (if this is an instance benchmark) generics are added to the
///    function automatically during expansion, so you should not add these manually on your
///    function definition (but you may make use of `T` and `I` anywhere within your benchmark
///    function, in any of the three sections (setup, call, verification).
/// 3. Arguments such as `u: Linear<10, 100>` are converted to `u: u32` to make the function
///    directly callable.
/// 4. A `verify: bool` param is added as the last argument. Specifying `true` will result in the
///    verification section of your function executing, while a value of `false` will skip
///    verification.
/// 5. If you specify a return type on the function definition, it must conform to the [rules
///    below](#support-for-result-benchmarkerror-and-the--operator), and the last statement of the
///    function definition must resolve to something compatible with `Result<(), BenchmarkError>`.
///
/// The reason we generate an actual function as part of the expansion is to allow the compiler
/// to enforce several constraints that would otherwise be difficult to enforce and to reduce
/// developer confusion (especially regarding the use of the `?` operator, as covered below).
///
/// Note that any attributes, comments, and doc comments attached to your benchmark function
/// definition are also carried over onto the resulting benchmark function and the struct for
/// that benchmark. As a result you should be careful about what attributes you attach here as
/// they will be replicated in multiple places.
///
/// ### Support for `Result<(), BenchmarkError>` and the `?` operator
///
/// You may optionally specify `Result<(), BenchmarkError>` as the return type of your
/// benchmark function definition. If you do so, you must return a compatible `Result<(),
/// BenchmarkError>` as the *last statement* of your benchmark function definition. You may
/// also use the `?` operator throughout your benchmark function definition if you choose to
/// follow this route. See the example below:
///
/// ```ignore
/// #![cfg(feature = "runtime-benchmarks")]
///
/// use super::{mock_helpers::*, Pallet as MyPallet};
/// use frame_benchmarking::v2::*;
///
/// #[benchmarks]
/// mod benchmarks {
/// 	use super::*;
///
/// 	#[benchmark]
/// 	fn bench_name(x: Linear<5, 25>) -> Result<(), BenchmarkError> {
/// 		// setup code
/// 		let z = x + 4;
/// 		let caller = whitelisted_caller();
///
/// 		// note we can make use of the ? operator here because of the return type
/// 		something(z)?;
///
/// 		#[extrinsic_call]
/// 		extrinsic_name(SystemOrigin::Signed(caller), other, arguments);
///
/// 		// verification code
/// 		assert_eq!(MyPallet::<T>::my_var(), z);
///
/// 		// we must return a valid `Result<(), BenchmarkError>` as the last line of our benchmark
/// 		// function definition. This line is not included as part of the verification code that
/// 		// appears above it.
/// 		Ok(())
/// 	}
/// }
/// ```
pub mod v2 {
	pub use super::*;
	pub use frame_support_procedural::{
		benchmark, benchmarks, block, extrinsic_call, instance_benchmarks,
	};

	// Used in #[benchmark] implementation to ensure that benchmark function arguments
	// implement [`ParamRange`].
	#[doc(hidden)]
	pub use static_assertions::{assert_impl_all, assert_type_eq_all};

	/// Used by the new benchmarking code to specify that a benchmarking variable is linear
	/// over some specified range, i.e. `Linear<0, 1_000>` means that the corresponding variable
	/// is allowed to range from `0` to `1000`, inclusive.
	///
	/// See [`v2`] for more info.
	pub struct Linear<const A: u32, const B: u32>;

	/// Trait that must be implemented by all structs that can be used as parameter range types
	/// in the new benchmarking code (i.e. `Linear<0, 1_000>`). Right now there is just
	/// [`Linear`] but this could later be extended to support additional non-linear parameter
	/// ranges.
	///
	/// See [`v2`] for more info.
	pub trait ParamRange {
		/// Represents the (inclusive) starting number of this `ParamRange`.
		fn start(&self) -> u32;

		/// Represents the (inclusive) ending number of this `ParamRange`.
		fn end(&self) -> u32;
	}

	impl<const A: u32, const B: u32> ParamRange for Linear<A, B> {
		fn start(&self) -> u32 {
			A
		}

		fn end(&self) -> u32 {
			B
		}
	}
}