referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_parachains/dmp/
benchmarking.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Benchmarks for the dmp pallet's internal queue helpers.
18
19#![cfg(feature = "runtime-benchmarks")]
20
21use super::{inbound_downward_queue::LAZY_DELETE_MAX_PAGES, migration, *};
22use alloc::{vec, vec::Vec};
23use frame_benchmarking::v2::*;
24use frame_support::{migrations::SteppedMigration, weights::WeightMeter};
25use polkadot_primitives::Id as ParaId;
26
27#[benchmarks]
28mod benchmarks {
29	use super::*;
30
31	#[benchmark]
32	fn lazy_delete_some() {
33		let para = ParaId::from(1);
34		let pages: u64 = LAZY_DELETE_MAX_PAGES as u64;
35		let max_size = configuration::ActiveConfig::<T>::get().max_downward_message_size as usize;
36		let payload = vec![0u8; max_size];
37
38		for i in 0..pages {
39			DownwardMessageQueuePages::<T>::insert(
40				para,
41				i,
42				InboundDownwardMessage {
43					sent_at: frame_system::Pallet::<T>::block_number(),
44					msg: payload.clone(),
45				},
46			);
47		}
48		DownwardMessageQueueLazyDelete::<T>::insert(para, (0u64, pages));
49
50		let mut meter = WeightMeter::new();
51
52		#[block]
53		{
54			InboundDownwardQueue::<T>::lazy_delete_some(&mut meter);
55		}
56
57		assert!(!DownwardMessageQueueLazyDelete::<T>::contains_key(para));
58	}
59
60	/// Base case for [`migration::MigrateV0ToV1::step`]: nothing left in
61	/// `v0::DownwardMessageQueues`, so the loop body terminates on the first
62	/// iter probe without doing any per-para work.
63	#[benchmark]
64	fn migrate_v0_to_v1_step_base() {
65		// A real runtime writes the current version at genesis; rewind so `step` runs the
66		// migration path instead of short-circuiting on the version check.
67		StorageVersion::new(0).put::<Pallet<T>>();
68
69		let mut meter = WeightMeter::new();
70
71		#[block]
72		{
73			migration::MigrateV0ToV1::<T>::step(None, &mut meter).expect("step has full meter");
74		}
75	}
76
77	#[benchmark]
78	fn migrate_v0_to_v1_step_iter() {
79		// A real runtime writes the current version at genesis; rewind so `step` runs the
80		// migration path instead of short-circuiting on the version check.
81		StorageVersion::new(0).put::<Pallet<T>>();
82
83		let para = ParaId::from(1);
84		let max_size = configuration::ActiveConfig::<T>::get().max_downward_message_size;
85		let payload = vec![0u8; max_size as usize];
86
87		// One step migrates two messages (the per-iter freebie plus one per-msg), so a third
88		// forces the write-back of the unmigrated suffix into `v0::DownwardMessageQueues`.
89		let messages: Vec<InboundDownwardMessage<BlockNumberFor<T>>> = (0..3)
90			.map(|_| InboundDownwardMessage {
91				sent_at: frame_system::Pallet::<T>::block_number(),
92				msg: payload.clone(),
93			})
94			.collect();
95
96		migration::v0::DownwardMessageQueues::<T>::insert(para, &messages);
97
98		// `step` and this bound read the same `WeightInfo`, so they agree on where the meter
99		// runs out: after one full iteration, mid-para.
100		let minimum = <T as Config>::WeightInfo::migrate_v0_to_v1_step_base()
101			.saturating_add(<T as Config>::WeightInfo::migrate_v0_to_v1_step_iter())
102			.saturating_add(<T as Config>::WeightInfo::migrate_v0_to_v1_step_msg());
103		let mut meter = WeightMeter::with_limit(minimum);
104
105		#[block]
106		{
107			migration::MigrateV0ToV1::<T>::step(None, &mut meter).expect("step has minimum meter");
108		}
109
110		let meta =
111			DownwardMessageQueueMeta::<T>::get(para).expect("meta written for non-empty queue");
112		assert_eq!(meta.first_full, 0);
113		assert_eq!(meta.first_free, 2);
114		assert_eq!(migration::v0::DownwardMessageQueues::<T>::decode_len(para), Some(1));
115	}
116
117	/// One re-enqueue from the inner loop of [`migration::MigrateV0ToV1::step`].
118	#[benchmark]
119	fn migrate_v0_to_v1_step_msg() {
120		let para = ParaId::from(1);
121		let max_size = configuration::ActiveConfig::<T>::get().max_downward_message_size as usize;
122		let msg = InboundDownwardMessage {
123			sent_at: frame_system::Pallet::<T>::block_number(),
124			msg: vec![0u8; max_size],
125		};
126
127		#[block]
128		{
129			InboundDownwardQueue::<T>::push_back_inbound(para, &msg)
130				.expect("push_back_inbound on empty queue cannot overflow");
131		}
132
133		assert!(DownwardMessageQueuePages::<T>::contains_key(para, 0u64));
134	}
135
136	impl_benchmark_test_suite!(
137		Pallet,
138		crate::mock::new_test_ext(Default::default()),
139		crate::mock::Test
140	);
141}