mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 09:51:10 +00:00
subsystem-bench: run cli benchmarks only using config files (#3239)
This PR removes the configuration of subsystem benchmarks via CLI arguments. After this, we only keep configurations only in yaml files. It removes unnecessary code duplication
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
//! A tool for running subsystem benchmark tests designed for development and
|
||||
//! CI regression testing.
|
||||
use clap::Parser;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use colored::Colorize;
|
||||
|
||||
@@ -28,24 +29,23 @@ use std::path::Path;
|
||||
|
||||
pub(crate) mod approval;
|
||||
pub(crate) mod availability;
|
||||
pub(crate) mod cli;
|
||||
pub(crate) mod core;
|
||||
mod valgrind;
|
||||
|
||||
const LOG_TARGET: &str = "subsystem-bench";
|
||||
|
||||
use availability::{prepare_test, NetworkEmulation, TestState};
|
||||
use cli::TestObjective;
|
||||
|
||||
use approval::{bench_approvals, ApprovalsOptions};
|
||||
use availability::DataAvailabilityReadOptions;
|
||||
use core::{
|
||||
configuration::TestConfiguration,
|
||||
display::display_configuration,
|
||||
environment::{TestEnvironment, GENESIS_HASH},
|
||||
};
|
||||
|
||||
use clap_num::number_range;
|
||||
|
||||
use crate::{approval::bench_approvals, core::display::display_configuration};
|
||||
|
||||
fn le_100(s: &str) -> Result<usize, String> {
|
||||
number_range(s, 0, 100)
|
||||
}
|
||||
@@ -54,6 +54,34 @@ fn le_5000(s: &str) -> Result<usize, String> {
|
||||
number_range(s, 0, 5000)
|
||||
}
|
||||
|
||||
/// Supported test objectives
|
||||
#[derive(Debug, Clone, Parser, Serialize, Deserialize)]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
pub enum TestObjective {
|
||||
/// Benchmark availability recovery strategies.
|
||||
DataAvailabilityRead(DataAvailabilityReadOptions),
|
||||
/// Benchmark availability and bitfield distribution.
|
||||
DataAvailabilityWrite,
|
||||
/// Benchmark the approval-voting and approval-distribution subsystems.
|
||||
ApprovalVoting(ApprovalsOptions),
|
||||
Unimplemented,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TestObjective {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::DataAvailabilityRead(_) => "DataAvailabilityRead",
|
||||
Self::DataAvailabilityWrite => "DataAvailabilityWrite",
|
||||
Self::ApprovalVoting(_) => "ApprovalVoting",
|
||||
Self::Unimplemented => "Unimplemented",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[allow(missing_docs)]
|
||||
struct BenchCli {
|
||||
@@ -61,9 +89,6 @@ struct BenchCli {
|
||||
/// The type of network to be emulated
|
||||
pub network: NetworkEmulation,
|
||||
|
||||
#[clap(flatten)]
|
||||
pub standard_configuration: cli::StandardTestOptions,
|
||||
|
||||
#[clap(short, long)]
|
||||
/// The bandwidth of emulated remote peers in KiB
|
||||
pub peer_bandwidth: Option<usize>,
|
||||
@@ -104,42 +129,12 @@ struct BenchCli {
|
||||
/// Shows the output in YAML format
|
||||
pub yaml_output: bool,
|
||||
|
||||
#[command(subcommand)]
|
||||
pub objective: cli::TestObjective,
|
||||
#[arg(required = true)]
|
||||
/// Path to the test sequence configuration file
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
impl BenchCli {
|
||||
fn create_test_configuration(&self) -> TestConfiguration {
|
||||
let configuration = &self.standard_configuration;
|
||||
|
||||
match self.network {
|
||||
NetworkEmulation::Healthy => TestConfiguration::healthy_network(
|
||||
self.objective.clone(),
|
||||
configuration.num_blocks,
|
||||
configuration.n_validators,
|
||||
configuration.n_cores,
|
||||
configuration.min_pov_size,
|
||||
configuration.max_pov_size,
|
||||
),
|
||||
NetworkEmulation::Degraded => TestConfiguration::degraded_network(
|
||||
self.objective.clone(),
|
||||
configuration.num_blocks,
|
||||
configuration.n_validators,
|
||||
configuration.n_cores,
|
||||
configuration.min_pov_size,
|
||||
configuration.max_pov_size,
|
||||
),
|
||||
NetworkEmulation::Ideal => TestConfiguration::ideal_network(
|
||||
self.objective.clone(),
|
||||
configuration.num_blocks,
|
||||
configuration.n_validators,
|
||||
configuration.n_cores,
|
||||
configuration.min_pov_size,
|
||||
configuration.max_pov_size,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn launch(self) -> eyre::Result<()> {
|
||||
let is_valgrind_running = valgrind::is_valgrind_running();
|
||||
if !is_valgrind_running && self.cache_misses {
|
||||
@@ -156,125 +151,56 @@ impl BenchCli {
|
||||
None
|
||||
};
|
||||
|
||||
let mut test_config = match self.objective {
|
||||
TestObjective::TestSequence(options) => {
|
||||
let test_sequence =
|
||||
core::configuration::TestSequence::new_from_file(Path::new(&options.path))
|
||||
.expect("File exists")
|
||||
.into_vec();
|
||||
let num_steps = test_sequence.len();
|
||||
gum::info!(
|
||||
"{}",
|
||||
format!("Sequence contains {} step(s)", num_steps).bright_purple()
|
||||
);
|
||||
for (index, test_config) in test_sequence.into_iter().enumerate() {
|
||||
let benchmark_name =
|
||||
format!("{} #{} {}", &options.path, index + 1, test_config.objective);
|
||||
gum::info!(target: LOG_TARGET, "{}", format!("Step {}/{}", index + 1, num_steps).bright_purple(),);
|
||||
display_configuration(&test_config);
|
||||
let test_sequence = core::configuration::TestSequence::new_from_file(Path::new(&self.path))
|
||||
.expect("File exists")
|
||||
.into_vec();
|
||||
let num_steps = test_sequence.len();
|
||||
gum::info!("{}", format!("Sequence contains {} step(s)", num_steps).bright_purple());
|
||||
for (index, test_config) in test_sequence.into_iter().enumerate() {
|
||||
let benchmark_name = format!("{} #{} {}", &self.path, index + 1, test_config.objective);
|
||||
gum::info!(target: LOG_TARGET, "{}", format!("Step {}/{}", index + 1, num_steps).bright_purple(),);
|
||||
display_configuration(&test_config);
|
||||
|
||||
let usage = match test_config.objective {
|
||||
TestObjective::DataAvailabilityRead(ref _opts) => {
|
||||
let mut state = TestState::new(&test_config);
|
||||
let (mut env, _protocol_config) = prepare_test(test_config, &mut state);
|
||||
env.runtime().block_on(availability::benchmark_availability_read(
|
||||
&benchmark_name,
|
||||
&mut env,
|
||||
state,
|
||||
))
|
||||
},
|
||||
TestObjective::ApprovalVoting(ref options) => {
|
||||
let (mut env, state) =
|
||||
approval::prepare_test(test_config.clone(), options.clone());
|
||||
env.runtime().block_on(bench_approvals(
|
||||
&benchmark_name,
|
||||
&mut env,
|
||||
state,
|
||||
))
|
||||
},
|
||||
TestObjective::DataAvailabilityWrite => {
|
||||
let mut state = TestState::new(&test_config);
|
||||
let (mut env, _protocol_config) = prepare_test(test_config, &mut state);
|
||||
env.runtime().block_on(availability::benchmark_availability_write(
|
||||
&benchmark_name,
|
||||
&mut env,
|
||||
state,
|
||||
))
|
||||
},
|
||||
TestObjective::TestSequence(_) => todo!(),
|
||||
TestObjective::Unimplemented => todo!(),
|
||||
};
|
||||
let usage = match test_config.objective {
|
||||
TestObjective::DataAvailabilityRead(ref _opts) => {
|
||||
let mut state = TestState::new(&test_config);
|
||||
let (mut env, _protocol_config) = prepare_test(test_config, &mut state);
|
||||
env.runtime().block_on(availability::benchmark_availability_read(
|
||||
&benchmark_name,
|
||||
&mut env,
|
||||
state,
|
||||
))
|
||||
},
|
||||
TestObjective::ApprovalVoting(ref options) => {
|
||||
let (mut env, state) =
|
||||
approval::prepare_test(test_config.clone(), options.clone());
|
||||
env.runtime().block_on(bench_approvals(&benchmark_name, &mut env, state))
|
||||
},
|
||||
TestObjective::DataAvailabilityWrite => {
|
||||
let mut state = TestState::new(&test_config);
|
||||
let (mut env, _protocol_config) = prepare_test(test_config, &mut state);
|
||||
env.runtime().block_on(availability::benchmark_availability_write(
|
||||
&benchmark_name,
|
||||
&mut env,
|
||||
state,
|
||||
))
|
||||
},
|
||||
TestObjective::Unimplemented => todo!(),
|
||||
};
|
||||
|
||||
let output = if self.yaml_output {
|
||||
serde_yaml::to_string(&vec![usage])?
|
||||
} else {
|
||||
usage.to_string()
|
||||
};
|
||||
println!("{}", output);
|
||||
}
|
||||
|
||||
return Ok(())
|
||||
},
|
||||
TestObjective::DataAvailabilityRead(ref _options) => self.create_test_configuration(),
|
||||
TestObjective::DataAvailabilityWrite => self.create_test_configuration(),
|
||||
TestObjective::ApprovalVoting(_) => todo!(),
|
||||
TestObjective::Unimplemented => todo!(),
|
||||
};
|
||||
|
||||
let mut latency_config = test_config.latency.clone().unwrap_or_default();
|
||||
|
||||
if let Some(latency) = self.peer_mean_latency {
|
||||
latency_config.mean_latency_ms = latency;
|
||||
let output = if self.yaml_output {
|
||||
serde_yaml::to_string(&vec![usage])?
|
||||
} else {
|
||||
usage.to_string()
|
||||
};
|
||||
println!("{}", output);
|
||||
}
|
||||
|
||||
if let Some(std_dev) = self.peer_latency_std_dev {
|
||||
latency_config.std_dev = std_dev;
|
||||
}
|
||||
|
||||
// Write back the updated latency.
|
||||
test_config.latency = Some(latency_config);
|
||||
|
||||
if let Some(connectivity) = self.connectivity {
|
||||
test_config.connectivity = connectivity;
|
||||
}
|
||||
|
||||
if let Some(bandwidth) = self.peer_bandwidth {
|
||||
// CLI expects bw in KiB
|
||||
test_config.peer_bandwidth = bandwidth * 1024;
|
||||
}
|
||||
|
||||
if let Some(bandwidth) = self.bandwidth {
|
||||
// CLI expects bw in KiB
|
||||
test_config.bandwidth = bandwidth * 1024;
|
||||
}
|
||||
|
||||
display_configuration(&test_config);
|
||||
|
||||
let mut state = TestState::new(&test_config);
|
||||
let (mut env, _protocol_config) = prepare_test(test_config, &mut state);
|
||||
|
||||
let benchmark_name = format!("{}", self.objective);
|
||||
let usage = match self.objective {
|
||||
TestObjective::DataAvailabilityRead(_options) => env.runtime().block_on(
|
||||
availability::benchmark_availability_read(&benchmark_name, &mut env, state),
|
||||
),
|
||||
TestObjective::DataAvailabilityWrite => env.runtime().block_on(
|
||||
availability::benchmark_availability_write(&benchmark_name, &mut env, state),
|
||||
),
|
||||
TestObjective::TestSequence(_options) => todo!(),
|
||||
TestObjective::ApprovalVoting(_) => todo!(),
|
||||
TestObjective::Unimplemented => todo!(),
|
||||
};
|
||||
|
||||
if let Some(agent_running) = agent_running {
|
||||
let agent_ready = agent_running.stop()?;
|
||||
agent_ready.shutdown();
|
||||
}
|
||||
|
||||
let output =
|
||||
if self.yaml_output { serde_yaml::to_string(&vec![usage])? } else { usage.to_string() };
|
||||
println!("{}", output);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user