Skip to content

Commit 058b4f5

Browse files
pallet scheduler: fix weight and add safety checks (#7785)
Changes: - Add runtime integrity test for scheduler pallet to ensure that lookups use sensible weights - Check all passed storage names in the omni bencher to be known by FRAME metadata - Trim storage names in omni bencher to fix V1 bench syntax bug - Fix V1 bench syntax storage name sanitization for specific Rust versions I re-ran the benchmarks with the omni-bencher modifications and it did not change the [proof size](https://weights.tasty.limo/compare?repo=polkadot-sdk&threshold=1&path_pattern=substrate%2Fframe%2F**%2Fsrc%2Fweights.rs%2Cpolkadot%2Fruntime%2F*%2Fsrc%2Fweights%2F**%2F*.rs%2Cpolkadot%2Fbridges%2Fmodules%2F*%2Fsrc%2Fweights.rs%2Ccumulus%2F**%2Fweights%2F*.rs%2Ccumulus%2F**%2Fweights%2Fxcm%2F*.rs%2Ccumulus%2F**%2Fsrc%2Fweights.rs&method=asymptotic&ignore_errors=true&unit=proof&old=cc0142510b81dcf1c1a22f7dc164c453c25287e6&new=bb19d78821eaeaf2262f6a23ee45f83dd4f94d29). I reverted [the commit](bb19d78) afterwards to reduce the noise for reviewers. --------- Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 047534b commit 058b4f5

5 files changed

Lines changed: 94 additions & 4 deletions

File tree

prdoc/pr_7785.prdoc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
title: 'pallet scheduler: fix weight and add safety checks'
2+
doc:
3+
- audience: Runtime Dev
4+
description: |-
5+
Changes:
6+
- Add runtime integrity test for scheduler pallet to ensure that lookups use sensible weights
7+
- Check all passed storage names in the omni bencher to be known by FRAME metadata
8+
- Trim storage names in omni bencher to fix V1 bench syntax bug
9+
- Fix V1 bench syntax storage name sanitization for specific Rust versions
10+
11+
I re-ran the benchmarks with the omni-bencher modifications and it did not change the [proof size](https://weights.tasty.limo/compare?repo=polkadot-sdk&threshold=1&path_pattern=substrate%2Fframe%2F**%2Fsrc%2Fweights.rs%2Cpolkadot%2Fruntime%2F*%2Fsrc%2Fweights%2F**%2F*.rs%2Cpolkadot%2Fbridges%2Fmodules%2F*%2Fsrc%2Fweights.rs%2Ccumulus%2F**%2Fweights%2F*.rs%2Ccumulus%2F**%2Fweights%2Fxcm%2F*.rs%2Ccumulus%2F**%2Fsrc%2Fweights.rs&method=asymptotic&ignore_errors=true&unit=proof&old=cc0142510b81dcf1c1a22f7dc164c453c25287e6&new=bb19d78821eaeaf2262f6a23ee45f83dd4f94d29). I reverted [the commit](https://github.com/paritytech/polkadot-sdk/pull/7785/commits/bb19d78821eaeaf2262f6a23ee45f83dd4f94d29) afterwards to reduce the noise for reviewers.
12+
crates:
13+
- name: frame-benchmarking-cli
14+
bump: minor
15+
- name: frame-benchmarking
16+
bump: minor
17+
- name: pallet-scheduler
18+
bump: minor
19+
- name: asset-hub-westend-runtime
20+
bump: minor
21+
- name: westend-runtime
22+
bump: minor

substrate/frame/benchmarking/src/v1.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,8 @@ macro_rules! impl_benchmark {
10081008
$(
10091009
(stringify!($pov_name).as_bytes().to_vec(),
10101010
$crate::__private::vec![
1011-
$( ( stringify!($storage).as_bytes().to_vec(),
1011+
// Stringify sometimes includes spaces, depending on the Rust version.
1012+
$( ( stringify!($storage).replace(" ", "").as_bytes().to_vec(),
10121013
stringify!($pov_mode).as_bytes().to_vec() ), )*
10131014
]),
10141015
)*

substrate/frame/scheduler/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,27 @@ pub mod pallet {
415415
Self::service_agendas(&mut weight_counter, now, u32::MAX);
416416
weight_counter.consumed()
417417
}
418+
419+
#[cfg(feature = "std")]
420+
fn integrity_test() {
421+
/// Calculate the maximum weight that a lookup of a given size can take.
422+
fn lookup_weight<T: Config>(s: usize) -> Weight {
423+
T::WeightInfo::service_agendas_base() +
424+
T::WeightInfo::service_agenda_base(T::MaxScheduledPerBlock::get()) +
425+
T::WeightInfo::service_task(Some(s), true, true)
426+
}
427+
428+
let limit = sp_runtime::Perbill::from_percent(90) * T::MaximumWeight::get();
429+
430+
let small_lookup = lookup_weight::<T>(128);
431+
assert!(small_lookup.all_lte(limit), "Must be possible to submit a small lookup");
432+
433+
let medium_lookup = lookup_weight::<T>(1024);
434+
assert!(medium_lookup.all_lte(limit), "Must be possible to submit a medium lookup");
435+
436+
let large_lookup = lookup_weight::<T>(1024 * 1024);
437+
assert!(large_lookup.all_lte(limit), "Must be possible to submit a large lookup");
438+
}
418439
}
419440

420441
#[pallet::call]

substrate/utils/frame/benchmarking-cli/src/pallet/command.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,8 @@ impl PalletCmd {
365365
let mut timer = time::SystemTime::now();
366366
// Maps (pallet, extrinsic) to its component ranges.
367367
let mut component_ranges = HashMap::<(String, String), Vec<ComponentRange>>::new();
368-
let pov_modes = Self::parse_pov_modes(&benchmarks_to_run)?;
368+
let pov_modes =
369+
Self::parse_pov_modes(&benchmarks_to_run, &storage_info, self.ignore_unknown_pov_mode)?;
369370
let mut failed = Vec::<(String, String)>::new();
370371

371372
'outer: for (i, SelectedBenchmark { pallet, instance, extrinsic, components, .. }) in
@@ -912,22 +913,29 @@ impl PalletCmd {
912913
}
913914

914915
/// Parses the PoV modes per benchmark that were specified by the `#[pov_mode]` attribute.
915-
fn parse_pov_modes(benchmarks: &Vec<SelectedBenchmark>) -> Result<PovModesMap> {
916+
fn parse_pov_modes(
917+
benchmarks: &Vec<SelectedBenchmark>,
918+
storage_info: &[StorageInfo],
919+
ignore_unknown_pov_mode: bool,
920+
) -> Result<PovModesMap> {
916921
use std::collections::hash_map::Entry;
917922
let mut parsed = PovModesMap::new();
918923

919924
for SelectedBenchmark { pallet, extrinsic, pov_modes, .. } in benchmarks {
920925
for (pallet_storage, mode) in pov_modes {
921926
let mode = PovEstimationMode::from_str(&mode)?;
927+
let pallet_storage = pallet_storage.replace(" ", "");
922928
let splits = pallet_storage.split("::").collect::<Vec<_>>();
929+
923930
if splits.is_empty() || splits.len() > 2 {
924931
return Err(format!(
925932
"Expected 'Pallet::Storage' as storage name but got: {}",
926933
pallet_storage
927934
)
928935
.into())
929936
}
930-
let (pov_pallet, pov_storage) = (splits[0], splits.get(1).unwrap_or(&"ALL"));
937+
let (pov_pallet, pov_storage) =
938+
(splits[0].trim(), splits.get(1).unwrap_or(&"ALL").trim());
931939

932940
match parsed
933941
.entry((pallet.clone(), extrinsic.clone()))
@@ -946,9 +954,43 @@ impl PalletCmd {
946954
}
947955
}
948956
}
957+
log::debug!("Parsed PoV modes: {:?}", parsed);
958+
Self::check_pov_modes(&parsed, storage_info, ignore_unknown_pov_mode)?;
959+
949960
Ok(parsed)
950961
}
951962

963+
fn check_pov_modes(
964+
pov_modes: &PovModesMap,
965+
storage_info: &[StorageInfo],
966+
ignore_unknown_pov_mode: bool,
967+
) -> Result<()> {
968+
// Check that all PoV modes are valid pallet storage keys
969+
for (pallet, storage) in pov_modes.values().flat_map(|i| i.keys()) {
970+
let (mut found_pallet, mut found_storage) = (false, false);
971+
972+
for info in storage_info {
973+
if pallet == "ALL" || info.pallet_name == pallet.as_bytes() {
974+
found_pallet = true;
975+
}
976+
if storage == "ALL" || info.storage_name == storage.as_bytes() {
977+
found_storage = true;
978+
}
979+
}
980+
if !found_pallet || !found_storage {
981+
let err = format!("The PoV mode references an unknown storage item or pallet: `{}::{}`. You can ignore this warning by specifying `--ignore-unknown-pov-mode`", pallet, storage);
982+
983+
if ignore_unknown_pov_mode {
984+
log::warn!(target: LOG_TARGET, "Error demoted to warning due to `--ignore-unknown-pov-mode`: {}", err);
985+
} else {
986+
return Err(err.into());
987+
}
988+
}
989+
}
990+
991+
Ok(())
992+
}
993+
952994
/// Sanity check the CLI arguments.
953995
fn check_args(
954996
&self,

substrate/utils/frame/benchmarking-cli/src/pallet/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ pub struct PalletCmd {
133133
#[arg(long, default_value("max-encoded-len"), value_enum)]
134134
pub default_pov_mode: command::PovEstimationMode,
135135

136+
/// Ignore the error when PoV modes reference unknown storage items or pallets.
137+
#[arg(long)]
138+
pub ignore_unknown_pov_mode: bool,
139+
136140
/// Set the heap pages while running benchmarks. If not set, the default value from the client
137141
/// is used.
138142
#[arg(long)]

0 commit comments

Comments
 (0)