benchmarking-cli: add --list-pallets and --all options (#3395)

closes #2844 

- adds `list-pallets` option which prints all unique available pallets
for benchmarking
```bash
./target/release/node benchmark pallet --list=pallets
```
- adds `all` option which runs benchmarks for all available pallets and
extrinsics (equivalent to `--pallet * --extrinsic *`)
```bash
./target/release/node benchmark pallet --all
```

- use the `list=pallets` syntax in `run_all_benchmarks.sh` script

cc ggwpez

---------

Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Dastan
2024-02-21 15:56:09 +01:00
committed by GitHub
parent 5a06771ecc
commit 165d075a5f
4 changed files with 86 additions and 25 deletions
@@ -15,7 +15,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use super::{writer, PalletCmd};
use super::{writer, ListOutput, PalletCmd};
use codec::{Decode, Encode};
use frame_benchmarking::{
Analysis, BenchmarkBatch, BenchmarkBatchSplitResults, BenchmarkList, BenchmarkParameter,
@@ -39,7 +39,13 @@ use sp_externalities::Extensions;
use sp_keystore::{testing::MemoryKeystore, KeystoreExt};
use sp_runtime::traits::Hash;
use sp_state_machine::StateMachine;
use std::{collections::HashMap, fmt::Debug, fs, str::FromStr, time};
use std::{
collections::{BTreeMap, BTreeSet, HashMap},
fmt::Debug,
fs,
str::FromStr,
time,
};
/// Logging target
const LOG_TARGET: &'static str = "frame::benchmark::pallet";
@@ -191,6 +197,7 @@ impl PalletCmd {
let spec = config.chain_spec;
let pallet = self.pallet.clone().unwrap_or_default();
let pallet = pallet.as_bytes();
let extrinsic = self.extrinsic.clone().unwrap_or_default();
let extrinsic_split: Vec<&str> = extrinsic.split(',').collect();
let extrinsics: Vec<_> = extrinsic_split.iter().map(|x| x.trim().as_bytes()).collect();
@@ -309,9 +316,8 @@ impl PalletCmd {
return Err("No benchmarks found which match your input.".into())
}
if self.list {
// List benchmarks instead of running them
list_benchmark(benchmarks_to_run);
if let Some(list_output) = self.list {
list_benchmark(benchmarks_to_run, list_output, self.no_csv_header);
return Ok(())
}
@@ -755,19 +761,43 @@ impl CliConfiguration for PalletCmd {
/// List the benchmarks available in the runtime, in a CSV friendly format.
fn list_benchmark(
mut benchmarks_to_run: Vec<(
benchmarks_to_run: Vec<(
Vec<u8>,
Vec<u8>,
Vec<(BenchmarkParameter, u32, u32)>,
Vec<(String, String)>,
)>,
list_output: ListOutput,
no_csv_header: bool,
) {
// Sort and de-dub by pallet and function name.
benchmarks_to_run.sort_by(|(pa, sa, _, _), (pb, sb, _, _)| (pa, sa).cmp(&(pb, sb)));
benchmarks_to_run.dedup_by(|(pa, sa, _, _), (pb, sb, _, _)| (pa, sa) == (pb, sb));
let mut benchmarks = BTreeMap::new();
println!("pallet, benchmark");
for (pallet, extrinsic, _, _) in benchmarks_to_run {
println!("{}, {}", String::from_utf8_lossy(&pallet), String::from_utf8_lossy(&extrinsic));
// Sort and de-dub by pallet and function name.
benchmarks_to_run.iter().for_each(|(pallet, extrinsic, _, _)| {
benchmarks
.entry(String::from_utf8_lossy(pallet).to_string())
.or_insert_with(BTreeSet::new)
.insert(String::from_utf8_lossy(extrinsic).to_string());
});
match list_output {
ListOutput::All => {
if !no_csv_header {
println!("pallet,extrinsic");
}
for (pallet, extrinsics) in benchmarks {
for extrinsic in extrinsics {
println!("{pallet},{extrinsic}");
}
}
},
ListOutput::Pallets => {
if !no_csv_header {
println!("pallet");
};
for pallet in benchmarks.keys() {
println!("{pallet}");
}
},
}
}
@@ -19,6 +19,7 @@ mod command;
mod writer;
use crate::shared::HostInfoParams;
use clap::ValueEnum;
use sc_cli::{
WasmExecutionMethod, WasmtimeInstantiationStrategy, DEFAULT_WASMTIME_INSTANTIATION_STRATEGY,
DEFAULT_WASM_EXECUTION_METHOD,
@@ -31,17 +32,32 @@ fn parse_pallet_name(pallet: &str) -> std::result::Result<String, String> {
Ok(pallet.replace("-", "_"))
}
/// List options for available benchmarks.
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum ListOutput {
/// List all available pallets and extrinsics.
All,
/// List all available pallets only.
Pallets,
}
/// Benchmark the extrinsic weight of FRAME Pallets.
#[derive(Debug, clap::Parser)]
pub struct PalletCmd {
/// Select a FRAME Pallet to benchmark, or `*` for all (in which case `extrinsic` must be `*`).
#[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input"])]
#[arg(short, long, value_parser = parse_pallet_name, required_unless_present_any = ["list", "json_input", "all"], default_value_if("all", "true", Some("*".into())))]
pub pallet: Option<String>,
/// Select an extrinsic inside the pallet to benchmark, or `*` for all.
#[arg(short, long, required_unless_present_any = ["list", "json_input"])]
#[arg(short, long, required_unless_present_any = ["list", "json_input", "all"], default_value_if("all", "true", Some("*".into())))]
pub extrinsic: Option<String>,
/// Run benchmarks for all pallets and extrinsics.
///
/// This is equivalent to running `--pallet * --extrinsic *`.
#[arg(long)]
pub all: bool,
/// Select how many samples we should take across the variable components.
#[arg(short, long, default_value_t = 50)]
pub steps: u32,
@@ -158,11 +174,15 @@ pub struct PalletCmd {
#[arg(long = "db-cache", value_name = "MiB", default_value_t = 1024)]
pub database_cache_size: u32,
/// List the benchmarks that match your query rather than running them.
/// List and print available benchmarks in a csv-friendly format.
///
/// When nothing is provided, we list all benchmarks.
#[arg(long)]
pub list: bool,
/// NOTE: `num_args` and `require_equals` are required to allow `--list`
#[arg(long, value_enum, ignore_case = true, num_args = 0..=1, require_equals = true, default_missing_value("All"))]
pub list: Option<ListOutput>,
/// Don't include csv header when listing benchmarks.
#[arg(long, requires("list"))]
pub no_csv_header: bool,
/// If enabled, the storage info is not displayed in the output next to the analysis.
///