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}