referrerpolicy=no-referrer-when-downgrade

sc_sysinfo/
lib.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
19//! This crate contains the code necessary to gather basic hardware
20//! and software telemetry information about the node on which we're running.
21
22use futures::prelude::*;
23use std::time::Duration;
24
25mod sysinfo;
26#[cfg(target_os = "freebsd")]
27mod sysinfo_freebsd;
28#[cfg(target_os = "linux")]
29mod sysinfo_linux;
30
31pub use sysinfo::{
32	benchmark_cpu, benchmark_cpu_parallelism, benchmark_disk_random_writes,
33	benchmark_disk_sequential_writes, benchmark_memory, benchmark_sr25519_verify, gather_hwbench,
34	gather_sysinfo, serialize_throughput, serialize_throughput_option, Metric, Requirement,
35	Requirements, Throughput,
36};
37
38/// The operating system part of the current target triplet.
39pub const TARGET_OS: &str = include_str!(concat!(env!("OUT_DIR"), "/target_os.txt"));
40
41/// The CPU ISA architecture part of the current target triplet.
42pub const TARGET_ARCH: &str = include_str!(concat!(env!("OUT_DIR"), "/target_arch.txt"));
43
44/// The environment part of the current target triplet.
45pub const TARGET_ENV: &str = include_str!(concat!(env!("OUT_DIR"), "/target_env.txt"));
46
47/// Hardware benchmark results for the node.
48#[derive(Clone, Debug, serde::Serialize)]
49pub struct HwBench {
50	/// The CPU speed, as measured in how many MB/s it can hash using the BLAKE2b-256 hash.
51	#[serde(serialize_with = "serialize_throughput")]
52	pub cpu_hashrate_score: Throughput,
53	/// The parallel CPU speed, as measured in how many MB/s it can hash in parallel using the
54	/// BLAKE2b-256 hash.
55	#[serde(serialize_with = "serialize_throughput")]
56	pub parallel_cpu_hashrate_score: Throughput,
57	/// The number of expected cores used for computing the parallel CPU speed.
58	pub parallel_cpu_cores: usize,
59	/// Memory bandwidth in MB/s, calculated by measuring the throughput of `memcpy`.
60	#[serde(serialize_with = "serialize_throughput")]
61	pub memory_memcpy_score: Throughput,
62	/// Sequential disk write speed in MB/s.
63	#[serde(
64		serialize_with = "serialize_throughput_option",
65		skip_serializing_if = "Option::is_none"
66	)]
67	pub disk_sequential_write_score: Option<Throughput>,
68	/// Random disk write speed in MB/s.
69	#[serde(
70		serialize_with = "serialize_throughput_option",
71		skip_serializing_if = "Option::is_none"
72	)]
73	pub disk_random_write_score: Option<Throughput>,
74}
75
76#[derive(Copy, Clone, Debug)]
77/// Limit the execution time of a benchmark.
78pub enum ExecutionLimit {
79	/// Limit by the maximal duration.
80	MaxDuration(Duration),
81
82	/// Limit by the maximal number of iterations.
83	MaxIterations(usize),
84
85	/// Limit by the maximal duration and maximal number of iterations.
86	Both { max_iterations: usize, max_duration: Duration },
87}
88
89impl ExecutionLimit {
90	/// Creates a new execution limit with the passed seconds as duration limit.
91	pub fn from_secs_f32(secs: f32) -> Self {
92		Self::MaxDuration(Duration::from_secs_f32(secs))
93	}
94
95	/// Returns the duration limit or `MAX` if none is present.
96	pub fn max_duration(&self) -> Duration {
97		match self {
98			Self::MaxDuration(d) => *d,
99			Self::Both { max_duration, .. } => *max_duration,
100			_ => Duration::from_secs(u64::MAX),
101		}
102	}
103
104	/// Returns the iterations limit or `MAX` if none is present.
105	pub fn max_iterations(&self) -> usize {
106		match self {
107			Self::MaxIterations(d) => *d,
108			Self::Both { max_iterations, .. } => *max_iterations,
109			_ => usize::MAX,
110		}
111	}
112}
113
114/// Prints out the system software/hardware information in the logs.
115pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) {
116	log::info!("๐Ÿ’ป Operating system: {}", TARGET_OS);
117	log::info!("๐Ÿ’ป CPU architecture: {}", TARGET_ARCH);
118	if !TARGET_ENV.is_empty() {
119		log::info!("๐Ÿ’ป Target environment: {}", TARGET_ENV);
120	}
121
122	if let Some(ref cpu) = sysinfo.cpu {
123		log::info!("๐Ÿ’ป CPU: {}", cpu);
124	}
125	if let Some(core_count) = sysinfo.core_count {
126		log::info!("๐Ÿ’ป CPU cores: {}", core_count);
127	}
128	if let Some(memory) = sysinfo.memory {
129		log::info!("๐Ÿ’ป Memory: {}MB", memory / (1024 * 1024));
130	}
131	if let Some(ref linux_kernel) = sysinfo.linux_kernel {
132		log::info!("๐Ÿ’ป Kernel: {}", linux_kernel);
133	}
134	if let Some(ref linux_distro) = sysinfo.linux_distro {
135		log::info!("๐Ÿ’ป Linux distribution: {}", linux_distro);
136	}
137	if let Some(is_virtual_machine) = sysinfo.is_virtual_machine {
138		log::info!("๐Ÿ’ป Virtual machine: {}", if is_virtual_machine { "yes" } else { "no" });
139	}
140}
141
142/// Prints out the results of the hardware benchmarks in the logs.
143pub fn print_hwbench(hwbench: &HwBench) {
144	log::info!(
145		"๐Ÿ CPU single core score: {}, parallelism score: {} with expected cores: {}",
146		hwbench.cpu_hashrate_score,
147		hwbench.parallel_cpu_hashrate_score,
148		hwbench.parallel_cpu_cores,
149	);
150	log::info!("๐Ÿ Memory score: {}", hwbench.memory_memcpy_score);
151
152	if let Some(score) = hwbench.disk_sequential_write_score {
153		log::info!("๐Ÿ Disk score (seq. writes): {}", score);
154	}
155	if let Some(score) = hwbench.disk_random_write_score {
156		log::info!("๐Ÿ Disk score (rand. writes): {}", score);
157	}
158}
159
160/// Initializes the hardware benchmarks telemetry.
161pub fn initialize_hwbench_telemetry(
162	telemetry_handle: sc_telemetry::TelemetryHandle,
163	hwbench: HwBench,
164) -> impl std::future::Future<Output = ()> {
165	let mut connect_stream = telemetry_handle.on_connect_stream();
166	async move {
167		let payload = serde_json::to_value(&hwbench)
168			.expect("the `HwBench` can always be serialized into a JSON object; qed");
169		let mut payload = match payload {
170			serde_json::Value::Object(map) => map,
171			_ => unreachable!("the `HwBench` always serializes into a JSON object; qed"),
172		};
173		payload.insert("msg".into(), "sysinfo.hwbench".into());
174		while connect_stream.next().await.is_some() {
175			telemetry_handle.send_telemetry(sc_telemetry::SUBSTRATE_INFO, payload.clone());
176		}
177	}
178}