mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-17 20:41:02 +00:00
Warn validators with slow hardware (#12620)
* move Metric * run hardware bench if validiator flag is being used * fix rustdoc & update node-template * fix * unused improt * warn * move Requirement * bench_result * ensure_requirements * make the code compile * check if authority * Update client/sysinfo/src/sysinfo.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * nit fixes * warning signs * Update client/sysinfo/src/sysinfo.rs Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
This commit is contained in:
@@ -21,6 +21,7 @@
|
|||||||
//! Service implementation. Specialized wrapper over substrate service.
|
//! Service implementation. Specialized wrapper over substrate service.
|
||||||
|
|
||||||
use codec::Encode;
|
use codec::Encode;
|
||||||
|
use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE;
|
||||||
use frame_system_rpc_runtime_api::AccountNonceApi;
|
use frame_system_rpc_runtime_api::AccountNonceApi;
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use kitchensink_runtime::RuntimeApi;
|
use kitchensink_runtime::RuntimeApi;
|
||||||
@@ -320,7 +321,11 @@ pub fn new_full_base(
|
|||||||
let hwbench = if !disable_hardware_benchmarks {
|
let hwbench = if !disable_hardware_benchmarks {
|
||||||
config.database.path().map(|database_path| {
|
config.database.path().map(|database_path| {
|
||||||
let _ = std::fs::create_dir_all(&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.clone(),
|
||||||
|
config.role.is_authority(),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ mod sysinfo_linux;
|
|||||||
pub use sysinfo::{
|
pub use sysinfo::{
|
||||||
benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes,
|
benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes,
|
||||||
benchmark_memory, benchmark_sr25519_verify, gather_hwbench, gather_sysinfo,
|
benchmark_memory, benchmark_sr25519_verify, gather_hwbench, gather_sysinfo,
|
||||||
serialize_throughput, serialize_throughput_option, Throughput,
|
serialize_throughput, serialize_throughput_option, Metric, Requirement, Requirements,
|
||||||
|
Throughput,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The operating system part of the current target triplet.
|
/// The operating system part of the current target triplet.
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ use crate::{ExecutionLimit, HwBench};
|
|||||||
use sc_telemetry::SysInfo;
|
use sc_telemetry::SysInfo;
|
||||||
use sp_core::{sr25519, Pair};
|
use sp_core::{sr25519, Pair};
|
||||||
use sp_io::crypto::sr25519_verify;
|
use sp_io::crypto::sr25519_verify;
|
||||||
use sp_std::{fmt, prelude::*};
|
use sp_std::{fmt, fmt::Formatter, prelude::*};
|
||||||
|
|
||||||
use rand::{seq::SliceRandom, Rng, RngCore};
|
use rand::{seq::SliceRandom, Rng, RngCore};
|
||||||
use serde::Serializer;
|
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::{
|
use std::{
|
||||||
fs::File,
|
fs::File,
|
||||||
io::{Seek, SeekFrom, Write},
|
io::{Seek, SeekFrom, Write},
|
||||||
@@ -33,6 +33,43 @@ use std::{
|
|||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A single hardware metric.
|
||||||
|
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum Metric {
|
||||||
|
/// SR25519 signature verification.
|
||||||
|
Sr25519Verify,
|
||||||
|
/// Blake2-256 hashing algorithm.
|
||||||
|
Blake2256,
|
||||||
|
/// Copying data in RAM.
|
||||||
|
MemCopy,
|
||||||
|
/// Disk sequential write.
|
||||||
|
DiskSeqWrite,
|
||||||
|
/// Disk random write.
|
||||||
|
DiskRndWrite,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Metric {
|
||||||
|
/// The category of the metric.
|
||||||
|
pub fn category(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Sr25519Verify | Self::Blake2256 => "CPU",
|
||||||
|
Self::MemCopy => "Memory",
|
||||||
|
Self::DiskSeqWrite | Self::DiskRndWrite => "Disk",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The name of the metric. It is always prefixed by the [`self.category()`].
|
||||||
|
pub fn name(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Sr25519Verify => "SR25519-Verify",
|
||||||
|
Self::Blake2256 => "BLAKE2-256",
|
||||||
|
Self::MemCopy => "Copy",
|
||||||
|
Self::DiskSeqWrite => "Seq Write",
|
||||||
|
Self::DiskRndWrite => "Rnd Write",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The unit in which the [`Throughput`] (bytes per second) is denoted.
|
/// The unit in which the [`Throughput`] (bytes per second) is denoted.
|
||||||
pub enum Unit {
|
pub enum Unit {
|
||||||
GiBs,
|
GiBs,
|
||||||
@@ -137,6 +174,54 @@ where
|
|||||||
serializer.serialize_none()
|
serializer.serialize_none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serializes throughput into MiBs and represents it as `f64`.
|
||||||
|
fn serialize_throughput_as_f64<S>(throughput: &Throughput, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_f64(throughput.as_mibs())
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ThroughputVisitor;
|
||||||
|
impl<'de> Visitor<'de> for ThroughputVisitor {
|
||||||
|
type Value = Throughput;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("A value that is a f64.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(Throughput::from_mibs(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_throughput<'de, D>(deserializer: D) -> Result<Throughput, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Ok(deserializer.deserialize_f64(ThroughputVisitor))?
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Multiple requirements for the hardware.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
|
pub struct Requirements(pub Vec<Requirement>);
|
||||||
|
|
||||||
|
/// A single requirement for the hardware.
|
||||||
|
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct Requirement {
|
||||||
|
/// The metric to measure.
|
||||||
|
pub metric: Metric,
|
||||||
|
/// The minimal throughput that needs to be archived for this requirement.
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "serialize_throughput_as_f64",
|
||||||
|
deserialize_with = "deserialize_throughput"
|
||||||
|
)]
|
||||||
|
pub minimum: Throughput,
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn benchmark<E>(
|
pub(crate) fn benchmark<E>(
|
||||||
name: &str,
|
name: &str,
|
||||||
@@ -503,8 +588,14 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> Throughput {
|
|||||||
|
|
||||||
/// Benchmarks the hardware and returns the results of those benchmarks.
|
/// Benchmarks the hardware and returns the results of those benchmarks.
|
||||||
///
|
///
|
||||||
/// Optionally accepts a path to a `scratch_directory` to use to benchmark the disk.
|
/// Optionally accepts a path to a `scratch_directory` to use to benchmark the
|
||||||
pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench {
|
/// 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,
|
||||||
|
is_authority: bool,
|
||||||
|
) -> HwBench {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut hwbench = HwBench {
|
let mut hwbench = HwBench {
|
||||||
cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT),
|
cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT),
|
||||||
@@ -534,9 +625,45 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if is_authority {
|
||||||
|
ensure_requirements(hwbench.clone(), requirements);
|
||||||
|
}
|
||||||
|
|
||||||
hwbench
|
hwbench
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn ensure_requirements(hwbench: HwBench, requirements: Requirements) {
|
||||||
|
let mut failed = 0;
|
||||||
|
for requirement in requirements.0.iter() {
|
||||||
|
match requirement.metric {
|
||||||
|
Metric::Blake2256 =>
|
||||||
|
if requirement.minimum > hwbench.cpu_hashrate_score {
|
||||||
|
failed += 1;
|
||||||
|
},
|
||||||
|
Metric::MemCopy =>
|
||||||
|
if requirement.minimum > hwbench.memory_memcpy_score {
|
||||||
|
failed += 1;
|
||||||
|
},
|
||||||
|
Metric::DiskSeqWrite =>
|
||||||
|
if let Some(score) = hwbench.disk_sequential_write_score {
|
||||||
|
if requirement.minimum > score {
|
||||||
|
failed += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Metric::DiskRndWrite =>
|
||||||
|
if let Some(score) = hwbench.disk_random_write_score {
|
||||||
|
if requirement.minimum > score {
|
||||||
|
failed += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Metric::Sr25519Verify => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if failed != 0 {
|
||||||
|
log::warn!("⚠️ Your hardware performance score was less than expected for role 'Authority'. See https://wiki.polkadot.network/docs/maintain-guides-how-to-validate-polkadot#reference-hardware");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ mod storage;
|
|||||||
|
|
||||||
pub use block::BlockCmd;
|
pub use block::BlockCmd;
|
||||||
pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory};
|
pub use extrinsic::{ExtrinsicBuilder, ExtrinsicCmd, ExtrinsicFactory};
|
||||||
pub use machine::{MachineCmd, Requirements, SUBSTRATE_REFERENCE_HARDWARE};
|
pub use machine::{MachineCmd, SUBSTRATE_REFERENCE_HARDWARE};
|
||||||
pub use overhead::OverheadCmd;
|
pub use overhead::OverheadCmd;
|
||||||
pub use pallet::PalletCmd;
|
pub use pallet::PalletCmd;
|
||||||
pub use sc_service::BasePath;
|
pub use sc_service::BasePath;
|
||||||
|
|||||||
@@ -18,40 +18,7 @@
|
|||||||
//! Contains types to define hardware requirements.
|
//! Contains types to define hardware requirements.
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use sc_sysinfo::Throughput;
|
use sc_sysinfo::Requirements;
|
||||||
use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
use sp_std::{fmt, fmt::Formatter};
|
|
||||||
|
|
||||||
/// Serializes throughput into MiBs and represents it as `f64`.
|
|
||||||
fn serialize_throughput_as_f64<S>(throughput: &Throughput, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
serializer.serialize_f64(throughput.as_mibs())
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ThroughputVisitor;
|
|
||||||
impl<'de> Visitor<'de> for ThroughputVisitor {
|
|
||||||
type Value = Throughput;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
|
||||||
formatter.write_str("A value that is a f64.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
Ok(Throughput::from_mibs(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize_throughput<'de, D>(deserializer: D) -> Result<Throughput, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
{
|
|
||||||
Ok(deserializer.deserialize_f64(ThroughputVisitor))?
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// The hardware requirements as measured on reference hardware.
|
/// The hardware requirements as measured on reference hardware.
|
||||||
@@ -67,62 +34,6 @@ lazy_static! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Multiple requirements for the hardware.
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
|
||||||
pub struct Requirements(pub Vec<Requirement>);
|
|
||||||
|
|
||||||
/// A single requirement for the hardware.
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub struct Requirement {
|
|
||||||
/// The metric to measure.
|
|
||||||
pub metric: Metric,
|
|
||||||
/// The minimal throughput that needs to be archived for this requirement.
|
|
||||||
#[serde(
|
|
||||||
serialize_with = "serialize_throughput_as_f64",
|
|
||||||
deserialize_with = "deserialize_throughput"
|
|
||||||
)]
|
|
||||||
pub minimum: Throughput,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A single hardware metric.
|
|
||||||
///
|
|
||||||
/// The implementation of these is in `sc-sysinfo`.
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub enum Metric {
|
|
||||||
/// SR25519 signature verification.
|
|
||||||
Sr25519Verify,
|
|
||||||
/// Blake2-256 hashing algorithm.
|
|
||||||
Blake2256,
|
|
||||||
/// Copying data in RAM.
|
|
||||||
MemCopy,
|
|
||||||
/// Disk sequential write.
|
|
||||||
DiskSeqWrite,
|
|
||||||
/// Disk random write.
|
|
||||||
DiskRndWrite,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Metric {
|
|
||||||
/// The category of the metric.
|
|
||||||
pub fn category(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::Sr25519Verify | Self::Blake2256 => "CPU",
|
|
||||||
Self::MemCopy => "Memory",
|
|
||||||
Self::DiskSeqWrite | Self::DiskRndWrite => "Disk",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The name of the metric. It is always prefixed by the [`self::category()`].
|
|
||||||
pub fn name(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::Sr25519Verify => "SR25519-Verify",
|
|
||||||
Self::Blake2256 => "BLAKE2-256",
|
|
||||||
Self::MemCopy => "Copy",
|
|
||||||
Self::DiskSeqWrite => "Seq Write",
|
|
||||||
Self::DiskRndWrite => "Rnd Write",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -30,11 +30,12 @@ use sc_cli::{CliConfiguration, Result, SharedParams};
|
|||||||
use sc_service::Configuration;
|
use sc_service::Configuration;
|
||||||
use sc_sysinfo::{
|
use sc_sysinfo::{
|
||||||
benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes,
|
benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes,
|
||||||
benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, Throughput,
|
benchmark_memory, benchmark_sr25519_verify, ExecutionLimit, Metric, Requirement, Requirements,
|
||||||
|
Throughput,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::shared::check_build_profile;
|
use crate::shared::check_build_profile;
|
||||||
pub use hardware::{Metric, Requirement, Requirements, SUBSTRATE_REFERENCE_HARDWARE};
|
pub use hardware::SUBSTRATE_REFERENCE_HARDWARE;
|
||||||
|
|
||||||
/// Command to benchmark the hardware.
|
/// Command to benchmark the hardware.
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user