]> git.proxmox.com Git - rustc.git/blame - src/vendor/num_cpus/src/lib.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / vendor / num_cpus / src / lib.rs
CommitLineData
041b39d2
XL
1//! # num_cpus
2//!
3//! A crate with utilities to determine the number of CPUs available on the
4//! current system.
5//!
6//! ## Example
7//!
8//! ```
9//! let cpus = num_cpus::get();
10//! ```
476ff2be
SL
11#![cfg_attr(test, deny(warnings))]
12#![deny(missing_docs)]
13#![allow(non_snake_case)]
14
15#[cfg(not(windows))]
16extern crate libc;
17
041b39d2
XL
18/// Returns the number of available CPUs of the current system.
19///
20/// # Note
21///
22/// This will check sched affinity on Linux.
476ff2be
SL
23#[inline]
24pub fn get() -> usize {
25 get_num_cpus()
26}
27
041b39d2
XL
28/// Returns the number of physical cores of the current system.
29///
30/// If not possible on the particular architecture, returns same as `get()`
31/// which is the logical CPUs.
7cac9316
XL
32#[inline]
33pub fn get_physical() -> usize {
34 get_num_physical_cpus()
35}
36
37
041b39d2 38#[cfg(not(any(target_os = "linux", target_os = "windows")))]
7cac9316
XL
39#[inline]
40fn get_num_physical_cpus() -> usize {
41 // Not implemented, fallback
42 get_num_cpus()
43}
44
041b39d2
XL
45#[cfg(target_os = "windows")]
46fn get_num_physical_cpus() -> usize {
47 match get_num_physical_cpus_windows() {
48 Some(num) => num,
49 None => get_num_cpus()
50 }
51}
52
53#[cfg(target_os = "windows")]
54fn get_num_physical_cpus_windows() -> Option<usize> {
55 // Inspired by https://msdn.microsoft.com/en-us/library/ms683194
56
57 use std::ptr;
58 use std::mem;
59
60 #[allow(non_upper_case_globals)]
61 const RelationProcessorCore: u32 = 0;
62
63 #[repr(C)]
64 #[allow(non_camel_case_types)]
65 struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION {
66 mask: usize,
67 relationship: u32,
68 _unused: [u64; 2]
69 }
70
71 extern "system" {
72 fn GetLogicalProcessorInformation(
73 info: *mut SYSTEM_LOGICAL_PROCESSOR_INFORMATION,
74 length: &mut u32
75 ) -> u32;
76 }
77
78 // First we need to determine how much space to reserve.
79
80 // The required size of the buffer, in bytes.
81 let mut needed_size = 0;
82
83 unsafe {
84 GetLogicalProcessorInformation(ptr::null_mut(), &mut needed_size);
85 }
86
87 let struct_size = mem::size_of::<SYSTEM_LOGICAL_PROCESSOR_INFORMATION>() as u32;
88
89 // Could be 0, or some other bogus size.
90 if needed_size == 0 || needed_size < struct_size || needed_size % struct_size != 0 {
91 return None;
92 }
93
94 let count = needed_size / struct_size;
95
96 // Allocate some memory where we will store the processor info.
97 let mut buf = Vec::with_capacity(count as usize);
98
99 let result;
100
101 unsafe {
102 result = GetLogicalProcessorInformation(buf.as_mut_ptr(), &mut needed_size);
103 }
104
105 // Failed for any reason.
106 if result == 0 {
107 return None;
108 }
109
110 let count = needed_size / struct_size;
111
112 unsafe {
113 buf.set_len(count as usize);
114 }
115
116 let phys_proc_count = buf.iter()
117 // Only interested in processor packages (physical processors.)
118 .filter(|proc_info| proc_info.relationship == RelationProcessorCore)
119 .count();
120
121 if phys_proc_count == 0 {
122 None
123 } else {
124 Some(phys_proc_count)
125 }
126}
127
7cac9316
XL
128#[cfg(target_os = "linux")]
129fn get_num_physical_cpus() -> usize {
130 use std::io::BufReader;
131 use std::io::BufRead;
132 use std::fs::File;
133 use std::collections::HashSet;
134
135 let file = match File::open("/proc/cpuinfo") {
136 Ok(val) => val,
137 Err(_) => {return get_num_cpus()},
138 };
139 let reader = BufReader::new(file);
140 let mut set = HashSet::new();
141 let mut coreid: u32 = 0;
142 let mut physid: u32 = 0;
143 let mut chgcount = 0;
144 for line in reader.lines().filter_map(|result| result.ok()) {
145 let parts: Vec<&str> = line.split(':').map(|s| s.trim()).collect();
146 if parts.len() != 2 {
147 continue
148 }
149 if parts[0] == "core id" || parts[0] == "physical id" {
150 let value = match parts[1].trim().parse() {
151 Ok(val) => val,
152 Err(_) => break,
153 };
154 match parts[0] {
155 "core id" => coreid = value,
156 "physical id" => physid = value,
157 _ => {},
158 }
159 chgcount += 1;
160 }
161 if chgcount == 2 {
162 set.insert((physid, coreid));
163 chgcount = 0;
164 }
165 }
166 let count = set.len();
167 if count == 0 { get_num_cpus() } else { count }
168}
169
476ff2be
SL
170#[cfg(windows)]
171fn get_num_cpus() -> usize {
172 #[repr(C)]
173 struct SYSTEM_INFO {
174 wProcessorArchitecture: u16,
175 wReserved: u16,
176 dwPageSize: u32,
177 lpMinimumApplicationAddress: *mut u8,
178 lpMaximumApplicationAddress: *mut u8,
179 dwActiveProcessorMask: *mut u8,
180 dwNumberOfProcessors: u32,
181 dwProcessorType: u32,
182 dwAllocationGranularity: u32,
183 wProcessorLevel: u16,
184 wProcessorRevision: u16,
185 }
186
187 extern "system" {
188 fn GetSystemInfo(lpSystemInfo: *mut SYSTEM_INFO);
189 }
190
191 unsafe {
192 let mut sysinfo: SYSTEM_INFO = std::mem::uninitialized();
193 GetSystemInfo(&mut sysinfo);
194 sysinfo.dwNumberOfProcessors as usize
195 }
196}
197
198#[cfg(any(target_os = "freebsd",
199 target_os = "dragonfly",
200 target_os = "bitrig",
201 target_os = "netbsd"))]
202fn get_num_cpus() -> usize {
203 let mut cpus: libc::c_uint = 0;
204 let mut cpus_size = std::mem::size_of_val(&cpus);
205
206 unsafe {
207 cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
208 }
209 if cpus < 1 {
210 let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
211 unsafe {
212 libc::sysctl(mib.as_mut_ptr(),
213 2,
214 &mut cpus as *mut _ as *mut _,
215 &mut cpus_size as *mut _ as *mut _,
216 0 as *mut _,
217 0);
218 }
219 if cpus < 1 {
220 cpus = 1;
221 }
222 }
223 cpus as usize
224}
225
226#[cfg(target_os = "openbsd")]
227fn get_num_cpus() -> usize {
228 let mut cpus: libc::c_uint = 0;
229 let mut cpus_size = std::mem::size_of_val(&cpus);
230 let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
231
232 unsafe {
233 libc::sysctl(mib.as_mut_ptr(),
234 2,
235 &mut cpus as *mut _ as *mut _,
236 &mut cpus_size as *mut _ as *mut _,
237 0 as *mut _,
238 0);
239 }
240 if cpus < 1 {
241 cpus = 1;
242 }
243 cpus as usize
244}
245
041b39d2
XL
246#[cfg(target_os = "linux")]
247fn get_num_cpus() -> usize {
248 let mut set: libc::cpu_set_t = unsafe { std::mem::zeroed() };
249 if unsafe { libc::sched_getaffinity(0, std::mem::size_of::<libc::cpu_set_t>(), &mut set) } == 0 {
250 let mut count: u32 = 0;
251 for i in 0..libc::CPU_SETSIZE as usize {
252 if unsafe { libc::CPU_ISSET(i, &set) } {
253 count += 1
254 }
255 }
256 count as usize
257 } else {
258 let cpus = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) };
259 if cpus < 1 {
260 1
261 } else {
262 cpus as usize
263 }
264 }
265}
266
267#[cfg(any(
268 target_os = "nacl",
269 target_os = "macos",
270 target_os = "ios",
271 target_os = "android",
272 target_os = "solaris",
273 target_os = "fuchsia")
476ff2be
SL
274)]
275fn get_num_cpus() -> usize {
041b39d2
XL
276 let cpus = unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) };
277 if cpus < 1 {
278 1
279 } else {
280 cpus as usize
476ff2be
SL
281 }
282}
041b39d2 283
7cac9316
XL
284#[cfg(any(target_os = "emscripten", target_os = "redox", target_os = "haiku"))]
285fn get_num_cpus() -> usize {
286 1
287}
476ff2be 288
041b39d2
XL
289#[cfg(test)]
290mod tests {
291 fn env_var(name: &'static str) -> Option<usize> {
292 ::std::env::var(name).ok().map(|val| val.parse().unwrap())
293 }
476ff2be 294
041b39d2
XL
295 #[test]
296 fn test_get() {
297 let num = super::get();
298 if let Some(n) = env_var("NUM_CPUS_TEST_GET") {
299 assert_eq!(num, n);
300 } else {
301 assert!(num > 0);
302 assert!(num < 236_451);
303 }
304 }
476ff2be 305
041b39d2
XL
306 #[test]
307 fn test_get_physical() {
308 let num = super::get_physical();
309 if let Some(n) = env_var("NUM_CPUS_TEST_GET_PHYSICAL") {
310 assert_eq!(num, n);
311 } else {
312 assert!(num > 0);
313 assert!(num < 236_451);
314 }
315 }
476ff2be 316}