referrerpolicy=no-referrer-when-downgrade

node_bench/
main.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
19mod common;
20mod construct;
21#[macro_use]
22mod core;
23mod generator;
24mod import;
25mod simple_trie;
26mod state_sizes;
27mod tempdb;
28mod trie;
29mod txpool;
30
31use clap::Parser;
32
33use node_testing::bench::{BlockType, DatabaseType as BenchDataBaseType, KeyTypes};
34
35use crate::{
36	common::SizeType,
37	construct::ConstructionBenchmarkDescription,
38	core::{run_benchmark, Mode as BenchmarkMode},
39	import::ImportBenchmarkDescription,
40	tempdb::DatabaseType,
41	trie::{DatabaseSize, TrieReadBenchmarkDescription, TrieWriteBenchmarkDescription},
42	txpool::PoolBenchmarkDescription,
43};
44
45#[derive(Debug, Parser)]
46#[command(name = "node-bench", about = "Node integration benchmarks")]
47struct Opt {
48	/// Show list of all available benchmarks.
49	///
50	/// Will output ("name", "path"). Benchmarks can then be filtered by path.
51	#[arg(short, long)]
52	list: bool,
53
54	/// Machine readable json output.
55	///
56	/// This also suppresses all regular output (except to stderr)
57	#[arg(short, long)]
58	json: bool,
59
60	/// Filter benchmarks.
61	///
62	/// Run with `--list` for the hint of what to filter.
63	filter: Option<String>,
64
65	/// Number of transactions for block import with `custom` size.
66	#[arg(long)]
67	transactions: Option<usize>,
68
69	/// Mode
70	///
71	/// "regular" for regular benchmark
72	///
73	/// "profile" mode adds pauses between measurable runs,
74	/// so that actual interval can be selected in the profiler of choice.
75	#[arg(short, long, default_value = "regular")]
76	mode: BenchmarkMode,
77}
78
79fn main() {
80	let opt = Opt::parse();
81
82	if !opt.json {
83		sp_tracing::try_init_simple();
84	}
85
86	let mut import_benchmarks = Vec::new();
87
88	for size in [
89		SizeType::Empty,
90		SizeType::Small,
91		SizeType::Medium,
92		SizeType::Large,
93		SizeType::Full,
94		SizeType::Custom(opt.transactions.unwrap_or(0)),
95	] {
96		for block_type in [
97			BlockType::RandomTransfersKeepAlive,
98			BlockType::RandomTransfersReaping,
99			BlockType::Noop,
100		] {
101			for database_type in [BenchDataBaseType::RocksDb, BenchDataBaseType::ParityDb] {
102				import_benchmarks.push((size, block_type, database_type));
103			}
104		}
105	}
106
107	let benchmarks = matrix!(
108		(size, block_type, database_type) in import_benchmarks.into_iter() =>
109			ImportBenchmarkDescription {
110				key_types: KeyTypes::Sr25519,
111				size,
112				block_type,
113				database_type,
114			},
115		(size, db_type) in
116			[
117				DatabaseSize::Empty, DatabaseSize::Smallest, DatabaseSize::Small,
118				DatabaseSize::Medium, DatabaseSize::Large, DatabaseSize::Huge,
119			]
120			.iter().flat_map(|size|
121			[
122				DatabaseType::RocksDb, DatabaseType::ParityDb
123			]
124			.iter().map(move |db_type| (size, db_type)))
125			=> TrieReadBenchmarkDescription { database_size: *size, database_type: *db_type },
126		(size, db_type) in
127			[
128				DatabaseSize::Empty, DatabaseSize::Smallest, DatabaseSize::Small,
129				DatabaseSize::Medium, DatabaseSize::Large, DatabaseSize::Huge,
130			]
131			.iter().flat_map(|size|
132			[
133				DatabaseType::RocksDb, DatabaseType::ParityDb
134			]
135			.iter().map(move |db_type| (size, db_type)))
136			=> TrieWriteBenchmarkDescription { database_size: *size, database_type: *db_type },
137		ConstructionBenchmarkDescription {
138			key_types: KeyTypes::Sr25519,
139			block_type: BlockType::RandomTransfersKeepAlive,
140			size: SizeType::Medium,
141			database_type: BenchDataBaseType::RocksDb,
142		},
143		ConstructionBenchmarkDescription {
144			key_types: KeyTypes::Sr25519,
145			block_type: BlockType::RandomTransfersKeepAlive,
146			size: SizeType::Large,
147			database_type: BenchDataBaseType::RocksDb,
148		},
149		PoolBenchmarkDescription { database_type: BenchDataBaseType::RocksDb },
150	);
151
152	if opt.list {
153		println!("Available benchmarks:");
154		if let Some(filter) = opt.filter.as_ref() {
155			println!("\t(filtered by \"{}\")", filter);
156		}
157		for benchmark in benchmarks.iter() {
158			if opt.filter.as_ref().map(|f| benchmark.path().has(f)).unwrap_or(true) {
159				println!("{}: {}", benchmark.name(), benchmark.path().full())
160			}
161		}
162		return
163	}
164
165	let mut results = Vec::new();
166	for benchmark in benchmarks {
167		if opt.filter.as_ref().map(|f| benchmark.path().has(f)).unwrap_or(true) {
168			log::info!("Starting {}", benchmark.name());
169			let result = run_benchmark(benchmark, opt.mode);
170			log::info!("{}", result);
171
172			results.push(result);
173		}
174	}
175
176	if results.is_empty() {
177		eprintln!("No benchmark was found for query");
178		std::process::exit(1);
179	}
180
181	if opt.json {
182		let json_result: String =
183			serde_json::to_string(&results).expect("Failed to construct json");
184		println!("{}", json_result);
185	}
186}