1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use futures::prelude::*;
use std::time::Duration;
mod sysinfo;
#[cfg(target_os = "linux")]
mod sysinfo_linux;
pub use sysinfo::{
benchmark_cpu, benchmark_disk_random_writes, benchmark_disk_sequential_writes,
benchmark_memory, benchmark_sr25519_verify, gather_hwbench, gather_sysinfo,
};
pub const TARGET_OS: &str = include_str!(concat!(env!("OUT_DIR"), "/target_os.txt"));
pub const TARGET_ARCH: &str = include_str!(concat!(env!("OUT_DIR"), "/target_arch.txt"));
pub const TARGET_ENV: &str = include_str!(concat!(env!("OUT_DIR"), "/target_env.txt"));
#[derive(Clone, Debug, serde::Serialize)]
pub struct HwBench {
pub cpu_hashrate_score: u64,
pub memory_memcpy_score: u64,
pub disk_sequential_write_score: Option<u64>,
pub disk_random_write_score: Option<u64>,
}
pub enum ExecutionLimit {
MaxDuration(Duration),
MaxIterations(usize),
Both { max_iterations: usize, max_duration: Duration },
}
impl ExecutionLimit {
pub fn from_secs_f32(secs: f32) -> Self {
Self::MaxDuration(Duration::from_secs_f32(secs))
}
pub fn max_duration(&self) -> Duration {
match self {
Self::MaxDuration(d) => *d,
Self::Both { max_duration, .. } => *max_duration,
_ => Duration::from_secs(u64::MAX),
}
}
pub fn max_iterations(&self) -> usize {
match self {
Self::MaxIterations(d) => *d,
Self::Both { max_iterations, .. } => *max_iterations,
_ => usize::MAX,
}
}
}
pub fn print_sysinfo(sysinfo: &sc_telemetry::SysInfo) {
log::info!("💻 Operating system: {}", TARGET_OS);
log::info!("💻 CPU architecture: {}", TARGET_ARCH);
if !TARGET_ENV.is_empty() {
log::info!("💻 Target environment: {}", TARGET_ENV);
}
if let Some(ref cpu) = sysinfo.cpu {
log::info!("💻 CPU: {}", cpu);
}
if let Some(core_count) = sysinfo.core_count {
log::info!("💻 CPU cores: {}", core_count);
}
if let Some(memory) = sysinfo.memory {
log::info!("💻 Memory: {}MB", memory / (1024 * 1024));
}
if let Some(ref linux_kernel) = sysinfo.linux_kernel {
log::info!("💻 Kernel: {}", linux_kernel);
}
if let Some(ref linux_distro) = sysinfo.linux_distro {
log::info!("💻 Linux distribution: {}", linux_distro);
}
if let Some(is_virtual_machine) = sysinfo.is_virtual_machine {
log::info!("💻 Virtual machine: {}", if is_virtual_machine { "yes" } else { "no" });
}
}
pub fn print_hwbench(hwbench: &HwBench) {
log::info!("🏁 CPU score: {}MB/s", hwbench.cpu_hashrate_score);
log::info!("🏁 Memory score: {}MB/s", hwbench.memory_memcpy_score);
if let Some(score) = hwbench.disk_sequential_write_score {
log::info!("🏁 Disk score (seq. writes): {}MB/s", score);
}
if let Some(score) = hwbench.disk_random_write_score {
log::info!("🏁 Disk score (rand. writes): {}MB/s", score);
}
}
pub fn initialize_hwbench_telemetry(
telemetry_handle: sc_telemetry::TelemetryHandle,
hwbench: HwBench,
) -> impl std::future::Future<Output = ()> {
let mut connect_stream = telemetry_handle.on_connect_stream();
async move {
let payload = serde_json::to_value(&hwbench)
.expect("the `HwBench` can always be serialized into a JSON object; qed");
let mut payload = match payload {
serde_json::Value::Object(map) => map,
_ => unreachable!("the `HwBench` always serializes into a JSON object; qed"),
};
payload.insert("msg".into(), "sysinfo.hwbench".into());
while connect_stream.next().await.is_some() {
telemetry_handle.send_telemetry(sc_telemetry::SUBSTRATE_INFO, payload.clone());
}
}
}