// This file is part of Substrate. // Copyright (C) 2022 Parity Technologies (UK) Ltd. // 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. //! Contains the [`OverheadCmd`] as entry point for the CLI to execute //! the *overhead* benchmarks. use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider}; use sc_cli::{CliConfiguration, ImportParams, Result, SharedParams}; use sc_client_api::Backend as ClientBackend; use sc_service::Configuration; use sp_api::{ApiExt, ProvideRuntimeApi}; use sp_runtime::{traits::Block as BlockT, DigestItem, OpaqueExtrinsic}; use clap::{Args, Parser}; use log::info; use serde::Serialize; use std::{fmt::Debug, path::PathBuf, sync::Arc}; use crate::{ extrinsic::{ bench::{Benchmark, BenchmarkParams as ExtrinsicBenchmarkParams}, ExtrinsicBuilder, }, overhead::template::TemplateData, shared::{HostInfoParams, WeightParams}, }; /// Benchmark the execution overhead per-block and per-extrinsic. #[derive(Debug, Parser)] pub struct OverheadCmd { #[allow(missing_docs)] #[clap(flatten)] pub shared_params: SharedParams, #[allow(missing_docs)] #[clap(flatten)] pub import_params: ImportParams, #[allow(missing_docs)] #[clap(flatten)] pub params: OverheadParams, } /// Configures the benchmark, the post-processing and weight generation. #[derive(Debug, Default, Serialize, Clone, PartialEq, Args)] pub struct OverheadParams { #[allow(missing_docs)] #[clap(flatten)] pub weight: WeightParams, #[allow(missing_docs)] #[clap(flatten)] pub bench: ExtrinsicBenchmarkParams, #[allow(missing_docs)] #[clap(flatten)] pub hostinfo: HostInfoParams, /// Add a header to the generated weight output file. /// /// Good for adding LICENSE headers. #[arg(long, value_name = "PATH")] pub header: Option, /// Enable the Trie cache. /// /// This should only be used for performance analysis and not for final results. #[arg(long)] pub enable_trie_cache: bool, } /// Type of a benchmark. #[derive(Serialize, Clone, PartialEq, Copy)] pub(crate) enum BenchmarkType { /// Measure the per-extrinsic execution overhead. Extrinsic, /// Measure the per-block execution overhead. Block, } impl OverheadCmd { /// Measure the per-block and per-extrinsic execution overhead. /// /// Writes the results to console and into two instances of the /// `weights.hbs` template, one for each benchmark. pub fn run( &self, cfg: Configuration, client: Arc, inherent_data: sp_inherents::InherentData, digest_items: Vec, ext_builder: &dyn ExtrinsicBuilder, ) -> Result<()> where Block: BlockT, BA: ClientBackend, C: BlockBuilderProvider + ProvideRuntimeApi, C::Api: ApiExt + BlockBuilderApi, { if ext_builder.pallet() != "system" || ext_builder.extrinsic() != "remark" { return Err(format!("The extrinsic builder is required to build `System::Remark` extrinsics but builds `{}` extrinsics instead", ext_builder.name()).into()); } let bench = Benchmark::new(client, self.params.bench.clone(), inherent_data, digest_items); // per-block execution overhead { let stats = bench.bench_block()?; info!("Per-block execution overhead [ns]:\n{:?}", stats); let template = TemplateData::new(BenchmarkType::Block, &cfg, &self.params, &stats)?; template.write(&self.params.weight.weight_path)?; } // per-extrinsic execution overhead { let stats = bench.bench_extrinsic(ext_builder)?; info!("Per-extrinsic execution overhead [ns]:\n{:?}", stats); let template = TemplateData::new(BenchmarkType::Extrinsic, &cfg, &self.params, &stats)?; template.write(&self.params.weight.weight_path)?; } Ok(()) } } impl BenchmarkType { /// Short name of the benchmark type. pub(crate) fn short_name(&self) -> &'static str { match self { Self::Extrinsic => "extrinsic", Self::Block => "block", } } /// Long name of the benchmark type. pub(crate) fn long_name(&self) -> &'static str { match self { Self::Extrinsic => "ExtrinsicBase", Self::Block => "BlockExecution", } } } // Boilerplate impl CliConfiguration for OverheadCmd { fn shared_params(&self) -> &SharedParams { &self.shared_params } fn import_params(&self) -> Option<&ImportParams> { Some(&self.import_params) } fn trie_cache_maximum_size(&self) -> Result> { if self.params.enable_trie_cache { Ok(self.import_params().map(|x| x.trie_cache_maximum_size()).unwrap_or_default()) } else { Ok(None) } } }