blasoxide_cpuinfo/
lib.rs

1#![deny(warnings)]
2
3#[derive(Debug, Clone, Copy)]
4pub struct CpuInfo {
5    pub l1_cache_size: usize,
6    pub l2_cache_size: usize,
7    pub l3_cache_size: usize,
8    pub num_cpus: usize,
9}
10
11impl CpuInfo {
12    #[cfg(target_os = "linux")]
13    pub fn try_new() -> Result<CpuInfo, ()> {
14        use libc::sysconf;
15
16        unsafe {
17            let l1_cache_size = sysconf(libc::_SC_LEVEL1_DCACHE_SIZE);
18            if l1_cache_size <= 0 {
19                return Err(());
20            }
21
22            let l2_cache_size = sysconf(libc::_SC_LEVEL2_CACHE_SIZE);
23            if l2_cache_size <= 0 {
24                return Err(());
25            }
26
27            let l3_cache_size = sysconf(libc::_SC_LEVEL3_CACHE_SIZE);
28            if l3_cache_size <= 0 {
29                return Err(());
30            }
31
32            let num_cpus = sysconf(libc::_SC_NPROCESSORS_CONF);
33            if num_cpus <= 0 {
34                return Err(());
35            }
36
37            Ok(CpuInfo {
38                l1_cache_size: l1_cache_size as usize,
39                l2_cache_size: l2_cache_size as usize,
40                l3_cache_size: l3_cache_size as usize,
41                num_cpus: num_cpus as usize,
42            })
43        }
44    }
45
46    #[cfg(target_os = "macos")]
47    pub fn try_new() -> Result<CpuInfo, ()> {
48        use std::{mem, ptr};
49        use libc::{c_int, c_void, sysconf, sysctl};
50
51        unsafe {
52            let mut l1_cache_size: c_int = 0;
53            let mut l2_cache_size: c_int = 0;
54            let mut l3_cache_size: c_int = 0;
55            let mut size = mem::size_of::<c_int>();
56
57            const NAMELEN: libc::c_uint = 2;
58
59            let mut name = [libc::CTL_HW, libc::HW_L1DCACHESIZE];
60            if sysctl(
61                name.as_mut_ptr(),
62                NAMELEN,
63                &mut l1_cache_size as *mut c_int as *mut c_void,
64                &mut size,
65                ptr::null_mut(),
66                0,
67            ) != 0
68            {
69                return Err(());
70            }
71
72            name[1] = libc::HW_L2CACHESIZE;
73            if sysctl(
74                name.as_mut_ptr(),
75                NAMELEN,
76                &mut l2_cache_size as *mut c_int as *mut c_void,
77                &mut size,
78                ptr::null_mut(),
79                0,
80            ) != 0
81            {
82                return Err(());
83            }
84
85            name[1] = libc::HW_L3CACHESIZE;
86            if sysctl(
87                name.as_mut_ptr(),
88                NAMELEN,
89                &mut l3_cache_size as *mut c_int as *mut c_void,
90                &mut size,
91                ptr::null_mut(),
92                0,
93            ) != 0
94            {
95                return Err(());
96            }
97
98            if l1_cache_size <= 0 || l2_cache_size <= 0 || l3_cache_size <= 0 {
99                return Err(());
100            }
101
102            let num_cpus = sysconf(libc::_SC_NPROCESSORS_CONF);
103            if num_cpus <= 0 {
104                return Err(());
105            }
106
107            Ok(CpuInfo {
108                l1_cache_size: l1_cache_size as usize,
109                l2_cache_size: l2_cache_size as usize,
110                l3_cache_size: l3_cache_size as usize,
111                num_cpus: num_cpus as usize,
112            })
113        }
114    }
115
116    #[cfg(target_os = "windows")]
117    pub fn try_new() -> Result<CpuInfo, ()> {
118        use std::{mem, ptr};
119        use winapi::shared::minwindef::{FALSE, TRUE};
120        use winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER;
121        use winapi::um::errhandlingapi::GetLastError;
122        use winapi::um::sysinfoapi::GetLogicalProcessorInformation;
123        use winapi::um::winnt::{
124            CacheData, RelationCache, RelationProcessorCore, SYSTEM_LOGICAL_PROCESSOR_INFORMATION,
125        };
126
127        unsafe {
128            let mut buffer = Vec::new();
129            let mut req_bytes = 0;
130            let struct_size = mem::size_of::<SYSTEM_LOGICAL_PROCESSOR_INFORMATION>();
131
132            if TRUE == GetLogicalProcessorInformation(ptr::null_mut(), &mut req_bytes) {
133                return Err(());
134            }
135
136            if GetLastError() == ERROR_INSUFFICIENT_BUFFER {
137                buffer.reserve(req_bytes as usize / struct_size);
138                buffer.set_len(req_bytes as usize / struct_size);
139            } else {
140                return Err(());
141            }
142
143            if FALSE == GetLogicalProcessorInformation(buffer.as_mut_ptr(), &mut req_bytes) {
144                return Err(());
145            }
146
147            let mut l1_cache_size = 0;
148            let mut l2_cache_size = 0;
149            let mut l3_cache_size = 0;
150            let mut num_cpus = 0;
151
152            for info in buffer {
153                if info.Relationship == RelationCache {
154                    let cache = info.u.Cache();
155                    match cache.Level {
156                        1 => {
157                            if cache.Type == CacheData {
158                                l1_cache_size = cache.Size
159                            }
160                        }
161                        2 => l2_cache_size = cache.Size,
162                        3 => l3_cache_size = cache.Size,
163                        _ => {
164                            return Err(());
165                        }
166                    }
167                } else if info.Relationship == RelationProcessorCore {
168                    num_cpus += 1;
169                }
170            }
171
172            if l1_cache_size == 0
173                || l2_cache_size == 0
174                || l3_cache_size == 0
175                || num_cpus == 0 {
176                    return Err(());
177            }
178
179            Ok(CpuInfo {
180                l1_cache_size: l1_cache_size as usize,
181                l2_cache_size: l2_cache_size as usize,
182                l3_cache_size: l3_cache_size as usize,
183                num_cpus,
184            })
185        }
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192
193    #[test]
194    fn test_create_cpu_info() {
195        let _info = CpuInfo::try_new().unwrap();
196    }
197}