pallet_migrations/
benchmarking.rs1#![cfg(feature = "runtime-benchmarks")]
19
20use super::*;
21
22use core::array;
23use frame_benchmarking::{v2::*, BenchmarkError};
24use frame_system::{Pallet as System, RawOrigin};
25use sp_core::{twox_128, Get};
26use sp_io::{storage, KillStorageResult};
27use sp_runtime::traits::One;
28
29fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
30 frame_system::Pallet::<T>::assert_has_event(generic_event.into());
31}
32
33fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
34 frame_system::Pallet::<T>::assert_last_event(generic_event.into());
35}
36
37#[benchmarks]
38mod benches {
39 use super::*;
40 use frame_support::traits::Hooks;
41
42 #[benchmark]
43 fn onboard_new_mbms() {
44 T::Migrations::set_fail_after(0); assert!(!Cursor::<T>::exists());
46
47 #[block]
48 {
49 Pallet::<T>::onboard_new_mbms();
50 }
51
52 assert_last_event::<T>(Event::UpgradeStarted { migrations: 1 }.into());
53 }
54
55 #[benchmark]
56 fn progress_mbms_none() {
57 T::Migrations::set_fail_after(0); assert!(!Cursor::<T>::exists());
59
60 #[block]
61 {
62 Pallet::<T>::progress_mbms(One::one());
63 }
64 }
65
66 #[benchmark]
68 fn exec_migration_completed() -> Result<(), BenchmarkError> {
69 T::Migrations::set_fail_after(0); assert_eq!(T::Migrations::len(), 1, "Setup failed");
71 let c = ActiveCursor { index: 1, inner_cursor: None, started_at: 0u32.into() };
72 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
73 System::<T>::set_block_number(1u32.into());
74
75 #[block]
76 {
77 Pallet::<T>::exec_migration(c, false, &mut meter);
78 }
79
80 assert_last_event::<T>(Event::UpgradeCompleted {}.into());
81
82 Ok(())
83 }
84
85 #[benchmark]
87 fn exec_migration_skipped_historic() -> Result<(), BenchmarkError> {
88 T::Migrations::set_fail_after(0); assert_eq!(T::Migrations::len(), 1, "Setup failed");
90 let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
91
92 let id: IdentifierOf<T> = T::Migrations::nth_id(0).unwrap().try_into().unwrap();
93 Historic::<T>::insert(id, ());
94
95 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
96 System::<T>::set_block_number(1u32.into());
97
98 #[block]
99 {
100 Pallet::<T>::exec_migration(c, false, &mut meter);
101 }
102
103 assert_last_event::<T>(Event::MigrationSkipped { index: 0 }.into());
104
105 Ok(())
106 }
107
108 #[benchmark]
110 fn exec_migration_advance() -> Result<(), BenchmarkError> {
111 T::Migrations::set_success_after(1);
112 assert_eq!(T::Migrations::len(), 1, "Setup failed");
113 let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
114 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
115 System::<T>::set_block_number(1u32.into());
116
117 #[block]
118 {
119 Pallet::<T>::exec_migration(c, false, &mut meter);
120 }
121
122 assert_last_event::<T>(Event::MigrationAdvanced { index: 0, took: One::one() }.into());
123
124 Ok(())
125 }
126
127 #[benchmark]
129 fn exec_migration_complete() -> Result<(), BenchmarkError> {
130 T::Migrations::set_success_after(0);
131 assert_eq!(T::Migrations::len(), 1, "Setup failed");
132 let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
133 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
134 System::<T>::set_block_number(1u32.into());
135
136 #[block]
137 {
138 Pallet::<T>::exec_migration(c, false, &mut meter);
139 }
140
141 assert_last_event::<T>(Event::MigrationCompleted { index: 0, took: One::one() }.into());
142
143 Ok(())
144 }
145
146 #[benchmark]
147 fn exec_migration_fail() -> Result<(), BenchmarkError> {
148 T::Migrations::set_fail_after(0);
149 assert_eq!(T::Migrations::len(), 1, "Setup failed");
150 let c = ActiveCursor { index: 0, inner_cursor: None, started_at: 0u32.into() };
151 let mut meter = WeightMeter::with_limit(T::MaxServiceWeight::get());
152 System::<T>::set_block_number(1u32.into());
153
154 #[block]
155 {
156 Pallet::<T>::exec_migration(c, false, &mut meter);
157 }
158
159 assert_has_event::<T>(Event::UpgradeFailed {}.into());
160
161 Ok(())
162 }
163
164 #[benchmark]
165 fn on_init_loop() {
166 T::Migrations::set_fail_after(0); System::<T>::set_block_number(1u32.into());
168 <Pallet<T> as Hooks<BlockNumberFor<T>>>::on_runtime_upgrade();
169
170 #[block]
171 {
172 Pallet::<T>::on_initialize(1u32.into());
173 }
174 }
175
176 #[benchmark]
177 fn force_set_cursor() {
178 #[extrinsic_call]
179 _(RawOrigin::Root, Some(cursor::<T>()));
180 }
181
182 #[benchmark]
183 fn force_set_active_cursor() {
184 #[extrinsic_call]
185 _(RawOrigin::Root, 0, None, None);
186 }
187
188 #[benchmark]
189 fn force_onboard_mbms() {
190 #[extrinsic_call]
191 _(RawOrigin::Root);
192 }
193
194 #[benchmark]
195 fn clear_historic(n: Linear<0, { DEFAULT_HISTORIC_BATCH_CLEAR_SIZE * 2 }>) {
196 let id_max_len = <T as Config>::IdentifierMaxLen::get();
197 assert!(id_max_len >= 4, "Precondition violated");
198
199 for i in 0..DEFAULT_HISTORIC_BATCH_CLEAR_SIZE * 2 {
200 let id = IdentifierOf::<T>::truncate_from(
201 i.encode().into_iter().cycle().take(id_max_len as usize).collect::<Vec<_>>(),
202 );
203
204 Historic::<T>::insert(&id, ());
205 }
206
207 #[extrinsic_call]
208 _(
209 RawOrigin::Root,
210 HistoricCleanupSelector::Wildcard { limit: n.into(), previous_cursor: None },
211 );
212 }
213
214 #[benchmark(skip_meta, pov_mode = Measured)]
215 fn reset_pallet_migration(n: Linear<0, 2048>) -> Result<(), BenchmarkError> {
216 let prefix: [u8; 16] = twox_128(b"__ResetPalletBenchmarkPrefix__");
217
218 for i in 0..n {
219 let mut iter = prefix.into_iter().chain(i.to_le_bytes());
221 let key: [u8; 20] = array::from_fn(|_| iter.next().unwrap());
222 storage::set(&key, &[0u8; 32]);
225 }
226
227 let result;
228 #[block]
229 {
230 result = storage::clear_prefix(&prefix, None);
231 }
232
233 match result {
237 KillStorageResult::AllRemoved(_i) => {
238 #[cfg(not(test))]
240 ensure!(_i == n, "Not all keys are removed");
241 },
242 _ => Err("Not all keys were removed")?,
243 }
244
245 Ok(())
246 }
247
248 fn cursor<T: Config>() -> CursorOf<T> {
249 MigrationCursor::Active(ActiveCursor {
254 index: u32::MAX,
255 inner_cursor: None,
256 started_at: 0u32.into(),
257 })
258 }
259
260 impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
263}