// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute // SPDX-License-Identifier: Apache-2.0 // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Benchmarking setup for pezcumulus-pezpallet-xcmp-queue use crate::{weights_ext::get_average_page_pos, *}; use alloc::vec; use codec::DecodeAll; use pezframe_benchmarking::v2::*; use pezframe_support::{assert_ok, traits::Hooks}; use pezframe_system::RawOrigin; use xcm::MAX_INSTRUCTIONS_TO_DECODE; #[benchmarks] mod benchmarks { use super::*; /// Modify any of the `QueueConfig` fields with a new `u32` value. /// /// Used as weight for: /// - update_suspend_threshold /// - update_drop_threshold /// - update_resume_threshold #[benchmark] fn set_config_with_u32() { #[extrinsic_call] Pezpallet::::update_resume_threshold(RawOrigin::Root, 1); } /// Add a XCMP message of `n` bytes to the message queue. /// /// The message will be added on a new page and also, the `BookState` will be added /// to the ready ring. #[benchmark] fn enqueue_n_bytes_xcmp_message(n: Linear<0, { MaxXcmpMessageLenOf::::get() }>) { #[cfg(test)] { mock::EnqueuedMessages::set(vec![]); } let msg = BoundedVec::try_from(vec![0; n as usize]).unwrap(); #[cfg(not(test))] let fp_before = T::XcmpQueue::footprint(0.into()); #[block] { assert_ok!(Pezpallet::::enqueue_xcmp_messages( 0.into(), &[msg.as_bounded_slice()], true, &mut WeightMeter::new() )); } #[cfg(not(test))] { let fp_after = T::XcmpQueue::footprint(0.into()); assert_eq!(fp_after.ready_pages, fp_before.ready_pages + 1); } } /// Add `n` XCMP message of 0 bytes to the message queue. /// /// Only for the first message a new page will be created and the `BookState` will be added /// to the ready ring. #[benchmark] fn enqueue_n_empty_xcmp_messages(n: Linear<0, 1000>) { #[cfg(test)] { mock::EnqueuedMessages::set(vec![]); >::set(QueueConfigData { suspend_threshold: 1100, drop_threshold: 1100, resume_threshold: 1100, }); } let msg = BoundedVec::new(); let msgs = vec![msg.as_bounded_slice(); n as usize]; #[cfg(not(test))] let fp_before = T::XcmpQueue::footprint(0.into()); #[block] { assert_ok!(Pezpallet::::enqueue_xcmp_messages( 0.into(), &msgs, true, &mut WeightMeter::new() )); } #[cfg(not(test))] { let fp_after = T::XcmpQueue::footprint(0.into()); if !msgs.is_empty() { assert_eq!(fp_after.ready_pages, fp_before.ready_pages + 1); } } } /// Add an XCMP message of 0 bytes to the message queue at the provided position /// on an existing page. #[benchmark(pov_mode = Measured)] fn enqueue_empty_xcmp_message_at( n: Linear<0, { crate::MaxXcmpMessageLenOf::::get() - 10 }>, ) { #[cfg(test)] { mock::EnqueuedMessages::set(vec![]); } assert_ok!(Pezpallet::::enqueue_xcmp_messages( 0.into(), &[BoundedVec::try_from(vec![0; n as usize]).unwrap().as_bounded_slice()], true, &mut WeightMeter::new() )); #[cfg(not(test))] let fp_before = T::XcmpQueue::footprint(0.into()); #[block] { assert_ok!(Pezpallet::::enqueue_xcmp_messages( 0.into(), &[BoundedVec::new().as_bounded_slice()], true, &mut WeightMeter::new() )); } #[cfg(not(test))] { let fp_after = T::XcmpQueue::footprint(0.into()); assert_eq!(fp_after.ready_pages, fp_before.ready_pages); } } /// Add `n` pages to the message queue. /// /// We add one page by enqueueing a maximal size message which fills it. #[benchmark] fn enqueue_n_full_pages(n: Linear<0, 100>) { #[cfg(test)] { mock::EnqueuedMessages::set(vec![]); } >::set(QueueConfigData { suspend_threshold: 200, drop_threshold: 200, resume_threshold: 200, }); let max_msg_len = MaxXcmpMessageLenOf::::get() as usize; let mut msgs = vec![]; for _i in 0..n { let msg = BoundedVec::try_from(vec![0; max_msg_len]).unwrap(); msgs.push(msg); } #[cfg(not(test))] let fp_before = T::XcmpQueue::footprint(0.into()); #[block] { assert_ok!(Pezpallet::::enqueue_xcmp_messages( 0.into(), &msgs.iter().map(|msg| msg.as_bounded_slice()).collect::>(), true, &mut WeightMeter::new() )); } #[cfg(not(test))] { let fp_after = T::XcmpQueue::footprint(0.into()); assert_eq!(fp_after.ready_pages, fp_before.ready_pages + n); } } #[benchmark(pov_mode = Measured)] fn enqueue_1000_small_xcmp_messages() { #[cfg(test)] { >::set(QueueConfigData { suspend_threshold: 1100, drop_threshold: 1100, resume_threshold: 1100, }); } assert_ok!(Pezpallet::::enqueue_xcmp_messages( 0.into(), &[BoundedVec::try_from(vec![ 0; get_average_page_pos(MaxXcmpMessageLenOf::::get()) as usize ]) .unwrap() .as_bounded_slice()], true, &mut WeightMeter::new() )); let mut msgs = vec![]; for _i in 0..1000 { msgs.push(BoundedVec::try_from(vec![0; 3]).unwrap()); } #[cfg(not(test))] let fp_before = T::XcmpQueue::footprint(0.into()); #[block] { assert_ok!(Pezpallet::::enqueue_xcmp_messages( 0.into(), &msgs.iter().map(|msg| msg.as_bounded_slice()).collect::>(), true, &mut WeightMeter::new() )); } #[cfg(not(test))] { let fp_after = T::XcmpQueue::footprint(0.into()); assert_eq!(fp_after.ready_pages, fp_before.ready_pages); } } #[benchmark] fn suspend_channel() { let para = 123.into(); let data = ChannelSignal::Suspend.encode(); #[block] { ChannelSignal::decode_all(&mut &data[..]).unwrap(); Pezpallet::::suspend_channel(para); } assert_eq!( OutboundXcmpStatus::::get() .iter() .find(|p| p.recipient == para) .unwrap() .state, OutboundState::Suspended ); } #[benchmark] fn resume_channel() { let para = 123.into(); let data = ChannelSignal::Resume.encode(); Pezpallet::::suspend_channel(para); #[block] { ChannelSignal::decode_all(&mut &data[..]).unwrap(); Pezpallet::::resume_channel(para); } assert!( OutboundXcmpStatus::::get().iter().all(|p| p.recipient != para), "No messages in the channel; therefore removed." ); } /// Split a singular XCM. #[benchmark] fn take_first_concatenated_xcm( n: Linear<0, { MAX_INSTRUCTIONS_TO_DECODE as u32 - MAX_XCM_DECODE_DEPTH }>, ) { let mut xcm = Xcm::(vec![ClearOrigin; n as usize]); for _ in 0..MAX_XCM_DECODE_DEPTH - 1 { xcm = Xcm::(vec![Instruction::SetAppendix(xcm)]); } let data = VersionedXcm::::from(xcm).encode(); #[block] { Pezpallet::::take_first_concatenated_xcm(&mut &data[..], &mut WeightMeter::new()) .unwrap(); } } /// Benchmark the migration for a maximal sized message. #[benchmark] fn on_idle_good_msg() { use migration::v3; let block = 5; let para = ParaId::from(4); let message = vec![123u8; MaxXcmpMessageLenOf::::get() as usize]; let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)]; v3::InboundXcmpMessages::::insert(para, block, message); v3::InboundXcmpStatus::::set(Some(vec![v3::InboundChannelDetails { sender: para, state: v3::InboundState::Ok, message_metadata, }])); #[block] { Pezpallet::::on_idle(0u32.into(), Weight::MAX); } } /// Benchmark the migration with a 64 KiB message that will not be possible to enqueue. #[benchmark] fn on_idle_large_msg() { use migration::v3; let block = 5; let para = ParaId::from(4); let message = vec![123u8; 1 << 16]; // 64 KiB message let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)]; v3::InboundXcmpMessages::::insert(para, block, message); v3::InboundXcmpStatus::::set(Some(vec![v3::InboundChannelDetails { sender: para, state: v3::InboundState::Ok, message_metadata, }])); #[block] { Pezpallet::::on_idle(0u32.into(), Weight::MAX); } } impl_benchmark_test_suite!(Pezpallet, crate::mock::new_test_ext(), crate::mock::Test); }