Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Move Throughput into sc-sysinfo #12368

Merged
merged 45 commits into from
Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ada0ee0
move Throughput to sc-sysinfo
Szegoo Sep 27, 2022
d25f110
replace u64
Szegoo Sep 27, 2022
8f7084e
Merge branch 'paritytech:master' into hardware-bench
Szegoo Sep 28, 2022
a564d4f
fix in tests
Szegoo Sep 29, 2022
7c30f8d
change Throughput
Szegoo Sep 29, 2022
d276670
refactored Throughput
Szegoo Sep 29, 2022
96ec3f0
fixes
Szegoo Sep 30, 2022
7226a57
moved tests & fixes
Szegoo Sep 30, 2022
f5530ac
custom serializer
Szegoo Sep 30, 2022
99b25a7
note
Szegoo Sep 30, 2022
cdd84d2
fix serializer
Szegoo Oct 1, 2022
9092ba0
forgot to remove
Szegoo Oct 1, 2022
621b56c
deserialize
Szegoo Oct 1, 2022
5f256b0
functioning deserialization :)
Szegoo Oct 1, 2022
5731506
try to make clipply happy
Szegoo Oct 1, 2022
8c61d1b
Serialize as function
Szegoo Oct 2, 2022
ed10eae
test HwBench
Szegoo Oct 2, 2022
0997131
rename
Szegoo Oct 2, 2022
3785a62
fix serialization
Szegoo Oct 3, 2022
7354ccb
deserialize as function
Szegoo Oct 3, 2022
c3d0995
unused import
Szegoo Oct 3, 2022
bab6f75
move serialize/deserialize
Szegoo Oct 3, 2022
51a71ac
don't serialize none
Szegoo Oct 3, 2022
a62ecb8
remove nonsense
Szegoo Oct 3, 2022
0ed3320
remove nonsense comment :P
Szegoo Oct 3, 2022
4f5dd61
fixes
Szegoo Oct 4, 2022
cd73e34
remove all the todos
Szegoo Oct 5, 2022
5028b9a
return enum
Szegoo Oct 5, 2022
1f08df9
fixes
Szegoo Oct 6, 2022
fee21a9
Merge branch 'paritytech:master' into hardware-bench
Szegoo Oct 6, 2022
f59280a
fix nit
Szegoo Oct 7, 2022
3173864
improve docs & readability
Szegoo Oct 7, 2022
2005c2b
Merge branch 'paritytech:master' into hardware-bench
Szegoo Oct 7, 2022
e63e6bd
Update client/sysinfo/src/sysinfo.rs
Szegoo Oct 12, 2022
1ee8772
fix all the nits
Szegoo Oct 12, 2022
38c584a
Merge branch 'paritytech:master' into hardware-bench
Szegoo Oct 12, 2022
02f3862
rename
Szegoo Oct 12, 2022
0679a4a
Merge branch 'paritytech:master' into hardware-bench
Szegoo Oct 15, 2022
cbca2c2
fix
Szegoo Oct 15, 2022
698d53e
Merge branch 'paritytech:master' into hardware-bench
Szegoo Oct 20, 2022
30fe5ee
Update client/sysinfo/src/sysinfo.rs
Szegoo Oct 20, 2022
7a3fe3e
remove unit from serialization
Szegoo Oct 29, 2022
70d48ba
Merge branch 'paritytech:master' into hardware-bench
Szegoo Oct 29, 2022
3590c83
Merge branch 'paritytech:master' into hardware-bench
Szegoo Oct 30, 2022
9211e14
Update utils/frame/benchmarking-cli/src/machine/hardware.rs
ggwpez Nov 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/sysinfo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" }
sp-core = { version = "6.0.0", path = "../../primitives/core" }
sp-io = { version = "6.0.0", path = "../../primitives/io" }
sp-std = { version = "4.0.0", path = "../../primitives/std" }
sp-runtime = { version = "6.0.0", path = "../../primitives/runtime" }
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
10 changes: 5 additions & 5 deletions client/sysinfo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ 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,
benchmark_memory, benchmark_sr25519_verify, gather_hwbench, gather_sysinfo, Throughput,
};

/// The operating system part of the current target triplet.
Expand All @@ -44,13 +44,13 @@ pub const TARGET_ENV: &str = include_str!(concat!(env!("OUT_DIR"), "/target_env.
#[derive(Clone, Debug, serde::Serialize)]
pub struct HwBench {
/// The CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 hash.
pub cpu_hashrate_score: u64,
pub cpu_hashrate_score: Throughput,
/// Memory bandwidth in MB/s, calculated by measuring the throughput of `memcpy`.
pub memory_memcpy_score: u64,
pub memory_memcpy_score: Throughput,
/// Sequential disk write speed in MB/s.
pub disk_sequential_write_score: Option<u64>,
pub disk_sequential_write_score: Option<Throughput>,
/// Random disk write speed in MB/s.
pub disk_random_write_score: Option<u64>,
pub disk_random_write_score: Option<Throughput>,
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
}
Szegoo marked this conversation as resolved.
Show resolved Hide resolved

/// Limit the execution time of a benchmark.
Expand Down
128 changes: 104 additions & 24 deletions client/sysinfo/src/sysinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ use crate::{ExecutionLimit, HwBench};
use sc_telemetry::SysInfo;
use sp_core::{sr25519, Pair};
use sp_io::crypto::sr25519_verify;
use sp_std::prelude::*;
use sp_std::{fmt, prelude::*};

use rand::{seq::SliceRandom, Rng, RngCore};
use serde::{Deserialize, Serialize};
use std::{
fs::File,
io::{Seek, SeekFrom, Write},
Expand All @@ -32,14 +33,76 @@ use std::{
time::{Duration, Instant},
};

/// Throughput as measured in bytes per second.
#[derive(Deserialize, Serialize, Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct Throughput(f64);

const KIBIBYTE: f64 = 1024.0;
Szegoo marked this conversation as resolved.
Show resolved Hide resolved

impl Throughput {
/// `f64` kibibyte/s to byte/s.
pub fn from_kibs(kibs: f64) -> Throughput {
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
Throughput(kibs * KIBIBYTE)
}

/// `f64` mebibyte/s to byte/s.
pub fn from_mibs(mibs: f64) -> Throughput {
Throughput(mibs * KIBIBYTE * KIBIBYTE)
}

/// `f64` gibibyte/s to byte/s.
pub fn from_gibs(gibs: f64) -> Throughput {
Throughput(gibs * KIBIBYTE * KIBIBYTE * KIBIBYTE)
}

pub fn as_f64(&self) -> f64 {
self.0
}

/// [`Self`] as number of kibibyte/s.
pub fn as_kibs(&self) -> f64 {
self.0 / KIBIBYTE
}

/// [`Self`] as number of mebibyte/s.
pub fn as_mibs(&self) -> f64 {
self.0 / (KIBIBYTE * KIBIBYTE)
}

/// [`Self`] as number of gibibyte/s.
pub fn as_gibs(&self) -> f64 {
self.0 / (KIBIBYTE * KIBIBYTE * KIBIBYTE)
}

/// Normalizes [`Self`] to use the larges unit possible.
fn normalize(&self) -> (f64, &'static str) {
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
let bs = self.0;

if bs >= KIBIBYTE * KIBIBYTE * KIBIBYTE {
(self.as_gibs(), "GiB/s")
} else if bs >= KIBIBYTE * KIBIBYTE {
(self.as_mibs(), "MiB/s")
} else {
(self.as_kibs(), "KiB/s")
}
}
}

impl fmt::Display for Throughput {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let (value, unit) = self.normalize();
write!(f, "{:.2?} {}", value, unit)
}
}

#[inline(always)]
pub(crate) fn benchmark<E>(
name: &str,
size: usize,
max_iterations: usize,
max_duration: Duration,
mut run: impl FnMut() -> Result<(), E>,
) -> Result<f64, E> {
) -> Result<Throughput, E> {
// Run the benchmark once as a warmup to get the code into the L1 cache.
run()?;

Expand All @@ -58,9 +121,9 @@ pub(crate) fn benchmark<E>(
}
}

let score = ((size * count) as f64 / elapsed.as_secs_f64()) / (1024.0 * 1024.0);
let score = Throughput((size * count) as f64 / elapsed.as_secs_f64());
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
log::trace!(
"Calculated {} of {:.2}MB/s in {} iterations in {}ms",
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
"Calculated {} of {:.2} in {} iterations in {}ms",
Szegoo marked this conversation as resolved.
Show resolved Hide resolved
name,
score,
count,
Expand Down Expand Up @@ -120,14 +183,14 @@ fn clobber_value<T>(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 MB/s.
pub fn benchmark_cpu(limit: ExecutionLimit) -> f64 {
// This benchmarks the CPU speed as measured by calculating BLAKE2b-256 hashes, in bytes per second.
pub fn benchmark_cpu(limit: ExecutionLimit) -> 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* MB/s we can hash,
// the bigger this is the *more* MB/s we can hash, up until a certain point
// 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
// where we can achieve roughly ~100% of what the hasher can do. If we'd plot
// this on a graph with the number of bytes we want to hash on the X axis
// and the speed in MB/s on the Y axis then we'd essentially see it grow
// and the speed in B/s on the Y axis then we'd essentially see it grow
// logarithmically.
//
// In practice however we might not always have enough data to hit the maximum
Expand Down Expand Up @@ -156,12 +219,12 @@ pub fn benchmark_cpu(limit: ExecutionLimit) -> f64 {
pub const DEFAULT_MEMORY_EXECUTION_LIMIT: ExecutionLimit =
ExecutionLimit::Both { max_iterations: 32, max_duration: Duration::from_millis(100) };

// This benchmarks the effective `memcpy` memory bandwidth available in MB/s.
// This benchmarks the effective `memcpy` memory bandwidth available in bytes per second.
//
// It doesn't technically measure the absolute maximum memory bandwidth available,
// but that's fine, because real code most of the time isn't optimized to take
// advantage of the full memory bandwidth either.
pub fn benchmark_memory(limit: ExecutionLimit) -> f64 {
pub fn benchmark_memory(limit: ExecutionLimit) -> Throughput {
// Ideally this should be at least as big as the CPU's L3 cache,
// and it should be big enough so that the `memcpy` takes enough
// time to be actually measurable.
Expand Down Expand Up @@ -253,7 +316,7 @@ pub const DEFAULT_DISK_EXECUTION_LIMIT: ExecutionLimit =
pub fn benchmark_disk_sequential_writes(
limit: ExecutionLimit,
directory: &Path,
) -> Result<f64, String> {
) -> Result<Throughput, String> {
const SIZE: usize = 64 * 1024 * 1024;

let buffer = random_data(SIZE);
Expand Down Expand Up @@ -295,7 +358,7 @@ pub fn benchmark_disk_sequential_writes(
pub fn benchmark_disk_random_writes(
limit: ExecutionLimit,
directory: &Path,
) -> Result<f64, String> {
) -> Result<Throughput, String> {
const SIZE: usize = 64 * 1024 * 1024;

let buffer = random_data(SIZE);
Expand Down Expand Up @@ -360,9 +423,9 @@ pub fn benchmark_disk_random_writes(

/// Benchmarks the verification speed of sr25519 signatures.
///
/// Returns the throughput in MB/s by convention.
/// Returns the throughput in B/s by convention.
/// The values are rather small (0.4-0.8) so it is advised to convert them into KB/s.
pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> f64 {
pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> Throughput {
const INPUT_SIZE: usize = 32;
const ITERATION_SIZE: usize = 2048;
let pair = sr25519::Pair::from_string("//Alice", None).unwrap();
Expand Down Expand Up @@ -402,8 +465,8 @@ pub fn benchmark_sr25519_verify(limit: ExecutionLimit) -> f64 {
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) as u64,
memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) as u64,
cpu_hashrate_score: benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT),
memory_memcpy_score: benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT),
disk_sequential_write_score: None,
disk_random_write_score: None,
};
Expand All @@ -412,7 +475,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench {
hwbench.disk_sequential_write_score =
match benchmark_disk_sequential_writes(DEFAULT_DISK_EXECUTION_LIMIT, scratch_directory)
{
Ok(score) => Some(score as u64),
Ok(score) => Some(score),
Err(error) => {
log::warn!("Failed to run the sequential write disk benchmark: {}", error);
None
Expand All @@ -421,7 +484,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench {

hwbench.disk_random_write_score =
match benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, scratch_directory) {
Ok(score) => Some(score as u64),
Ok(score) => Some(score),
Err(error) => {
log::warn!("Failed to run the random write disk benchmark: {}", error);
None
Expand All @@ -435,6 +498,7 @@ pub fn gather_hwbench(scratch_directory: Option<&Path>) -> HwBench {
#[cfg(test)]
mod tests {
use super::*;
use sp_runtime::assert_eq_error_rate_float;

#[cfg(target_os = "linux")]
#[test]
Expand All @@ -450,32 +514,48 @@ mod tests {

#[test]
fn test_benchmark_cpu() {
assert!(benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT) > 0.0);
assert!(benchmark_cpu(DEFAULT_CPU_EXECUTION_LIMIT) > Throughput(0.0));
}

#[test]
fn test_benchmark_memory() {
assert!(benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) > 0.0);
assert!(benchmark_memory(DEFAULT_MEMORY_EXECUTION_LIMIT) > Throughput(0.0));
}

#[test]
fn test_benchmark_disk_sequential_writes() {
assert!(
benchmark_disk_sequential_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() >
0.0
Throughput(0.0)
);
}

#[test]
fn test_benchmark_disk_random_writes() {
assert!(
benchmark_disk_random_writes(DEFAULT_DISK_EXECUTION_LIMIT, "./".as_ref()).unwrap() >
0.0
Throughput(0.0)
);
}

#[test]
fn test_benchmark_sr25519_verify() {
assert!(benchmark_sr25519_verify(ExecutionLimit::MaxIterations(1)) > 0.0);
assert!(benchmark_sr25519_verify(ExecutionLimit::MaxIterations(1)) > Throughput(0.0));
}

/// Test the [`Throughput`].
#[test]
fn throughput_works() {
/// Float precision.
const EPS: f64 = 0.1;
let gib = Throughput::from_gibs(14.324);

assert_eq_error_rate_float!(14.324, gib.as_gibs(), EPS);
assert_eq_error_rate_float!(14667.776, gib.as_mibs(), EPS);
assert_eq_error_rate_float!(14667.776 * 1024.0, gib.as_kibs(), EPS);
assert_eq!("14.32 GiB/s", gib.to_string());

let mib = Throughput::from_mibs(1029.0);
assert_eq!("1.00 GiB/s", mib.to_string());
}
}
Loading