Skip to content
Snippets Groups Projects
Unverified Commit dca14239 authored by Alexandru Gheorghe's avatar Alexandru Gheorghe Committed by GitHub
Browse files

substrate: sysinfo: Expose failed hardware requirements (#2144)


The check_hardware functions does not give us too much information as to
what is failing, so let's return the list of failed metrics, so that callers can print 
it.

This would make debugging easier, rather than try to guess which
dimension is actually failing.

Signed-off-by: default avatarAlexandru Gheorghe <alexandru.gheorghe@parity.io>
parent e9987401
Branches
No related merge requests found
Pipeline #409087 passed with stages
in 52 minutes and 45 seconds
...@@ -15980,6 +15980,7 @@ dependencies = [ ...@@ -15980,6 +15980,7 @@ dependencies = [
name = "sc-sysinfo" name = "sc-sysinfo"
version = "6.0.0-dev" version = "6.0.0-dev"
dependencies = [ dependencies = [
"derive_more",
"futures", "futures",
"libc", "libc",
"log", "log",
......
...@@ -255,10 +255,14 @@ async fn start_node_impl( ...@@ -255,10 +255,14 @@ async fn start_node_impl(
// Here you can check whether the hardware meets your chains' requirements. Putting a link // 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 // 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. // requirements for a para-chain are dictated by its relay-chain.
if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && validator { match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) {
log::warn!( Err(err) if validator => {
"⚠️ The hardware does not meet the minimal requirements for role 'Authority'." log::warn!(
"⚠️ The hardware does not meet the minimal requirements {} for role 'Authority'.",
err
); );
},
_ => {},
} }
if let Some(ref mut telemetry) = telemetry { if let Some(ref mut telemetry) = telemetry {
......
...@@ -1955,10 +1955,11 @@ pub async fn start_contracts_rococo_node( ...@@ -1955,10 +1955,11 @@ pub async fn start_contracts_rococo_node(
fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) { fn warn_if_slow_hardware(hwbench: &sc_sysinfo::HwBench) {
// Polkadot para-chains should generally use these requirements to ensure that the relay-chain // Polkadot para-chains should generally use these requirements to ensure that the relay-chain
// will not take longer than expected to import its blocks. // will not take longer than expected to import its blocks.
if !frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) { if let Err(err) = frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE.check_hardware(hwbench) {
log::warn!( log::warn!(
"⚠️ The hardware does not meet the minimal requirements for role 'Authority' find out more at:\n\ "⚠️ 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" https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware",
err
); );
} }
} }
...@@ -965,11 +965,15 @@ pub fn new_full<OverseerGenerator: OverseerGen>( ...@@ -965,11 +965,15 @@ pub fn new_full<OverseerGenerator: OverseerGen>(
if let Some(hwbench) = hwbench { if let Some(hwbench) = hwbench {
sc_sysinfo::print_hwbench(&hwbench); sc_sysinfo::print_hwbench(&hwbench);
if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && role.is_authority() { match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) {
log::warn!( Err(err) if role.is_authority() => {
"⚠️ The hardware does not meet the minimal requirements for role 'Authority' find out more at:\n\ log::warn!(
https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware" "⚠️ 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 let Some(ref mut telemetry) = telemetry { if let Some(ref mut telemetry) = telemetry {
......
...@@ -449,10 +449,14 @@ pub fn new_full_base( ...@@ -449,10 +449,14 @@ pub fn new_full_base(
if let Some(hwbench) = hwbench { if let Some(hwbench) = hwbench {
sc_sysinfo::print_hwbench(&hwbench); sc_sysinfo::print_hwbench(&hwbench);
if !SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) && role.is_authority() { match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) {
log::warn!( Err(err) if role.is_authority() => {
"⚠️ The hardware does not meet the minimal requirements for role 'Authority'." log::warn!(
); "⚠️ The hardware does not meet the minimal requirements {} for role 'Authority'.",
err
);
},
_ => {},
} }
if let Some(ref mut telemetry) = telemetry { if let Some(ref mut telemetry) = telemetry {
......
...@@ -19,6 +19,7 @@ libc = "0.2" ...@@ -19,6 +19,7 @@ libc = "0.2"
log = "0.4.17" log = "0.4.17"
rand = "0.8.5" rand = "0.8.5"
rand_pcg = "0.3.1" rand_pcg = "0.3.1"
derive_more = "0.99"
regex = "1" regex = "1"
serde = { version = "1.0.188", features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.107" serde_json = "1.0.107"
......
...@@ -23,9 +23,11 @@ use sp_core::{sr25519, Pair}; ...@@ -23,9 +23,11 @@ use sp_core::{sr25519, Pair};
use sp_io::crypto::sr25519_verify; use sp_io::crypto::sr25519_verify;
use sp_std::{fmt, fmt::Formatter, prelude::*}; use sp_std::{fmt, fmt::Formatter, prelude::*};
use derive_more::From;
use rand::{seq::SliceRandom, Rng, RngCore}; use rand::{seq::SliceRandom, Rng, RngCore};
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use std::{ use std::{
fmt::Display,
fs::File, fs::File,
io::{Seek, SeekFrom, Write}, io::{Seek, SeekFrom, Write},
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
...@@ -48,6 +50,37 @@ pub enum Metric { ...@@ -48,6 +50,37 @@ pub enum Metric {
DiskRndWrite, DiskRndWrite,
} }
/// Describes a checking failure for the hardware requirements.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct CheckFailure {
/// The metric that failed the check.
pub metric: Metric,
/// The expected minimum value.
pub expected: Throughput,
/// The measured value.
pub found: Throughput,
}
/// A list of metrics that failed to meet the minimum hardware requirements.
#[derive(Debug, Clone, PartialEq, From)]
pub struct CheckFailures(pub Vec<CheckFailure>);
impl Display for CheckFailures {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "Failed checks: ")?;
for failure in &self.0 {
write!(
formatter,
"{}(expected: {}, found: {}), ",
failure.metric.name(),
failure.expected,
failure.found
)?
}
Ok(())
}
}
impl Metric { impl Metric {
/// The category of the metric. /// The category of the metric.
pub fn category(&self) -> &'static str { pub fn category(&self) -> &'static str {
...@@ -626,33 +659,54 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench { ...@@ -626,33 +659,54 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench {
impl Requirements { impl Requirements {
/// Whether the hardware requirements are met by the provided benchmark results. /// Whether the hardware requirements are met by the provided benchmark results.
pub fn check_hardware(&self, hwbench: &HwBench) -> bool { pub fn check_hardware(&self, hwbench: &HwBench) -> Result<(), CheckFailures> {
let mut failures = Vec::new();
for requirement in self.0.iter() { for requirement in self.0.iter() {
match requirement.metric { match requirement.metric {
Metric::Blake2256 => Metric::Blake2256 =>
if requirement.minimum > hwbench.cpu_hashrate_score { if requirement.minimum > hwbench.cpu_hashrate_score {
return false failures.push(CheckFailure {
metric: requirement.metric,
expected: requirement.minimum,
found: hwbench.cpu_hashrate_score,
});
}, },
Metric::MemCopy => Metric::MemCopy =>
if requirement.minimum > hwbench.memory_memcpy_score { if requirement.minimum > hwbench.memory_memcpy_score {
return false failures.push(CheckFailure {
metric: requirement.metric,
expected: requirement.minimum,
found: hwbench.memory_memcpy_score,
});
}, },
Metric::DiskSeqWrite => Metric::DiskSeqWrite =>
if let Some(score) = hwbench.disk_sequential_write_score { if let Some(score) = hwbench.disk_sequential_write_score {
if requirement.minimum > score { if requirement.minimum > score {
return false failures.push(CheckFailure {
metric: requirement.metric,
expected: requirement.minimum,
found: score,
});
} }
}, },
Metric::DiskRndWrite => Metric::DiskRndWrite =>
if let Some(score) = hwbench.disk_random_write_score { if let Some(score) = hwbench.disk_random_write_score {
if requirement.minimum > score { if requirement.minimum > score {
return false failures.push(CheckFailure {
metric: requirement.metric,
expected: requirement.minimum,
found: score,
});
} }
}, },
Metric::Sr25519Verify => {}, Metric::Sr25519Verify => {},
} }
} }
true if failures.is_empty() {
Ok(())
} else {
Err(failures.into())
}
} }
} }
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment