3 //! A crate with utilities to determine the number of CPUs available on the
9 //! let cpus = num_cpus::get();
11 #![cfg_attr(test, deny(warnings))]
12 #![deny(missing_docs)]
13 #![doc(html_root_url = "https://docs.rs/num_cpus/1.7.0")]
14 #![allow(non_snake_case)]
20 /// Returns the number of available CPUs of the current system.
24 /// This will check sched affinity on Linux.
26 pub fn get() -> usize {
30 /// Returns the number of physical cores of the current system.
32 /// If not possible on the particular architecture, returns same as `get()`
33 /// which is the logical CPUs.
35 pub fn get_physical() -> usize {
36 get_num_physical_cpus()
40 #[cfg(not(any(target_os = "linux", target_os = "windows", target_os="macos")))]
42 fn get_num_physical_cpus() -> usize {
43 // Not implemented, fallback
47 #[cfg(target_os = "windows")]
48 fn get_num_physical_cpus() -> usize {
49 match get_num_physical_cpus_windows() {
51 None
=> get_num_cpus()
55 #[cfg(target_os = "windows")]
56 fn get_num_physical_cpus_windows() -> Option
<usize> {
57 // Inspired by https://msdn.microsoft.com/en-us/library/ms683194
62 #[allow(non_upper_case_globals)]
63 const RelationProcessorCore
: u32 = 0;
66 #[allow(non_camel_case_types)]
67 struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
74 fn GetLogicalProcessorInformation(
75 info
: *mut SYSTEM_LOGICAL_PROCESSOR_INFORMATION
,
80 // First we need to determine how much space to reserve.
82 // The required size of the buffer, in bytes.
83 let mut needed_size
= 0;
86 GetLogicalProcessorInformation(ptr
::null_mut(), &mut needed_size
);
89 let struct_size
= mem
::size_of
::<SYSTEM_LOGICAL_PROCESSOR_INFORMATION
>() as u32;
91 // Could be 0, or some other bogus size.
92 if needed_size
== 0 || needed_size
< struct_size
|| needed_size
% struct_size
!= 0 {
96 let count
= needed_size
/ struct_size
;
98 // Allocate some memory where we will store the processor info.
99 let mut buf
= Vec
::with_capacity(count
as usize);
104 result
= GetLogicalProcessorInformation(buf
.as_mut_ptr(), &mut needed_size
);
107 // Failed for any reason.
112 let count
= needed_size
/ struct_size
;
115 buf
.set_len(count
as usize);
118 let phys_proc_count
= buf
.iter()
119 // Only interested in processor packages (physical processors.)
120 .filter(|proc_info
| proc_info
.relationship
== RelationProcessorCore
)
123 if phys_proc_count
== 0 {
126 Some(phys_proc_count
)
130 #[cfg(target_os = "linux")]
131 fn get_num_physical_cpus() -> usize {
132 use std
::io
::BufReader
;
133 use std
::io
::BufRead
;
135 use std
::collections
::HashSet
;
137 let file
= match File
::open("/proc/cpuinfo") {
139 Err(_
) => {return get_num_cpus()}
,
141 let reader
= BufReader
::new(file
);
142 let mut set
= HashSet
::new();
143 let mut coreid
: u32 = 0;
144 let mut physid
: u32 = 0;
145 let mut chgcount
= 0;
146 for line
in reader
.lines().filter_map(|result
| result
.ok()) {
147 let parts
: Vec
<&str> = line
.split('
:'
).map(|s
| s
.trim()).collect();
148 if parts
.len() != 2 {
151 if parts
[0] == "core id" || parts
[0] == "physical id" {
152 let value
= match parts
[1].trim().parse() {
157 "core id" => coreid
= value
,
158 "physical id" => physid
= value
,
164 set
.insert((physid
, coreid
));
168 let count
= set
.len();
169 if count
== 0 { get_num_cpus() }
else { count }
173 fn get_num_cpus() -> usize {
176 wProcessorArchitecture
: u16,
179 lpMinimumApplicationAddress
: *mut u8,
180 lpMaximumApplicationAddress
: *mut u8,
181 dwActiveProcessorMask
: *mut u8,
182 dwNumberOfProcessors
: u32,
183 dwProcessorType
: u32,
184 dwAllocationGranularity
: u32,
185 wProcessorLevel
: u16,
186 wProcessorRevision
: u16,
190 fn GetSystemInfo(lpSystemInfo
: *mut SYSTEM_INFO
);
194 let mut sysinfo
: SYSTEM_INFO
= std
::mem
::uninitialized();
195 GetSystemInfo(&mut sysinfo
);
196 sysinfo
.dwNumberOfProcessors
as usize
200 #[cfg(any(target_os = "freebsd",
201 target_os
= "dragonfly",
202 target_os
= "bitrig",
203 target_os
= "netbsd"))]
204 fn get_num_cpus() -> usize {
205 let mut cpus
: libc
::c_uint
= 0;
206 let mut cpus_size
= std
::mem
::size_of_val(&cpus
);
209 cpus
= libc
::sysconf(libc
::_SC_NPROCESSORS_ONLN
) as libc
::c_uint
;
212 let mut mib
= [libc
::CTL_HW
, libc
::HW_NCPU
, 0, 0];
214 libc
::sysctl(mib
.as_mut_ptr(),
216 &mut cpus
as *mut _
as *mut _
,
217 &mut cpus_size
as *mut _
as *mut _
,
228 #[cfg(target_os = "openbsd")]
229 fn get_num_cpus() -> usize {
230 let mut cpus
: libc
::c_uint
= 0;
231 let mut cpus_size
= std
::mem
::size_of_val(&cpus
);
232 let mut mib
= [libc
::CTL_HW
, libc
::HW_NCPU
, 0, 0];
235 libc
::sysctl(mib
.as_mut_ptr(),
237 &mut cpus
as *mut _
as *mut _
,
238 &mut cpus_size
as *mut _
as *mut _
,
249 #[cfg(target_os = "macos")]
250 fn get_num_physical_cpus() -> usize {
254 let mut cpus
: i32 = 0;
255 let mut cpus_size
= std
::mem
::size_of_val(&cpus
);
257 let sysctl_name
= CStr
::from_bytes_with_nul(b
"hw.physicalcpu\0")
258 .expect("byte literal is missing NUL");
261 if 0 != libc
::sysctlbyname(sysctl_name
.as_ptr(),
262 &mut cpus
as *mut _
as *mut _
,
263 &mut cpus_size
as *mut _
as *mut _
,
266 return get_num_cpus();
272 #[cfg(target_os = "linux")]
273 fn get_num_cpus() -> usize {
274 let mut set
: libc
::cpu_set_t
= unsafe { std::mem::zeroed() }
;
275 if unsafe { libc::sched_getaffinity(0, std::mem::size_of::<libc::cpu_set_t>(), &mut set) }
== 0 {
276 let mut count
: u32 = 0;
277 for i
in 0..libc
::CPU_SETSIZE
as usize {
278 if unsafe { libc::CPU_ISSET(i, &set) }
{
284 let cpus
= unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) }
;
297 target_os
= "android",
298 target_os
= "solaris",
299 target_os
= "fuchsia")
301 fn get_num_cpus() -> usize {
302 // On ARM targets, processors could be turned off to save power.
303 // Use `_SC_NPROCESSORS_CONF` to get the real number.
304 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
305 const CONF_NAME
: libc
::c_int
= libc
::_SC_NPROCESSORS_CONF
;
306 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
307 const CONF_NAME
: libc
::c_int
= libc
::_SC_NPROCESSORS_ONLN
;
309 let cpus
= unsafe { libc::sysconf(CONF_NAME) }
;
317 #[cfg(any(target_os = "emscripten", target_os = "redox", target_os = "haiku"))]
318 fn get_num_cpus() -> usize {
324 fn env_var(name
: &'
static str) -> Option
<usize> {
325 ::std
::env
::var(name
).ok().map(|val
| val
.parse().unwrap())
330 let num
= super::get();
331 if let Some(n
) = env_var("NUM_CPUS_TEST_GET") {
335 assert
!(num
< 236_451);
340 fn test_get_physical() {
341 let num
= super::get_physical();
342 if let Some(n
) = env_var("NUM_CPUS_TEST_GET_PHYSICAL") {
346 assert
!(num
< 236_451);