Skip to content

Commit

Permalink
Add overhead benchmark to frame-omni-bencher (#5891)
Browse files Browse the repository at this point in the history
# Benchmark Overhead Command for Parachains

This implements the `benchmark overhead` command for parachains. Full
context is available at:
#5303. Previous attempt
was this #5283, but here
we have integration into frame-omni-bencher and improved tooling.

## Changes Overview

Users are now able to use `frame-omni-bencher` to generate
`extrinsic_weight.rs` and `block_weight.rs` files for their runtime. The
core logic for generating these remains untouched; this PR provides
mostly machinery to make it work for parachains at all.

Similar to the pallet benchmarks, we gain the option to benchmark based
on just a runtime:

```
frame-omni-bencher v1 benchmark overhead --runtime {{runtime}}
```

or with a spec:

```
frame-omni-bencher v1 benchmark overhead --chain {{spec}} --genesis-builder spec
```

In this case, the genesis state is generated from the runtime presets.
However, it is also possible to use `--chain` and genesis builder `spec`
to generate the genesis state from the chain spec.

Additionally, we use metadata to perform some checks based on the
pallets the runtime exposes:

- If we see the `ParaInherent` pallet, we assume that we are dealing
with a relay chain. This means that we don't need proof recording during
import (since there is no storage weight).
- If we detect the `ParachainSystem` pallet, we assume that we are
dealing with a parachain and take corresponding actions like patching a
para id into the genesis state.

On the inherent side, I am currently supplying the standard inherents
every parachain needs.

In the current state, `frame-omni-bencher` supports all system chains.
In follow-up PRs, we could add additional inherents to increase
compatibility.

Since we are building a block during the benchmark, we also need to
build an extrinsic. By default, I am leveraging subxt to build the xt
dynamically. If a chain is not compatible with the `SubstrateConfig`
that comes with `subxt`, it can provide a custom extrinsic builder to
benchmarking-cli. This requires either a custom bencher implementation
or an integration into the parachains node.

Also cumulus-test-runtime has been migrated to provide genesis configs.

## Chain Compatibility
The current version here is compatible with the system chains and common
substrate chains. The way to go for others would be to customize the
frame-omni-bencher by providing a custom extrinsicbuilder. I did an
example implementation that works for mythical:
https://github.com/skunert/mythical-bencher

## Follow-Ups
- After #6040 is finished, we should integrate this here to make the
tooling truly useful. In the current form, the state is fairly small and
not representative.

## How to Review
I recommend starting from
[here](https://github.com/paritytech/polkadot-sdk/pull/5891/files#diff-50830ff756b3ac3403b7739d66c9e3a5185dbea550669ca71b28d19c7a2a54ecR264),
this method is the main entry point for omni-bencher and `polkadot`
binary.

TBD:
- [x] PRDoc

---------

Co-authored-by: Michal Kucharczyk <[email protected]>
  • Loading branch information
skunert and michalkucharczyk authored Oct 30, 2024
1 parent 6f96f72 commit 40547f9
Show file tree
Hide file tree
Showing 44 changed files with 2,201 additions and 590 deletions.
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cumulus/client/parachain-inherent/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
/// in addition to the messages themselves, you must provide some information about
/// your parachain's configuration in order to mock the MQC heads properly.
/// See [`MockXcmConfig`] for more information
#[derive(Default)]
pub struct MockValidationDataInherentDataProvider<R = ()> {
/// The current block number of the local block chain (the parachain).
pub current_para_block: u32,
Expand Down
10 changes: 10 additions & 0 deletions cumulus/polkadot-omni-node/lib/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ pub struct RunConfig {
pub runtime_resolver: Box<dyn RuntimeResolver>,
}

impl RunConfig {
/// Create a new `RunConfig`
pub fn new(
runtime_resolver: Box<dyn RuntimeResolver>,
chain_spec_loader: Box<dyn LoadSpec>,
) -> Self {
RunConfig { chain_spec_loader, runtime_resolver }
}
}

pub fn new_aura_node_spec<Block>(
aura_id: AuraConsensusId,
extra_args: &NodeExtraArgs,
Expand Down
5 changes: 1 addition & 4 deletions cumulus/polkadot-omni-node/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ impl CliConfigT for CliConfig {
fn main() -> color_eyre::eyre::Result<()> {
color_eyre::install()?;

let config = RunConfig {
chain_spec_loader: Box::new(DiskChainSpecLoader),
runtime_resolver: Box::new(DefaultRuntimeResolver),
};
let config = RunConfig::new(Box::new(DefaultRuntimeResolver), Box::new(DiskChainSpecLoader));
Ok(run::<CliConfig>(config)?)
}
8 changes: 4 additions & 4 deletions cumulus/polkadot-parachain/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ impl CliConfigT for CliConfig {
fn main() -> color_eyre::eyre::Result<()> {
color_eyre::install()?;

let config = RunConfig {
chain_spec_loader: Box::new(chain_spec::ChainSpecLoader),
runtime_resolver: Box::new(chain_spec::RuntimeResolver),
};
let config = RunConfig::new(
Box::new(chain_spec::RuntimeResolver),
Box::new(chain_spec::ChainSpecLoader),
);
Ok(run::<CliConfig>(config)?)
}
6 changes: 3 additions & 3 deletions cumulus/test/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use sp_consensus_aura::{AuraApi, Slot};
use sp_core::Pair;
use sp_io::TestExternalities;
use sp_keystore::testing::MemoryKeystore;
use sp_runtime::{generic::Era, traits::Header, BuildStorage, SaturatedConversion};
use sp_runtime::{generic::Era, traits::Header, BuildStorage, MultiAddress, SaturatedConversion};
use std::sync::Arc;
pub use substrate_test_client::*;

Expand Down Expand Up @@ -158,7 +158,7 @@ pub fn generate_extrinsic_with_pair(

UncheckedExtrinsic::new_signed(
function,
origin.public().into(),
MultiAddress::Id(origin.public().into()),
Signature::Sr25519(signature),
tx_ext,
)
Expand All @@ -181,7 +181,7 @@ pub fn transfer(
value: Balance,
) -> UncheckedExtrinsic {
let function = RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death {
dest: dest.public().into(),
dest: MultiAddress::Id(dest.public().into()),
value,
});

Expand Down
4 changes: 4 additions & 0 deletions cumulus/test/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ workspace = true
[dependencies]
codec = { features = ["derive"], workspace = true }
scale-info = { features = ["derive"], workspace = true }
serde_json = { workspace = true }

# Substrate
frame-executive = { workspace = true }
Expand Down Expand Up @@ -38,6 +39,7 @@ sp-session = { workspace = true }
sp-consensus-aura = { workspace = true }
sp-transaction-pool = { workspace = true }
sp-version = { workspace = true }
sp-keyring = { workspace = true }

# Cumulus
cumulus-pallet-parachain-system = { workspace = true }
Expand Down Expand Up @@ -76,13 +78,15 @@ std = [
"pallet-transaction-payment/std",
"parachain-info/std",
"scale-info/std",
"serde_json/std",
"sp-api/std",
"sp-block-builder/std",
"sp-consensus-aura/std",
"sp-core/std",
"sp-genesis-builder/std",
"sp-inherents/std",
"sp-io/std",
"sp-keyring/std",
"sp-offchain/std",
"sp-runtime/std",
"sp-session/std",
Expand Down
72 changes: 72 additions & 0 deletions cumulus/test/runtime/src/genesis_config_presets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Cumulus.

// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.

use super::{
AccountId, AuraConfig, AuraId, BalancesConfig, ParachainInfoConfig, RuntimeGenesisConfig,
SudoConfig,
};
use alloc::{vec, vec::Vec};

use cumulus_primitives_core::ParaId;
use frame_support::build_struct_json_patch;
use sp_genesis_builder::PresetId;
use sp_keyring::Sr25519Keyring;

fn cumulus_test_runtime(
invulnerables: Vec<AuraId>,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> serde_json::Value {
build_struct_json_patch!(RuntimeGenesisConfig {
balances: BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
},
sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.public().into()) },
parachain_info: ParachainInfoConfig { parachain_id: id },
aura: AuraConfig { authorities: invulnerables },
})
}

fn testnet_genesis_with_default_endowed(self_para_id: ParaId) -> serde_json::Value {
let endowed = Sr25519Keyring::well_known().map(|x| x.to_account_id()).collect::<Vec<_>>();

let invulnerables =
Sr25519Keyring::invulnerable().map(|x| x.public().into()).collect::<Vec<_>>();
cumulus_test_runtime(invulnerables, endowed, self_para_id)
}

/// List of supported presets.
pub fn preset_names() -> Vec<PresetId> {
vec![
PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET),
PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET),
]
}

/// Provides the JSON representation of predefined genesis config for given `id`.
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
let patch = match id.try_into() {
Ok(sp_genesis_builder::DEV_RUNTIME_PRESET) |
Ok(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET) =>
testnet_genesis_with_default_endowed(100.into()),
_ => return None,
};
Some(
serde_json::to_string(&patch)
.expect("serialization to json is expected to work. qed.")
.into_bytes(),
)
}
13 changes: 6 additions & 7 deletions cumulus/test/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub mod elastic_scaling {
include!(concat!(env!("OUT_DIR"), "/wasm_binary_elastic_scaling.rs"));
}

mod genesis_config_presets;
mod test_pallet;

extern crate alloc;
Expand All @@ -45,9 +46,9 @@ use sp_core::{ConstBool, ConstU32, ConstU64, OpaqueMetadata};
use cumulus_primitives_core::{ClaimQueueOffset, CoreSelector};
use sp_runtime::{
create_runtime_str, generic, impl_opaque_keys,
traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, IdentityLookup, Verify},
traits::{BlakeTwo256, Block as BlockT, IdentifyAccount, Verify},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult, MultiSignature,
ApplyExtrinsicResult, MultiAddress, MultiSignature,
};
#[cfg(feature = "std")]
use sp_version::NativeVersion;
Expand Down Expand Up @@ -208,8 +209,6 @@ parameter_types! {
impl frame_system::Config for Runtime {
/// The identifier used to distinguish between accounts.
type AccountId = AccountId;
/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
type Lookup = IdentityLookup<AccountId>;
/// The index type for storing how many extrinsics an account has signed.
type Nonce = Nonce;
/// The type for hashing blocks and tries.
Expand Down Expand Up @@ -363,7 +362,7 @@ pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::Account
pub type NodeBlock = generic::Block<Header, sp_runtime::OpaqueExtrinsic>;

/// The address format for describing accounts.
pub type Address = AccountId;
pub type Address = MultiAddress<AccountId, ()>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type as expected by this runtime.
Expand Down Expand Up @@ -544,11 +543,11 @@ impl_runtime_apis! {
}

fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
get_preset::<RuntimeGenesisConfig>(id, |_| None)
get_preset::<RuntimeGenesisConfig>(id, genesis_config_presets::get_preset)
}

fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
vec![]
genesis_config_presets::preset_names()
}
}
}
Expand Down
1 change: 1 addition & 0 deletions cumulus/test/service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ sp-core = { workspace = true, default-features = true }
sp-io = { workspace = true, default-features = true }
sp-api = { workspace = true, default-features = true }
sp-keyring = { workspace = true, default-features = true }
sp-genesis-builder = { workspace = true, default-features = true }
sp-runtime = { workspace = true }
sp-state-machine = { workspace = true, default-features = true }
sp-tracing = { workspace = true, default-features = true }
Expand Down
6 changes: 3 additions & 3 deletions cumulus/test/service/benches/transaction_throughput.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn create_account_extrinsics(client: &Client, accounts: &[sr25519::Pair]) -> Vec
SudoCall::sudo {
call: Box::new(
BalancesCall::force_set_balance {
who: AccountId::from(a.public()),
who: AccountId::from(a.public()).into(),
new_free: 0,
}
.into(),
Expand All @@ -69,7 +69,7 @@ fn create_account_extrinsics(client: &Client, accounts: &[sr25519::Pair]) -> Vec
SudoCall::sudo {
call: Box::new(
BalancesCall::force_set_balance {
who: AccountId::from(a.public()),
who: AccountId::from(a.public()).into(),
new_free: 1_000_000_000_000 * ExistentialDeposit::get(),
}
.into(),
Expand All @@ -96,7 +96,7 @@ fn create_benchmark_extrinsics(
construct_extrinsic(
client,
BalancesCall::transfer_allow_death {
dest: Bob.to_account_id(),
dest: Bob.to_account_id().into(),
value: ExistentialDeposit::get(),
},
account.clone(),
Expand Down
5 changes: 4 additions & 1 deletion cumulus/test/service/benches/validate_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ fn create_extrinsics(
let extrinsic: UncheckedExtrinsic = generate_extrinsic_with_pair(
client,
src.clone(),
BalancesCall::transfer_keep_alive { dest: AccountId::from(dst.public()), value: 10000 },
BalancesCall::transfer_keep_alive {
dest: AccountId::from(dst.public()).into(),
value: 10000,
},
None,
);

Expand Down
Loading

0 comments on commit 40547f9

Please sign in to comment.