1#![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#[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#[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#[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 (
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 (
252 { $( $instance:ident )? }
253 $runtime:ident
254 $pallet:ident
255 ( $( $names:tt )* ) ( $( $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 (
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 (
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 (
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 (
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 (
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 (
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 (
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 (
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 (
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 (
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 (
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 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#[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 #[allow(non_camel_case_types)]
690 enum SelectedBenchmark {
691 $( $bench, )*
692 }
693
694 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 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 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 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 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 if $crate::Zero::is_zero(&frame_system::Pallet::<$runtime>::block_number()) {
797 frame_system::Pallet::<$runtime>::set_block_number(1u32.into());
798 }
799
800 $crate::benchmarking::commit_db();
803
804 $crate::benchmarking::reset_read_write_count();
806 };
807
808 for _ in 0 .. internal_repeats.max(1) {
810 $crate::defer!($crate::benchmarking::wipe_db());
812
813 $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 let elapsed_extrinsic = recording.elapsed_extrinsic().expect("elapsed time should be recorded");
824 let diff_pov = recording.diff_pov().unwrap_or_default();
825
826 $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 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 $crate::benchmarking::wipe_db();
865 }
866
867 return Ok(results);
868 }
869 }
870
871 #[cfg(test)]
872 impl Benchmark {
873 #[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#[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 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 <SelectedBenchmark as $crate::BenchmarkingSetup<$runtime, _>>::test_instance(&selected_benchmark, &c, &on_before_start)?;
931
932 $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 for component_value in $crate::vec![low, high] {
945 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#[macro_export]
1045macro_rules! impl_benchmark_test_suite {
1046 (
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 (
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 (
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 (
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 (
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 $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 $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 $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
1208pub 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#[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 $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#[macro_export]
1357macro_rules! cb_add_benchmarks {
1358 ( $params:ident, $batches:ident, [ $name:path, $( $location:tt )* ] ) => {
1360 add_benchmark!( $params, $batches, $name, $( $location )* );
1361 };
1362 ( $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#[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#[macro_export]
1405macro_rules! cb_list_benchmarks {
1406 ( $list:ident, $extra:ident, [ $name:path, $( $location:tt )* ] ) => {
1408 list_benchmark!( $list, $extra, $name, $( $location )* );
1409 };
1410 ( $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#[macro_export]
1421macro_rules! define_benchmarks {
1422 ( $([ $names:path, $( $locations:tt )* ])* ) => {
1423 #[macro_export]
1431 macro_rules! list_benchmarks {
1432 ( $list:ident, $extra:ident ) => {
1433 cb_list_benchmarks!( $list, $extra, $([ $names, $( $locations )* ])+ );
1434 }
1435 }
1436
1437 #[macro_export]
1445 macro_rules! add_benchmarks {
1446 ( $params:ident, $batches:ident ) => {
1447 cb_add_benchmarks!( $params, $batches, $([ $names, $( $locations )* ])+ );
1448 }
1449 }
1450 }
1451}