Skip to main content

astra_core/
hal.rs

1#[derive(Debug, Clone, Copy)]
2pub enum IoMode {
3    IoUring,
4    Posix,
5}
6
7#[derive(Debug, Clone)]
8pub struct HalProfile {
9    pub arch: String,
10    pub kernel_release: Option<String>,
11    pub io_mode: IoMode,
12    pub sse42: bool,
13    pub avx2: bool,
14    pub neon: bool,
15}
16
17impl HalProfile {
18    pub fn detect() -> Self {
19        let arch = std::env::consts::ARCH.to_string();
20        let kernel_release = detect_kernel_release();
21
22        #[cfg(target_arch = "x86_64")]
23        let sse42 = std::is_x86_feature_detected!("sse4.2");
24        #[cfg(not(target_arch = "x86_64"))]
25        let sse42 = false;
26
27        #[cfg(target_arch = "x86_64")]
28        let avx2 = std::is_x86_feature_detected!("avx2");
29        #[cfg(not(target_arch = "x86_64"))]
30        let avx2 = false;
31
32        #[cfg(target_arch = "aarch64")]
33        let neon = std::arch::is_aarch64_feature_detected!("neon");
34        #[cfg(not(target_arch = "aarch64"))]
35        let neon = false;
36
37        let io_mode = if supports_io_uring(kernel_release.as_deref()) {
38            IoMode::IoUring
39        } else {
40            IoMode::Posix
41        };
42
43        Self {
44            arch,
45            kernel_release,
46            io_mode,
47            sse42,
48            avx2,
49            neon,
50        }
51    }
52
53    pub fn startup_line(&self) -> String {
54        let io = match self.io_mode {
55            IoMode::IoUring => "io_uring",
56            IoMode::Posix => "epoll/preadv/pwritev fallback",
57        };
58
59        format!(
60            "HAL detected arch={} kernel={:?} io_mode={} sse4.2={} avx2={} neon={}",
61            self.arch, self.kernel_release, io, self.sse42, self.avx2, self.neon
62        )
63    }
64}
65
66fn detect_kernel_release() -> Option<String> {
67    #[cfg(target_os = "linux")]
68    {
69        std::fs::read_to_string("/proc/sys/kernel/osrelease")
70            .ok()
71            .map(|s| s.trim().to_string())
72    }
73
74    #[cfg(not(target_os = "linux"))]
75    {
76        None
77    }
78}
79
80fn supports_io_uring(kernel_release: Option<&str>) -> bool {
81    #[cfg(not(target_os = "linux"))]
82    {
83        let _ = kernel_release;
84        return false;
85    }
86
87    #[cfg(target_os = "linux")]
88    {
89        let Some(release) = kernel_release else {
90            return false;
91        };
92
93        let mut parts = release
94            .split(['.', '-'])
95            .filter_map(|p| p.parse::<u64>().ok());
96
97        let major = parts.next().unwrap_or(0);
98        let minor = parts.next().unwrap_or(0);
99
100        major > 5 || (major == 5 && minor >= 1)
101    }
102}
103
104#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
105#[multiversion::multiversion(targets("x86_64+avx2", "x86_64+sse4.2", "aarch64+neon"))]
106pub fn simd_accumulate(bytes: &[u8]) -> u64 {
107    bytes.iter().map(|b| u64::from(*b)).sum()
108}
109
110#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
111pub fn simd_accumulate(bytes: &[u8]) -> u64 {
112    bytes.iter().map(|b| u64::from(*b)).sum()
113}