Skip to main content

entrenar/efficiency/device/
apple.rs

1//! Apple Silicon information and detection.
2
3use serde::{Deserialize, Serialize};
4
5/// Apple Silicon information
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
7pub struct AppleSiliconInfo {
8    /// Chip model (e.g., "M1", "M2 Pro", "M3 Max")
9    pub chip: String,
10    /// Performance cores
11    pub p_cores: u32,
12    /// Efficiency cores
13    pub e_cores: u32,
14    /// GPU cores
15    pub gpu_cores: u32,
16    /// Neural Engine cores
17    pub neural_cores: u32,
18    /// Unified memory in bytes
19    pub unified_memory_bytes: u64,
20}
21
22impl AppleSiliconInfo {
23    /// Create new Apple Silicon info
24    pub fn new(chip: impl Into<String>) -> Self {
25        Self {
26            chip: chip.into(),
27            p_cores: 0,
28            e_cores: 0,
29            gpu_cores: 0,
30            neural_cores: 16, // Default for most Apple Silicon
31            unified_memory_bytes: 0,
32        }
33    }
34
35    /// Set core configuration
36    pub fn with_cores(mut self, p_cores: u32, e_cores: u32, gpu_cores: u32) -> Self {
37        self.p_cores = p_cores;
38        self.e_cores = e_cores;
39        self.gpu_cores = gpu_cores;
40        self
41    }
42
43    /// Set unified memory
44    pub fn with_memory(mut self, bytes: u64) -> Self {
45        self.unified_memory_bytes = bytes;
46        self
47    }
48
49    /// Get total CPU cores
50    pub fn total_cpu_cores(&self) -> u32 {
51        self.p_cores + self.e_cores
52    }
53
54    /// Get unified memory in GB
55    pub fn unified_memory_gb(&self) -> f64 {
56        self.unified_memory_bytes as f64 / (1024.0 * 1024.0 * 1024.0)
57    }
58
59    /// Detect Apple Silicon information (macOS only)
60    #[cfg(target_os = "macos")]
61    pub fn detect() -> Option<Self> {
62        // Check if we're on Apple Silicon
63        let arch = std::env::consts::ARCH;
64        if arch != "aarch64" {
65            return None;
66        }
67
68        // Get chip name from sysctl
69        let chip = std::process::Command::new("sysctl")
70            .args(["-n", "machdep.cpu.brand_string"])
71            .output()
72            .ok()
73            .and_then(|output| String::from_utf8(output.stdout).ok())
74            .map(|s| s.trim().to_string())
75            .unwrap_or_else(|| "Apple Silicon".to_string());
76
77        // Get core counts
78        let p_cores = std::process::Command::new("sysctl")
79            .args(["-n", "hw.perflevel0.logicalcpu"])
80            .output()
81            .ok()
82            .and_then(|output| String::from_utf8(output.stdout).ok())
83            .and_then(|s| s.trim().parse().ok())
84            .unwrap_or(0);
85
86        let e_cores = std::process::Command::new("sysctl")
87            .args(["-n", "hw.perflevel1.logicalcpu"])
88            .output()
89            .ok()
90            .and_then(|output| String::from_utf8(output.stdout).ok())
91            .and_then(|s| s.trim().parse().ok())
92            .unwrap_or(0);
93
94        // Get memory
95        let memory = std::process::Command::new("sysctl")
96            .args(["-n", "hw.memsize"])
97            .output()
98            .ok()
99            .and_then(|output| String::from_utf8(output.stdout).ok())
100            .and_then(|s| s.trim().parse().ok())
101            .unwrap_or(0);
102
103        Some(
104            Self::new(chip)
105                .with_cores(p_cores, e_cores, 0) // GPU cores harder to detect
106                .with_memory(memory),
107        )
108    }
109
110    #[cfg(not(target_os = "macos"))]
111    pub fn detect() -> Option<Self> {
112        None
113    }
114}