referrerpolicy=no-referrer-when-downgrade

node_bench/
core.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use serde::Serialize;
20use std::{
21	borrow::{Cow, ToOwned},
22	fmt,
23};
24
25pub struct Path(Vec<String>);
26
27impl Path {
28	pub fn new(initial: &'static [&'static str]) -> Self {
29		Path(initial.iter().map(|x| x.to_string()).collect())
30	}
31}
32
33impl Path {
34	pub fn push(&mut self, item: &str) {
35		self.0.push(item.to_string());
36	}
37
38	pub fn full(&self) -> String {
39		self.0.iter().fold(String::new(), |mut val, next| {
40			val.push_str("::");
41			val.push_str(next);
42			val
43		})
44	}
45
46	pub fn has(&self, path: &str) -> bool {
47		self.full().contains(path)
48	}
49}
50
51pub trait BenchmarkDescription {
52	fn path(&self) -> Path;
53
54	fn setup(self: Box<Self>) -> Box<dyn Benchmark>;
55
56	fn name(&self) -> Cow<'static, str>;
57}
58
59pub trait Benchmark {
60	fn run(&mut self, mode: Mode) -> std::time::Duration;
61}
62
63#[derive(Debug, Clone, Serialize)]
64pub struct BenchmarkOutput {
65	name: String,
66	raw_average: u64,
67	average: u64,
68}
69
70pub struct NsFormatter(pub u64);
71
72impl fmt::Display for NsFormatter {
73	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74		let v = self.0;
75		match v {
76			v if v < 100 => write!(f, "{} ns", v),
77			v if v < 100_000 => write!(f, "{:.1} µs", v as f64 / 1000.0),
78			v if v < 1_000_000 => write!(f, "{:.4} ms", v as f64 / 1_000_000.0),
79			v if v < 100_000_000 => write!(f, "{:.1} ms", v as f64 / 1_000_000.0),
80			_ => write!(f, "{:.4} s", v as f64 / 1_000_000_000.0),
81		}
82	}
83}
84
85#[derive(Debug, Clone, Copy, PartialEq)]
86pub enum Mode {
87	Regular,
88	Profile,
89}
90
91impl std::str::FromStr for Mode {
92	type Err = &'static str;
93	fn from_str(day: &str) -> Result<Self, Self::Err> {
94		match day {
95			"regular" => Ok(Mode::Regular),
96			"profile" => Ok(Mode::Profile),
97			_ => Err("Could not parse mode"),
98		}
99	}
100}
101
102impl fmt::Display for BenchmarkOutput {
103	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104		write!(
105			f,
106			"{}: avg {}, w_avg {}",
107			self.name,
108			NsFormatter(self.raw_average),
109			NsFormatter(self.average),
110		)
111	}
112}
113
114pub fn run_benchmark(benchmark: Box<dyn BenchmarkDescription>, mode: Mode) -> BenchmarkOutput {
115	let name = benchmark.name().to_owned();
116	let mut benchmark = benchmark.setup();
117
118	let mut durations: Vec<u128> = vec![];
119	for _ in 0..50 {
120		let duration = benchmark.run(mode);
121		durations.push(duration.as_nanos());
122	}
123
124	durations.sort();
125
126	let raw_average = (durations.iter().sum::<u128>() / (durations.len() as u128)) as u64;
127	let average = (durations.iter().skip(10).take(30).sum::<u128>() / 30) as u64;
128
129	BenchmarkOutput { name: name.into(), raw_average, average }
130}
131
132macro_rules! matrix(
133	( $var:tt in $over:expr => $tt:expr,  $( $rest:tt )* ) => {
134		{
135			let mut res = Vec::<Box<dyn crate::core::BenchmarkDescription>>::new();
136			for $var in $over {
137				res.push(Box::new($tt));
138			}
139			res.extend(matrix!( $($rest)* ));
140			res
141		}
142	};
143	( $var:expr, $( $rest:tt )*) => {
144		{
145			let mut res = vec![Box::new($var) as Box<dyn crate::core::BenchmarkDescription>];
146			res.extend(matrix!( $($rest)* ));
147			res
148		}
149	};
150	() => { vec![] }
151);