1use futures::prelude::*;
23use std::time::Duration;
24
25mod sysinfo;
26#[cfg(target_os = "linux")]
27mod sysinfo_linux;
28
29pub use sysinfo::{
30 benchmark_cpu, benchmark_cpu_parallelism, benchmark_disk_random_writes,
31 benchmark_disk_sequential_writes, benchmark_memory, benchmark_sr25519_verify, gather_hwbench,
32 gather_sysinfo, serialize_throughput, serialize_throughput_option, Metric, Requirement,
33 Requirements, Throughput,
34};
35
36pub const TARGET_OS: &str = include_str!(concat!(env!("OUT_DIR"), "/target_os.txt"));
38
39pub const TARGET_ARCH: &str = include_str!(concat!(env!("OUT_DIR"), "/target_arch.txt"));
41
42pub const TARGET_ENV: &str = include_str!(concat!(env!("OUT_DIR"), "/target_env.txt"));
44
45#[derive(Clone, Debug, serde::Serialize)]
47pub struct HwBench {
48 #[serde(serialize_with = "serialize_throughput")]
50 pub cpu_hashrate_score: Throughput,
51 #[serde(serialize_with = "serialize_throughput")]
54 pub parallel_cpu_hashrate_score: Throughput,
55 pub parallel_cpu_cores: usize,
57 #[serde(serialize_with = "serialize_throughput")]
59 pub memory_memcpy_score: Throughput,
60 #[serde(
62 serialize_with = "serialize_throughput_option",
63 skip_serializing_if = "Option::is_none"
64 )]
65 pub disk_sequential_write_score: Option<Throughput>,
66 #[serde(
68 serialize_with = "serialize_throughput_option",
69 skip_serializing_if = "Option::is_none"
70 )]
71 pub disk_random_write_score: Option<Throughput>,
72}
73
74#[derive(Copy, Clone, Debug)]
75pub enum ExecutionLimit {
77 MaxDuration(Duration),
79
80 MaxIterations(usize),
82
83 Both { max_iterations: usize, max_duration: Duration },
85}
86
87impl ExecutionLimit {
88 pub fn from_secs_f32(secs: f32) -> Self {
90 Self::MaxDuration(Duration::from_secs_f32(secs))
91 }
92
93 pub fn max_duration(&self) -> Duration {
95 match self {
96 Self::MaxDuration(d) => *d,
97 Self::Both { max_duration, .. } => *max_duration,
98 _ => Duration::from_secs(u64::MAX),
99 }
100 }
101
102 pub fn max_iterations(&self) -> usize {
104 match self {
105 Self::MaxIterations(d) => *d,
106 Self::Both { max_iterations, .. } => *max_iterations,
107 _ => usize::MAX,
108 }
109 }
110}
111
112pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) {
114 log::info!("💻 Operating system: {}", TARGET_OS);
115 log::info!("💻 CPU architecture: {}", TARGET_ARCH);
116 if !TARGET_ENV.is_empty() {
117 log::info!("💻 Target environment: {}", TARGET_ENV);
118 }
119
120 if let Some(ref cpu) = sysinfo.cpu {
121 log::info!("💻 CPU: {}", cpu);
122 }
123 if let Some(core_count) = sysinfo.core_count {
124 log::info!("💻 CPU cores: {}", core_count);
125 }
126 if let Some(memory) = sysinfo.memory {
127 log::info!("💻 Memory: {}MB", memory / (1024 * 1024));
128 }
129 if let Some(ref linux_kernel) = sysinfo.linux_kernel {
130 log::info!("💻 Kernel: {}", linux_kernel);
131 }
132 if let Some(ref linux_distro) = sysinfo.linux_distro {
133 log::info!("💻 Linux distribution: {}", linux_distro);
134 }
135 if let Some(is_virtual_machine) = sysinfo.is_virtual_machine {
136 log::info!("💻 Virtual machine: {}", if is_virtual_machine { "yes" } else { "no" });
137 }
138}
139
140pub fn print_hwbench(hwbench: &HwBench) {
142 log::info!(
143 "🏁 CPU single core score: {}, parallelism score: {} with expected cores: {}",
144 hwbench.cpu_hashrate_score,
145 hwbench.parallel_cpu_hashrate_score,
146 hwbench.parallel_cpu_cores,
147 );
148 log::info!("🏁 Memory score: {}", hwbench.memory_memcpy_score);
149
150 if let Some(score) = hwbench.disk_sequential_write_score {
151 log::info!("🏁 Disk score (seq. writes): {}", score);
152 }
153 if let Some(score) = hwbench.disk_random_write_score {
154 log::info!("🏁 Disk score (rand. writes): {}", score);
155 }
156}
157
158pub fn initialize_hwbench_telemetry(
160 telemetry_handle: sc_telemetry::TelemetryHandle,
161 hwbench: HwBench,
162) -> impl std::future::Future<Output = ()> {
163 let mut connect_stream = telemetry_handle.on_connect_stream();
164 async move {
165 let payload = serde_json::to_value(&hwbench)
166 .expect("the `HwBench` can always be serialized into a JSON object; qed");
167 let mut payload = match payload {
168 serde_json::Value::Object(map) => map,
169 _ => unreachable!("the `HwBench` always serializes into a JSON object; qed"),
170 };
171 payload.insert("msg".into(), "sysinfo.hwbench".into());
172 while connect_stream.next().await.is_some() {
173 telemetry_handle.send_telemetry(sc_telemetry::SUBSTRATE_INFO, payload.clone());
174 }
175 }
176}