Skip to content

Commit 9e6298e

Browse files
AndreiEressandreim
andauthored
subsystem-bench: Prepare CI output (paritytech#3158)
1. Benchmark results are collected in a single struct. 2. The output of the results is prettified. 3. The result struct used to save the output as a yaml and store it in artifacts in a CI job. ``` $ cargo run -p polkadot-subsystem-bench --release -- test-sequence --path polkadot/node/subsystem-bench/examples/availability_read.yaml | tee output.txt $ cat output.txt polkadot/node/subsystem-bench/examples/availability_read.yaml #1 Network usage, KiB total per block Received from peers 510796.000 170265.333 Sent to peers 221.000 73.667 CPU usage, s total per block availability-recovery 38.671 12.890 Test environment 0.255 0.085 polkadot/node/subsystem-bench/examples/availability_read.yaml #2 Network usage, KiB total per block Received from peers 413633.000 137877.667 Sent to peers 353.000 117.667 CPU usage, s total per block availability-recovery 52.630 17.543 Test environment 0.271 0.090 polkadot/node/subsystem-bench/examples/availability_read.yaml #3 Network usage, KiB total per block Received from peers 424379.000 141459.667 Sent to peers 703.000 234.333 CPU usage, s total per block availability-recovery 51.128 17.043 Test environment 0.502 0.167 ``` ``` $ cargo run -p polkadot-subsystem-bench --release -- --ci test-sequence --path polkadot/node/subsystem-bench/examples/availability_read.yaml | tee output.txt $ cat output.txt - benchmark_name: 'polkadot/node/subsystem-bench/examples/availability_read.yaml #1' network: - resource: Received from peers total: 509011.0 per_block: 169670.33333333334 - resource: Sent to peers total: 220.0 per_block: 73.33333333333333 cpu: - resource: availability-recovery total: 31.845848445 per_block: 10.615282815 - resource: Test environment total: 0.23582828799999941 per_block: 0.07860942933333313 - benchmark_name: 'polkadot/node/subsystem-bench/examples/availability_read.yaml #2' network: - resource: Received from peers total: 411738.0 per_block: 137246.0 - resource: Sent to peers total: 351.0 per_block: 117.0 cpu: - resource: availability-recovery total: 18.93596025099999 per_block: 6.31198675033333 - resource: Test environment total: 0.2541994199999979 per_block: 0.0847331399999993 - benchmark_name: 'polkadot/node/subsystem-bench/examples/availability_read.yaml #3' network: - resource: Received from peers total: 424548.0 per_block: 141516.0 - resource: Sent to peers total: 703.0 per_block: 234.33333333333334 cpu: - resource: availability-recovery total: 16.54178526900001 per_block: 5.513928423000003 - resource: Test environment total: 0.43960946299999537 per_block: 0.14653648766666513 ``` --------- Co-authored-by: Andrei Sandu <54316454+sandreim@users.noreply.github.com>
1 parent 8c1c99f commit 9e6298e

5 files changed

Lines changed: 173 additions & 75 deletions

File tree

polkadot/node/subsystem-bench/src/approval/mod.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ use crate::{
2929
},
3030
core::{
3131
configuration::{TestAuthorities, TestConfiguration},
32-
environment::{TestEnvironment, TestEnvironmentDependencies, MAX_TIME_OF_FLIGHT},
32+
environment::{
33+
BenchmarkUsage, TestEnvironment, TestEnvironmentDependencies, MAX_TIME_OF_FLIGHT,
34+
},
3335
mock::{
3436
dummy_builder,
3537
network_bridge::{MockNetworkBridgeRx, MockNetworkBridgeTx},
@@ -876,7 +878,11 @@ fn prepare_test_inner(
876878
)
877879
}
878880

879-
pub async fn bench_approvals(env: &mut TestEnvironment, mut state: ApprovalTestState) {
881+
pub async fn bench_approvals(
882+
benchmark_name: &str,
883+
env: &mut TestEnvironment,
884+
mut state: ApprovalTestState,
885+
) -> BenchmarkUsage {
880886
let producer_rx = state
881887
.start_message_production(
882888
env.network(),
@@ -885,15 +891,16 @@ pub async fn bench_approvals(env: &mut TestEnvironment, mut state: ApprovalTestS
885891
env.registry().clone(),
886892
)
887893
.await;
888-
bench_approvals_run(env, state, producer_rx).await
894+
bench_approvals_run(benchmark_name, env, state, producer_rx).await
889895
}
890896

891897
/// Runs the approval benchmark.
892898
pub async fn bench_approvals_run(
899+
benchmark_name: &str,
893900
env: &mut TestEnvironment,
894901
state: ApprovalTestState,
895902
producer_rx: oneshot::Receiver<()>,
896-
) {
903+
) -> BenchmarkUsage {
897904
let config = env.config().clone();
898905

899906
env.metrics().set_n_validators(config.n_validators);
@@ -1054,6 +1061,5 @@ pub async fn bench_approvals_run(
10541061
state.total_unique_messages.load(std::sync::atomic::Ordering::SeqCst)
10551062
);
10561063

1057-
env.display_network_usage();
1058-
env.display_cpu_usage(&["approval-distribution", "approval-voting"]);
1064+
env.collect_resource_usage(benchmark_name, &["approval-distribution", "approval-voting"])
10591065
}

polkadot/node/subsystem-bench/src/availability/mod.rs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
// You should have received a copy of the GNU General Public License
1515
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
16-
use crate::{core::mock::ChainApiState, TestEnvironment};
16+
use crate::{
17+
core::{environment::BenchmarkUsage, mock::ChainApiState},
18+
TestEnvironment,
19+
};
1720
use av_store::NetworkAvailabilityState;
1821
use bitvec::bitvec;
1922
use colored::Colorize;
@@ -430,7 +433,11 @@ impl TestState {
430433
}
431434
}
432435

433-
pub async fn benchmark_availability_read(env: &mut TestEnvironment, mut state: TestState) {
436+
pub async fn benchmark_availability_read(
437+
benchmark_name: &str,
438+
env: &mut TestEnvironment,
439+
mut state: TestState,
440+
) -> BenchmarkUsage {
434441
let config = env.config().clone();
435442

436443
env.import_block(new_block_import_info(Hash::repeat_byte(1), 1)).await;
@@ -490,12 +497,15 @@ pub async fn benchmark_availability_read(env: &mut TestEnvironment, mut state: T
490497
format!("{} ms", test_start.elapsed().as_millis() / env.config().num_blocks as u128).red()
491498
);
492499

493-
env.display_network_usage();
494-
env.display_cpu_usage(&["availability-recovery"]);
495500
env.stop().await;
501+
env.collect_resource_usage(benchmark_name, &["availability-recovery"])
496502
}
497503

498-
pub async fn benchmark_availability_write(env: &mut TestEnvironment, mut state: TestState) {
504+
pub async fn benchmark_availability_write(
505+
benchmark_name: &str,
506+
env: &mut TestEnvironment,
507+
mut state: TestState,
508+
) -> BenchmarkUsage {
499509
let config = env.config().clone();
500510

501511
env.metrics().set_n_validators(config.n_validators);
@@ -648,15 +658,11 @@ pub async fn benchmark_availability_write(env: &mut TestEnvironment, mut state:
648658
format!("{} ms", test_start.elapsed().as_millis() / env.config().num_blocks as u128).red()
649659
);
650660

651-
env.display_network_usage();
652-
653-
env.display_cpu_usage(&[
654-
"availability-distribution",
655-
"bitfield-distribution",
656-
"availability-store",
657-
]);
658-
659661
env.stop().await;
662+
env.collect_resource_usage(
663+
benchmark_name,
664+
&["availability-distribution", "bitfield-distribution", "availability-store"],
665+
)
660666
}
661667

662668
pub fn peer_bitfield_message_v2(

polkadot/node/subsystem-bench/src/cli.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@ pub enum TestObjective {
4040
Unimplemented,
4141
}
4242

43+
impl std::fmt::Display for TestObjective {
44+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45+
write!(
46+
f,
47+
"{}",
48+
match self {
49+
Self::DataAvailabilityRead(_) => "DataAvailabilityRead",
50+
Self::DataAvailabilityWrite => "DataAvailabilityWrite",
51+
Self::TestSequence(_) => "TestSequence",
52+
Self::ApprovalVoting(_) => "ApprovalVoting",
53+
Self::Unimplemented => "Unimplemented",
54+
}
55+
)
56+
}
57+
}
58+
4359
#[derive(Debug, clap::Parser)]
4460
#[clap(rename_all = "kebab-case")]
4561
#[allow(missing_docs)]

polkadot/node/subsystem-bench/src/core/environment.rs

Lines changed: 83 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use colored::Colorize;
2222
use core::time::Duration;
2323
use futures::{Future, FutureExt};
2424
use polkadot_overseer::{BlockInfo, Handle as OverseerHandle};
25+
use serde::{Deserialize, Serialize};
2526

2627
use polkadot_node_subsystem::{messages::AllMessages, Overseer, SpawnGlue, TimeoutExt};
2728
use polkadot_node_subsystem_types::Hash;
@@ -347,57 +348,102 @@ impl TestEnvironment {
347348
}
348349
}
349350

350-
/// Display network usage stats.
351-
pub fn display_network_usage(&self) {
352-
let stats = self.network().peer_stats(0);
353-
354-
let total_node_received = stats.received() / 1024;
355-
let total_node_sent = stats.sent() / 1024;
356-
357-
println!(
358-
"\nPayload bytes received from peers: {}, {}",
359-
format!("{:.2} KiB total", total_node_received).blue(),
360-
format!("{:.2} KiB/block", total_node_received / self.config().num_blocks)
361-
.bright_blue()
362-
);
351+
pub fn collect_resource_usage(
352+
&self,
353+
benchmark_name: &str,
354+
subsystems_under_test: &[&str],
355+
) -> BenchmarkUsage {
356+
BenchmarkUsage {
357+
benchmark_name: benchmark_name.to_string(),
358+
network_usage: self.network_usage(),
359+
cpu_usage: self.cpu_usage(subsystems_under_test),
360+
}
361+
}
363362

364-
println!(
365-
"Payload bytes sent to peers: {}, {}",
366-
format!("{:.2} KiB total", total_node_sent).blue(),
367-
format!("{:.2} KiB/block", total_node_sent / self.config().num_blocks).bright_blue()
368-
);
363+
fn network_usage(&self) -> Vec<ResourceUsage> {
364+
let stats = self.network().peer_stats(0);
365+
let total_node_received = (stats.received() / 1024) as f64;
366+
let total_node_sent = (stats.sent() / 1024) as f64;
367+
let num_blocks = self.config().num_blocks as f64;
368+
369+
vec![
370+
ResourceUsage {
371+
resource_name: "Received from peers".to_string(),
372+
total: total_node_received,
373+
per_block: total_node_received / num_blocks,
374+
},
375+
ResourceUsage {
376+
resource_name: "Sent to peers".to_string(),
377+
total: total_node_sent,
378+
per_block: total_node_sent / num_blocks,
379+
},
380+
]
369381
}
370382

371-
/// Print CPU usage stats in the CLI.
372-
pub fn display_cpu_usage(&self, subsystems_under_test: &[&str]) {
383+
fn cpu_usage(&self, subsystems_under_test: &[&str]) -> Vec<ResourceUsage> {
373384
let test_metrics = super::display::parse_metrics(self.registry());
385+
let mut usage = vec![];
386+
let num_blocks = self.config().num_blocks as f64;
374387

375388
for subsystem in subsystems_under_test.iter() {
376389
let subsystem_cpu_metrics =
377390
test_metrics.subset_with_label_value("task_group", subsystem);
378391
let total_cpu = subsystem_cpu_metrics.sum_by("substrate_tasks_polling_duration_sum");
379-
println!(
380-
"{} CPU usage {}",
381-
subsystem.to_string().bright_green(),
382-
format!("{:.3}s", total_cpu).bright_purple()
383-
);
384-
println!(
385-
"{} CPU usage per block {}",
386-
subsystem.to_string().bright_green(),
387-
format!("{:.3}s", total_cpu / self.config().num_blocks as f64).bright_purple()
388-
);
392+
usage.push(ResourceUsage {
393+
resource_name: subsystem.to_string(),
394+
total: total_cpu,
395+
per_block: total_cpu / num_blocks,
396+
});
389397
}
390398

391399
let test_env_cpu_metrics =
392400
test_metrics.subset_with_label_value("task_group", "test-environment");
393401
let total_cpu = test_env_cpu_metrics.sum_by("substrate_tasks_polling_duration_sum");
394-
println!(
395-
"Total test environment CPU usage {}",
396-
format!("{:.3}s", total_cpu).bright_purple()
397-
);
398-
println!(
399-
"Test environment CPU usage per block {}",
400-
format!("{:.3}s", total_cpu / self.config().num_blocks as f64).bright_purple()
402+
403+
usage.push(ResourceUsage {
404+
resource_name: "Test environment".to_string(),
405+
total: total_cpu,
406+
per_block: total_cpu / num_blocks,
407+
});
408+
409+
usage
410+
}
411+
}
412+
413+
#[derive(Debug, Serialize, Deserialize)]
414+
pub struct BenchmarkUsage {
415+
benchmark_name: String,
416+
network_usage: Vec<ResourceUsage>,
417+
cpu_usage: Vec<ResourceUsage>,
418+
}
419+
420+
impl std::fmt::Display for BenchmarkUsage {
421+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
422+
write!(
423+
f,
424+
"\n{}\n\n{}\n{}\n\n{}\n{}\n",
425+
self.benchmark_name.purple(),
426+
format!("{:<32}{:>12}{:>12}", "Network usage, KiB", "total", "per block").blue(),
427+
self.network_usage
428+
.iter()
429+
.map(|v| v.to_string())
430+
.collect::<Vec<String>>()
431+
.join("\n"),
432+
format!("{:<32}{:>12}{:>12}", "CPU usage in seconds", "total", "per block").blue(),
433+
self.cpu_usage.iter().map(|v| v.to_string()).collect::<Vec<String>>().join("\n")
401434
)
402435
}
403436
}
437+
438+
#[derive(Debug, Serialize, Deserialize)]
439+
pub struct ResourceUsage {
440+
resource_name: String,
441+
total: f64,
442+
per_block: f64,
443+
}
444+
445+
impl std::fmt::Display for ResourceUsage {
446+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
447+
write!(f, "{:<32}{:>12.3}{:>12.3}", self.resource_name.cyan(), self.total, self.per_block)
448+
}
449+
}

polkadot/node/subsystem-bench/src/subsystem-bench.rs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ struct BenchCli {
100100
/// Enable Cache Misses Profiling with Valgrind. Linux only, Valgrind must be in the PATH
101101
pub cache_misses: bool,
102102

103+
#[clap(long, default_value_t = false)]
104+
/// Shows the output in YAML format
105+
pub yaml_output: bool,
106+
103107
#[command(subcommand)]
104108
pub objective: cli::TestObjective,
105109
}
@@ -164,34 +168,51 @@ impl BenchCli {
164168
format!("Sequence contains {} step(s)", num_steps).bright_purple()
165169
);
166170
for (index, test_config) in test_sequence.into_iter().enumerate() {
171+
let benchmark_name =
172+
format!("{} #{} {}", &options.path, index + 1, test_config.objective);
167173
gum::info!(target: LOG_TARGET, "{}", format!("Step {}/{}", index + 1, num_steps).bright_purple(),);
168174
display_configuration(&test_config);
169175

170-
match test_config.objective {
176+
let usage = match test_config.objective {
171177
TestObjective::DataAvailabilityRead(ref _opts) => {
172178
let mut state = TestState::new(&test_config);
173179
let (mut env, _protocol_config) = prepare_test(test_config, &mut state);
174180
env.runtime().block_on(availability::benchmark_availability_read(
175-
&mut env, state,
176-
));
181+
&benchmark_name,
182+
&mut env,
183+
state,
184+
))
177185
},
178186
TestObjective::ApprovalVoting(ref options) => {
179187
let (mut env, state) =
180188
approval::prepare_test(test_config.clone(), options.clone());
181-
182-
env.runtime().block_on(bench_approvals(&mut env, state));
189+
env.runtime().block_on(bench_approvals(
190+
&benchmark_name,
191+
&mut env,
192+
state,
193+
))
183194
},
184195
TestObjective::DataAvailabilityWrite => {
185196
let mut state = TestState::new(&test_config);
186197
let (mut env, _protocol_config) = prepare_test(test_config, &mut state);
187198
env.runtime().block_on(availability::benchmark_availability_write(
188-
&mut env, state,
189-
));
199+
&benchmark_name,
200+
&mut env,
201+
state,
202+
))
190203
},
191204
TestObjective::TestSequence(_) => todo!(),
192205
TestObjective::Unimplemented => todo!(),
193-
}
206+
};
207+
208+
let output = if self.yaml_output {
209+
serde_yaml::to_string(&vec![usage])?
210+
} else {
211+
usage.to_string()
212+
};
213+
println!("{}", output);
194214
}
215+
195216
return Ok(())
196217
},
197218
TestObjective::DataAvailabilityRead(ref _options) => self.create_test_configuration(),
@@ -232,25 +253,28 @@ impl BenchCli {
232253
let mut state = TestState::new(&test_config);
233254
let (mut env, _protocol_config) = prepare_test(test_config, &mut state);
234255

235-
match self.objective {
236-
TestObjective::DataAvailabilityRead(_options) => {
237-
env.runtime()
238-
.block_on(availability::benchmark_availability_read(&mut env, state));
239-
},
240-
TestObjective::DataAvailabilityWrite => {
241-
env.runtime()
242-
.block_on(availability::benchmark_availability_write(&mut env, state));
243-
},
244-
TestObjective::TestSequence(_options) => {},
256+
let benchmark_name = format!("{}", self.objective);
257+
let usage = match self.objective {
258+
TestObjective::DataAvailabilityRead(_options) => env.runtime().block_on(
259+
availability::benchmark_availability_read(&benchmark_name, &mut env, state),
260+
),
261+
TestObjective::DataAvailabilityWrite => env.runtime().block_on(
262+
availability::benchmark_availability_write(&benchmark_name, &mut env, state),
263+
),
264+
TestObjective::TestSequence(_options) => todo!(),
245265
TestObjective::ApprovalVoting(_) => todo!(),
246266
TestObjective::Unimplemented => todo!(),
247-
}
267+
};
248268

249269
if let Some(agent_running) = agent_running {
250270
let agent_ready = agent_running.stop()?;
251271
agent_ready.shutdown();
252272
}
253273

274+
let output =
275+
if self.yaml_output { serde_yaml::to_string(&vec![usage])? } else { usage.to_string() };
276+
println!("{}", output);
277+
254278
Ok(())
255279
}
256280
}

0 commit comments

Comments
 (0)