use std::sync::OnceLock;
mod banner;
mod platform;
mod select;
mod tier;
pub mod thresholds;
pub use banner::startup_banner;
pub use select::{
clear_test_backend_override, forced_backend_from_env, forced_backend_from_env_uncached,
gpu_could_engage, parse_backend_str, select_backend, select_backend_for_batch,
set_test_backend_override,
};
pub use tier::{
classify_gpu_tier, gpu_min_bytes_for_tier, gpu_pattern_breakeven_for_tier,
gpu_solo_bytes_for_tier, GpuTier,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ScanBackend {
Gpu,
MegaScan,
SimdCpu,
CpuFallback,
}
impl ScanBackend {
#[must_use]
pub fn label(self) -> &'static str {
match self {
Self::Gpu => "gpu-zero-copy",
Self::MegaScan => "gpu-mega-scan",
Self::SimdCpu => "simd-regex",
Self::CpuFallback => "cpu-fallback",
}
}
}
#[derive(Debug, Clone)]
pub struct HardwareCaps {
pub physical_cores: usize,
pub logical_cores: usize,
pub has_avx2: bool,
pub has_avx512: bool,
pub has_neon: bool,
pub gpu_available: bool,
pub gpu_name: Option<String>,
pub gpu_vram_mb: Option<u64>,
pub gpu_is_software: bool,
pub total_memory_mb: Option<u64>,
pub io_uring_available: bool,
pub hyperscan_available: bool,
}
static HW_PROBE: OnceLock<HardwareCaps> = OnceLock::new();
pub fn probe_hardware() -> &'static HardwareCaps {
HW_PROBE.get_or_init(|| {
let logical_cores = std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(1);
let physical_cores = platform::physical_core_count().unwrap_or(logical_cores);
#[cfg(target_arch = "x86_64")]
let (has_avx2, has_avx512, has_neon) = (
std::arch::is_x86_feature_detected!("avx2"),
std::arch::is_x86_feature_detected!("avx512f"),
false,
);
#[cfg(target_arch = "aarch64")]
let (has_avx2, has_avx512, has_neon) = (false, false, true);
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
let (has_avx2, has_avx512, has_neon) = (false, false, false);
let (gpu_available, gpu_name, gpu_vram_mb) = crate::gpu::gpu_probe();
let gpu_is_software = gpu_name.as_deref().is_some_and(|name: &str| {
let lower = name.to_ascii_lowercase();
lower.contains("llvmpipe")
|| lower.contains("lavapipe")
|| lower.contains("swiftshader")
});
if gpu_is_software {
tracing::warn!(
gpu = ?gpu_name,
"Software GPU detected: GPU scanning disabled (slower than CPU)"
);
}
let hyperscan_available = cfg!(feature = "simd");
let total_memory_mb = platform::detect_total_memory_mb();
let io_uring_available = platform::detect_io_uring();
let caps = HardwareCaps {
physical_cores,
logical_cores,
has_avx2,
has_avx512,
has_neon,
gpu_available,
gpu_name: gpu_name.clone(),
gpu_vram_mb,
gpu_is_software,
total_memory_mb,
io_uring_available,
hyperscan_available,
};
tracing::info!(
physical_cores,
logical_cores,
gpu_available,
gpu_name = ?gpu_name,
has_avx512 = caps.has_avx512,
has_avx2 = caps.has_avx2,
has_neon = caps.has_neon,
hyperscan = hyperscan_available,
io_uring = io_uring_available,
"hardware probe complete"
);
caps
})
}