use std::sync::{Arc, LazyLock};
pub static SYSTEM: LazyLock<Arc<SystemProfile>> =
LazyLock::new(|| Arc::new(SystemProfile::detect()));
#[derive(Debug, Clone)]
pub struct SystemProfile {
pub cpu_count: usize,
pub physical_cpu_count: usize,
pub total_memory: u64,
pub available_memory: u64,
pub os_name: String,
pub os_version: String,
pub hostname: String,
pub is_macos: bool,
pub is_windows: bool,
pub is_linux: bool,
pub recommended_io_workers: usize,
pub recommended_cpu_workers: usize,
}
impl SystemProfile {
fn detect() -> Self {
use sysinfo::System;
let cpu_count = num_cpus::get();
let physical_cpu_count = num_cpus::get_physical();
let mut sys = System::new_with_specifics(
sysinfo::RefreshKind::new().with_memory(sysinfo::MemoryRefreshKind::everything()),
);
sys.refresh_memory();
let total_memory = sys.total_memory();
let available_memory = sys.available_memory();
let os_name = System::name().unwrap_or_else(|| "Unknown".to_string());
let os_version = System::os_version().unwrap_or_else(|| "Unknown".to_string());
let hostname = System::host_name().unwrap_or_else(|| "Unknown".to_string());
let is_macos = cfg!(target_os = "macos");
let is_windows = cfg!(target_os = "windows");
let is_linux = cfg!(target_os = "linux");
let recommended_io_workers = cpu_count * 2;
let recommended_cpu_workers = physical_cpu_count;
Self {
cpu_count,
physical_cpu_count,
total_memory,
available_memory,
os_name,
os_version,
hostname,
is_macos,
is_windows,
is_linux,
recommended_io_workers,
recommended_cpu_workers,
}
}
pub fn get() -> Arc<SystemProfile> {
SYSTEM.clone()
}
pub fn calculate_workers(&self, percentage: usize) -> usize {
let percentage = percentage.min(100) as f32 / 100.0;
((self.cpu_count as f32 * percentage).ceil() as usize).max(1)
}
pub fn calculate_workers_with_limit(&self, percentage: usize, max_threads: usize) -> usize {
if max_threads > 0 {
self.calculate_workers(percentage).min(max_threads)
} else {
self.calculate_workers(percentage)
}
}
pub fn adapt_workers_for_workload(&self, item_count: usize, max_workers: usize) -> usize {
match item_count {
0..=10 => 1.min(max_workers), 11..=50 => (max_workers / 2).max(1), 51..=100 => (max_workers * 3 / 4).max(1), _ => max_workers, }
}
pub fn should_use_parallel(&self, min_memory_mb: u64) -> bool {
self.cpu_count > 1 && self.available_memory > (min_memory_mb * 1024 * 1024)
}
pub fn summary(&self) -> String {
format!(
"System: {} {} on {}\nCPUs: {} ({} physical)\nMemory: {:.2} GB ({:.2} GB \
available)\nHost: {}",
self.os_name,
self.os_version,
if self.is_macos {
"macOS"
} else if self.is_windows {
"Windows"
} else if self.is_linux {
"Linux"
} else {
"Other"
},
self.cpu_count,
self.physical_cpu_count,
self.total_memory as f64 / (1024.0 * 1024.0 * 1024.0),
self.available_memory as f64 / (1024.0 * 1024.0 * 1024.0),
self.hostname
)
}
pub fn total_memory_gb(&self) -> f64 {
self.total_memory as f64 / (1024.0 * 1024.0 * 1024.0)
}
pub fn available_memory_gb(&self) -> f64 {
self.available_memory as f64 / (1024.0 * 1024.0 * 1024.0)
}
}
impl SystemProfile {
pub fn cpu_count() -> usize {
SYSTEM.cpu_count
}
pub fn physical_cpu_count() -> usize {
SYSTEM.physical_cpu_count
}
pub fn is_multicore() -> bool {
SYSTEM.cpu_count > 1
}
pub fn is_macos() -> bool {
SYSTEM.is_macos
}
pub fn is_windows() -> bool {
SYSTEM.is_windows
}
pub fn is_linux() -> bool {
SYSTEM.is_linux
}
}
#[cfg(feature = "gpu")]
pub mod gpu {
#[derive(Debug, Clone)]
pub struct GpuInfo {
pub name: String,
pub memory_mb: u64,
pub cuda_cores: Option<u32>,
}
pub fn detect_nvidia_gpus() -> Vec<GpuInfo> {
vec![]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_system_profile_initialization() {
let profile = SystemProfile::get();
assert!(profile.cpu_count > 0);
assert!(profile.physical_cpu_count > 0);
assert!(profile.total_memory > 0);
assert!(profile.is_macos || profile.is_windows || profile.is_linux);
}
#[test]
fn test_worker_calculation() {
let profile = SystemProfile::get();
let half_workers = profile.calculate_workers(50);
assert!(half_workers >= 1);
assert!(half_workers <= profile.cpu_count);
let full_workers = profile.calculate_workers(100);
assert_eq!(full_workers, profile.cpu_count);
let limited = profile.calculate_workers_with_limit(100, 4);
assert!(limited <= 4);
}
#[test]
fn test_workload_adaptation() {
let profile = SystemProfile::get();
let max_workers = 8;
assert_eq!(profile.adapt_workers_for_workload(5, max_workers), 1);
let medium = profile.adapt_workers_for_workload(30, max_workers);
assert!(medium <= max_workers / 2);
assert_eq!(
profile.adapt_workers_for_workload(200, max_workers),
max_workers
);
}
#[test]
fn test_static_access() {
let profile1 = SystemProfile::get();
let profile2 = SystemProfile::get();
assert_eq!(profile1.cpu_count, profile2.cpu_count);
assert_eq!(SystemProfile::cpu_count(), profile1.cpu_count);
assert_eq!(
SystemProfile::physical_cpu_count(),
profile1.physical_cpu_count
);
}
#[test]
fn test_summary() {
let profile = SystemProfile::get();
let summary = profile.summary();
assert!(summary.contains("CPUs:"));
assert!(summary.contains("Memory:"));
assert!(summary.contains("System:"));
}
}