use crate::{weights_ext::get_average_page_pos, *};
use alloc::vec;
use codec::DecodeAll;
use frame_benchmarking::v2::*;
use frame_support::{assert_ok, traits::Hooks};
use frame_system::RawOrigin;
use xcm::MAX_INSTRUCTIONS_TO_DECODE;
#[benchmarks]
mod benchmarks {
use super::*;
#[benchmark]
fn set_config_with_u32() {
#[extrinsic_call]
Pallet::<T>::update_resume_threshold(RawOrigin::Root, 1);
}
#[benchmark]
fn enqueue_n_bytes_xcmp_message(n: Linear<0, { MaxXcmpMessageLenOf::<T>::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!(Pallet::<T>::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);
}
}
#[benchmark]
fn enqueue_n_empty_xcmp_messages(n: Linear<0, 1000>) {
#[cfg(test)]
{
mock::EnqueuedMessages::set(vec![]);
<QueueConfig<T>>::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!(Pallet::<T>::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);
}
}
}
#[benchmark(pov_mode = Measured)]
fn enqueue_empty_xcmp_message_at(
n: Linear<0, { crate::MaxXcmpMessageLenOf::<T>::get() - 10 }>,
) {
#[cfg(test)]
{
mock::EnqueuedMessages::set(vec![]);
}
assert_ok!(Pallet::<T>::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!(Pallet::<T>::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);
}
}
#[benchmark]
fn enqueue_n_full_pages(n: Linear<0, 100>) {
#[cfg(test)]
{
mock::EnqueuedMessages::set(vec![]);
}
<QueueConfig<T>>::set(QueueConfigData {
suspend_threshold: 200,
drop_threshold: 200,
resume_threshold: 200,
});
let max_msg_len = MaxXcmpMessageLenOf::<T>::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!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&msgs.iter().map(|msg| msg.as_bounded_slice()).collect::<Vec<_>>(),
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)]
{
<QueueConfig<T>>::set(QueueConfigData {
suspend_threshold: 1100,
drop_threshold: 1100,
resume_threshold: 1100,
});
}
assert_ok!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&[BoundedVec::try_from(vec![
0;
get_average_page_pos(MaxXcmpMessageLenOf::<T>::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!(Pallet::<T>::enqueue_xcmp_messages(
0.into(),
&msgs.iter().map(|msg| msg.as_bounded_slice()).collect::<Vec<_>>(),
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();
Pallet::<T>::suspend_channel(para);
}
assert_eq!(
OutboundXcmpStatus::<T>::get()
.iter()
.find(|p| p.recipient == para)
.unwrap()
.state,
OutboundState::Suspended
);
}
#[benchmark]
fn resume_channel() {
let para = 123.into();
let data = ChannelSignal::Resume.encode();
Pallet::<T>::suspend_channel(para);
#[block]
{
ChannelSignal::decode_all(&mut &data[..]).unwrap();
Pallet::<T>::resume_channel(para);
}
assert!(
OutboundXcmpStatus::<T>::get().iter().all(|p| p.recipient != para),
"No messages in the channel; therefore removed."
);
}
#[benchmark]
fn take_first_concatenated_xcm(
n: Linear<0, { MAX_INSTRUCTIONS_TO_DECODE as u32 - MAX_XCM_DECODE_DEPTH }>,
) {
let mut xcm = Xcm::<T>(vec![ClearOrigin; n as usize]);
for _ in 0..MAX_XCM_DECODE_DEPTH - 1 {
xcm = Xcm::<T>(vec![Instruction::SetAppendix(xcm)]);
}
let data = VersionedXcm::<T>::from(xcm).encode();
#[block]
{
Pallet::<T>::take_first_concatenated_xcm(&mut &data[..], &mut WeightMeter::new())
.unwrap();
}
}
#[benchmark]
fn on_idle_good_msg() {
use migration::v3;
let block = 5;
let para = ParaId::from(4);
let message = vec![123u8; MaxXcmpMessageLenOf::<T>::get() as usize];
let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)];
v3::InboundXcmpMessages::<T>::insert(para, block, message);
v3::InboundXcmpStatus::<T>::set(Some(vec![v3::InboundChannelDetails {
sender: para,
state: v3::InboundState::Ok,
message_metadata,
}]));
#[block]
{
Pallet::<T>::on_idle(0u32.into(), Weight::MAX);
}
}
#[benchmark]
fn on_idle_large_msg() {
use migration::v3;
let block = 5;
let para = ParaId::from(4);
let message = vec![123u8; 1 << 16]; let message_metadata = vec![(block, XcmpMessageFormat::ConcatenatedVersionedXcm)];
v3::InboundXcmpMessages::<T>::insert(para, block, message);
v3::InboundXcmpStatus::<T>::set(Some(vec![v3::InboundChannelDetails {
sender: para,
state: v3::InboundState::Ok,
message_metadata,
}]));
#[block]
{
Pallet::<T>::on_idle(0u32.into(), Weight::MAX);
}
}
impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
}