hft_benchmarks/
server_config.rs

1//! Server-optimized benchmark configuration
2
3use std::time::Duration;
4
5/// Configure Criterion for server benchmarking with high precision
6pub fn configure_for_server_memory_benchmarks(group: &mut criterion::BenchmarkGroup<criterion::measurement::WallTime>) {
7    // Server-specific configuration for memory benchmarks
8    #[cfg(target_arch = "x86_64")]
9    {
10        // x86_64 server configuration
11        group.sample_size(5000);                              // High sample size for precision
12        group.measurement_time(Duration::from_secs(180));     // Long measurement time
13        group.warm_up_time(Duration::from_secs(30));          // Extended warmup
14        group.confidence_level(0.95);                         // Standard 95% confidence
15        group.noise_threshold(0.005);                         // Very low noise tolerance (0.5%)
16        group.significance_level(0.01);                       // Strict significance testing
17    }
18    #[cfg(target_arch = "aarch64")]
19    {
20        // ARM64 server configuration (less common but supported)
21        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
30/// Configure Criterion for server CPU benchmarks
31pub 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);                             // Very high sample size
35        group.measurement_time(Duration::from_secs(240));     // 4 minutes for stability
36        group.warm_up_time(Duration::from_secs(20));
37        group.confidence_level(0.99);                         // 99% confidence for critical measurements
38        group.noise_threshold(0.002);                         // Ultra-low noise tolerance (0.2%)
39        group.significance_level(0.005);                      // Very strict significance
40    }
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
52/// Pre-warm system for server benchmarking
53pub fn prewarm_server_subsystems() {
54    println!("šŸ”„ Pre-warming server subsystems...");
55    
56    // Warm up allocators across NUMA nodes
57    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            // Allocate memory on this NUMA node
64            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    // CPU cache warming
74    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    // System call warming
81    for _ in 0..100 {
82        let _ = std::time::SystemTime::now();
83        std::thread::yield_now();
84    }
85    
86    // Allow system to settle
87    std::thread::sleep(Duration::from_secs(5));
88    println!("āœ… Server subsystems warmed up");
89}
90
91/// Check server environment suitability
92pub 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    // Check if running in container/VM
98    if is_virtualized() {
99        issues.push("Running on virtualized hardware - not optimal for HFT".to_string());
100    }
101    
102    // Check CPU count
103    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    // Check memory
110    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    // Check CPU governor
122    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    // Check system load
130    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    // Check for NUMA
137    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
151/// Server environment assessment
152pub 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        // System Information
165        println!("\nšŸ“Š System Information:");
166        for (key, value) in &self.info {
167            println!("   {}: {}", key.replace('_', " "), value);
168        }
169        
170        // Assessment
171        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        // Recommendations
192        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
205// Helper functions
206
207fn is_virtualized() -> bool {
208    // Check for common virtualization indicators
209    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,       // Convert to GB
235            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}