frame_benchmarking_pallet_pov/
benchmarking.rs1#![cfg(feature = "runtime-benchmarks")]
21
22use super::*;
23
24use frame_benchmarking::v2::*;
25use frame_support::traits::UnfilteredDispatchable;
26use frame_system::{Pallet as System, RawOrigin};
27use sp_runtime::traits::Hash;
28
29#[benchmarks]
30mod benchmarks {
31 use super::*;
32
33 #[benchmark]
34 fn storage_single_value_read() {
35 Value::<T>::put(123);
36
37 #[block]
38 {
39 assert_eq!(Value::<T>::get(), Some(123));
40 }
41 }
42
43 #[benchmark(pov_mode = Ignored)]
44 fn storage_single_value_ignored_read() {
45 Value::<T>::put(123);
46 #[block]
47 {
48 assert_eq!(Value::<T>::get(), Some(123));
49 }
50 }
51
52 #[benchmark(pov_mode = MaxEncodedLen {
53 Pov::Value2: Ignored
54 })]
55 fn storage_single_value_ignored_some_read() {
56 Value::<T>::put(123);
57 Value2::<T>::put(123);
58
59 #[block]
60 {
61 assert_eq!(Value::<T>::get(), Some(123));
62 assert_eq!(Value2::<T>::get(), Some(123));
63 }
64 }
65
66 #[benchmark]
67 fn storage_single_value_read_twice() {
68 Value::<T>::put(123);
69
70 #[block]
71 {
72 assert_eq!(Value::<T>::get(), Some(123));
73 assert_eq!(Value::<T>::get(), Some(123));
74 }
75 }
76
77 #[benchmark]
78 fn storage_single_value_write() {
79 #[block]
80 {
81 Value::<T>::put(123);
82 }
83
84 assert_eq!(Value::<T>::get(), Some(123));
85 }
86
87 #[benchmark]
88 fn storage_single_value_kill() {
89 Value::<T>::put(123);
90
91 #[block]
92 {
93 Value::<T>::kill();
94 }
95
96 assert!(!Value::<T>::exists());
97 }
98
99 #[benchmark(pov_mode = Measured)]
106 fn storage_1m_map_read_one_value_two_additional_layers() {
107 (0..(1 << 10)).for_each(|i| Map1M::<T>::insert(i, i));
108 (0..(1u32 << 4)).for_each(|i| {
110 let k = T::Hashing::hash(&i.to_be_bytes());
111 frame_support::storage::unhashed::put(k.as_ref(), &i);
112 });
113
114 #[block]
115 {
116 assert_eq!(Map1M::<T>::get(1 << 9), Some(1 << 9));
117 }
118 }
119
120 #[benchmark(pov_mode = Measured)]
121 fn storage_1m_map_read_one_value_three_additional_layers() {
122 (0..(1 << 10)).for_each(|i| Map1M::<T>::insert(i, i));
123 (0..(1u32 << 8)).for_each(|i| {
125 let k = T::Hashing::hash(&i.to_be_bytes());
126 frame_support::storage::unhashed::put(k.as_ref(), &i);
127 });
128
129 #[block]
130 {
131 assert_eq!(Map1M::<T>::get(1 << 9), Some(1 << 9));
132 }
133 }
134
135 #[benchmark(pov_mode = Measured)]
136 fn storage_1m_map_read_one_value_four_additional_layers() {
137 (0..(1 << 10)).for_each(|i| Map1M::<T>::insert(i, i));
138 (0..(1u32 << 12)).for_each(|i| {
140 let k = T::Hashing::hash(&i.to_be_bytes());
141 frame_support::storage::unhashed::put(k.as_ref(), &i);
142 });
143
144 #[block]
145 {
146 assert_eq!(Map1M::<T>::get(1 << 9), Some(1 << 9));
147 }
148 }
149
150 #[benchmark]
152 fn storage_map_read_per_component(n: Linear<0, 100>, m: Linear<0, 100>) {
153 (0..m * 10).for_each(|i| Map1M::<T>::insert(i, i));
154 (0..n * 10).for_each(|i| Map16M::<T>::insert(i, i));
155
156 #[block]
157 {
158 (0..m).for_each(|i| assert_eq!(Map1M::<T>::get(i * 10), Some(i * 10)));
159 (0..n).for_each(|i| assert_eq!(Map16M::<T>::get(i * 10), Some(i * 10)));
160 }
161 }
162
163 #[benchmark(pov_mode = MaxEncodedLen {
164 Pov::Map1M: Ignored
165 })]
166 fn storage_map_read_per_component_one_ignored(n: Linear<0, 100>, m: Linear<0, 100>) {
167 (0..m * 10).for_each(|i| Map1M::<T>::insert(i, i));
168 (0..n * 10).for_each(|i| Map16M::<T>::insert(i, i));
169
170 #[block]
171 {
172 (0..m).for_each(|i| assert_eq!(Map1M::<T>::get(i * 10), Some(i * 10)));
173 (0..n).for_each(|i| assert_eq!(Map16M::<T>::get(i * 10), Some(i * 10)));
174 }
175 }
176
177 #[benchmark]
179 fn storage_1m_map_one_entry_repeated_read(n: Linear<0, 100>) {
180 Map1M::<T>::insert(0, 0);
181
182 #[block]
183 {
184 (0..n).for_each(|_| assert_eq!(Map1M::<T>::get(0), Some(0)));
185 }
186 }
187
188 #[benchmark]
190 fn storage_1m_map_multiple_entry_repeated_read(n: Linear<0, 100>) {
191 (0..n).for_each(|i| Map1M::<T>::insert(i, i));
192
193 #[block]
194 {
195 (0..n).for_each(|i| {
196 (0..10).for_each(|_| assert_eq!(Map1M::<T>::get(i), Some(i)));
198 });
199 }
200 }
201
202 #[benchmark]
203 fn storage_1m_double_map_read_per_component(n: Linear<0, 1024>) {
204 (0..(1 << 10)).for_each(|i| DoubleMap1M::<T>::insert(i, i, i));
205
206 #[block]
207 {
208 (0..n).for_each(|i| assert_eq!(DoubleMap1M::<T>::get(i, i), Some(i)));
209 }
210 }
211
212 #[benchmark]
213 fn storage_value_bounded_read() {
214 #[block]
215 {
216 assert!(BoundedValue::<T>::get().is_none());
217 }
218 }
219
220 #[benchmark]
222 fn storage_value_unbounded_read() {
223 #[block]
224 {
225 assert!(UnboundedValue::<T>::get().is_none());
226 }
227 }
228
229 #[benchmark(pov_mode = Ignored)]
230 fn storage_value_unbounded_ignored_read() {
231 #[block]
232 {
233 assert!(UnboundedValue::<T>::get().is_none());
234 }
235 }
236
237 #[benchmark]
239 fn storage_value_bounded_and_unbounded_read() {
240 (0..1024).for_each(|i| Map1M::<T>::insert(i, i));
241 #[block]
242 {
243 assert!(UnboundedValue::<T>::get().is_none());
244 assert!(BoundedValue::<T>::get().is_none());
245 }
246 }
247
248 #[benchmark(pov_mode = Measured)]
249 fn measured_storage_value_read_linear_size(l: Linear<0, { 1 << 22 }>) {
250 let v: sp_runtime::BoundedVec<u8, _> = alloc::vec![0u8; l as usize].try_into().unwrap();
251 LargeValue::<T>::put(&v);
252 #[block]
253 {
254 assert!(LargeValue::<T>::get().is_some());
255 }
256 }
257
258 #[benchmark(pov_mode = MaxEncodedLen)]
259 fn mel_storage_value_read_linear_size(l: Linear<0, { 1 << 22 }>) {
260 let v: sp_runtime::BoundedVec<u8, _> = alloc::vec![0u8; l as usize].try_into().unwrap();
261 LargeValue::<T>::put(&v);
262 #[block]
263 {
264 assert!(LargeValue::<T>::get().is_some());
265 }
266 }
267
268 #[benchmark(pov_mode = Measured)]
269 fn measured_storage_double_value_read_linear_size(l: Linear<0, { 1 << 22 }>) {
270 let v: sp_runtime::BoundedVec<u8, _> = alloc::vec![0u8; l as usize].try_into().unwrap();
271 LargeValue::<T>::put(&v);
272 LargeValue2::<T>::put(&v);
273 #[block]
274 {
275 assert!(LargeValue::<T>::get().is_some());
276 assert!(LargeValue2::<T>::get().is_some());
277 }
278 }
279
280 #[benchmark(pov_mode = MaxEncodedLen)]
281 fn mel_storage_double_value_read_linear_size(l: Linear<0, { 1 << 22 }>) {
282 let v: sp_runtime::BoundedVec<u8, _> = alloc::vec![0u8; l as usize].try_into().unwrap();
283 LargeValue::<T>::put(&v);
284 LargeValue2::<T>::put(&v);
285 #[block]
286 {
287 assert!(LargeValue::<T>::get().is_some());
288 assert!(LargeValue2::<T>::get().is_some());
289 }
290 }
291
292 #[benchmark(pov_mode = MaxEncodedLen {
293 Pov::LargeValue2: Measured
294 })]
295 fn mel_mixed_storage_double_value_read_linear_size(l: Linear<0, { 1 << 22 }>) {
296 let v: sp_runtime::BoundedVec<u8, _> = alloc::vec![0u8; l as usize].try_into().unwrap();
297 LargeValue::<T>::put(&v);
298 LargeValue2::<T>::put(&v);
299 #[block]
300 {
301 assert!(LargeValue::<T>::get().is_some());
302 assert!(LargeValue2::<T>::get().is_some());
303 }
304 }
305
306 #[benchmark(pov_mode = Measured {
307 Pov::LargeValue2: MaxEncodedLen
308 })]
309 fn measured_mixed_storage_double_value_read_linear_size(l: Linear<0, { 1 << 22 }>) {
310 let v: sp_runtime::BoundedVec<u8, _> = alloc::vec![0u8; l as usize].try_into().unwrap();
311 LargeValue::<T>::put(&v);
312 LargeValue2::<T>::put(&v);
313 #[block]
314 {
315 assert!(LargeValue::<T>::get().is_some());
316 assert!(LargeValue2::<T>::get().is_some());
317 }
318 }
319
320 #[benchmark(pov_mode = Measured)]
321 fn storage_map_unbounded_both_measured_read(i: Linear<0, 1000>) {
322 UnboundedMap::<T>::insert(i, alloc::vec![0; i as usize]);
323 UnboundedMap2::<T>::insert(i, alloc::vec![0; i as usize]);
324 #[block]
325 {
326 assert!(UnboundedMap::<T>::get(i).is_some());
327 assert!(UnboundedMap2::<T>::get(i).is_some());
328 }
329 }
330
331 #[benchmark(pov_mode = MaxEncodedLen {
332 Pov::UnboundedMap: Measured
333 })]
334 fn storage_map_partial_unbounded_read(i: Linear<0, 1000>) {
335 Map1M::<T>::insert(i, 0);
336 UnboundedMap::<T>::insert(i, alloc::vec![0; i as usize]);
337 #[block]
338 {
339 assert!(Map1M::<T>::get(i).is_some());
340 assert!(UnboundedMap::<T>::get(i).is_some());
341 }
342 }
343
344 #[benchmark(pov_mode = MaxEncodedLen {
345 Pov::UnboundedMap: Ignored
346 })]
347 fn storage_map_partial_unbounded_ignored_read(i: Linear<0, 1000>) {
348 Map1M::<T>::insert(i, 0);
349 UnboundedMap::<T>::insert(i, alloc::vec![0; i as usize]);
350 #[block]
351 {
352 assert!(Map1M::<T>::get(i).is_some());
353 assert!(UnboundedMap::<T>::get(i).is_some());
354 }
355 }
356
357 #[benchmark]
359 fn emit_event() {
360 let call = Call::<T>::emit_event {};
362 #[block]
363 {
364 call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap();
365 }
366 assert_eq!(System::<T>::events().len(), 1);
367 }
368
369 #[benchmark]
371 fn noop() {
372 let call = Call::<T>::noop {};
373 #[block]
374 {
375 call.dispatch_bypass_filter(RawOrigin::Root.into()).unwrap();
376 }
377 }
378
379 #[benchmark]
380 fn storage_iteration() {
381 for i in 0..65000 {
382 UnboundedMapTwox::<T>::insert(i, alloc::vec![0; 64]);
383 }
384 #[block]
385 {
386 for (key, value) in UnboundedMapTwox::<T>::iter() {
387 unsafe {
388 core::ptr::read_volatile(&key);
389 core::ptr::read_volatile(value.as_ptr());
390 }
391 }
392 }
393 }
394
395 impl_benchmark_test_suite!(Pallet, super::mock::new_test_ext(), super::mock::Test,);
396}
397
398#[cfg(test)]
399mod mock {
400 use frame_support::derive_impl;
401 use sp_runtime::{testing::H256, BuildStorage};
402
403 type AccountId = u64;
404 type Nonce = u32;
405
406 type Block = frame_system::mocking::MockBlock<Test>;
407
408 frame_support::construct_runtime!(
409 pub enum Test
410 {
411 System: frame_system,
412 Baseline: crate,
413 }
414 );
415
416 #[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
417 impl frame_system::Config for Test {
418 type BaseCallFilter = frame_support::traits::Everything;
419 type BlockWeights = ();
420 type BlockLength = ();
421 type DbWeight = ();
422 type RuntimeOrigin = RuntimeOrigin;
423 type Nonce = Nonce;
424 type RuntimeCall = RuntimeCall;
425 type Hash = H256;
426 type Hashing = ::sp_runtime::traits::BlakeTwo256;
427 type AccountId = AccountId;
428 type Lookup = sp_runtime::traits::IdentityLookup<Self::AccountId>;
429 type Block = Block;
430 type RuntimeEvent = RuntimeEvent;
431 type BlockHashCount = ();
432 type Version = ();
433 type PalletInfo = PalletInfo;
434 type AccountData = ();
435 type OnNewAccount = ();
436 type OnKilledAccount = ();
437 type SystemWeightInfo = ();
438 type SS58Prefix = ();
439 type OnSetCode = ();
440 type MaxConsumers = frame_support::traits::ConstU32<16>;
441 }
442
443 impl crate::Config for Test {
444 type RuntimeEvent = RuntimeEvent;
445 }
446
447 pub fn new_test_ext() -> sp_io::TestExternalities {
448 frame_system::GenesisConfig::<Test>::default().build_storage().unwrap().into()
449 }
450}