hft_benchmarks/
server_config.rs1use std::time::Duration;
4
5pub fn configure_for_server_memory_benchmarks(group: &mut criterion::BenchmarkGroup<criterion::measurement::WallTime>) {
7 #[cfg(target_arch = "x86_64")]
9 {
10 group.sample_size(5000); group.measurement_time(Duration::from_secs(180)); group.warm_up_time(Duration::from_secs(30)); group.confidence_level(0.95); group.noise_threshold(0.005); group.significance_level(0.01); }
18 #[cfg(target_arch = "aarch64")]
19 {
20 group.sample_size(3000);
22 group.measurement_time(Duration::from_secs(120));
23 group.warm_up_time(Duration::from_secs(20));
24 group.confidence_level(0.95);
25 group.noise_threshold(0.01);
26 group.significance_level(0.01);
27 }
28}
29
30pub fn configure_for_server_cpu_benchmarks(group: &mut criterion::BenchmarkGroup<criterion::measurement::WallTime>) {
32 #[cfg(target_arch = "x86_64")]
33 {
34 group.sample_size(10000); group.measurement_time(Duration::from_secs(240)); group.warm_up_time(Duration::from_secs(20));
37 group.confidence_level(0.99); group.noise_threshold(0.002); group.significance_level(0.005); }
41 #[cfg(target_arch = "aarch64")]
42 {
43 group.sample_size(7000);
44 group.measurement_time(Duration::from_secs(180));
45 group.warm_up_time(Duration::from_secs(15));
46 group.confidence_level(0.99);
47 group.noise_threshold(0.005);
48 group.significance_level(0.01);
49 }
50}
51
52pub fn prewarm_server_subsystems() {
54 println!("š„ Pre-warming server subsystems...");
55
56 for node in 0..get_numa_node_count() {
58 if let Ok(_) = std::process::Command::new("numactl")
59 .args([&format!("--cpunodebind={node}"), "--membind", &node.to_string()])
60 .args(["echo", "warming", "node"])
61 .output()
62 {
63 let sizes = [1024, 4096, 16384, 65536];
65 for &size in &sizes {
66 let vec = vec![0u8; size];
67 std::hint::black_box(&vec);
68 drop(vec);
69 }
70 }
71 }
72
73 for _ in 0..1000 {
75 let data: Vec<u64> = (0..1000).collect();
76 let _sum: u64 = data.iter().sum();
77 std::hint::black_box(_sum);
78 }
79
80 for _ in 0..100 {
82 let _ = std::time::SystemTime::now();
83 std::thread::yield_now();
84 }
85
86 std::thread::sleep(Duration::from_secs(5));
88 println!("ā
Server subsystems warmed up");
89}
90
91pub fn check_server_environment() -> ServerEnvironment {
93 let mut issues = Vec::new();
94 let mut warnings = Vec::new();
95 let mut info = std::collections::HashMap::new();
96
97 if is_virtualized() {
99 issues.push("Running on virtualized hardware - not optimal for HFT".to_string());
100 }
101
102 let cpu_count = num_cpus::get();
104 info.insert("cpu_count".to_string(), cpu_count.to_string());
105 if cpu_count < 8 {
106 warnings.push(format!("Low CPU count: {cpu_count} (recommended: 16+)"));
107 }
108
109 let (total_mem_gb, available_mem_gb) = get_memory_info();
111 info.insert("total_memory_gb".to_string(), format!("{total_mem_gb:.1}"));
112 info.insert("available_memory_gb".to_string(), format!("{available_mem_gb:.1}"));
113
114 if total_mem_gb < 16.0 {
115 warnings.push(format!("Low total memory: {total_mem_gb:.1}GB (recommended: 32GB+)"));
116 }
117 if available_mem_gb < 8.0 {
118 issues.push(format!("Low available memory: {available_mem_gb:.1}GB"));
119 }
120
121 if let Some(governor) = get_cpu_governor() {
123 info.insert("cpu_governor".to_string(), governor.clone());
124 if governor != "performance" {
125 warnings.push(format!("CPU governor not optimal: {governor} (should be 'performance')"));
126 }
127 }
128
129 let load_avg = get_load_average();
131 info.insert("load_average".to_string(), format!("{load_avg:.2}"));
132 if load_avg > 2.0 {
133 warnings.push(format!("High system load: {load_avg:.2}"));
134 }
135
136 let numa_nodes = get_numa_node_count();
138 info.insert("numa_nodes".to_string(), numa_nodes.to_string());
139 if numa_nodes > 1 {
140 info.insert("numa_topology".to_string(), "detected".to_string());
141 }
142
143 ServerEnvironment {
144 is_optimal: issues.is_empty(),
145 issues,
146 warnings,
147 info,
148 }
149}
150
151pub struct ServerEnvironment {
153 pub is_optimal: bool,
154 pub issues: Vec<String>,
155 pub warnings: Vec<String>,
156 pub info: std::collections::HashMap<String, String>,
157}
158
159impl ServerEnvironment {
160 pub fn print_detailed_report(&self) {
161 println!("š„ļø Server Benchmark Environment Report");
162 println!("=======================================");
163
164 println!("\nš System Information:");
166 for (key, value) in &self.info {
167 println!(" {}: {}", key.replace('_', " "), value);
168 }
169
170 if self.is_optimal {
172 println!("\nā
OPTIMAL: Server environment is ideal for HFT benchmarking");
173 } else {
174 println!("\nā ISSUES DETECTED: Server environment has problems");
175 }
176
177 if !self.issues.is_empty() {
178 println!("\nā Critical Issues:");
179 for issue in &self.issues {
180 println!(" - {issue}");
181 }
182 }
183
184 if !self.warnings.is_empty() {
185 println!("\nā ļø Warnings:");
186 for warning in &self.warnings {
187 println!(" - {warning}");
188 }
189 }
190
191 if !self.is_optimal || !self.warnings.is_empty() {
193 println!("\nš” Recommendations:");
194 println!(" - Run with: sudo ./scripts/server-benchmark-setup.sh run");
195 println!(" - Ensure bare metal (no virtualization)");
196 println!(" - Set CPU governor to 'performance'");
197 println!(" - Stop non-essential services");
198 println!(" - Use CPU isolation and NUMA binding");
199 }
200
201 println!("=======================================");
202 }
203}
204
205fn is_virtualized() -> bool {
208 std::fs::read_to_string("/proc/cpuinfo")
210 .map(|content| content.contains("hypervisor"))
211 .unwrap_or(false)
212 || std::path::Path::new("/proc/xen").exists()
213 || std::path::Path::new("/sys/hypervisor/uuid").exists()
214}
215
216fn get_memory_info() -> (f64, f64) {
217 if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
218 let mut total_kb = 0u64;
219 let mut available_kb = 0u64;
220
221 for line in meminfo.lines() {
222 if line.starts_with("MemTotal:") {
223 total_kb = line.split_whitespace().nth(1)
224 .and_then(|s| s.parse().ok())
225 .unwrap_or(0);
226 } else if line.starts_with("MemAvailable:") {
227 available_kb = line.split_whitespace().nth(1)
228 .and_then(|s| s.parse().ok())
229 .unwrap_or(0);
230 }
231 }
232
233 (
234 total_kb as f64 / 1024.0 / 1024.0, available_kb as f64 / 1024.0 / 1024.0,
236 )
237 } else {
238 (0.0, 0.0)
239 }
240}
241
242fn get_cpu_governor() -> Option<String> {
243 std::fs::read_to_string("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor")
244 .ok()
245 .map(|s| s.trim().to_string())
246}
247
248fn get_load_average() -> f64 {
249 std::fs::read_to_string("/proc/loadavg")
250 .ok()
251 .and_then(|content| {
252 content.split_whitespace()
253 .next()
254 .and_then(|s| s.parse().ok())
255 })
256 .unwrap_or(0.0)
257}
258
259fn get_numa_node_count() -> usize {
260 std::process::Command::new("numactl")
261 .args(["--hardware"])
262 .output()
263 .ok()
264 .and_then(|output| {
265 let output_str = String::from_utf8_lossy(&output.stdout);
266 output_str.lines()
267 .find(|line| line.contains("available:"))
268 .and_then(|line| {
269 line.split_whitespace()
270 .nth(1)
271 .and_then(|s| s.parse().ok())
272 })
273 })
274 .unwrap_or(1)
275}