orml_benchmarking/
lib.rs

1//! Macro for benchmarking a Substrate runtime. A fork of `frame-benchmarking`
2//! pallet.
3
4#![cfg_attr(not(feature = "std"), no_std)]
5
6mod tests;
7
8pub use frame_benchmarking::{
9	benchmarking, whitelisted_caller, BenchmarkBatch, BenchmarkConfig, BenchmarkError, BenchmarkList,
10	BenchmarkMetadata, BenchmarkParameter, BenchmarkRecording, BenchmarkResult, Benchmarking, BenchmarkingSetup,
11	Recording,
12};
13
14#[cfg(not(feature = "std"))]
15extern crate alloc;
16#[cfg(not(feature = "std"))]
17use alloc::{format, string::String};
18#[cfg(feature = "std")]
19pub use frame_benchmarking::{Analysis, BenchmarkSelector};
20#[doc(hidden)]
21pub use frame_support;
22#[doc(hidden)]
23pub use log;
24#[doc(hidden)]
25pub use parity_scale_codec;
26#[doc(hidden)]
27pub use paste;
28#[doc(hidden)]
29pub use sp_core::defer;
30#[doc(hidden)]
31pub use sp_io::storage::root as storage_root;
32#[doc(hidden)]
33pub use sp_runtime::traits::Zero;
34#[doc(hidden)]
35pub use sp_std::{self, boxed::Box, prelude::Vec, str, vec};
36#[doc(hidden)]
37pub use sp_storage::{StateVersion, TrackedStorageKey};
38
39/// Whitelist the given account.
40#[macro_export]
41macro_rules! whitelist_account {
42	($acc:ident) => {
43		frame_benchmarking::benchmarking::add_to_whitelist(
44			frame_system::Account::<Runtime>::hashed_key_for(&$acc).into(),
45		);
46	};
47}
48
49/// Construct pallet benchmarks for weighing dispatchables.
50///
51/// Works around the idea of complexity parameters, named by a single letter
52/// (which is usually upper cased in complexity notation but is lower-cased for
53/// use in this macro).
54///
55/// Complexity parameters ("parameters") have a range which is a `u32` pair.
56/// Every time a benchmark is prepared and run, this parameter takes a concrete
57/// value within the range. There is an associated instancing block, which is a
58/// single expression that is evaluated during preparation. It may use `?`
59/// (`i.e. `return Err(...)`) to bail with a string error. Here's a
60/// few examples:
61///
62/// ```ignore
63/// // These two are equivalent:
64/// let x in 0 .. 10;
65/// let x in 0 .. 10 => ();
66/// // This one calls a setup function and might return an error (which would be terminal).
67/// let y in 0 .. 10 => setup(y)?;
68/// // This one uses a code block to do lots of stuff:
69/// let z in 0 .. 10 => {
70///   let a = z * z / 5;
71///   let b = do_something(a)?;
72///   combine_into(z, b);
73/// }
74/// ```
75///
76/// Note that due to parsing restrictions, if the `from` expression is not a
77/// single token (i.e. a literal or constant), then it must be parenthesised.
78///
79/// The macro allows for a number of "arms", each representing an individual
80/// benchmark. Using the simple syntax, the associated dispatchable function
81/// maps 1:1 with the benchmark and the name of the benchmark is the same as
82/// that of the associated function. However, extended syntax allows
83/// for arbitrary expression to be evaluated in a benchmark (including for
84/// example, `on_initialize`).
85///
86/// Note that the ranges are *inclusive* on both sides. This is in contrast to
87/// ranges in Rust which are left-inclusive right-exclusive.
88///
89/// Each arm may also have a block of code which is run prior to any instancing
90/// and a block of code which is run afterwards. All code blocks may draw upon
91/// the specific value of each parameter at any time. Local variables are shared
92/// between the two pre- and post- code blocks, but do not leak from the
93/// interior of any instancing expressions.
94///
95/// Example:
96/// ```ignore
97/// use path_to_node_runtime::MyRuntime;
98/// use path_to_account_id::AccountId;
99/// use frame_benchmarking::account;
100/// use orml_benchmarking::runtime_benchmarks;
101///
102/// runtime_benchmarks! {
103///   // The constructed runtime struct, and the pallet to benchmark.
104///   { MyRuntime, my_pallet }
105///
106///
107///   // first dispatchable: foo; this is a user dispatchable and operates on a `u8` vector of
108///   // size `l`, which we allow to be initialized as usual.
109///   foo {
110///     let caller = account::<AccountId>(b"caller", 0, benchmarks_seed);
111///     let l in 1 .. MAX_LENGTH => initialize_l(l);
112///   }: _(RuntimeOrigin::signed(caller), vec![0u8; l])
113///
114///   // second dispatchable: bar; this is a root dispatchable and accepts a `u8` vector of size
115///   // `l`.
116///   // In this case, we explicitly name the call using `bar` instead of `_`.
117///   bar {
118///     let l in 1 .. MAX_LENGTH => initialize_l(l);
119///   }: bar(RuntimeOrigin::root, vec![0u8; l])
120///
121///   // third dispatchable: baz; this is a user dispatchable. It isn't dependent on length like the
122///   // other two but has its own complexity `c` that needs setting up. It uses `caller` (in the
123///   // pre-instancing block) within the code block. This is only allowed in the param instancers
124///   // of arms.
125///   baz1 {
126///     let caller = account::<AccountId>(b"caller", 0, benchmarks_seed);
127///     let c = 0 .. 10 => setup_c(&caller, c);
128///   }: baz(RuntimeOrigin::signed(caller))
129///
130///   // this is a second benchmark of the baz dispatchable with a different setup.
131///   baz2 {
132///     let caller = account::<AccountId>(b"caller", 0, benchmarks_seed);
133///     let c = 0 .. 10 => setup_c_in_some_other_way(&caller, c);
134///   }: baz(RuntimeOrigin::signed(caller))
135///
136///   // this is benchmarking some code that is not a dispatchable.
137///   populate_a_set {
138///     let x in 0 .. 10_000;
139///     let mut m = Vec::<u32>::new();
140///     for i in 0..x {
141///       m.insert(i);
142///     }
143///   }: { m.into_iter().collect::<BTreeSet>() }
144/// }
145/// ```
146///
147/// Test functions are automatically generated for each benchmark and are
148/// accessible to you when you run `cargo test`. All tests are named
149/// `test_benchmark_<benchmark_name>`, expect you to pass them the Runtime
150/// Config, and run them in a test externalities environment. The test function
151/// runs your benchmark just like a regular benchmark, but only testing at the
152/// lowest and highest values for each component. The function will return
153/// `Ok(())` if the benchmarks return no errors.
154///
155/// You can optionally add a `verify` code block at the end of a benchmark to
156/// test any final state of your benchmark in a unit test. For example:
157///
158/// ```ignore
159/// sort_vector {
160///     let x in 1 .. 10000;
161///     let mut m = Vec::<u32>::new();
162///     for i in (0..x).rev() {
163///         m.push(i);
164///     }
165/// }: {
166///     m.sort();
167/// } verify {
168///     ensure!(m[0] == 0, "You forgot to sort!")
169/// }
170/// ```
171///
172/// These `verify` blocks will not affect your benchmark results!
173///
174/// You can construct benchmark tests like so:
175///
176/// ```ignore
177/// #[test]
178/// fn test_benchmarks() {
179///   new_test_ext().execute_with(|| {
180///     assert_ok!(test_benchmark_dummy());
181///     assert_err!(test_benchmark_other_name(), "Bad origin");
182///     assert_ok!(test_benchmark_sort_vector());
183///     assert_err!(test_benchmark_broken_benchmark(), "You forgot to sort!");
184///   });
185/// }
186/// ```
187#[macro_export]
188macro_rules! runtime_benchmarks {
189	(
190		{ $runtime:ident, $pallet:ident }
191		$( $rest:tt )*
192	) => {
193		$crate::benchmarks_iter!(
194			{ }
195			$runtime
196			$pallet
197			( )
198			( )
199			( )
200			$( $rest )*
201		);
202	}
203}
204
205/// Same as [`benchmarks`] but for instantiable module.
206#[macro_export]
207macro_rules! runtime_benchmarks_instance {
208	(
209		{ $runtime:ident, $pallet:ident, $instance:ident }
210		$( $rest:tt )*
211	) => {
212		$crate::benchmarks_iter!(
213			{ $instance }
214			$runtime
215			$pallet
216			( )
217			( )
218			( )
219			$( $rest )*
220		);
221	}
222}
223
224#[macro_export]
225#[doc(hidden)]
226macro_rules! benchmarks_iter {
227	// detect and extract `#[extra] tag:
228	(
229		{ $( $instance:ident )? }
230		$runtime:ident
231		$pallet:ident
232		( $( $names:tt )* )
233		( $( $names_extra:tt )* )
234		( $( $names_skip_meta:tt )* )
235		#[extra]
236		$name:ident
237		$( $rest:tt )*
238	) => {
239		$crate::benchmarks_iter! {
240			{ $( $instance)? }
241			$runtime
242			$pallet
243			( $( $names )* )
244			( $( $names_extra )* $name )
245			( $( $names_skip_meta )* )
246			$name
247			$( $rest )*
248		}
249	};
250	// mutation arm:
251	(
252		{ $( $instance:ident )? }
253		$runtime:ident
254		$pallet:ident
255		( $( $names:tt )* ) // This contains $( $( { $instance } )? $name:ident )*
256		( $( $names_extra:tt )* )
257		( $( $names_skip_meta:tt )* )
258		$name:ident { $( $code:tt )* }: _ $(< $origin_type:ty>)? ( $origin:expr $( , $arg:expr )* )
259		verify $postcode:block
260		$( $rest:tt )*
261	) => {
262		$crate::benchmarks_iter! {
263			{ $( $instance)? }
264			$runtime
265			$pallet
266			( $( $names )* )
267			( $( $names_extra )* )
268			( $( $names_skip_meta )* )
269			$name { $( $code )* }: $name $(< $origin_type >)? ( $origin $( , $arg )* )
270			verify $postcode
271			$( $rest )*
272		}
273	};
274	// mutation arm:
275	(
276		{ $( $instance:ident )? }
277		$runtime:ident
278		$pallet:ident
279		( $( $names:tt )* )
280		( $( $names_extra:tt )* )
281		( $( $names_skip_meta:tt )* )
282		$name:ident { $( $code:tt )* }: $dispatch:ident $(< $origin_type:ty>)? ( $origin:expr $( , $arg:expr )* )
283		verify $postcode:block
284		$( $rest:tt )*
285	) => {
286		$crate::paste::paste! {
287			$crate::benchmarks_iter! {
288				{ $( $instance)? }
289				$runtime
290				$pallet
291				( $( $names )* )
292					( $( $names_extra )* )
293					( $( $names_skip_meta )* )
294					$name {
295						$( $code )*
296							let __call =
297							$pallet::Call::<$runtime $(, $instance )?
298									>:: [< new_call_variant_ $dispatch >] (
299								$($arg),*
300							);
301						let __benchmarked_call_encoded = $crate::parity_scale_codec::Encode::encode(
302							&__call
303						);
304					}: {
305						let __call_decoded = <
306								$pallet::Call::<$runtime $(, $instance )?>
307								as $crate::parity_scale_codec::Decode
308								>::decode(&mut &__benchmarked_call_encoded[..])
309							.expect("call is encoded above, encoding must be correct");
310						let __origin = $crate::to_origin!($origin $(, $origin_type)?);
311						<$pallet::Call::<$runtime $(, $instance )?> as $crate::frame_support::traits::UnfilteredDispatchable
312							>::dispatch_bypass_filter(__call_decoded, __origin)?;
313					}
314				verify $postcode
315					$( $rest )*
316			}
317		}
318	};
319	// iteration arm:
320	(
321		{ $( $instance:ident )? }
322		$runtime:ident
323		$pallet:ident
324		( $( $names:tt )* )
325		( $( $names_extra:tt )* )
326		( $( $names_skip_meta:tt )* )
327		$name:ident { $( $code:tt )* }: $eval:block
328		verify $postcode:block
329		$( $rest:tt )*
330	) => {
331		$crate::benchmark_backend! {
332			{ $( $instance)? }
333			$name
334			$runtime
335			$pallet
336			{ }
337			{ $eval }
338			{ $( $code )* }
339			$postcode
340		}
341
342		#[cfg(test)]
343		$crate::impl_benchmark_test!(
344			$runtime
345			$pallet
346			{ $( $instance)? }
347			$name
348		);
349
350		$crate::benchmarks_iter!(
351			{ $( $instance)? }
352			$runtime
353			$pallet
354			( $( $names )* { $( $instance )? } $name )
355			( $( $names_extra )* )
356			( $( $names_skip_meta )* )
357			$( $rest )*
358		);
359	};
360	// iteration-exit arm
361	(
362		{ $( $instance:ident )? }
363		$runtime:ident
364		$pallet:ident
365		( $( $names:tt )* )
366		( $( $names_extra:tt )* )
367		( $( $names_skip_meta:tt )* )
368	) => {
369		$crate::selected_benchmark!(
370			$runtime
371			$pallet
372			{ $( $instance)? }
373			$( $names )*
374		);
375		$crate::impl_benchmark!(
376			$runtime
377			$pallet
378			{ $( $instance)? }
379			( $( $names )* )
380			( $( $names_extra ),* )
381			( $( $names_skip_meta )* )
382		);
383	};
384	// add verify block to _() format
385	(
386		{ $( $instance:ident )? }
387		$runtime:ident
388		$pallet:ident
389		( $( $names:tt )* )
390		( $( $names_extra:tt )* )
391		( $( $names_skip_meta:tt )* )
392		$name:ident { $( $code:tt )* }: _ ( $origin:expr $( , $arg:expr )* )
393		$( $rest:tt )*
394	) => {
395		$crate::benchmarks_iter! {
396			{ $( $instance)? }
397			$runtime
398			$pallet
399			( $( $names )* )
400			( $( $names_extra )* )
401			( $( $names_skip_meta )* )
402			$name { $( $code )* }: _ ( $origin $( , $arg )* )
403			verify { }
404			$( $rest )*
405		}
406	};
407	// add verify block to name() format
408	(
409		{ $( $instance:ident )? }
410		$runtime:ident
411		$pallet:ident
412		( $( $names:tt )* )
413		( $( $names_extra:tt )* )
414		( $( $names_skip_meta:tt )* )
415		$name:ident { $( $code:tt )* }: $dispatch:ident ( $origin:expr $( , $arg:expr )* )
416		$( $rest:tt )*
417	) => {
418		$crate::benchmarks_iter! {
419			{ $( $instance)? }
420			$runtime
421			$pallet
422			( $( $names )* )
423			( $( $names_extra )* )
424			( $( $names_skip_meta )* )
425			$name { $( $code )* }: $dispatch ( $origin $( , $arg )* )
426			verify { }
427			$( $rest )*
428		}
429	};
430	// add verify block to {} format
431	(
432		{ $( $instance:ident )? }
433		$runtime:ident
434		$pallet:ident
435		( $( $names:tt )* )
436		( $( $names_extra:tt )* )
437		( $( $names_skip_meta:tt )* )
438		$name:ident { $( $code:tt )* }: $eval:block
439		$( $rest:tt )*
440	) => {
441		$crate::benchmarks_iter!(
442			{ $( $instance)? }
443			$runtime
444			$pallet
445			( $( $names )* )
446			( $( $names_extra )* )
447			( $( $names_skip_meta )* )
448			$name { $( $code )* }: $eval
449			verify { }
450			$( $rest )*
451		);
452	};
453}
454
455#[macro_export]
456#[doc(hidden)]
457macro_rules! to_origin {
458	($origin:expr) => {
459		$origin.into()
460	};
461	($origin:expr, $origin_type:ty) => {
462		<<$runtime as frame_system::Config>::RuntimeOrigin as From<$origin_type>>::from($origin)
463	};
464}
465
466#[macro_export]
467#[doc(hidden)]
468macro_rules! benchmark_backend {
469	// parsing arms
470	(
471		{ $( $instance:ident )? }
472		$name:ident
473		$runtime:ident
474		$pallet:ident
475		{ $( PRE { $( $pre_parsed:tt )* } )* }
476		{ $eval:block }
477		{
478			let $pre_id:tt : $pre_ty:ty = $pre_ex:expr;
479			$( $rest:tt )*
480		}
481		$postcode:block
482	) => {
483		$crate::benchmark_backend! {
484			{ $( $instance)? }
485			$name
486			$runtime
487			$pallet
488			{
489				$( PRE { $( $pre_parsed )* } )*
490				PRE { $pre_id , $pre_ty , $pre_ex }
491			}
492			{ $eval }
493			{ $( $rest )* }
494			$postcode
495		}
496	};
497	(
498		{ $( $instance:ident )? }
499		$name:ident
500		$runtime:ident
501		$pallet:ident
502		{ $( $parsed:tt )* }
503		{ $eval:block }
504		{
505			let $param:ident in ( $param_from:expr ) .. $param_to:expr => $param_instancer:expr;
506			$( $rest:tt )*
507		}
508		$postcode:block
509	) => {
510		$crate::benchmark_backend! {
511			{ $( $instance)? }
512			$name
513			$runtime
514			$pallet
515			{
516				$( $parsed )*
517				PARAM { $param , $param_from , $param_to , $param_instancer }
518			}
519			{ $eval }
520			{ $( $rest )* }
521			$postcode
522		}
523	};
524	// mutation arm to look after a single tt for param_from.
525	(
526		{ $( $instance:ident )? }
527		$name:ident
528		$runtime:ident
529		$pallet:ident
530		{ $( $parsed:tt )* }
531		{ $eval:block }
532		{
533			let $param:ident in $param_from:tt .. $param_to:expr => $param_instancer:expr ;
534			$( $rest:tt )*
535		}
536		$postcode:block
537	) => {
538		$crate::benchmark_backend! {
539			{ $( $instance)? }
540			$name
541			$runtime
542			$pallet
543			{ $( $parsed )* }
544			{ $eval }
545			{
546				let $param in ( $param_from ) .. $param_to => $param_instancer;
547				$( $rest )*
548			}
549			$postcode
550		}
551	};
552	// mutation arm to look after the default tail of `=> ()`
553	(
554		{ $( $instance:ident )? }
555		$name:ident
556		$runtime:ident
557		$pallet:ident
558		{ $( $parsed:tt )* }
559		{ $eval:block }
560		{
561			let $param:ident in $param_from:tt .. $param_to:expr;
562			$( $rest:tt )*
563		}
564		$postcode:block
565	) => {
566		$crate::benchmark_backend! {
567			{ $( $instance)? }
568			$name
569			$runtime
570			$pallet
571			{ $( $parsed )* }
572			{ $eval }
573			{
574				let $param in $param_from .. $param_to => ();
575				$( $rest )*
576			}
577			$postcode
578		}
579	};
580	// mutation arm to look after `let _ =`
581	(
582		{ $( $instance:ident )? }
583		$name:ident
584		$runtime:ident
585		$pallet:ident
586		{ $( $parsed:tt )* }
587		{ $eval:block }
588		{
589			let $pre_id:tt = $pre_ex:expr;
590			$( $rest:tt )*
591		}
592		$postcode:block
593	) => {
594		$crate::benchmark_backend! {
595			{ $( $instance)? }
596			$name
597			$runtime
598			$pallet
599			{ $( $parsed )* }
600			{ $eval }
601			{
602				let $pre_id : _ = $pre_ex;
603				$( $rest )*
604			}
605			$postcode
606		}
607	};
608	// actioning arm
609	(
610		{ $( $instance:ident )? }
611		$name:ident
612		$runtime:ident
613		$pallet:ident
614		{
615			$( PRE { $pre_id:tt , $pre_ty:ty , $pre_ex:expr } )*
616			$( PARAM { $param:ident , $param_from:expr , $param_to:expr , $param_instancer:expr } )*
617		}
618		{ $eval:block }
619		{ $( $post:tt )* }
620		$postcode:block
621	) => {
622		#[allow(non_camel_case_types)]
623		struct $name;
624		#[allow(unused_variables)]
625		impl $crate::BenchmarkingSetup<$runtime $(, $instance)?> for $name {
626			fn components(&self) -> $crate::Vec<($crate::BenchmarkParameter, u32, u32)> {
627				$crate::vec! [
628					$(
629						($crate::BenchmarkParameter::$param, $param_from, $param_to)
630					),*
631				]
632			}
633
634			fn instance(
635				&self,
636				recording: &mut impl $crate::Recording,
637				components: &[($crate::BenchmarkParameter, u32)],
638				verify: bool
639			) -> Result<(), $crate::BenchmarkError> {
640				$(
641					// Prepare instance
642					let $param = components.iter()
643						.find(|&c| c.0 == $crate::BenchmarkParameter::$param)
644						.ok_or("Could not find component in benchmark preparation.")?
645						.1;
646				)*
647				$(
648					let $pre_id : $pre_ty = $pre_ex;
649				)*
650				$( $param_instancer ; )*
651				$( $post )*
652
653				recording.start();
654                $eval;
655                recording.stop();
656
657				if verify {
658					$postcode;
659				}
660				Ok(())
661			}
662		}
663	};
664}
665
666// Creates a `SelectedBenchmark` enum implementing `BenchmarkingSetup`.
667//
668// Every variant must implement [`BenchmarkingSetup`].
669//
670// ```nocompile
671// struct Transfer;
672// impl BenchmarkingSetup for Transfer { ... }
673//
674// struct SetBalance;
675// impl BenchmarkingSetup for SetBalance { ... }
676//
677// selected_benchmark!({} Transfer {} SetBalance);
678// ```
679#[macro_export]
680#[doc(hidden)]
681macro_rules! selected_benchmark {
682	(
683		$runtime:ident
684		$pallet:ident
685		{ $( $instance:ident )? }
686		$( { $( $bench_inst:ident )? } $bench:ident )*
687	) => {
688		// The list of available benchmarks for this pallet.
689		#[allow(non_camel_case_types)]
690		enum SelectedBenchmark {
691			$( $bench, )*
692		}
693
694		// Allow us to select a benchmark from the list of available benchmarks.
695		impl $crate::BenchmarkingSetup<$runtime $(, $instance)?> for SelectedBenchmark {
696			fn components(&self) -> $crate::Vec<($crate::BenchmarkParameter, u32, u32)> {
697				match self {
698					$(
699						Self::$bench => <
700							$bench as $crate::BenchmarkingSetup<$runtime $(, $bench_inst)? >
701						>::components(&$bench),
702					)*
703				}
704			}
705
706			fn instance(
707				&self,
708				recording: &mut impl $crate::Recording,
709				components: &[($crate::BenchmarkParameter, u32)],
710				verify: bool
711			) -> Result<(), $crate::BenchmarkError> {
712				match self {
713					$(
714						Self::$bench => <
715							$bench as $crate::BenchmarkingSetup<$runtime $(, $bench_inst)? >
716						>::instance(&$bench, recording, components, verify),
717					)*
718				}
719			}
720		}
721	};
722}
723
724#[macro_export]
725#[doc(hidden)]
726macro_rules! impl_benchmark {
727	(
728		$runtime:ident
729		$pallet:ident
730		{ $( $instance:ident )? }
731		( $( { $( $name_inst:ident )? } $name:ident )* )
732		( $( $name_extra:ident ),* )
733		( $( $name_skip_meta:ident ),* )
734	) => {
735		pub struct Benchmark;
736
737		impl $crate::Benchmarking for Benchmark {
738			fn benchmarks(extra: bool) -> $crate::Vec<$crate::BenchmarkMetadata> {
739				let mut all_names = $crate::vec![ $( stringify!($name).as_ref() ),* ];
740				if !extra {
741					let extra = [ $( stringify!($name_extra).as_ref() ),* ];
742					all_names.retain(|x| !extra.contains(x));
743				}
744				all_names.into_iter().map(|benchmark| {
745					let selected_benchmark = match benchmark {
746						$( stringify!($name) => SelectedBenchmark::$name, )*
747						_ => panic!("all benchmarks should be selectable"),
748					};
749					let components = <
750						SelectedBenchmark as $crate::BenchmarkingSetup<$runtime $(, $instance)?>
751					>::components(&selected_benchmark);
752
753					$crate::BenchmarkMetadata {
754						name: benchmark.as_bytes().to_vec(),
755						components,
756						// TODO: Not supported by V2 syntax as of yet.
757						// https://github.com/paritytech/substrate/issues/13132
758						pov_modes: vec![],
759					}
760				}).collect::<$crate::Vec<_>>()
761			}
762
763			fn run_benchmark(
764				extrinsic: &[u8],
765				c: &[($crate::BenchmarkParameter, u32)],
766				whitelist: &[$crate::TrackedStorageKey],
767				verify: bool,
768				internal_repeats: u32,
769			) -> Result<$crate::Vec<$crate::BenchmarkResult>, $crate::BenchmarkError> {
770				// Map the input to the selected benchmark.
771				let extrinsic = $crate::str::from_utf8(extrinsic)
772					.map_err(|_| "`extrinsic` is not a valid utf8 string!")?;
773				let selected_benchmark = match extrinsic {
774					$( stringify!($name) => SelectedBenchmark::$name, )*
775					_ => return Err("Could not find extrinsic.".into()),
776				};
777
778				// Add whitelist to DB including whitelisted caller
779				let mut whitelist = whitelist.to_vec();
780				let whitelisted_caller_key =
781					<frame_system::Account::<$runtime> as $crate::frame_support::storage::StorageMap<_,_>>::hashed_key_for(
782						$crate::whitelisted_caller::<<$runtime as frame_system::Config>::AccountId>()
783					);
784				whitelist.push(whitelisted_caller_key.into());
785				// Whitelist the transactional layer.
786				let transactional_layer_key = $crate::TrackedStorageKey::new(
787					$crate::frame_support::storage::transactional::TRANSACTION_LEVEL_KEY.into()
788				);
789				whitelist.push(transactional_layer_key);
790				$crate::benchmarking::set_whitelist(whitelist);
791
792				let mut results: $crate::Vec<$crate::BenchmarkResult> = $crate::Vec::new();
793
794				let on_before_start = || {
795					// Set the block number to at least 1 so events are deposited.
796					if $crate::Zero::is_zero(&frame_system::Pallet::<$runtime>::block_number()) {
797						frame_system::Pallet::<$runtime>::set_block_number(1u32.into());
798					}
799
800					// Commit the externalities to the database, flushing the DB cache.
801					// This will enable worst case scenario for reading from the database.
802					$crate::benchmarking::commit_db();
803
804					// Reset the read/write counter so we don't count operations in the setup process.
805					$crate::benchmarking::reset_read_write_count();
806				};
807
808				// Always do at least one internal repeat...
809				for _ in 0 .. internal_repeats.max(1) {
810					// Always reset the state after the benchmark.
811					$crate::defer!($crate::benchmarking::wipe_db());
812
813					// Time the extrinsic logic.
814					$crate::log::trace!(
815						target: "benchmark",
816						"Start Benchmark: {:?}", c
817					);
818
819					let mut recording = $crate::BenchmarkRecording::new(&on_before_start);
820					<SelectedBenchmark as $crate::BenchmarkingSetup<$runtime>>::instance(&selected_benchmark, &mut recording, c, verify)?;
821
822					// Calculate the diff caused by the benchmark.
823					let elapsed_extrinsic = recording.elapsed_extrinsic().expect("elapsed time should be recorded");
824					let diff_pov = recording.diff_pov().unwrap_or_default();
825
826					// Commit the changes to get proper write count
827					$crate::benchmarking::commit_db();
828					$crate::log::trace!(
829						target: "benchmark",
830						"End Benchmark: {} ns", elapsed_extrinsic
831					);
832					let read_write_count = $crate::benchmarking::read_write_count();
833					$crate::log::trace!(
834						target: "benchmark",
835						"Read/Write Count {:?}", read_write_count
836					);
837
838					// Time the storage root recalculation.
839					let start_storage_root = $crate::benchmarking::current_time();
840					$crate::storage_root($crate::StateVersion::V0);
841					let finish_storage_root = $crate::benchmarking::current_time();
842					let elapsed_storage_root = finish_storage_root - start_storage_root;
843
844					let skip_meta = [ $( stringify!($name_skip_meta).as_ref() ),* ];
845					let read_and_written_keys = if skip_meta.contains(&extrinsic) {
846						$crate::vec![(b"Skipped Metadata".to_vec(), 0, 0, false)]
847					} else {
848						$crate::benchmarking::get_read_and_written_keys()
849					};
850
851					results.push($crate::BenchmarkResult {
852						components: c.to_vec(),
853						extrinsic_time: elapsed_extrinsic,
854						storage_root_time: elapsed_storage_root,
855						reads: read_write_count.0,
856						repeat_reads: read_write_count.1,
857						writes: read_write_count.2,
858						repeat_writes: read_write_count.3,
859						proof_size: diff_pov,
860						keys: read_and_written_keys,
861					});
862
863					// Wipe the DB back to the genesis state.
864					$crate::benchmarking::wipe_db();
865				}
866
867				return Ok(results);
868			}
869		}
870
871		#[cfg(test)]
872		impl Benchmark {
873			/// Test a particular benchmark by name.
874			///
875			/// This isn't called `test_benchmark_by_name` just in case some end-user eventually
876			/// writes a benchmark, itself called `by_name`; the function would be shadowed in
877			/// that case.
878			///
879			/// This is generally intended to be used by child test modules such as those created
880			/// by the `impl_benchmark_test_suite` macro. However, it is not an error if a pallet
881			/// author chooses not to implement benchmarks.
882			#[allow(unused)]
883			fn test_bench_by_name(name: &[u8]) -> Result<(), $crate::BenchmarkError> {
884				let name = $crate::str::from_utf8(name)
885					.map_err(|_| -> $crate::BenchmarkError { "`name` is not a valid utf8 string!".into() })?;
886				match name {
887					$( stringify!($name) => {
888						$crate::paste::paste! { Self::[< test_benchmark_ $name >]() }
889					} )*
890					_ => Err("Could not find test for requested benchmark.".into()),
891				}
892			}
893		}
894	};
895}
896
897// This creates a unit test for one benchmark of the main benchmark macro.
898// It runs the benchmark using the `high` and `low` value for each component
899// and ensure that everything completes successfully.
900#[macro_export]
901#[doc(hidden)]
902macro_rules! impl_benchmark_test {
903	(
904		$runtime:ident
905		$pallet:ident
906		{ $( $instance:ident )? }
907		$name:ident
908	) => {
909		$crate::paste::item! {
910			impl Benchmark {
911				#[allow(unused)]
912				fn [<test_benchmark_ $name>] () -> Result<(), $crate::BenchmarkError> {
913					let selected_benchmark = SelectedBenchmark::$name;
914					let components = <
915						SelectedBenchmark as $crate::BenchmarkingSetup<$runtime, _>
916					>::components(&selected_benchmark);
917
918					let execute_benchmark = |
919						c: $crate::Vec<($crate::BenchmarkParameter, u32)>
920					| -> Result<(), $crate::BenchmarkError> {
921
922						let on_before_start = || {
923							// Set the block number to at least 1 so events are deposited.
924							if $crate::Zero::is_zero(&frame_system::Pallet::<$runtime>::block_number()) {
925								frame_system::Pallet::<$runtime>::set_block_number(1u32.into());
926							}
927						};
928
929						// Run execution + verification
930						<SelectedBenchmark as $crate::BenchmarkingSetup<$runtime, _>>::test_instance(&selected_benchmark, &c, &on_before_start)?;
931
932						// Reset the state
933						$crate::benchmarking::wipe_db();
934
935						Ok(())
936					};
937
938					if components.is_empty() {
939						execute_benchmark(Default::default())?;
940					} else {
941						for (name, low, high) in components.iter() {
942							// Test only the low and high value, assuming values in the middle
943							// won't break
944							for component_value in $crate::vec![low, high] {
945								// Select the max value for all the other components.
946								let c: $crate::Vec<($crate::BenchmarkParameter, u32)> = components
947									.iter()
948									.map(|(n, _, h)|
949										if n == name {
950											(*n, *component_value)
951										} else {
952											(*n, *h)
953										}
954									)
955									.collect();
956
957								execute_benchmark(c)?;
958							}
959						}
960					}
961					Ok(())
962				}
963			}
964		}
965	};
966}
967
968/// This creates a test suite which runs the module's benchmarks.
969///
970/// When called in `pallet_example` as
971///
972/// ```rust,ignore
973/// impl_benchmark_test_suite!(crate::tests::new_test_ext());
974/// ```
975///
976/// It expands to the equivalent of:
977///
978/// ```rust,ignore
979/// #[cfg(test)]
980/// mod tests {
981///     use super::*;
982///     use crate::tests::new_test_ext;
983///     use frame_support::assert_ok;
984///
985///     #[test]
986///     fn test_benchmarks() {
987///         new_test_ext().execute_with(|| {
988///             assert_ok!(test_benchmark_accumulate_dummy());
989///             assert_ok!(test_benchmark_set_dummy());
990///             assert_ok!(test_benchmark_another_set_dummy());
991///             assert_ok!(test_benchmark_sort_vector());
992///         });
993///     }
994/// }
995/// ```
996///
997/// ## Arguments
998///
999/// The first argument, `new_test_ext`, must be a function call which returns
1000/// either a `sp_io::TestExternalities`, or some other type with a similar
1001/// interface.
1002///
1003/// Note that this function call is _not_ evaluated at compile time, but is
1004/// instead copied textually into each appropriate invocation site.
1005///
1006/// There is an optional second argument, with keyword syntax: `benchmarks_path
1007/// = path_to_benchmarks_invocation`. In the typical case in which this macro is
1008/// in the same module as the `benchmarks!` invocation, you don't need to supply
1009/// this. However, if the `impl_benchmark_test_suite!` invocation is in a
1010/// different module than the `runtime_benchmarks!` invocation, then you should
1011/// provide the path to the module containing the `benchmarks!` invocation:
1012///
1013/// ```rust,ignore
1014/// mod benches {
1015///     runtime_benchmarks!{
1016///         ...
1017///     }
1018/// }
1019///
1020/// mod tests {
1021///     // because of macro syntax limitations, benches can't be paths, but has
1022///     // to be idents in the scope of `impl_benchmark_test_suite`.
1023///     use crate::benches;
1024///
1025///     impl_benchmark_test_suite!(new_test_ext(), benchmarks_path = benches);
1026///
1027///     // new_test_ext are defined later in this module
1028/// }
1029/// ```
1030///
1031/// There is an optional 3rd argument, with keyword syntax: `extra = true` or
1032/// `extra = false`. By default, this generates a test suite which iterates over
1033/// all benchmarks, including those marked with the `#[extra]` annotation.
1034/// Setting `extra = false` excludes those.
1035///
1036/// There is an optional 4th argument, with keyword syntax: `exec_name =
1037/// custom_exec_name`. By default, this macro uses `execute_with` for this
1038/// parameter. This argument, if set, is subject to these restrictions:
1039///
1040/// - It must be the name of a method applied to the output of the
1041///   `new_test_ext` argument.
1042/// - That method must have a signature capable of receiving a single argument
1043///   of the form `impl FnOnce()`.
1044#[macro_export]
1045macro_rules! impl_benchmark_test_suite {
1046	// user might or might not have set some keyword arguments; set the defaults
1047	//
1048	// The weird syntax indicates that `rest` comes only after a comma, which is otherwise optional
1049	(
1050		$new_test_ext:expr,
1051		$(, $( $rest:tt )* )?
1052	) => {
1053		$crate::impl_benchmark_test_suite!(
1054			@selected:
1055				$new_test_ext,
1056				benchmarks_path = super,
1057				extra = true,
1058				exec_name = execute_with,
1059			@user:
1060				$( $( $rest )* )?
1061		);
1062	};
1063	// pick off the benchmarks_path keyword argument
1064	(
1065		@selected:
1066			$new_test_ext:expr,
1067			benchmarks_path = $old:ident,
1068			extra = $extra:expr,
1069			exec_name = $exec_name:ident,
1070		@user:
1071			benchmarks_path = $benchmarks_path:ident
1072			$(, $( $rest:tt )* )?
1073	) => {
1074		$crate::impl_benchmark_test_suite!(
1075			@selected:
1076				$new_test_ext,
1077				benchmarks_path = $benchmarks_path,
1078				extra = $extra,
1079				exec_name = $exec_name,
1080			@user:
1081				$( $( $rest )* )?
1082		);
1083	};
1084	// pick off the extra keyword argument
1085	(
1086		@selected:
1087			$new_test_ext:expr,
1088			benchmarks_path = $benchmarks_path:ident,
1089			extra = $old:expr,
1090			exec_name = $exec_name:ident,
1091		@user:
1092			extra = $extra:expr
1093			$(, $( $rest:tt )* )?
1094	) => {
1095		$crate::impl_benchmark_test_suite!(
1096			@selected:
1097				$new_test_ext,
1098				benchmarks_path = $benchmarks_path,
1099				extra = $extra,
1100				exec_name = $exec_name,
1101			@user:
1102				$( $( $rest )* )?
1103		);
1104	};
1105	// pick off the exec_name keyword argument
1106	(
1107		@selected:
1108			$new_test_ext:expr,
1109			benchmarks_path = $benchmarks_path:ident,
1110			extra = $extra:expr,
1111			exec_name = $old:ident,
1112		@user:
1113			exec_name = $exec_name:ident
1114			$(, $( $rest:tt )* )?
1115	) => {
1116		$crate::impl_benchmark_test_suite!(
1117			@selected:
1118				$new_test_ext,
1119				benchmarks_path = $benchmarks_path,
1120				extra = $extra,
1121				exec_name = $exec_name,
1122			@user:
1123				$( $( $rest )* )?
1124		);
1125	};
1126	// all options set; nothing else in user-provided keyword arguments
1127	(
1128		@selected:
1129			$new_test_ext:expr,
1130			benchmarks_path = $path_to_benchmarks_invocation:ident,
1131			extra = $extra:expr,
1132			exec_name = $exec_name:ident,
1133		@user:
1134			$(,)?
1135	) => {
1136		#[cfg(test)]
1137		mod benchmark_tests {
1138			use super::*;
1139
1140			#[test]
1141			fn test_benchmarks() {
1142				$new_test_ext.$exec_name(|| {
1143					use $crate::Benchmarking;
1144
1145					let mut anything_failed = false;
1146					println!("failing benchmark tests:");
1147					for benchmark_metadata in $path_to_benchmarks_invocation::Benchmark::benchmarks($extra) {
1148						let benchmark_name = &benchmark_metadata.name;
1149						match std::panic::catch_unwind(|| {
1150							Benchmark::test_bench_by_name(benchmark_name)
1151						}) {
1152							Err(err) => {
1153								println!(
1154									"{}: {:?}",
1155									$crate::str::from_utf8(benchmark_name)
1156										.expect("benchmark name is always a valid string!"),
1157									err,
1158								);
1159								anything_failed = true;
1160							},
1161							Ok(Err(err)) => {
1162								match err {
1163									$crate::BenchmarkError::Stop(err) => {
1164										println!(
1165											"{}: {:?}",
1166											$crate::str::from_utf8(benchmark_name)
1167												.expect("benchmark name is always a valid string!"),
1168											err,
1169										);
1170										anything_failed = true;
1171									},
1172									$crate::BenchmarkError::Override(_) => {
1173										// This is still considered a success condition.
1174										$crate::log::error!(
1175											"WARNING: benchmark error overrided - {}",
1176											$crate::str::from_utf8(benchmark_name)
1177												.expect("benchmark name is always a valid string!"),
1178										);
1179									},
1180									$crate::BenchmarkError::Skip => {
1181										// This is considered a success condition.
1182										$crate::log::error!(
1183											"WARNING: benchmark error skipped - {}",
1184											$crate::str::from_utf8(benchmark_name)
1185												.expect("benchmark name is always a valid string!"),
1186										);
1187									},
1188									$crate::BenchmarkError::Weightless => {
1189										// This is considered a success condition.
1190										$crate::log::error!(
1191											"WARNING: benchmark error weightless skipped - {}",
1192											$crate::str::from_utf8(benchmark_name)
1193												.expect("benchmark name is always a valid string!"),
1194										);
1195									}
1196								}
1197							},
1198							Ok(Ok(())) => (),
1199						}
1200					}
1201					assert!(!anything_failed);
1202				});
1203			}
1204		}
1205	};
1206}
1207
1208/// show error message and debugging info for the case of an error happening
1209/// during a benchmark
1210pub fn show_benchmark_debug_info(
1211	instance_string: &[u8],
1212	benchmark: &[u8],
1213	components: &[(BenchmarkParameter, u32)],
1214	verify: &bool,
1215	error_message: &str,
1216) -> String {
1217	format!(
1218		"\n* Pallet: {}\n\
1219		* Benchmark: {}\n\
1220		* Components: {:?}\n\
1221		* Verify: {:?}\n\
1222		* Error message: {}",
1223		sp_std::str::from_utf8(instance_string).expect("it's all just strings ran through the wasm interface. qed"),
1224		sp_std::str::from_utf8(benchmark).expect("it's all just strings ran through the wasm interface. qed"),
1225		components,
1226		verify,
1227		error_message,
1228	)
1229}
1230
1231/// This macro adds pallet benchmarks to a `Vec<BenchmarkBatch>` object.
1232///
1233/// First create an object that holds in the input parameters for the benchmark:
1234///
1235/// ```ignore
1236/// let params = (&config, &whitelist);
1237/// ```
1238///
1239/// The `whitelist` is a parameter you pass to control the DB read/write
1240/// tracking. We use a vector of
1241/// [TrackedStorageKey](./struct.TrackedStorageKey.html), which is a simple
1242/// struct used to set if a key has been read or written to.
1243///
1244/// For values that should be skipped entirely, we can just pass `key.into()`.
1245/// For example:
1246///
1247/// ```
1248/// use sp_storage::TrackedStorageKey;
1249/// let whitelist: Vec<TrackedStorageKey> = vec![
1250///     // Block Number
1251///     hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
1252///     // Total Issuance
1253///     hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
1254///     // Execution Phase
1255///     hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
1256///     // Event Count
1257///     hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
1258/// ];
1259/// ```
1260///
1261/// Then define a mutable local variable to hold your `BenchmarkBatch` object:
1262/// ```ignore
1263/// let mut batches = Vec::<BenchmarkBatch>::new();
1264/// ````
1265///
1266/// Then add the pallets you want to benchmark to this object, using their crate
1267/// name and generated module struct:
1268/// ```ignore
1269/// add_benchmark!(params, batches, pallet_balances, Balances);
1270/// add_benchmark!(params, batches, pallet_session, SessionBench::<Runtime>);
1271/// add_benchmark!(params, batches, frame_system, SystemBench::<Runtime>);
1272/// ...
1273/// ```
1274///
1275/// At the end of `dispatch_benchmark`, you should return this batches object.
1276#[macro_export]
1277macro_rules! add_benchmark {
1278	( $params:ident, $batches:ident, $name:path, $( $location:tt )* ) => (
1279		let name_string = stringify!($name).as_bytes();
1280		let instance_string = stringify!( $( $location )* ).as_bytes();
1281		let (config, whitelist) = $params;
1282		let $crate::BenchmarkConfig {
1283			pallet,
1284			benchmark,
1285			selected_components,
1286			verify,
1287			internal_repeats,
1288		} = config;
1289		if &pallet[..] == &name_string[..] {
1290			let benchmark_result = $( $location )*::Benchmark::run_benchmark(
1291				&benchmark[..],
1292				&selected_components[..],
1293				whitelist,
1294				*verify,
1295				*internal_repeats,
1296			);
1297
1298			let final_results = match benchmark_result {
1299				Ok(results) => Some(results),
1300				Err($crate::BenchmarkError::Override(mut result)) => {
1301					// Insert override warning as the first storage key.
1302					$crate::log::error!(
1303						"WARNING: benchmark error overrided - {}",
1304						$crate::str::from_utf8(benchmark)
1305							.expect("benchmark name is always a valid string!")
1306					);
1307					result.keys.insert(0,
1308						(b"Benchmark Override".to_vec(), 0, 0, false)
1309					);
1310					Some($crate::vec![result])
1311				},
1312				Err($crate::BenchmarkError::Stop(e)) => {
1313					$crate::show_benchmark_debug_info(
1314						instance_string,
1315						benchmark,
1316						selected_components,
1317						verify,
1318						e,
1319					);
1320					return Err(e.into());
1321				},
1322				Err($crate::BenchmarkError::Skip) => {
1323					$crate::log::error!(
1324						"WARNING: benchmark error skipped - {}",
1325						$crate::str::from_utf8(benchmark)
1326							.expect("benchmark name is always a valid string!")
1327					);
1328					None
1329				},
1330				Err($crate::BenchmarkError::Weightless) => {
1331					$crate::log::error!(
1332						"WARNING: benchmark weightless skipped - {}",
1333						$crate::str::from_utf8(benchmark)
1334							.expect("benchmark name is always a valid string!")
1335					);
1336					Some(vec![$crate::BenchmarkResult {
1337						components: selected_components.clone(),
1338						.. Default::default()
1339					}])
1340				}
1341			};
1342
1343			if let Some(final_results) = final_results {
1344				$batches.push($crate::BenchmarkBatch {
1345					pallet: name_string.to_vec(),
1346					instance: instance_string.to_vec(),
1347					benchmark: benchmark.clone(),
1348					results: final_results,
1349				});
1350			}
1351		}
1352	)
1353}
1354
1355/// Callback for `define_benchmarks` to call `add_benchmark`.
1356#[macro_export]
1357macro_rules! cb_add_benchmarks {
1358    // anchor
1359	( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] ) => {
1360        add_benchmark!( $params, $batches, $name, $( $location )* );
1361	};
1362    // recursion tail
1363	( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] $([ $names:path, $( $locations:tt )* ])+ ) => {
1364        cb_add_benchmarks!( $params, $batches, [ $name, $( $location )* ] );
1365        cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ );
1366    }
1367}
1368
1369/// This macro allows users to easily generate a list of benchmarks for the
1370/// pallets configured in the runtime.
1371///
1372/// To use this macro, first create a an object to store the list:
1373///
1374/// ```ignore
1375/// let mut list = Vec::<BenchmarkList>::new();
1376/// ```
1377///
1378/// Then pass this `list` to the macro, along with the `extra` boolean, the
1379/// pallet crate, and pallet struct:
1380///
1381/// ```ignore
1382/// list_benchmark!(list, extra, pallet_balances, Balances);
1383/// list_benchmark!(list, extra, pallet_session, SessionBench::<Runtime>);
1384/// list_benchmark!(list, extra, frame_system, SystemBench::<Runtime>);
1385/// ```
1386///
1387/// This should match what exists with the `add_benchmark!` macro.
1388#[macro_export]
1389macro_rules! list_benchmark {
1390	( $list:ident, $extra:ident, $name:path, $( $location:tt )* ) => (
1391		let pallet_string = stringify!($name).as_bytes();
1392		let instance_string = stringify!( $( $location )* ).as_bytes();
1393		let benchmarks = $( $location )*::Benchmark::benchmarks($extra);
1394		let pallet_benchmarks = $crate::BenchmarkList {
1395			pallet: pallet_string.to_vec(),
1396			instance: instance_string.to_vec(),
1397			benchmarks: benchmarks.to_vec(),
1398		};
1399		$list.push(pallet_benchmarks)
1400	)
1401}
1402
1403/// Callback for `define_benchmarks` to call `list_benchmark`.
1404#[macro_export]
1405macro_rules! cb_list_benchmarks {
1406    // anchor
1407	( $list:ident, $extra:ident, [ $name:path, $( $location:tt )* ] ) => {
1408        list_benchmark!( $list, $extra, $name, $( $location )* );
1409	};
1410    // recursion tail
1411	( $list:ident, $extra:ident, [ $name:path, $( $location:tt )* ] $([ $names:path, $( $locations:tt )* ])+ ) => {
1412        cb_list_benchmarks!( $list, $extra, [ $name, $( $location )* ] );
1413        cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ );
1414    }
1415}
1416
1417/// Defines pallet configs that `add_benchmarks` and `list_benchmarks` use.
1418/// Should be preferred instead of having a repetitive list of configs
1419/// in `add_benchmark` and `list_benchmark`.
1420#[macro_export]
1421macro_rules! define_benchmarks {
1422    ( $([ $names:path, $( $locations:tt )* ])* ) => {
1423		/// Calls `list_benchmark` with all configs from `define_benchmarks`
1424		/// and passes the first two parameters on.
1425		///
1426		/// Use as:
1427		/// ```ignore
1428		/// list_benchmarks!(list, extra);
1429		/// ```
1430		#[macro_export]
1431		macro_rules! list_benchmarks {
1432            ( $list:ident, $extra:ident ) => {
1433                cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ );
1434            }
1435        }
1436
1437		/// Calls `add_benchmark` with all configs from `define_benchmarks`
1438		/// and passes the first two parameters on.
1439		///
1440		/// Use as:
1441		/// ```ignore
1442		/// add_benchmarks!(params, batches);
1443		/// ```
1444		#[macro_export]
1445		macro_rules! add_benchmarks {
1446            ( $params:ident, $batches:ident ) => {
1447                cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ );
1448            }
1449        }
1450    }
1451}