From 9662dedbb35f2290e97468386c644ee0630f3be5 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Wed, 24 Jul 2024 17:02:00 +0300 Subject: [PATCH 01/11] Add benchmark for the number of the minimum cpu cores Signed-off-by: Alexandru Gheorghe --- polkadot/node/service/src/lib.rs | 20 ++++-- substrate/client/sysinfo/src/lib.rs | 14 ++-- substrate/client/sysinfo/src/sysinfo.rs | 69 ++++++++++++++++++- .../frame/benchmarking-cli/src/machine/mod.rs | 7 +- .../src/machine/reference_hardware.json | 4 ++ 5 files changed, 99 insertions(+), 15 deletions(-) diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index b4f63bd2aa06..85662af66372 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -765,6 +765,7 @@ pub fn new_full< use polkadot_availability_recovery::FETCH_CHUNKS_THRESHOLD; use polkadot_node_network_protocol::request_response::IncomingRequest; use sc_network_sync::WarpSyncParams; + use sc_sysinfo::Metric; let is_offchain_indexing_enabled = config.offchain_worker.indexing_enabled; let role = config.role.clone(); @@ -1082,11 +1083,20 @@ pub fn new_full< sc_sysinfo::print_hwbench(&hwbench); match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { Err(err) if role.is_authority() => { - log::warn!( - "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ - https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", - err - ); + if err.0.iter().any(|failure| failure.metric == Metric::Blake2256Parallel) { + log::info!( + "⚠️ The hardware will fail the minimal parallel performance requirements {} for role 'Authority', find out more when this will become mandatory at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err + ); + } + if err.0.iter().any(|failure| failure.metric != Metric::Blake2256Parallel) { + log::warn!( + "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + err + ); + } }, _ => {}, } diff --git a/substrate/client/sysinfo/src/lib.rs b/substrate/client/sysinfo/src/lib.rs index 7065c9b997e7..97ffcc51f6d3 100644 --- a/substrate/client/sysinfo/src/lib.rs +++ b/substrate/client/sysinfo/src/lib.rs @@ -27,10 +27,10 @@ mod sysinfo; mod sysinfo_linux; pub use sysinfo::{ - benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes, - benchmark_memory, benchmark_sr25519_verify, gather_hwbench, gather_sysinfo, - serialize_throughput, serialize_throughput_option, Metric, Requirement, Requirements, - Throughput, + benchmark_cpu, benchmark_cpu_parallelism, benchmark_disk_random_writes, + benchmark_disk_sequential_writes, benchmark_memory, benchmark_sr25519_verify, gather_hwbench, + gather_sysinfo, serialize_throughput, serialize_throughput_option, Metric, Requirement, + Requirements, Throughput, }; /// The operating system part of the current target triplet. @@ -48,6 +48,10 @@ pub struct HwBench { /// The CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 hash. #[serde(serialize_with = "serialize_throughput")] pub cpu_hashrate_score: Throughput, + /// The parallel CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 + /// hash, when using `EXPECTED_NUM_CORES` threads. + #[serde(serialize_with = "serialize_throughput")] + pub parallel_cpu_hashrate_score: Throughput, /// Memory bandwidth in MB/s, calculated by measuring the throughput of `memcpy`. #[serde(serialize_with = "serialize_throughput")] pub memory_memcpy_score: Throughput, @@ -65,6 +69,7 @@ pub struct HwBench { pub disk_random_write_score: Option, } +#[derive(Copy, Clone, Debug)] /// Limit the execution time of a benchmark. pub enum ExecutionLimit { /// Limit by the maximal duration. @@ -133,6 +138,7 @@ pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) { /// Prints out the results of the hardware benchmarks in the logs. pub fn print_hwbench(hwbench: &HwBench) { log::info!("🏁 CPU score: {}", hwbench.cpu_hashrate_score); + log::info!("🏁 CPU parallelism score: {}", hwbench.parallel_cpu_hashrate_score); log::info!("🏁 Memory score: {}", hwbench.memory_memcpy_score); if let Some(score) = hwbench.disk_sequential_write_score { diff --git a/substrate/client/sysinfo/src/sysinfo.rs b/substrate/client/sysinfo/src/sysinfo.rs index 37b35fcb9103..1fbaec23d210 100644 --- a/substrate/client/sysinfo/src/sysinfo.rs +++ b/substrate/client/sysinfo/src/sysinfo.rs @@ -22,16 +22,17 @@ use sc_telemetry::SysInfo; use sp_core::{sr25519, Pair}; use sp_io::crypto::sr25519_verify; +use core::f64; use derive_more::From; use rand::{seq::SliceRandom, Rng, RngCore}; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use std::{ - fmt, - fmt::{Display, Formatter}, + fmt::{self, Display, Formatter}, fs::File, io::{Seek, SeekFrom, Write}, ops::{Deref, DerefMut}, path::{Path, PathBuf}, + sync::{Arc, Barrier}, time::{Duration, Instant}, }; @@ -42,6 +43,8 @@ pub enum Metric { Sr25519Verify, /// Blake2-256 hashing algorithm. Blake2256, + /// Blake2-256 hashing algorithm executed in parallel. + Blake2256Parallel, /// Copying data in RAM. MemCopy, /// Disk sequential write. @@ -85,7 +88,7 @@ impl Metric { /// The category of the metric. pub fn category(&self) -> &'static str { match self { - Self::Sr25519Verify | Self::Blake2256 => "CPU", + Self::Sr25519Verify | Self::Blake2256 | Self::Blake2256Parallel => "CPU", Self::MemCopy => "Memory", Self::DiskSeqWrite | Self::DiskRndWrite => "Disk", } @@ -96,6 +99,7 @@ impl Metric { match self { Self::Sr25519Verify => "SR25519-Verify", Self::Blake2256 => "BLAKE2-256", + Self::Blake2256Parallel => "BLAKE2-256-Parallel", Self::MemCopy => "Copy", Self::DiskSeqWrite => "Seq Write", Self::DiskRndWrite => "Rnd Write", @@ -375,6 +379,49 @@ pub fn benchmark_cpu(limit: ExecutionLimit) -> Throughput { .expect("benchmark cannot fail; qed") } +// This benchmarks the entire CPU speed as measured by calculating BLAKE2b-256 hashes, in bytes per +// second. It spawns multiple threads to measure the throughput of the entire CPU and averages the +// score obtained by each thread. If we have at least `EXPECTED_NUM_CORES` available then the +// average throughput should be relatively close to the single core performance as measured by +// `benchmark_cpu`. +pub fn benchmark_cpu_parallelism(limit: ExecutionLimit) -> Throughput { + const SIZE: usize = 32 * 1024; + const EXPECTED_NUM_CORES: usize = 8; + + let ready_to_run_benchmark = Arc::new(Barrier::new(EXPECTED_NUM_CORES)); + let mut benchmark_threads = Vec::new(); + + // Spawn a thread for each expected core and average the throughput for each of them. + for _ in 0..EXPECTED_NUM_CORES { + let ready_to_run_benchmark = ready_to_run_benchmark.clone(); + + let handle = std::thread::spawn(move || { + let mut buffer = Vec::new(); + buffer.resize(SIZE, 0x66); + let mut hash = Default::default(); + + let run = || -> Result<(), ()> { + clobber_slice(&mut buffer); + hash = sp_crypto_hashing::blake2_256(&buffer); + clobber_slice(&mut hash); + + Ok(()) + }; + ready_to_run_benchmark.wait(); + benchmark("CPU score", SIZE, limit.max_iterations(), limit.max_duration(), run) + .expect("benchmark cannot fail; qed") + }); + benchmark_threads.push(handle); + } + + let average_score = benchmark_threads + .into_iter() + .map(|thread| thread.join().map(|throughput| throughput.as_kibs()).unwrap_or(f64::MIN)) + .sum::() / + EXPECTED_NUM_CORES as f64; + Throughput::from_kibs(average_score) +} + /// A default [`ExecutionLimit`] that can be used to call [`benchmark_memory`]. pub const DEFAULT_MEMORY_EXECUTION_LIMIT: ExecutionLimit = ExecutionLimit::Both { max_iterations: 32, max_duration: Duration::from_millis(100) }; @@ -628,6 +675,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { #[allow(unused_mut)] let mut hwbench = HwBench { cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT), + parallel_cpu_hashrate_score: benchmark_cpu_parallelism(DEFAULT_CPU_EXECUTION_LIMIT), memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT), disk_sequential_write_score: None, disk_random_write_score: None, @@ -671,6 +719,14 @@ impl Requirements { found: hwbench.cpu_hashrate_score, }); }, + Metric::Blake2256Parallel => + if requirement.minimum > hwbench.parallel_cpu_hashrate_score { + failures.push(CheckFailure { + metric: requirement.metric, + expected: requirement.minimum, + found: hwbench.parallel_cpu_hashrate_score, + }); + }, Metric::MemCopy => if requirement.minimum > hwbench.memory_memcpy_score { failures.push(CheckFailure { @@ -732,6 +788,13 @@ mod tests { assert!(benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT) > Throughput::from_mibs(0.0)); } + #[test] + fn test_benchmark_parallel_cpu() { + assert!( + benchmark_cpu_parallelism(DEFAULT_CPU_EXECUTION_LIMIT) > Throughput::from_mibs(0.0) + ); + } + #[test] fn test_benchmark_memory() { assert!(benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) > Throughput::from_mibs(0.0)); diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/mod.rs b/substrate/utils/frame/benchmarking-cli/src/machine/mod.rs index fb9f14c9a4af..fdb8e88ee2d0 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -29,9 +29,9 @@ use log::{error, info, warn}; use sc_cli::{CliConfiguration, Result, SharedParams}; use sc_service::Configuration; use sc_sysinfo::{ - benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes, - benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, Metric, Requirement, Requirements, - Throughput, + benchmark_cpu, benchmark_cpu_parallelism, benchmark_disk_random_writes, + benchmark_disk_sequential_writes, benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, + Metric, Requirement, Requirements, Throughput, }; use crate::shared::check_build_profile; @@ -150,6 +150,7 @@ impl MachineCmd { let score = match metric { Metric::Blake2256 => benchmark_cpu(hash_limit), + Metric::Blake2256Parallel => benchmark_cpu_parallelism(hash_limit), Metric::Sr25519Verify => benchmark_sr25519_verify(verify_limit), Metric::MemCopy => benchmark_memory(memory_limit), Metric::DiskSeqWrite => benchmark_disk_sequential_writes(disk_limit, dir)?, diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json b/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json index c2fb4c7d4a28..cb07c44438d3 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json +++ b/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json @@ -3,6 +3,10 @@ "metric": "Blake2256", "minimum": 783.27 }, + { + "metric": "Blake2256Parallel", + "minimum": 783.27 + }, { "metric": "Sr25519Verify", "minimum": 0.547529297 From 213953c03591d6afe376334ec7ad04172289ccbb Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Wed, 24 Jul 2024 18:02:51 +0300 Subject: [PATCH 02/11] Make clippy happy Signed-off-by: Alexandru Gheorghe --- substrate/client/sysinfo/src/sysinfo.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substrate/client/sysinfo/src/sysinfo.rs b/substrate/client/sysinfo/src/sysinfo.rs index 1fbaec23d210..418adf6fb328 100644 --- a/substrate/client/sysinfo/src/sysinfo.rs +++ b/substrate/client/sysinfo/src/sysinfo.rs @@ -844,6 +844,7 @@ mod tests { fn hwbench_serialize_works() { let hwbench = HwBench { cpu_hashrate_score: Throughput::from_gibs(1.32), + parallel_cpu_hashrate_score: Throughput::from_gibs(1.32), memory_memcpy_score: Throughput::from_kibs(9342.432), disk_sequential_write_score: Some(Throughput::from_kibs(4332.12)), disk_random_write_score: None, @@ -851,6 +852,6 @@ mod tests { let serialized = serde_json::to_string(&hwbench).unwrap(); // Throughput from all of the benchmarks should be converted to MiBs. - assert_eq!(serialized, "{\"cpu_hashrate_score\":1351,\"memory_memcpy_score\":9,\"disk_sequential_write_score\":4}"); + assert_eq!(serialized, "{\"cpu_hashrate_score\":1351,\"parallel_cpu_hashrate_score\":1351,\"memory_memcpy_score\":9,\"disk_sequential_write_score\":4}"); } } From 62f00f6ab8db987f7f440bc0c450356b9ae092bf Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Thu, 25 Jul 2024 14:16:35 +0300 Subject: [PATCH 03/11] Make benchmark parametrizable Signed-off-by: Alexandru Gheorghe --- cumulus/polkadot-parachain/src/command.rs | 5 +- cumulus/polkadot-parachain/src/service.rs | 4 +- polkadot/cli/src/command.rs | 2 +- polkadot/node/service/src/lib.rs | 14 ++++- substrate/bin/node/cli/src/service.rs | 4 +- substrate/client/sysinfo/src/sysinfo.rs | 56 ++++++++++++++----- .../benchmarking-cli/src/machine/hardware.rs | 25 ++++++++- .../frame/benchmarking-cli/src/machine/mod.rs | 3 +- .../src/machine/reference_hardware.json | 5 +- templates/parachain/node/src/command.rs | 5 +- templates/parachain/node/src/service.rs | 2 +- 11 files changed, 95 insertions(+), 30 deletions(-) diff --git a/cumulus/polkadot-parachain/src/command.rs b/cumulus/polkadot-parachain/src/command.rs index e867a41bee2b..865f44c656b4 100644 --- a/cumulus/polkadot-parachain/src/command.rs +++ b/cumulus/polkadot-parachain/src/command.rs @@ -559,7 +559,10 @@ pub fn run() -> Result<()> { let hwbench = (!cli.no_hardware_benchmarks) .then_some(config.database.path().map(|database_path| { let _ = std::fs::create_dir_all(database_path); - sc_sysinfo::gather_hwbench(Some(database_path)) + sc_sysinfo::gather_hwbench( + Some(database_path), + &SUBSTRATE_REFERENCE_HARDWARE, + ) })) .flatten(); diff --git a/cumulus/polkadot-parachain/src/service.rs b/cumulus/polkadot-parachain/src/service.rs index ef01f7f1f6a6..d69bc495b2dc 100644 --- a/cumulus/polkadot-parachain/src/service.rs +++ b/cumulus/polkadot-parachain/src/service.rs @@ -849,7 +849,9 @@ where fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { // Polkadot para-chains should generally use these requirements to ensure that the relay-chain // will not take longer than expected to import its blocks. - if let Err(err) = frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { + if let Err(err) = + frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench, false) + { log::warn!( "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", diff --git a/polkadot/cli/src/command.rs b/polkadot/cli/src/command.rs index 62d99122c301..168a645430ed 100644 --- a/polkadot/cli/src/command.rs +++ b/polkadot/cli/src/command.rs @@ -230,7 +230,7 @@ where let hwbench = (!cli.run.no_hardware_benchmarks) .then_some(config.database.path().map(|database_path| { let _ = std::fs::create_dir_all(&database_path); - sc_sysinfo::gather_hwbench(Some(database_path)) + sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE) })) .flatten(); diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 85662af66372..47f9faabfe6b 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -1081,16 +1081,24 @@ pub fn new_full< if let Some(hwbench) = hwbench { sc_sysinfo::print_hwbench(&hwbench); - match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { + match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench, role.is_authority()) { Err(err) if role.is_authority() => { - if err.0.iter().any(|failure| failure.metric == Metric::Blake2256Parallel) { + if err + .0 + .iter() + .any(|failure| matches!(failure.metric, Metric::Blake2256Parallel { .. })) + { log::info!( "⚠️ The hardware will fail the minimal parallel performance requirements {} for role 'Authority', find out more when this will become mandatory at:\n\ https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", err ); } - if err.0.iter().any(|failure| failure.metric != Metric::Blake2256Parallel) { + if err + .0 + .iter() + .any(|failure| !matches!(failure.metric, Metric::Blake2256Parallel { .. })) + { log::warn!( "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority' find out more at:\n\ https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", diff --git a/substrate/bin/node/cli/src/service.rs b/substrate/bin/node/cli/src/service.rs index e57ca04f3b74..ddc06ecefc06 100644 --- a/substrate/bin/node/cli/src/service.rs +++ b/substrate/bin/node/cli/src/service.rs @@ -418,7 +418,7 @@ pub fn new_full_base::Hash>>( let hwbench = (!disable_hardware_benchmarks) .then_some(config.database.path().map(|database_path| { let _ = std::fs::create_dir_all(&database_path); - sc_sysinfo::gather_hwbench(Some(database_path)) + sc_sysinfo::gather_hwbench(Some(database_path), &SUBSTRATE_REFERENCE_HARDWARE) })) .flatten(); @@ -553,7 +553,7 @@ pub fn new_full_base::Hash>>( if let Some(hwbench) = hwbench { sc_sysinfo::print_hwbench(&hwbench); - match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { + match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench, false) { Err(err) if role.is_authority() => { log::warn!( "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority'.", diff --git a/substrate/client/sysinfo/src/sysinfo.rs b/substrate/client/sysinfo/src/sysinfo.rs index 418adf6fb328..9dd71c395f16 100644 --- a/substrate/client/sysinfo/src/sysinfo.rs +++ b/substrate/client/sysinfo/src/sysinfo.rs @@ -43,8 +43,8 @@ pub enum Metric { Sr25519Verify, /// Blake2-256 hashing algorithm. Blake2256, - /// Blake2-256 hashing algorithm executed in parallel. - Blake2256Parallel, + /// Blake2-256 hashing algorithm executed in parallel + Blake2256Parallel { num_cores: usize }, /// Copying data in RAM. MemCopy, /// Disk sequential write. @@ -88,7 +88,7 @@ impl Metric { /// The category of the metric. pub fn category(&self) -> &'static str { match self { - Self::Sr25519Verify | Self::Blake2256 | Self::Blake2256Parallel => "CPU", + Self::Sr25519Verify | Self::Blake2256 | Self::Blake2256Parallel { .. } => "CPU", Self::MemCopy => "Memory", Self::DiskSeqWrite | Self::DiskRndWrite => "Disk", } @@ -99,7 +99,8 @@ impl Metric { match self { Self::Sr25519Verify => "SR25519-Verify", Self::Blake2256 => "BLAKE2-256", - Self::Blake2256Parallel => "BLAKE2-256-Parallel", + Self::Blake2256Parallel { num_cores } => + format!("BLAKE2-256-Parallel-{}", num_cores).leak(), Self::MemCopy => "Copy", Self::DiskSeqWrite => "Seq Write", Self::DiskRndWrite => "Rnd Write", @@ -257,6 +258,14 @@ pub struct Requirement { deserialize_with = "deserialize_throughput" )] pub minimum: Throughput, + /// Check this requirement only for relay chain authority nodes. + #[serde(default)] + #[serde(skip_serializing_if = "is_false")] + pub check_on_rc_authority: bool, +} + +fn is_false(value: &bool) -> bool { + !value } #[inline(always)] @@ -384,15 +393,14 @@ pub fn benchmark_cpu(limit: ExecutionLimit) -> Throughput { // score obtained by each thread. If we have at least `EXPECTED_NUM_CORES` available then the // average throughput should be relatively close to the single core performance as measured by // `benchmark_cpu`. -pub fn benchmark_cpu_parallelism(limit: ExecutionLimit) -> Throughput { +pub fn benchmark_cpu_parallelism(limit: ExecutionLimit, refhw_num_cores: usize) -> Throughput { const SIZE: usize = 32 * 1024; - const EXPECTED_NUM_CORES: usize = 8; - let ready_to_run_benchmark = Arc::new(Barrier::new(EXPECTED_NUM_CORES)); + let ready_to_run_benchmark = Arc::new(Barrier::new(refhw_num_cores)); let mut benchmark_threads = Vec::new(); // Spawn a thread for each expected core and average the throughput for each of them. - for _ in 0..EXPECTED_NUM_CORES { + for _ in 0..refhw_num_cores { let ready_to_run_benchmark = ready_to_run_benchmark.clone(); let handle = std::thread::spawn(move || { @@ -418,7 +426,7 @@ pub fn benchmark_cpu_parallelism(limit: ExecutionLimit) -> Throughput { .into_iter() .map(|thread| thread.join().map(|throughput| throughput.as_kibs()).unwrap_or(f64::MIN)) .sum::() / - EXPECTED_NUM_CORES as f64; + refhw_num_cores as f64; Throughput::from_kibs(average_score) } @@ -671,11 +679,23 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> Throughput { /// Optionally accepts a path to a `scratch_directory` to use to benchmark the /// disk. Also accepts the `requirements` for the hardware benchmark and a /// boolean to specify if the node is an authority. -pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { +pub fn gather_hwbench(scratch_directory: Option<&Path>, requirements: &Requirements) -> HwBench { + let parallel_num_cores = requirements + .0 + .iter() + .filter_map(|requirement| match requirement.metric { + Metric::Blake2256Parallel { num_cores } => Some(num_cores), + _ => None, + }) + .next() + .unwrap_or(1); #[allow(unused_mut)] let mut hwbench = HwBench { cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT), - parallel_cpu_hashrate_score: benchmark_cpu_parallelism(DEFAULT_CPU_EXECUTION_LIMIT), + parallel_cpu_hashrate_score: benchmark_cpu_parallelism( + DEFAULT_CPU_EXECUTION_LIMIT, + parallel_num_cores, + ), memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT), disk_sequential_write_score: None, disk_random_write_score: None, @@ -707,9 +727,17 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { impl Requirements { /// Whether the hardware requirements are met by the provided benchmark results. - pub fn check_hardware(&self, hwbench: &HwBench) -> Result<(), CheckFailures> { + pub fn check_hardware( + &self, + hwbench: &HwBench, + is_rc_authority: bool, + ) -> Result<(), CheckFailures> { let mut failures = Vec::new(); for requirement in self.0.iter() { + if requirement.check_on_rc_authority && !is_rc_authority { + continue + } + match requirement.metric { Metric::Blake2256 => if requirement.minimum > hwbench.cpu_hashrate_score { @@ -719,7 +747,7 @@ impl Requirements { found: hwbench.cpu_hashrate_score, }); }, - Metric::Blake2256Parallel => + Metric::Blake2256Parallel { .. } => if requirement.minimum > hwbench.parallel_cpu_hashrate_score { failures.push(CheckFailure { metric: requirement.metric, @@ -791,7 +819,7 @@ mod tests { #[test] fn test_benchmark_parallel_cpu() { assert!( - benchmark_cpu_parallelism(DEFAULT_CPU_EXECUTION_LIMIT) > Throughput::from_mibs(0.0) + benchmark_cpu_parallelism(DEFAULT_CPU_EXECUTION_LIMIT, 8) > Throughput::from_mibs(0.0) ); } diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs index 5a4b7c797b6f..6611130f4abe 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -51,17 +51,36 @@ mod tests { assert_eq!( *SUBSTRATE_REFERENCE_HARDWARE, Requirements(vec![ - Requirement { metric: Metric::Blake2256, minimum: Throughput::from_mibs(783.27) }, + Requirement { + metric: Metric::Blake2256, + minimum: Throughput::from_mibs(783.27), + check_on_rc_authority: false + }, + Requirement { + metric: Metric::Blake2256Parallel { num_cores: 8 }, + minimum: Throughput::from_mibs(783.27), + check_on_rc_authority: true, + }, Requirement { metric: Metric::Sr25519Verify, minimum: Throughput::from_kibs(560.670000128), + check_on_rc_authority: false }, Requirement { metric: Metric::MemCopy, minimum: Throughput::from_gibs(11.4925205078125003), + check_on_rc_authority: false, + }, + Requirement { + metric: Metric::DiskSeqWrite, + minimum: Throughput::from_mibs(950.0), + check_on_rc_authority: false, + }, + Requirement { + metric: Metric::DiskRndWrite, + minimum: Throughput::from_mibs(420.0), + check_on_rc_authority: false }, - Requirement { metric: Metric::DiskSeqWrite, minimum: Throughput::from_mibs(950.0) }, - Requirement { metric: Metric::DiskRndWrite, minimum: Throughput::from_mibs(420.0) }, ]) ); } diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/mod.rs b/substrate/utils/frame/benchmarking-cli/src/machine/mod.rs index fdb8e88ee2d0..0186ca58762d 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/mod.rs +++ b/substrate/utils/frame/benchmarking-cli/src/machine/mod.rs @@ -150,7 +150,8 @@ impl MachineCmd { let score = match metric { Metric::Blake2256 => benchmark_cpu(hash_limit), - Metric::Blake2256Parallel => benchmark_cpu_parallelism(hash_limit), + Metric::Blake2256Parallel { num_cores } => + benchmark_cpu_parallelism(hash_limit, *num_cores), Metric::Sr25519Verify => benchmark_sr25519_verify(verify_limit), Metric::MemCopy => benchmark_memory(memory_limit), Metric::DiskSeqWrite => benchmark_disk_sequential_writes(disk_limit, dir)?, diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json b/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json index cb07c44438d3..4383c6718435 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json +++ b/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json @@ -4,8 +4,9 @@ "minimum": 783.27 }, { - "metric": "Blake2256Parallel", - "minimum": 783.27 + "metric": {"Blake2256Parallel":{"num_cores":8}}, + "minimum": 783.27, + "check_on_rc_authority": true }, { "metric": "Sr25519Verify", diff --git a/templates/parachain/node/src/command.rs b/templates/parachain/node/src/command.rs index eba7fdcdae71..b97e34049ce2 100644 --- a/templates/parachain/node/src/command.rs +++ b/templates/parachain/node/src/command.rs @@ -222,7 +222,10 @@ pub fn run() -> Result<()> { let hwbench = (!cli.no_hardware_benchmarks) .then_some(config.database.path().map(|database_path| { let _ = std::fs::create_dir_all(database_path); - sc_sysinfo::gather_hwbench(Some(database_path)) + sc_sysinfo::gather_hwbench( + Some(database_path), + &SUBSTRATE_REFERENCE_HARDWARE, + ) })) .flatten(); diff --git a/templates/parachain/node/src/service.rs b/templates/parachain/node/src/service.rs index 3e7d4de10553..5d10108200f7 100644 --- a/templates/parachain/node/src/service.rs +++ b/templates/parachain/node/src/service.rs @@ -335,7 +335,7 @@ pub async fn start_parachain_node( // Here you can check whether the hardware meets your chains' requirements. Putting a link // in there and swapping out the requirements for your own are probably a good idea. The // requirements for a para-chain are dictated by its relay-chain. - match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) { + match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench, false) { Err(err) if validator => { log::warn!( "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority'.", From 05c98749ee553f3ae6c600b859037ec47dce6e42 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Fri, 26 Jul 2024 08:52:37 +0300 Subject: [PATCH 04/11] Fix comment Signed-off-by: Alexandru Gheorghe --- polkadot/node/service/src/lib.rs | 2 +- substrate/client/sysinfo/src/lib.rs | 4 ++-- substrate/client/sysinfo/src/sysinfo.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 47f9faabfe6b..5169514ee404 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -1089,7 +1089,7 @@ pub fn new_full< .any(|failure| matches!(failure.metric, Metric::Blake2256Parallel { .. })) { log::info!( - "⚠️ The hardware will fail the minimal parallel performance requirements {} for role 'Authority', find out more when this will become mandatory at:\n\ + "⚠️ The hardware will fail the minimal physical CPU cores requirements {} for role 'Authority', find out more when this will become mandatory at:\n\ https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", err ); diff --git a/substrate/client/sysinfo/src/lib.rs b/substrate/client/sysinfo/src/lib.rs index 97ffcc51f6d3..f7f6c3962c81 100644 --- a/substrate/client/sysinfo/src/lib.rs +++ b/substrate/client/sysinfo/src/lib.rs @@ -48,8 +48,8 @@ pub struct HwBench { /// The CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 hash. #[serde(serialize_with = "serialize_throughput")] pub cpu_hashrate_score: Throughput, - /// The parallel CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 - /// hash, when using `EXPECTED_NUM_CORES` threads. + /// The parallel CPU speed, as measured in how many MB/s it can hash in parallel using the + /// BLAKE2b-256 hash. #[serde(serialize_with = "serialize_throughput")] pub parallel_cpu_hashrate_score: Throughput, /// Memory bandwidth in MB/s, calculated by measuring the throughput of `memcpy`. diff --git a/substrate/client/sysinfo/src/sysinfo.rs b/substrate/client/sysinfo/src/sysinfo.rs index 9dd71c395f16..b9df295b4654 100644 --- a/substrate/client/sysinfo/src/sysinfo.rs +++ b/substrate/client/sysinfo/src/sysinfo.rs @@ -390,7 +390,7 @@ pub fn benchmark_cpu(limit: ExecutionLimit) -> Throughput { // This benchmarks the entire CPU speed as measured by calculating BLAKE2b-256 hashes, in bytes per // second. It spawns multiple threads to measure the throughput of the entire CPU and averages the -// score obtained by each thread. If we have at least `EXPECTED_NUM_CORES` available then the +// score obtained by each thread. If we have at least `refhw_num_cores` available then the // average throughput should be relatively close to the single core performance as measured by // `benchmark_cpu`. pub fn benchmark_cpu_parallelism(limit: ExecutionLimit, refhw_num_cores: usize) -> Throughput { From 0df211c4c8824179418138cb6fbdc3c3dd197665 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Wed, 31 Jul 2024 13:29:12 +0300 Subject: [PATCH 05/11] Update parallel with the reference_hw value Signed-off-by: Alexandru Gheorghe --- substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs | 2 +- .../frame/benchmarking-cli/src/machine/reference_hardware.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs index 6611130f4abe..6c805779e9e4 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -58,7 +58,7 @@ mod tests { }, Requirement { metric: Metric::Blake2256Parallel { num_cores: 8 }, - minimum: Throughput::from_mibs(783.27), + minimum: Throughput::from_mibs(966.43), check_on_rc_authority: true, }, Requirement { diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json b/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json index 4383c6718435..c9ef714d3ec1 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json +++ b/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json @@ -5,7 +5,7 @@ }, { "metric": {"Blake2256Parallel":{"num_cores":8}}, - "minimum": 783.27, + "minimum": 966.43, "check_on_rc_authority": true }, { From 48f3d0f54e5c44dc9afcd67aaa5bb9884668532a Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Wed, 14 Aug 2024 17:37:30 +0300 Subject: [PATCH 06/11] Update warning tests Signed-off-by: Alexandru Gheorghe --- polkadot/node/service/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 4d38228b590a..7736d4c037ee 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -1091,8 +1091,9 @@ pub fn new_full< .any(|failure| matches!(failure.metric, Metric::Blake2256Parallel { .. })) { log::info!( - "⚠️ The hardware will fail the minimal physical CPU cores requirements {} for role 'Authority', find out more when this will become mandatory at:\n\ - https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", + "⚠️ Starting January 2025 the hardware will fail the minimal physical CPU cores requirements {} for role 'Authority',\n\ + find out more when this will become mandatory at:\n\ + https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", err ); } From 2892f94591c6f7f8cdfd7cd779917b544d58a11e Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Wed, 28 Aug 2024 17:58:01 +0300 Subject: [PATCH 07/11] Address review findings Signed-off-by: Alexandru Gheorghe --- polkadot/node/service/src/lib.rs | 2 +- substrate/client/sysinfo/src/lib.rs | 7 ++- substrate/client/sysinfo/src/sysinfo.rs | 57 ++++++++++--------------- 3 files changed, 28 insertions(+), 38 deletions(-) diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs index 7736d4c037ee..29be611c1068 100644 --- a/polkadot/node/service/src/lib.rs +++ b/polkadot/node/service/src/lib.rs @@ -1090,7 +1090,7 @@ pub fn new_full< .iter() .any(|failure| matches!(failure.metric, Metric::Blake2256Parallel { .. })) { - log::info!( + log::warn!( "⚠️ Starting January 2025 the hardware will fail the minimal physical CPU cores requirements {} for role 'Authority',\n\ find out more when this will become mandatory at:\n\ https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware", diff --git a/substrate/client/sysinfo/src/lib.rs b/substrate/client/sysinfo/src/lib.rs index f7f6c3962c81..302a44c24adb 100644 --- a/substrate/client/sysinfo/src/lib.rs +++ b/substrate/client/sysinfo/src/lib.rs @@ -137,8 +137,11 @@ pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) { /// Prints out the results of the hardware benchmarks in the logs. pub fn print_hwbench(hwbench: &HwBench) { - log::info!("🏁 CPU score: {}", hwbench.cpu_hashrate_score); - log::info!("🏁 CPU parallelism score: {}", hwbench.parallel_cpu_hashrate_score); + log::info!( + "🏁 CPU single core score: {}, parallelism score: {}", + hwbench.cpu_hashrate_score, + hwbench.parallel_cpu_hashrate_score, + ); log::info!("🏁 Memory score: {}", hwbench.memory_memcpy_score); if let Some(score) = hwbench.disk_sequential_write_score { diff --git a/substrate/client/sysinfo/src/sysinfo.rs b/substrate/client/sysinfo/src/sysinfo.rs index b9df295b4654..f25963e73297 100644 --- a/substrate/client/sysinfo/src/sysinfo.rs +++ b/substrate/client/sysinfo/src/sysinfo.rs @@ -106,6 +106,14 @@ impl Metric { Self::DiskRndWrite => "Rnd Write", } } + + /// The number of cores used in the parallel BLAKE2-256 hashing. + pub fn num_cores(&self) -> Option { + match self { + Self::Blake2256Parallel { num_cores } => Some(*num_cores), + _ => None, + } + } } /// The unit in which the [`Throughput`] (bytes per second) is denoted. @@ -260,14 +268,10 @@ pub struct Requirement { pub minimum: Throughput, /// Check this requirement only for relay chain authority nodes. #[serde(default)] - #[serde(skip_serializing_if = "is_false")] + #[serde(skip_serializing_if = "core::ops::Not::not")] pub check_on_rc_authority: bool, } -fn is_false(value: &bool) -> bool { - !value -} - #[inline(always)] pub(crate) fn benchmark( name: &str, @@ -356,8 +360,18 @@ fn clobber_value(input: &mut T) { pub const DEFAULT_CPU_EXECUTION_LIMIT: ExecutionLimit = ExecutionLimit::Both { max_iterations: 4 * 1024, max_duration: Duration::from_millis(100) }; -// This benchmarks the CPU speed as measured by calculating BLAKE2b-256 hashes, in bytes per second. +// This benchmarks the single core CPU speed as measured by calculating BLAKE2b-256 hashes, in bytes +// per second. pub fn benchmark_cpu(limit: ExecutionLimit) -> Throughput { + benchmark_cpu_parallelism(limit, 1) +} + +// This benchmarks the entire CPU speed as measured by calculating BLAKE2b-256 hashes, in bytes per +// second. It spawns multiple threads to measure the throughput of the entire CPU and averages the +// score obtained by each thread. If we have at least `refhw_num_cores` available then the +// average throughput should be relatively close to the single core performance as measured by +// calling this function with refhw_num_cores equal to 1. +pub fn benchmark_cpu_parallelism(limit: ExecutionLimit, refhw_num_cores: usize) -> Throughput { // In general the results of this benchmark are somewhat sensitive to how much // data we hash at the time. The smaller this is the *less* B/s we can hash, // the bigger this is the *more* B/s we can hash, up until a certain point @@ -372,30 +386,6 @@ pub fn benchmark_cpu(limit: ExecutionLimit) -> Throughput { // but without hitting its theoretical maximum speed. const SIZE: usize = 32 * 1024; - let mut buffer = Vec::new(); - buffer.resize(SIZE, 0x66); - let mut hash = Default::default(); - - let run = || -> Result<(), ()> { - clobber_slice(&mut buffer); - hash = sp_crypto_hashing::blake2_256(&buffer); - clobber_slice(&mut hash); - - Ok(()) - }; - - benchmark("CPU score", SIZE, limit.max_iterations(), limit.max_duration(), run) - .expect("benchmark cannot fail; qed") -} - -// This benchmarks the entire CPU speed as measured by calculating BLAKE2b-256 hashes, in bytes per -// second. It spawns multiple threads to measure the throughput of the entire CPU and averages the -// score obtained by each thread. If we have at least `refhw_num_cores` available then the -// average throughput should be relatively close to the single core performance as measured by -// `benchmark_cpu`. -pub fn benchmark_cpu_parallelism(limit: ExecutionLimit, refhw_num_cores: usize) -> Throughput { - const SIZE: usize = 32 * 1024; - let ready_to_run_benchmark = Arc::new(Barrier::new(refhw_num_cores)); let mut benchmark_threads = Vec::new(); @@ -424,7 +414,7 @@ pub fn benchmark_cpu_parallelism(limit: ExecutionLimit, refhw_num_cores: usize) let average_score = benchmark_threads .into_iter() - .map(|thread| thread.join().map(|throughput| throughput.as_kibs()).unwrap_or(f64::MIN)) + .map(|thread| thread.join().map(|throughput| throughput.as_kibs()).unwrap_or(0.0)) .sum::() / refhw_num_cores as f64; Throughput::from_kibs(average_score) @@ -683,10 +673,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>, requirements: &Requireme let parallel_num_cores = requirements .0 .iter() - .filter_map(|requirement| match requirement.metric { - Metric::Blake2256Parallel { num_cores } => Some(num_cores), - _ => None, - }) + .filter_map(|requirement| requirement.metric.num_cores()) .next() .unwrap_or(1); #[allow(unused_mut)] From d3d5bab2dc1e5a585eeecfcd6219f9009bb325e3 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Thu, 29 Aug 2024 12:07:51 +0300 Subject: [PATCH 08/11] Address review findings Signed-off-by: Alexandru Gheorghe --- substrate/client/sysinfo/src/sysinfo.rs | 49 +++++++++---------- .../benchmarking-cli/src/machine/hardware.rs | 12 ++--- .../src/machine/reference_hardware.json | 2 +- 3 files changed, 30 insertions(+), 33 deletions(-) diff --git a/substrate/client/sysinfo/src/sysinfo.rs b/substrate/client/sysinfo/src/sysinfo.rs index f25963e73297..c291be1089ed 100644 --- a/substrate/client/sysinfo/src/sysinfo.rs +++ b/substrate/client/sysinfo/src/sysinfo.rs @@ -27,6 +27,7 @@ use derive_more::From; use rand::{seq::SliceRandom, Rng, RngCore}; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use std::{ + borrow::Cow, fmt::{self, Display, Formatter}, fs::File, io::{Seek, SeekFrom, Write}, @@ -95,23 +96,15 @@ impl Metric { } /// The name of the metric. It is always prefixed by the [`self.category()`]. - pub fn name(&self) -> &'static str { + pub fn name(&self) -> Cow<'static, str> { match self { - Self::Sr25519Verify => "SR25519-Verify", - Self::Blake2256 => "BLAKE2-256", + Self::Sr25519Verify => Cow::Borrowed("SR25519-Verify"), + Self::Blake2256 => Cow::Borrowed("BLAKE2-256"), Self::Blake2256Parallel { num_cores } => - format!("BLAKE2-256-Parallel-{}", num_cores).leak(), - Self::MemCopy => "Copy", - Self::DiskSeqWrite => "Seq Write", - Self::DiskRndWrite => "Rnd Write", - } - } - - /// The number of cores used in the parallel BLAKE2-256 hashing. - pub fn num_cores(&self) -> Option { - match self { - Self::Blake2256Parallel { num_cores } => Some(*num_cores), - _ => None, + Cow::Owned(format!("BLAKE2-256-Parallel-{}", num_cores)), + Self::MemCopy => Cow::Borrowed("Copy"), + Self::DiskSeqWrite => Cow::Borrowed("Seq Write"), + Self::DiskRndWrite => Cow::Borrowed("Rnd Write"), } } } @@ -266,10 +259,10 @@ pub struct Requirement { deserialize_with = "deserialize_throughput" )] pub minimum: Throughput, - /// Check this requirement only for relay chain authority nodes. + /// Check this requirement only for relay chain validator nodes. #[serde(default)] #[serde(skip_serializing_if = "core::ops::Not::not")] - pub check_on_rc_authority: bool, + pub validator_only: bool, } #[inline(always)] @@ -670,19 +663,23 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> Throughput { /// disk. Also accepts the `requirements` for the hardware benchmark and a /// boolean to specify if the node is an authority. pub fn gather_hwbench(scratch_directory: Option<&Path>, requirements: &Requirements) -> HwBench { - let parallel_num_cores = requirements + let cpu_hashrate_score = benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT); + let parallel_cpu_hashrate_score = requirements .0 .iter() - .filter_map(|requirement| requirement.metric.num_cores()) + .filter_map(|req| { + if let Metric::Blake2256Parallel { num_cores } = req.metric { + Some(benchmark_cpu_parallelism(DEFAULT_CPU_EXECUTION_LIMIT, num_cores)) + } else { + None + } + }) .next() - .unwrap_or(1); + .unwrap_or(cpu_hashrate_score); #[allow(unused_mut)] let mut hwbench = HwBench { - cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT), - parallel_cpu_hashrate_score: benchmark_cpu_parallelism( - DEFAULT_CPU_EXECUTION_LIMIT, - parallel_num_cores, - ), + cpu_hashrate_score, + parallel_cpu_hashrate_score, memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT), disk_sequential_write_score: None, disk_random_write_score: None, @@ -721,7 +718,7 @@ impl Requirements { ) -> Result<(), CheckFailures> { let mut failures = Vec::new(); for requirement in self.0.iter() { - if requirement.check_on_rc_authority && !is_rc_authority { + if requirement.validator_only && !is_rc_authority { continue } diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs index e44c67fbf1db..ee1d490b8547 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs +++ b/substrate/utils/frame/benchmarking-cli/src/machine/hardware.rs @@ -54,32 +54,32 @@ mod tests { Requirement { metric: Metric::Blake2256, minimum: Throughput::from_mibs(1000.00), - check_on_rc_authority: false + validator_only: false }, Requirement { metric: Metric::Blake2256Parallel { num_cores: 8 }, minimum: Throughput::from_mibs(1000.00), - check_on_rc_authority: true, + validator_only: true, }, Requirement { metric: Metric::Sr25519Verify, minimum: Throughput::from_kibs(637.619999744), - check_on_rc_authority: false + validator_only: false }, Requirement { metric: Metric::MemCopy, minimum: Throughput::from_gibs(11.4925205078125003), - check_on_rc_authority: false, + validator_only: false, }, Requirement { metric: Metric::DiskSeqWrite, minimum: Throughput::from_mibs(950.0), - check_on_rc_authority: false, + validator_only: false, }, Requirement { metric: Metric::DiskRndWrite, minimum: Throughput::from_mibs(420.0), - check_on_rc_authority: false + validator_only: false }, ]) ); diff --git a/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json b/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json index 7b4e473174ad..654eaa6ff138 100644 --- a/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json +++ b/substrate/utils/frame/benchmarking-cli/src/machine/reference_hardware.json @@ -6,7 +6,7 @@ { "metric": {"Blake2256Parallel":{"num_cores":8}}, "minimum": 1000.00, - "check_on_rc_authority": true + "validator_only": true }, { "metric": "Sr25519Verify", From 4d717185a4dbb5bcd6d799134229ad7dbc12ee38 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Mon, 2 Sep 2024 15:05:54 +0300 Subject: [PATCH 09/11] Add prdoc Signed-off-by: Alexandru Gheorghe --- prdoc/pr_5127.prdoc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 prdoc/pr_5127.prdoc diff --git a/prdoc/pr_5127.prdoc b/prdoc/pr_5127.prdoc new file mode 100644 index 000000000000..ad4c4c387ae1 --- /dev/null +++ b/prdoc/pr_5127.prdoc @@ -0,0 +1,25 @@ +title: Add benchmark to check upcoming minimum required hw cores + +doc: + - audience: Node Operator + description: | + Add benchmark that checks hardware satisifies the minimum requirements for a validators. + The new minimum requirements are schedule to come into effect in January 2025, see for + more details: https://polkadot.subsquare.io/referenda/1051. + + +crates: + - name: sc-sysinfo + bump: major + - name: frame-benchmarking-cli + bump: major + - name: staging-node-cli + bump: patch + - name: polkadot-service + bump: patch + - name: polkadot-parachain-lib + bump: patch + - name: polkadot-cli + bump: patch + - name: parachain-template-node + bump: patch From db943bc3294e5ac1107f7e95b2502f4c63f60540 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe Date: Tue, 3 Sep 2024 13:10:30 +0300 Subject: [PATCH 10/11] Print the number of expected cores Signed-off-by: Alexandru Gheorghe --- substrate/client/sysinfo/src/lib.rs | 5 ++++- substrate/client/sysinfo/src/sysinfo.rs | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/substrate/client/sysinfo/src/lib.rs b/substrate/client/sysinfo/src/lib.rs index 302a44c24adb..7bc30ae0221d 100644 --- a/substrate/client/sysinfo/src/lib.rs +++ b/substrate/client/sysinfo/src/lib.rs @@ -52,6 +52,8 @@ pub struct HwBench { /// BLAKE2b-256 hash. #[serde(serialize_with = "serialize_throughput")] pub parallel_cpu_hashrate_score: Throughput, + /// The number of expected cores used for computing the parallel CPU speed. + pub parallel_cpu_cores: usize, /// Memory bandwidth in MB/s, calculated by measuring the throughput of `memcpy`. #[serde(serialize_with = "serialize_throughput")] pub memory_memcpy_score: Throughput, @@ -138,9 +140,10 @@ pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) { /// Prints out the results of the hardware benchmarks in the logs. pub fn print_hwbench(hwbench: &HwBench) { log::info!( - "🏁 CPU single core score: {}, parallelism score: {}", + "🏁 CPU single core score: {}, parallelism score: {} with expected cores: {}", hwbench.cpu_hashrate_score, hwbench.parallel_cpu_hashrate_score, + hwbench.parallel_cpu_cores, ); log::info!("🏁 Memory score: {}", hwbench.memory_memcpy_score); diff --git a/substrate/client/sysinfo/src/sysinfo.rs b/substrate/client/sysinfo/src/sysinfo.rs index c291be1089ed..4bcdd673455c 100644 --- a/substrate/client/sysinfo/src/sysinfo.rs +++ b/substrate/client/sysinfo/src/sysinfo.rs @@ -664,22 +664,23 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> Throughput { /// boolean to specify if the node is an authority. pub fn gather_hwbench(scratch_directory: Option<&Path>, requirements: &Requirements) -> HwBench { let cpu_hashrate_score = benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT); - let parallel_cpu_hashrate_score = requirements + let (parallel_cpu_hashrate_score, parallel_cpu_cores) = requirements .0 .iter() .filter_map(|req| { if let Metric::Blake2256Parallel { num_cores } = req.metric { - Some(benchmark_cpu_parallelism(DEFAULT_CPU_EXECUTION_LIMIT, num_cores)) + Some((benchmark_cpu_parallelism(DEFAULT_CPU_EXECUTION_LIMIT, num_cores), num_cores)) } else { None } }) .next() - .unwrap_or(cpu_hashrate_score); + .unwrap_or((cpu_hashrate_score, 1)); #[allow(unused_mut)] let mut hwbench = HwBench { cpu_hashrate_score, parallel_cpu_hashrate_score, + parallel_cpu_cores, memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT), disk_sequential_write_score: None, disk_random_write_score: None, @@ -857,6 +858,7 @@ mod tests { let hwbench = HwBench { cpu_hashrate_score: Throughput::from_gibs(1.32), parallel_cpu_hashrate_score: Throughput::from_gibs(1.32), + parallel_cpu_cores: 4, memory_memcpy_score: Throughput::from_kibs(9342.432), disk_sequential_write_score: Some(Throughput::from_kibs(4332.12)), disk_random_write_score: None, @@ -864,6 +866,6 @@ mod tests { let serialized = serde_json::to_string(&hwbench).unwrap(); // Throughput from all of the benchmarks should be converted to MiBs. - assert_eq!(serialized, "{\"cpu_hashrate_score\":1351,\"parallel_cpu_hashrate_score\":1351,\"memory_memcpy_score\":9,\"disk_sequential_write_score\":4}"); + assert_eq!(serialized, "{\"cpu_hashrate_score\":1351,\"parallel_cpu_hashrate_score\":1351,\"parallel_cpu_cores\":4,\"memory_memcpy_score\":9,\"disk_sequential_write_score\":4}"); } } From 6f57715b9a3e99231b0bc1b4220dd4a966929db1 Mon Sep 17 00:00:00 2001 From: Alexandru Gheorghe <49718502+alexggh@users.noreply.github.com> Date: Thu, 5 Sep 2024 15:04:51 +0300 Subject: [PATCH 11/11] Update pr_5127.prdoc --- prdoc/pr_5127.prdoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/prdoc/pr_5127.prdoc b/prdoc/pr_5127.prdoc index ad4c4c387ae1..c08f4e7fb8fa 100644 --- a/prdoc/pr_5127.prdoc +++ b/prdoc/pr_5127.prdoc @@ -3,9 +3,9 @@ title: Add benchmark to check upcoming minimum required hw cores doc: - audience: Node Operator description: | - Add benchmark that checks hardware satisifies the minimum requirements for a validators. - The new minimum requirements are schedule to come into effect in January 2025, see for - more details: https://polkadot.subsquare.io/referenda/1051. + Add benchmark that checks hardware satisifies the minimum required hardware cores + for a validators. The new minimum requirements are schedule to come into effect + in January 2025, for more details see: https://polkadot.subsquare.io/referenda/1051. crates: