Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: pop bench pallet logic implementation #407

Open
wants to merge 55 commits into
base: chungquantin/feat-pop_bench_command
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
d051d35
feat: add bench subcommand
chungquantin Feb 10, 2025
0cb63a0
feat: integrates frame-benchmarking-cli
chungquantin Feb 10, 2025
9798c5d
refactor: PalletCmd run with spec
chungquantin Feb 10, 2025
9719f05
feat: set RUST_LOG=info for benchmarking display
chungquantin Feb 10, 2025
9b94bbf
feat: add CLI messages and tests
chungquantin Feb 10, 2025
5bd6946
feat: add benchmark runtime wasm test
chungquantin Feb 11, 2025
949f972
chore: fix comment
chungquantin Feb 11, 2025
7dbe642
fix: operator cannot be applied to type
chungquantin Feb 11, 2025
1285436
chore: display error and refactor test file
chungquantin Feb 12, 2025
52760a4
chore: rename `bench` file
chungquantin Feb 13, 2025
d6a4c19
chore: clippy warning
chungquantin Feb 17, 2025
2d618e6
refactor: parachain feature in bench command
chungquantin Feb 17, 2025
760e8df
feat: add bench subcommand
chungquantin Feb 10, 2025
89eb0a5
feat: integrates frame-benchmarking-cli
chungquantin Feb 10, 2025
0aa7bcb
refactor: PalletCmd run with spec
chungquantin Feb 10, 2025
a24205a
feat: add CLI messages and tests
chungquantin Feb 10, 2025
33d6544
feat: add benchmark runtime wasm test
chungquantin Feb 11, 2025
001afac
chore: fix comment
chungquantin Feb 11, 2025
4d53b7c
fix: operator cannot be applied to type
chungquantin Feb 11, 2025
1fe3728
chore: display error and refactor test file
chungquantin Feb 12, 2025
c1f84a4
chore: rename `bench` file
chungquantin Feb 13, 2025
8a2a0d8
chore: clippy warning
chungquantin Feb 17, 2025
3ca377a
refactor: parachain feature in bench command
chungquantin Feb 17, 2025
5a33cb5
chore: revert mod.rs
chungquantin Feb 17, 2025
4fb8a52
Merge branch 'chungquantin/feat-pop_bench_command' into chungquantin/…
chungquantin Feb 18, 2025
bc3844f
feat: add bench subcommand
chungquantin Feb 10, 2025
81ca595
chore: revert mod.rs
chungquantin Feb 17, 2025
5c69429
feat: add bench subcommand
chungquantin Feb 10, 2025
3166017
feat: integrates frame-benchmarking-cli
chungquantin Feb 10, 2025
932e2a9
refactor: PalletCmd run with spec
chungquantin Feb 10, 2025
eedefd7
feat: set RUST_LOG=info for benchmarking display
chungquantin Feb 10, 2025
2ed185f
feat: add CLI messages and tests
chungquantin Feb 10, 2025
4c2b2de
feat: add benchmark runtime wasm test
chungquantin Feb 11, 2025
43e85b3
chore: fix comment
chungquantin Feb 11, 2025
ad5159c
fix: operator cannot be applied to type
chungquantin Feb 11, 2025
7d32588
chore: display error and refactor test file
chungquantin Feb 12, 2025
06d6528
chore: rename `bench` file
chungquantin Feb 13, 2025
b3e726b
chore: clippy warning
chungquantin Feb 17, 2025
c8cf39b
refactor: parachain feature in bench command
chungquantin Feb 17, 2025
832088a
feat: add bench subcommand
chungquantin Feb 10, 2025
0340eaf
feat: integrates frame-benchmarking-cli
chungquantin Feb 10, 2025
0dd02b0
refactor: PalletCmd run with spec
chungquantin Feb 10, 2025
f5eef31
feat: add CLI messages and tests
chungquantin Feb 10, 2025
ce95ff0
feat: add benchmark runtime wasm test
chungquantin Feb 11, 2025
e42d1c3
chore: fix comment
chungquantin Feb 11, 2025
52dfb95
fix: operator cannot be applied to type
chungquantin Feb 11, 2025
2785e52
chore: display error and refactor test file
chungquantin Feb 12, 2025
6435fc9
chore: rename `bench` file
chungquantin Feb 13, 2025
834307a
chore: clippy warning
chungquantin Feb 17, 2025
704196b
refactor: parachain feature in bench command
chungquantin Feb 17, 2025
1ef73f5
chore: revert mod.rs
chungquantin Feb 17, 2025
028a2bc
feat: add bench subcommand
chungquantin Feb 10, 2025
ad10ab4
chore: revert mod.rs
chungquantin Feb 17, 2025
146ab34
Merge remote-tracking branch 'refs/remotes/origin/chungquantin/feat-p…
chungquantin Feb 18, 2025
9d7c1b7
chore: revert changes
chungquantin Feb 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7,412 changes: 6,444 additions & 968 deletions Cargo.lock

Large diffs are not rendered by default.

15 changes: 13 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,13 @@ subxt = "0.38.0"
ink_env = "5.0.0"
sp-core = "32.0.0"
sp-weights = "31.0.0"
scale-info = { version = "2.11.4", default-features = false, features = ["derive"] }
scale-value = { version = "0.17.0", default-features = false, features = ["from-string", "parser-ss58"] }
scale-info = { version = "2.11.4", default-features = false, features = [
"derive",
] }
scale-value = { version = "0.17.0", default-features = false, features = [
"from-string",
"parser-ss58",
] }
contract-build = "5.0.2"
contract-extrinsics = "5.0.2"
contract-transcode = "5.0.2"
Expand All @@ -68,6 +73,12 @@ serde = { version = "1.0", features = ["derive"] }
zombienet-sdk = "0.2.18"
git2_credentials = "0.13.0"

# benchmarking
cumulus-primitives-proof-size-hostfunction = "0.10.0"
frame-benchmarking-cli = "46.0.0"
sp-runtime = "40.0.1"
sp-statement-store = "15.0.0"

# pop-cli
clap = { version = "4.5", features = ["derive"] }
cliclack = "0.3.1"
Expand Down
6 changes: 6 additions & 0 deletions crates/pop-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ axum.workspace = true
open.workspace = true
tower-http = { workspace = true, features = ["fs", "cors"] }

# benchmarking
cumulus-primitives-proof-size-hostfunction.workspace = true
frame-benchmarking-cli.workspace = true
sp-runtime.workspace = true
sp-statement-store.workspace = true

[dev-dependencies]
assert_cmd.workspace = true
contract-extrinsics.workspace = true
Expand Down
161 changes: 161 additions & 0 deletions crates/pop-cli/src/commands/bench/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// SPDX-License-Identifier: GPL-3.0

use crate::{
cli::{self, traits::Cli},
common::prompt::display_message,
};
use clap::{Args, Subcommand};
use frame_benchmarking_cli::PalletCmd;
use pop_parachains::generate_benchmarks;

/// Arguments for bencharmking a project.
#[derive(Args)]
#[command(args_conflicts_with_subcommands = true)]
pub struct BenchmarkArgs {
#[command(subcommand)]
pub command: Command,
}

/// Benchmark a pallet or parachain.
#[derive(Subcommand)]
pub enum Command {
/// Benchmark the extrinsic weight of FRAME Pallets
#[clap(alias = "p")]
Pallet(PalletCmd),
}

impl Command {
/// Executes the command.
pub(crate) fn execute(args: BenchmarkArgs) -> anyhow::Result<()> {
let mut cli = cli::Cli;

let result = match args.command {
Command::Pallet(cmd) => Command::bechmark_pallet(cmd, &mut cli),
};
match result {
Ok(()) => display_message("Benchmark completed successfully!", true, &mut cli),
Err(e) => display_message(&e.to_string(), false, &mut cli),
}
}

fn bechmark_pallet(cmd: PalletCmd, cli: &mut impl Cli) -> anyhow::Result<()> {
cli.intro("Benchmarking your pallets")?;
cli.warning(
"NOTE: the `pop bench pallet` is not yet battle tested - double check the results.",
)?;

if let Some(spec) = cmd.shared_params.chain {
return display_message(
&format!(
"Chain specs are not supported. Please remove `--chain={spec}` \
and use `--runtime=<PATH>` instead"
),
false,
cli,
);
}
cli.warning("NOTE: this may take some time...")?;

if let Err(e) = generate_benchmarks(&cmd) {
return display_message(&e.to_string(), false, cli);
}

if let Some(output_path) = cmd.output {
console::Term::stderr().clear_last_lines(1)?;
cli.info(format!("Weight file is generated to {}", output_path.as_path().display()))?;
}
Ok(())
}
}

#[cfg(test)]
mod tests {
use super::*;

use crate::cli::MockCli;
use clap::Parser;
use std::env;

#[test]
fn benchmark_pallet_works() -> anyhow::Result<()> {
let mut cli = MockCli::new()
.expect_intro("Benchmarking your pallets")
.expect_warning(
"NOTE: the `pop bench pallet` is not yet battle tested - double check the results.",
)
.expect_warning("NOTE: this may take some time...");

let cmd = PalletCmd::try_parse_from(&[
"",
"--runtime",
get_mock_runtime_path().to_str().unwrap(),
"--pallet",
"pallet_timestamp",
"--extrinsic",
"",
])?;
Command::bechmark_pallet(cmd, &mut cli)?;
cli.verify()?;
Ok(())
}

#[test]
fn benchmark_pallet_with_chainspec_fails() -> anyhow::Result<()> {
let spec = "path-to-chainspec";
let expected = format!(
"Chain specs are not supported. Please remove `--chain={spec}` \
and use `--runtime=<PATH>` instead"
);
let mut cli = MockCli::new()
.expect_intro("Benchmarking your pallets")
.expect_warning(
"NOTE: the `pop bench pallet` is not yet battle tested - double check the results.",
)
.expect_outro_cancel(expected.clone());

let cmd = PalletCmd::try_parse_from(&[
"",
"--chain",
spec,
"--pallet",
"pallet_timestamp",
"--extrinsic",
"",
])?;

Command::bechmark_pallet(cmd, &mut cli)?;
cli.verify()?;
Ok(())
}

#[test]
fn benchmark_pallet_fails_with_error() -> anyhow::Result<()> {
let mut cli = MockCli::new()
.expect_intro("Benchmarking your pallets")
.expect_warning(
"NOTE: the `pop bench pallet` is not yet battle tested - double check the results.",
)
.expect_outro_cancel(format!(
"Failed to run benchmarking: Invalid input: No benchmarks found which match your input."
));

let cmd = PalletCmd::try_parse_from(&[
"",
"--runtime",
get_mock_runtime_path().to_str().unwrap(),
"--pallet",
"unknown-pallet-name",
"--extrinsic",
"",
])?;

Command::bechmark_pallet(cmd, &mut cli)?;
cli.verify()?;
Ok(())
}

// Construct the path to the mock runtime WASM file.
fn get_mock_runtime_path() -> std::path::PathBuf {
env::current_dir().unwrap().join("tests/files/base_parachain.wasm")
}
}
25 changes: 4 additions & 21 deletions crates/pop-cli/src/commands/call/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use std::path::Path;

use crate::{
cli::{self, traits::*},
common::wallet::{prompt_to_use_wallet, request_signature},
common::{
prompt::display_message,
wallet::{prompt_to_use_wallet, request_signature},
},
};
use anyhow::{anyhow, Result};
use clap::Args;
Expand Down Expand Up @@ -499,16 +502,6 @@ async fn submit_extrinsic_with_wallet(
Ok(())
}

// Displays a message to the user, with formatting based on the success status.
fn display_message(message: &str, success: bool, cli: &mut impl Cli) -> Result<()> {
if success {
cli.outro(message)?;
} else {
cli.outro_cancel(message)?;
}
Ok(())
}

// Prompts the user for some predefined actions.
fn prompt_predefined_actions(pallets: &[Pallet], cli: &mut impl Cli) -> Result<Option<Action>> {
let mut predefined_action = cli.select("What would you like to do?");
Expand Down Expand Up @@ -995,16 +988,6 @@ mod tests {
Ok(())
}

#[test]
fn display_message_works() -> Result<()> {
let mut cli = MockCli::new().expect_outro(&"Call completed successfully!");
display_message("Call completed successfully!", true, &mut cli)?;
cli.verify()?;
let mut cli = MockCli::new().expect_outro_cancel("Call failed.");
display_message("Call failed.", false, &mut cli)?;
cli.verify()
}

#[tokio::test]
async fn prompt_predefined_actions_works() -> Result<()> {
let client = set_up_client(POP_NETWORK_TESTNET_URL).await?;
Expand Down
20 changes: 1 addition & 19 deletions crates/pop-cli/src/commands/call/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
common::{
builds::get_project_path,
contracts::has_contract_been_built,
prompt::display_message,
wallet::{prompt_to_use_wallet, request_signature},
},
};
Expand Down Expand Up @@ -549,15 +550,6 @@ impl CallContractCommand {
}
}

fn display_message(message: &str, success: bool, cli: &mut impl Cli) -> Result<()> {
if success {
cli.outro(message)?;
} else {
cli.outro_cancel(message)?;
}
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -1188,14 +1180,4 @@ mod tests {
assert!(!call_config.is_contract_build_required());
Ok(())
}

#[test]
fn display_message_works() -> Result<()> {
let mut cli = MockCli::new().expect_outro(&"Call completed successfully!");
display_message("Call completed successfully!", true, &mut cli)?;
cli.verify()?;
let mut cli = MockCli::new().expect_outro_cancel("Call failed.");
display_message("Call failed.", false, &mut cli)?;
cli.verify()
}
}
7 changes: 7 additions & 0 deletions crates/pop-cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use clap::Subcommand;
use pop_common::templates::Template;
use serde_json::{json, Value};

#[cfg(feature = "parachain")]
pub(crate) mod bench;
pub(crate) mod build;
pub(crate) mod call;
pub(crate) mod clean;
Expand All @@ -23,6 +25,9 @@ pub(crate) enum Command {
#[clap(alias = "n")]
#[cfg(any(feature = "parachain", feature = "contract"))]
New(new::NewArgs),
/// Benchmark a pallet or parachain.
#[cfg(feature = "parachain")]
Bench(bench::BenchmarkArgs),
#[clap(alias = "b", about = about_build())]
#[cfg(any(feature = "parachain", feature = "contract"))]
Build(build::BuildArgs),
Expand Down Expand Up @@ -93,6 +98,8 @@ impl Command {
cmd.execute().await.map(|_| json!("default"))
},
},
#[cfg(feature = "parachain")]
Self::Bench(args) => bench::Command::execute(args).map(|_| Value::Null),
#[cfg(any(feature = "parachain", feature = "contract"))]
Self::Build(args) => match args.command {
None => build::Command::execute(args).map(|t| json!(t)),
Expand Down
1 change: 1 addition & 0 deletions crates/pop-cli/src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pub mod builds;
#[cfg(feature = "contract")]
pub mod contracts;
pub mod helpers;
pub mod prompt;
pub mod wallet;
29 changes: 29 additions & 0 deletions crates/pop-cli/src/common/prompt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use crate::cli::traits::Cli;
use anyhow::Result;

// Displays a message to the user, with formatting based on the success status.
pub(crate) fn display_message(message: &str, success: bool, cli: &mut impl Cli) -> Result<()> {
chungquantin marked this conversation as resolved.
Show resolved Hide resolved
if success {
cli.outro(message)?;
} else {
cli.outro_cancel(message)?;
}
Ok(())
}

#[cfg(test)]
mod tests {
use super::display_message;
use crate::cli::MockCli;
use anyhow::Result;

#[test]
fn display_message_works() -> Result<()> {
let mut cli = MockCli::new().expect_outro(&"Call completed successfully!");
display_message("Call completed successfully!", true, &mut cli)?;
cli.verify()?;
let mut cli = MockCli::new().expect_outro_cancel("Call failed.");
display_message("Call failed.", false, &mut cli)?;
cli.verify()
}
}
5 changes: 5 additions & 0 deletions crates/pop-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,60 +1,65 @@
// SPDX-License-Identifier: GPL-3.0

#[cfg(not(any(feature = "contract", feature = "parachain")))]
compile_error!("feature \"contract\" or feature \"parachain\" must be enabled");

use anyhow::{anyhow, Result};
use clap::Parser;
use commands::*;
use serde_json::json;
use std::{fs::create_dir_all, path::PathBuf};
#[cfg(feature = "telemetry")]
use {
pop_telemetry::{config_file_path, record_cli_command, record_cli_used, Telemetry},
std::env::args,
};

mod cli;
#[cfg(any(feature = "parachain", feature = "contract"))]
mod commands;
mod common;
mod style;
mod wallet_integration;

#[tokio::main]
async fn main() -> Result<()> {
// Set environment for logging configuration, requires for `pop bench`.
if std::env::var("RUST_LOG").is_err() {
AlexD10S marked this conversation as resolved.
Show resolved Hide resolved
std::env::set_var("RUST_LOG", "info");
}

#[cfg(feature = "telemetry")]
let maybe_tel = init().unwrap_or(None);

let cli = Cli::parse();
let res = cli.command.execute().await;

#[cfg(feature = "telemetry")]
if let Some(tel) = maybe_tel.clone() {
// `args` is guaranteed to have at least 3 elements as clap will display help message if not
// set.
let (command, subcommand) = parse_args(args().collect());

if let Ok(sub_data) = &res {
// Best effort to send on first try, no action if failure.
let _ = record_cli_command(
tel.clone(),
&command,
json!({&subcommand: sub_data.to_string()}),
)
.await;
} else {
let _ = record_cli_command(tel, "error", json!({&command: &subcommand})).await;
}
}

// map result from Result<Value> to Result<()>
res.map(|_| ())
}

#[derive(Parser)]
#[command(author, version, about, styles=style::get_styles())]
pub struct Cli {

Check warning on line 62 in crates/pop-cli/src/main.rs

View workflow job for this annotation

GitHub Actions / clippy

missing documentation for a struct

warning: missing documentation for a struct --> crates/pop-cli/src/main.rs:62:1 | 62 | pub struct Cli { | ^^^^^^^^^^^^^^
#[command(subcommand)]
command: Command,
}
Expand Down
Binary file added crates/pop-cli/tests/files/base_parachain.wasm
Binary file not shown.
6 changes: 6 additions & 0 deletions crates/pop-parachains/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ walkdir.workspace = true
# Zombienet
zombienet-sdk.workspace = true

# Benchmarking
cumulus-primitives-proof-size-hostfunction.workspace = true
frame-benchmarking-cli.workspace = true
sp-runtime.workspace = true
sp-statement-store.workspace = true

# Pop
pop-common = { path = "../pop-common", version = "0.6.0" }

Expand Down
17 changes: 17 additions & 0 deletions crates/pop-parachains/src/bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use anyhow::Result;
use frame_benchmarking_cli::PalletCmd;
use sp_runtime::traits::BlakeTwo256;

type HostFunctions = (
sp_statement_store::runtime_api::HostFunctions,
cumulus_primitives_proof_size_hostfunction::storage_proof_size::HostFunctions,
);

/// Generate benchmarks for a pallet.
///
/// # Arguments
/// * `cmd` - Command to benchmark the extrinsic weight of FRAME Pallets.
pub fn generate_benchmarks(cmd: &PalletCmd) -> Result<()> {
cmd.run_with_spec::<BlakeTwo256, HostFunctions>(None)
.map_err(|e| anyhow::anyhow!(format!("Failed to run benchmarking: {}", e.to_string())))
}
Loading
Loading