Add benchmark machine placeholder (#11198)

* Move new_rng to shared code

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add bechmark machine command

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use sc-sysinfo

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add --no-hardware-benchmarks

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Lockfile

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Do not create components if not needed

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Fix tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Revert "Add --no-hardware-benchmarks"

This reverts commit d4ee98222bf1a5ea62ac60dd7d5c62070e2d7f70.

* Fix tests

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update Cargo deps

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Move sr255119::verify bench to sc-sysinfo

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Move sr255119::verify bench to sc-sysinfo

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Switch benchmarks to return f64

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Review fixes

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* fmt

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Hide command until completed

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Use concrete rand implementation

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Put clobber into a function

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add test

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add comment

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Update cargo to match polkadot

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Remove doc that does not format in the console

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Limit benchmark by time

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add ExecutionLimit and make function infallible

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* CI

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>

* Add doc

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
This commit is contained in:
Oliver Tale-Yazdi
2022-04-15 14:09:16 +02:00
committed by GitHub
parent ae75a371bf
commit 362dc50940
15 changed files with 351 additions and 46 deletions
+75 -16
View File
@@ -16,9 +16,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use crate::HwBench;
use rand::{seq::SliceRandom, Rng};
use crate::{ExecutionLimit, HwBench};
use sc_telemetry::SysInfo;
use sp_core::{sr25519, Pair};
use sp_io::crypto::sr25519_verify;
use sp_std::prelude::*;
use rand::{seq::SliceRandom, Rng, RngCore};
use std::{
fs::File,
io::{Seek, SeekFrom, Write},
@@ -34,7 +39,7 @@ pub(crate) fn benchmark<E>(
max_iterations: usize,
max_duration: Duration,
mut run: impl FnMut() -> Result<(), E>,
) -> Result<u64, E> {
) -> Result<f64, E> {
// Run the benchmark once as a warmup to get the code into the L1 cache.
run()?;
@@ -53,11 +58,11 @@ pub(crate) fn benchmark<E>(
}
}
let score = (((size * count) as f64 / elapsed.as_secs_f64()) / (1024.0 * 1024.0)) as u64;
let score = ((size * count) as f64 / elapsed.as_secs_f64()) / (1024.0 * 1024.0);
log::trace!(
"Calculated {} of {}MB/s in {} iterations in {}ms",
name,
score,
score as u64,
count,
elapsed.as_millis()
);
@@ -83,7 +88,7 @@ pub fn gather_sysinfo() -> SysInfo {
}
#[inline(never)]
fn clobber(slice: &mut [u8]) {
fn clobber_slice<T>(slice: &mut [T]) {
assert!(!slice.is_empty());
// Discourage the compiler from optimizing out our benchmarks.
@@ -102,8 +107,17 @@ fn clobber(slice: &mut [u8]) {
}
}
#[inline(never)]
fn clobber_value<T>(input: &mut T) {
// Look into `clobber_slice` for a comment.
unsafe {
let value = std::ptr::read_volatile(input);
std::ptr::write_volatile(input, value);
}
}
// This benchmarks the CPU speed as measured by calculating BLAKE2b-256 hashes, in MB/s.
fn benchmark_cpu() -> u64 {
pub fn benchmark_cpu() -> u64 {
// 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
@@ -125,15 +139,15 @@ fn benchmark_cpu() -> u64 {
let mut hash = Default::default();
let run = || -> Result<(), ()> {
clobber(&mut buffer);
clobber_slice(&mut buffer);
hash = sp_core::hashing::blake2_256(&buffer);
clobber(&mut hash);
clobber_slice(&mut hash);
Ok(())
};
benchmark("CPU score", SIZE, MAX_ITERATIONS, MAX_DURATION, run)
.expect("benchmark cannot fail; qed")
.expect("benchmark cannot fail; qed") as u64
}
// This benchmarks the effective `memcpy` memory bandwidth available in MB/s.
@@ -141,7 +155,7 @@ fn benchmark_cpu() -> u64 {
// 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.
fn benchmark_memory() -> u64 {
pub fn benchmark_memory() -> u64 {
// 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.
@@ -161,8 +175,8 @@ fn benchmark_memory() -> u64 {
dst.resize(SIZE, 0x77);
let run = || -> Result<(), ()> {
clobber(&mut src);
clobber(&mut dst);
clobber_slice(&mut src);
clobber_slice(&mut dst);
// SAFETY: Both vectors are of the same type and of the same size,
// so copying data between them is safe.
@@ -172,14 +186,14 @@ fn benchmark_memory() -> u64 {
libc::memcpy(dst.as_mut_ptr().cast(), src.as_ptr().cast(), SIZE);
}
clobber(&mut dst);
clobber(&mut src);
clobber_slice(&mut dst);
clobber_slice(&mut src);
Ok(())
};
benchmark("memory score", SIZE, MAX_ITERATIONS, MAX_DURATION, run)
.expect("benchmark cannot fail; qed")
.expect("benchmark cannot fail; qed") as u64
}
struct TemporaryFile {
@@ -260,6 +274,7 @@ pub fn benchmark_disk_sequential_writes(directory: &Path) -> Result<u64, String>
};
benchmark("disk sequential write score", SIZE, MAX_ITERATIONS, MAX_DURATION, run)
.map(|s| s as u64)
}
pub fn benchmark_disk_random_writes(directory: &Path) -> Result<u64, String> {
@@ -319,6 +334,45 @@ pub fn benchmark_disk_random_writes(directory: &Path) -> Result<u64, String> {
// We only wrote half of the bytes hence `SIZE / 2`.
benchmark("disk random write score", SIZE / 2, MAX_ITERATIONS, MAX_DURATION, run)
.map(|s| s as u64)
}
/// Benchmarks the verification speed of sr25519 signatures.
///
/// Returns the throughput in MB/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 {
const INPUT_SIZE: usize = 32;
const ITERATION_SIZE: usize = 2048;
let pair = sr25519::Pair::from_string("//Alice", None).unwrap();
let mut rng = rng();
let mut msgs = Vec::new();
let mut sigs = Vec::new();
for _ in 0..ITERATION_SIZE {
let mut msg = vec![0u8; INPUT_SIZE];
rng.fill_bytes(&mut msg[..]);
sigs.push(pair.sign(&msg));
msgs.push(msg);
}
let run = || -> Result<(), String> {
for (sig, msg) in sigs.iter().zip(msgs.iter()) {
let mut ok = sr25519_verify(&sig, &msg[..], &pair.public());
clobber_value(&mut ok);
}
Ok(())
};
benchmark(
"sr25519 verification score",
INPUT_SIZE * ITERATION_SIZE,
limit.max_iterations(),
limit.max_duration(),
run,
)
.expect("sr25519 verification cannot fail; qed")
}
/// Benchmarks the hardware and returns the results of those benchmarks.
@@ -390,4 +444,9 @@ mod tests {
fn test_benchmark_disk_random_writes() {
assert!(benchmark_disk_random_writes("./".as_ref()).unwrap() > 0);
}
#[test]
fn test_benchmark_sr25519_verify() {
assert!(benchmark_sr25519_verify(ExecutionLimit::MaxIterations(1)) > 0.0);
}
}