difftreelog
fix priority benchmarks
in: master
1 file changed
pallets/scheduler-v2/src/benchmarking.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Original license:18// This file is part of Substrate.1920// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd.21// SPDX-License-Identifier: Apache-2.02223// Licensed under the Apache License, Version 2.0 (the "License");24// you may not use this file except in compliance with the License.25// You may obtain a copy of the License at26//27// http://www.apache.org/licenses/LICENSE-2.028//29// Unless required by applicable law or agreed to in writing, software30// distributed under the License is distributed on an "AS IS" BASIS,31// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.32// See the License for the specific language governing permissions and33// limitations under the License.3435//! Scheduler pallet benchmarking.3637use super::*;38use frame_benchmarking::{account, benchmarks};39use frame_support::{40 ensure,41 traits::{schedule::Priority, PreimageRecipient},42};43use frame_system::RawOrigin;44use sp_std::{prelude::*, vec};4546use crate::{Pallet as Scheduler, ScheduledCall, EncodedCall};47use frame_system::Call as SystemCall;4849const SEED: u32 = 0;5051const BLOCK_NUMBER: u32 = 2;5253type SystemOrigin<T> = <T as frame_system::Config>::Origin;5455/// Add `n` items to the schedule.56///57/// For `resolved`:58/// - `59/// - `None`: aborted (hash without preimage)60/// - `Some(true)`: hash resolves into call if possible, plain call otherwise61/// - `Some(false)`: plain call62fn fill_schedule<T: Config>(when: T::BlockNumber, n: u32) -> Result<(), &'static str> {63 let t = DispatchTime::At(when);64 let origin: <T as Config>::PalletsOrigin = frame_system::RawOrigin::Root.into();65 for i in 0..n {66 let call = make_call::<T>(None);67 let period = Some(((i + 100).into(), 100));68 let name = u32_to_name(i);69 Scheduler::<T>::do_schedule_named(name, t, period, 0, origin.clone(), call)?;70 }71 ensure!(72 Agenda::<T>::get(when).len() == n as usize,73 "didn't fill schedule"74 );75 Ok(())76}7778fn u32_to_name(i: u32) -> TaskName {79 i.using_encoded(blake2_256)80}8182fn make_task<T: Config>(83 periodic: bool,84 named: bool,85 signed: bool,86 maybe_lookup_len: Option<u32>,87 priority: Priority,88) -> ScheduledOf<T> {89 let call = make_call::<T>(maybe_lookup_len);90 let maybe_periodic = match periodic {91 true => Some((100u32.into(), 100)),92 false => None,93 };94 let maybe_id = match named {95 true => Some(u32_to_name(0)),96 false => None,97 };98 let origin = make_origin::<T>(signed);99 Scheduled {100 maybe_id,101 priority,102 call,103 maybe_periodic,104 origin,105 _phantom: PhantomData,106 }107}108109fn bounded<T: Config>(len: u32) -> Option<ScheduledCall<T>> {110 let call = <<T as Config>::Call>::from(SystemCall::remark {111 remark: vec![0; len as usize],112 });113 ScheduledCall::new(call).ok()114}115116fn make_call<T: Config>(maybe_lookup_len: Option<u32>) -> ScheduledCall<T> {117 let bound = EncodedCall::bound() as u32;118 let mut len = match maybe_lookup_len {119 Some(len) => {120 len.min(<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get() - 2)121 .max(bound) - 3122 }123 None => bound.saturating_sub(4),124 };125126 loop {127 let c = match bounded::<T>(len) {128 Some(x) => x,129 None => {130 len -= 1;131 continue;132 }133 };134 if c.lookup_needed() == maybe_lookup_len.is_some() {135 break c;136 }137 if maybe_lookup_len.is_some() {138 len += 1;139 } else {140 if len > 0 {141 len -= 1;142 } else {143 break c;144 }145 }146 }147}148149fn make_origin<T: Config>(signed: bool) -> <T as Config>::PalletsOrigin {150 match signed {151 true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(),152 false => frame_system::RawOrigin::Root.into(),153 }154}155156fn dummy_counter() -> WeightCounter {157 WeightCounter {158 used: Weight::zero(),159 limit: Weight::MAX,160 }161}162163benchmarks! {164 // `service_agendas` when no work is done.165 service_agendas_base {166 let now = T::BlockNumber::from(BLOCK_NUMBER);167 IncompleteSince::<T>::put(now - One::one());168 }: {169 Scheduler::<T>::service_agendas(&mut dummy_counter(), now, 0);170 } verify {171 assert_eq!(IncompleteSince::<T>::get(), Some(now - One::one()));172 }173174 // `service_agenda` when no work is done.175 service_agenda_base {176 let now = BLOCK_NUMBER.into();177 let s in 0 .. T::MaxScheduledPerBlock::get();178 fill_schedule::<T>(now, s)?;179 let mut executed = 0;180 }: {181 Scheduler::<T>::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0);182 } verify {183 assert_eq!(executed, 0);184 }185186 // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not187 // dispatched (e.g. due to being overweight).188 service_task_base {189 let now = BLOCK_NUMBER.into();190 let task = make_task::<T>(false, false, false, None, 0);191 // prevent any tasks from actually being executed as we only want the surrounding weight.192 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };193 }: {194 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);195 } verify {196 //assert_eq!(result, Ok(()));197 }198199 // `service_task` when the task is a non-periodic, non-named, fetched call (with a known200 // preimage length) and which is not dispatched (e.g. due to being overweight).201 service_task_fetched {202 let s in (EncodedCall::bound() as u32) .. (<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get());203 let now = BLOCK_NUMBER.into();204 let task = make_task::<T>(false, false, false, Some(s), 0);205 // prevent any tasks from actually being executed as we only want the surrounding weight.206 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };207 }: {208 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);209 } verify {210 }211212 // `service_task` when the task is a non-periodic, named, non-fetched call which is not213 // dispatched (e.g. due to being overweight).214 service_task_named {215 let now = BLOCK_NUMBER.into();216 let task = make_task::<T>(false, true, false, None, 0);217 // prevent any tasks from actually being executed as we only want the surrounding weight.218 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };219 }: {220 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);221 } verify {222 }223224 // `service_task` when the task is a periodic, non-named, non-fetched call which is not225 // dispatched (e.g. due to being overweight).226 service_task_periodic {227 let now = BLOCK_NUMBER.into();228 let task = make_task::<T>(true, false, false, None, 0);229 // prevent any tasks from actually being executed as we only want the surrounding weight.230 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };231 }: {232 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);233 } verify {234 }235236 // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight.237 execute_dispatch_signed {238 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };239 let origin = make_origin::<T>(true);240 let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;241 }: {242 assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());243 }244 verify {245 }246247 // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight.248 execute_dispatch_unsigned {249 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };250 let origin = make_origin::<T>(false);251 let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;252 }: {253 assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());254 }255 verify {256 }257258 schedule {259 let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);260 let when = BLOCK_NUMBER.into();261 let periodic = Some((T::BlockNumber::one(), 100));262 let priority = 0;263 // Essentially a no-op call.264 let call = Box::new(SystemCall::set_storage { items: vec![] }.into());265266 fill_schedule::<T>(when, s)?;267 }: _(RawOrigin::Root, when, periodic, priority, call)268 verify {269 ensure!(270 Agenda::<T>::get(when).len() == (s + 1) as usize,271 "didn't add to schedule"272 );273 }274275 cancel {276 let s in 1 .. T::MaxScheduledPerBlock::get();277 let when = BLOCK_NUMBER.into();278279 fill_schedule::<T>(when, s)?;280 assert_eq!(Agenda::<T>::get(when).len(), s as usize);281 let schedule_origin = T::ScheduleOrigin::successful_origin();282 }: _<SystemOrigin<T>>(schedule_origin, when, 0)283 verify {284 ensure!(285 Lookup::<T>::get(u32_to_name(0)).is_none(),286 "didn't remove from lookup"287 );288 // Removed schedule is NONE289 ensure!(290 Agenda::<T>::get(when)[0].is_none(),291 "didn't remove from schedule"292 );293 }294295 schedule_named {296 let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);297 let id = u32_to_name(s);298 let when = BLOCK_NUMBER.into();299 let periodic = Some((T::BlockNumber::one(), 100));300 let priority = 0;301 // Essentially a no-op call.302 let call = Box::new(SystemCall::set_storage { items: vec![] }.into());303304 fill_schedule::<T>(when, s)?;305 }: _(RawOrigin::Root, id, when, periodic, priority, call)306 verify {307 ensure!(308 Agenda::<T>::get(when).len() == (s + 1) as usize,309 "didn't add to schedule"310 );311 }312313 cancel_named {314 let s in 1 .. T::MaxScheduledPerBlock::get();315 let when = BLOCK_NUMBER.into();316317 fill_schedule::<T>(when, s)?;318 }: _(RawOrigin::Root, u32_to_name(0))319 verify {320 ensure!(321 Lookup::<T>::get(u32_to_name(0)).is_none(),322 "didn't remove from lookup"323 );324 // Removed schedule is NONE325 ensure!(326 Agenda::<T>::get(when)[0].is_none(),327 "didn't remove from schedule"328 );329 }330331 // impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test);332}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617// Original license:18// This file is part of Substrate.1920// Copyright (C) 2020-2022 Parity Technologies (UK) Ltd.21// SPDX-License-Identifier: Apache-2.02223// Licensed under the Apache License, Version 2.0 (the "License");24// you may not use this file except in compliance with the License.25// You may obtain a copy of the License at26//27// http://www.apache.org/licenses/LICENSE-2.028//29// Unless required by applicable law or agreed to in writing, software30// distributed under the License is distributed on an "AS IS" BASIS,31// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.32// See the License for the specific language governing permissions and33// limitations under the License.3435//! Scheduler pallet benchmarking.3637use super::*;38use frame_benchmarking::{account, benchmarks};39use frame_support::{40 ensure,41 traits::{schedule::Priority, PreimageRecipient},42};43use frame_system::RawOrigin;44use sp_std::{prelude::*, vec};45use sp_io::hashing::blake2_256;4647use crate::{Pallet as Scheduler, ScheduledCall, EncodedCall};48use frame_system::Call as SystemCall;4950const SEED: u32 = 0;5152const BLOCK_NUMBER: u32 = 2;5354type SystemOrigin<T> = <T as frame_system::Config>::Origin;5556/// Add `n` items to the schedule.57///58/// For `resolved`:59/// - `60/// - `None`: aborted (hash without preimage)61/// - `Some(true)`: hash resolves into call if possible, plain call otherwise62/// - `Some(false)`: plain call63fn fill_schedule<T: Config>(when: T::BlockNumber, n: u32) -> Result<(), &'static str> {64 let t = DispatchTime::At(when);65 let origin: <T as Config>::PalletsOrigin = frame_system::RawOrigin::Root.into();66 for i in 0..n {67 let call = make_call::<T>(None);68 let period = Some(((i + 100).into(), 100));69 let name = u32_to_name(i);70 Scheduler::<T>::do_schedule_named(name, t, period, 0, origin.clone(), call)?;71 }72 ensure!(73 Agenda::<T>::get(when).len() == n as usize,74 "didn't fill schedule"75 );76 Ok(())77}7879fn u32_to_name(i: u32) -> TaskName {80 i.using_encoded(blake2_256)81}8283fn make_task<T: Config>(84 periodic: bool,85 named: bool,86 signed: bool,87 maybe_lookup_len: Option<u32>,88 priority: Priority,89) -> ScheduledOf<T> {90 let call = make_call::<T>(maybe_lookup_len);91 let maybe_periodic = match periodic {92 true => Some((100u32.into(), 100)),93 false => None,94 };95 let maybe_id = match named {96 true => Some(u32_to_name(0)),97 false => None,98 };99 let origin = make_origin::<T>(signed);100 Scheduled {101 maybe_id,102 priority,103 call,104 maybe_periodic,105 origin,106 _phantom: PhantomData,107 }108}109110fn bounded<T: Config>(len: u32) -> Option<ScheduledCall<T>> {111 let call = <<T as Config>::Call>::from(SystemCall::remark {112 remark: vec![0; len as usize],113 });114 ScheduledCall::new(call).ok()115}116117fn make_call<T: Config>(maybe_lookup_len: Option<u32>) -> ScheduledCall<T> {118 let bound = EncodedCall::bound() as u32;119 let mut len = match maybe_lookup_len {120 Some(len) => {121 len.min(<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get() - 2)122 .max(bound) - 3123 }124 None => bound.saturating_sub(4),125 };126127 loop {128 let c = match bounded::<T>(len) {129 Some(x) => x,130 None => {131 len -= 1;132 continue;133 }134 };135 if c.lookup_needed() == maybe_lookup_len.is_some() {136 break c;137 }138 if maybe_lookup_len.is_some() {139 len += 1;140 } else {141 if len > 0 {142 len -= 1;143 } else {144 break c;145 }146 }147 }148}149150fn make_origin<T: Config>(signed: bool) -> <T as Config>::PalletsOrigin {151 match signed {152 true => frame_system::RawOrigin::Signed(account("origin", 0, SEED)).into(),153 false => frame_system::RawOrigin::Root.into(),154 }155}156157fn dummy_counter() -> WeightCounter {158 WeightCounter {159 used: Weight::zero(),160 limit: Weight::MAX,161 }162}163164benchmarks! {165 // `service_agendas` when no work is done.166 service_agendas_base {167 let now = T::BlockNumber::from(BLOCK_NUMBER);168 IncompleteSince::<T>::put(now - One::one());169 }: {170 Scheduler::<T>::service_agendas(&mut dummy_counter(), now, 0);171 } verify {172 assert_eq!(IncompleteSince::<T>::get(), Some(now - One::one()));173 }174175 // `service_agenda` when no work is done.176 service_agenda_base {177 let now = BLOCK_NUMBER.into();178 let s in 0 .. T::MaxScheduledPerBlock::get();179 fill_schedule::<T>(now, s)?;180 let mut executed = 0;181 }: {182 Scheduler::<T>::service_agenda(&mut dummy_counter(), &mut executed, now, now, 0);183 } verify {184 assert_eq!(executed, 0);185 }186187 // `service_task` when the task is a non-periodic, non-named, non-fetched call which is not188 // dispatched (e.g. due to being overweight).189 service_task_base {190 let now = BLOCK_NUMBER.into();191 let task = make_task::<T>(false, false, false, None, 0);192 // prevent any tasks from actually being executed as we only want the surrounding weight.193 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };194 }: {195 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);196 } verify {197 //assert_eq!(result, Ok(()));198 }199200 // `service_task` when the task is a non-periodic, non-named, fetched call (with a known201 // preimage length) and which is not dispatched (e.g. due to being overweight).202 service_task_fetched {203 let s in (EncodedCall::bound() as u32) .. (<T::Preimages as PreimageRecipient<T::Hash>>::MaxSize::get());204 let now = BLOCK_NUMBER.into();205 let task = make_task::<T>(false, false, false, Some(s), 0);206 // prevent any tasks from actually being executed as we only want the surrounding weight.207 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };208 }: {209 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);210 } verify {211 }212213 // `service_task` when the task is a non-periodic, named, non-fetched call which is not214 // dispatched (e.g. due to being overweight).215 service_task_named {216 let now = BLOCK_NUMBER.into();217 let task = make_task::<T>(false, true, false, None, 0);218 // prevent any tasks from actually being executed as we only want the surrounding weight.219 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };220 }: {221 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);222 } verify {223 }224225 // `service_task` when the task is a periodic, non-named, non-fetched call which is not226 // dispatched (e.g. due to being overweight).227 service_task_periodic {228 let now = BLOCK_NUMBER.into();229 let task = make_task::<T>(true, false, false, None, 0);230 // prevent any tasks from actually being executed as we only want the surrounding weight.231 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::zero() };232 }: {233 let result = Scheduler::<T>::service_task(&mut counter, now, now, 0, true, task);234 } verify {235 }236237 // `execute_dispatch` when the origin is `Signed`, not counting the dispatable's weight.238 execute_dispatch_signed {239 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };240 let origin = make_origin::<T>(true);241 let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;242 }: {243 assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());244 }245 verify {246 }247248 // `execute_dispatch` when the origin is not `Signed`, not counting the dispatable's weight.249 execute_dispatch_unsigned {250 let mut counter = WeightCounter { used: Weight::zero(), limit: Weight::MAX };251 let origin = make_origin::<T>(false);252 let call = T::Preimages::realize(&make_call::<T>(None)).unwrap().0;253 }: {254 assert!(Scheduler::<T>::execute_dispatch(&mut counter, origin, call).is_ok());255 }256 verify {257 }258259 schedule {260 let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);261 let when = BLOCK_NUMBER.into();262 let periodic = Some((T::BlockNumber::one(), 100));263 let priority = Some(0);264 // Essentially a no-op call.265 let call = Box::new(SystemCall::set_storage { items: vec![] }.into());266267 fill_schedule::<T>(when, s)?;268 }: _(RawOrigin::Root, when, periodic, priority, call)269 verify {270 ensure!(271 Agenda::<T>::get(when).len() == (s + 1) as usize,272 "didn't add to schedule"273 );274 }275276 cancel {277 let s in 1 .. T::MaxScheduledPerBlock::get();278 let when = BLOCK_NUMBER.into();279280 fill_schedule::<T>(when, s)?;281 assert_eq!(Agenda::<T>::get(when).len(), s as usize);282 let schedule_origin = T::ScheduleOrigin::successful_origin();283 }: _<SystemOrigin<T>>(schedule_origin, when, 0)284 verify {285 ensure!(286 Lookup::<T>::get(u32_to_name(0)).is_none(),287 "didn't remove from lookup"288 );289 // Removed schedule is NONE290 ensure!(291 Agenda::<T>::get(when)[0].is_none(),292 "didn't remove from schedule"293 );294 }295296 schedule_named {297 let s in 0 .. (T::MaxScheduledPerBlock::get() - 1);298 let id = u32_to_name(s);299 let when = BLOCK_NUMBER.into();300 let periodic = Some((T::BlockNumber::one(), 100));301 let priority = Some(0);302 // Essentially a no-op call.303 let call = Box::new(SystemCall::set_storage { items: vec![] }.into());304305 fill_schedule::<T>(when, s)?;306 }: _(RawOrigin::Root, id, when, periodic, priority, call)307 verify {308 ensure!(309 Agenda::<T>::get(when).len() == (s + 1) as usize,310 "didn't add to schedule"311 );312 }313314 cancel_named {315 let s in 1 .. T::MaxScheduledPerBlock::get();316 let when = BLOCK_NUMBER.into();317318 fill_schedule::<T>(when, s)?;319 }: _(RawOrigin::Root, u32_to_name(0))320 verify {321 ensure!(322 Lookup::<T>::get(u32_to_name(0)).is_none(),323 "didn't remove from lookup"324 );325 // Removed schedule is NONE326 ensure!(327 Agenda::<T>::get(when)[0].is_none(),328 "didn't remove from schedule"329 );330 }331332 change_named_priority {333 let origin: RawOrigin<T::AccountId> = frame_system::RawOrigin::Root;334 let s in 1 .. T::MaxScheduledPerBlock::get();335 let when = BLOCK_NUMBER.into();336 let idx = s - 1;337 let id = u32_to_name(idx);338 let priority = 42;339 fill_schedule::<T>(when, s)?;340 }: _(origin, id, priority)341 verify {342 ensure!(343 Agenda::<T>::get(when)[idx as usize].clone().unwrap().priority == priority,344 "didn't change the priority"345 );346 }347348 impl_benchmark_test_suite!(Scheduler, crate::mock::new_test_ext(), crate::mock::Test);349}