Add std:🧵:available_concurrency
This commit is contained in:
parent
a8d6da3f57
commit
3717646366
4 changed files with 166 additions and 101 deletions
157
library/std/src/thread/available_concurrency.rs
Normal file
157
library/std/src/thread/available_concurrency.rs
Normal file
|
@ -0,0 +1,157 @@
|
|||
use crate::io;
|
||||
use crate::num::NonZeroUsize;
|
||||
|
||||
/// Returns the number of hardware threads available to the program.
|
||||
///
|
||||
/// This value should be considered only a hint.
|
||||
///
|
||||
/// # Platform-specific behavior
|
||||
///
|
||||
/// If interpreted as the number of actual hardware threads, it may undercount on
|
||||
/// Windows systems with more than 64 hardware threads. If interpreted as the
|
||||
/// available concurrency for that process, it may overcount on Windows systems
|
||||
/// when limited by a process wide affinity mask or job object limitations, and
|
||||
/// it may overcount on Linux systems when limited by a process wide affinity
|
||||
/// mask or affected by cgroups limits.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error in the following situations, but is not
|
||||
/// limited to just these cases:
|
||||
///
|
||||
/// - If the number of hardware threads is not known for the target platform.
|
||||
/// - The process lacks permissions to view the number of hardware threads
|
||||
/// available.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![allow(dead_code)]
|
||||
/// #![feature(available_concurrency)]
|
||||
/// use std::thread;
|
||||
///
|
||||
/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1);
|
||||
/// ```
|
||||
#[unstable(feature = "available_concurrency", issue = "74479")]
|
||||
pub fn available_concurrency() -> io::Result<NonZeroUsize> {
|
||||
available_concurrency_internal()
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
#[allow(nonstandard_style)]
|
||||
fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
|
||||
#[repr(C)]
|
||||
struct SYSTEM_INFO {
|
||||
wProcessorArchitecture: u16,
|
||||
wReserved: u16,
|
||||
dwPageSize: u32,
|
||||
lpMinimumApplicationAddress: *mut u8,
|
||||
lpMaximumApplicationAddress: *mut u8,
|
||||
dwActiveProcessorMask: *mut u8,
|
||||
dwNumberOfProcessors: u32,
|
||||
dwProcessorType: u32,
|
||||
dwAllocationGranularity: u32,
|
||||
wProcessorLevel: u16,
|
||||
wProcessorRevision: u16,
|
||||
}
|
||||
extern "system" {
|
||||
fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
|
||||
}
|
||||
let res = unsafe {
|
||||
let mut sysinfo = crate::mem::zeroed();
|
||||
GetSystemInfo(&mut sysinfo);
|
||||
sysinfo.dwNumberOfProcessors as usize
|
||||
};
|
||||
match res {
|
||||
0 => Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
|
||||
cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
|
||||
}
|
||||
}
|
||||
} else if #[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "cloudabi",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
))] {
|
||||
fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
|
||||
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
|
||||
-1 => Err(io::Error::last_os_error()),
|
||||
0 => Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
|
||||
cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
|
||||
}
|
||||
}
|
||||
} else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
|
||||
fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
|
||||
use crate::ptr;
|
||||
|
||||
let mut cpus: libc::c_uint = 0;
|
||||
let mut cpus_size = crate::mem::size_of_val(&cpus);
|
||||
|
||||
unsafe {
|
||||
cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
|
||||
}
|
||||
|
||||
// Fallback approach in case of errors or no hardware threads.
|
||||
if cpus < 1 {
|
||||
let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
|
||||
let res = unsafe {
|
||||
libc::sysctl(
|
||||
mib.as_mut_ptr(),
|
||||
2,
|
||||
&mut cpus as *mut _ as *mut _,
|
||||
&mut cpus_size as *mut _ as *mut _,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
// Handle errors if any.
|
||||
if res == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
} else if cpus == 0 {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
|
||||
}
|
||||
}
|
||||
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
|
||||
}
|
||||
} else if #[cfg(target_os = "openbsd")] {
|
||||
fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
|
||||
use crate::ptr;
|
||||
|
||||
let mut cpus: libc::c_uint = 0;
|
||||
let mut cpus_size = crate::mem::size_of_val(&cpus);
|
||||
let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
|
||||
|
||||
let res = unsafe {
|
||||
libc::sysctl(
|
||||
mib.as_mut_ptr(),
|
||||
2,
|
||||
&mut cpus as *mut _ as *mut _,
|
||||
&mut cpus_size as *mut _ as *mut _,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
)
|
||||
};
|
||||
|
||||
// Handle errors if any.
|
||||
if res == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
} else if cpus == 0 {
|
||||
return Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
|
||||
}
|
||||
|
||||
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
|
||||
}
|
||||
} else {
|
||||
// FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
|
||||
fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -175,9 +175,15 @@ use crate::time::Duration;
|
|||
#[macro_use]
|
||||
mod local;
|
||||
|
||||
#[unstable(feature = "available_concurrency", issue = "74479")]
|
||||
mod available_concurrency;
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use self::local::{AccessError, LocalKey};
|
||||
|
||||
#[unstable(feature = "available_concurrency", issue = "74479")]
|
||||
pub use available_concurrency::available_concurrency;
|
||||
|
||||
// The types used by the thread_local! macro to access TLS keys. Note that there
|
||||
// are two types, the "OS" type and the "fast" type. The OS thread local key
|
||||
// type is accessed via platform-specific API calls and is slow, while the fast
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! Helper module which helps to determine amount of threads to be used
|
||||
//! during tests execution.
|
||||
use std::env;
|
||||
use std::thread;
|
||||
|
||||
#[allow(deprecated)]
|
||||
pub fn get_concurrency() -> usize {
|
||||
|
@ -12,106 +13,6 @@ pub fn get_concurrency() -> usize {
|
|||
_ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", s),
|
||||
}
|
||||
}
|
||||
Err(..) => num_cpus(),
|
||||
}
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
#[allow(nonstandard_style)]
|
||||
fn num_cpus() -> usize {
|
||||
#[repr(C)]
|
||||
struct SYSTEM_INFO {
|
||||
wProcessorArchitecture: u16,
|
||||
wReserved: u16,
|
||||
dwPageSize: u32,
|
||||
lpMinimumApplicationAddress: *mut u8,
|
||||
lpMaximumApplicationAddress: *mut u8,
|
||||
dwActiveProcessorMask: *mut u8,
|
||||
dwNumberOfProcessors: u32,
|
||||
dwProcessorType: u32,
|
||||
dwAllocationGranularity: u32,
|
||||
wProcessorLevel: u16,
|
||||
wProcessorRevision: u16,
|
||||
}
|
||||
extern "system" {
|
||||
fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
|
||||
}
|
||||
unsafe {
|
||||
let mut sysinfo = std::mem::zeroed();
|
||||
GetSystemInfo(&mut sysinfo);
|
||||
sysinfo.dwNumberOfProcessors as usize
|
||||
}
|
||||
}
|
||||
} else if #[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "cloudabi",
|
||||
target_os = "emscripten",
|
||||
target_os = "fuchsia",
|
||||
target_os = "ios",
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos",
|
||||
))] {
|
||||
fn num_cpus() -> usize {
|
||||
unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize }
|
||||
}
|
||||
} else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
|
||||
fn num_cpus() -> usize {
|
||||
use std::ptr;
|
||||
|
||||
let mut cpus: libc::c_uint = 0;
|
||||
let mut cpus_size = std::mem::size_of_val(&cpus);
|
||||
|
||||
unsafe {
|
||||
cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
|
||||
}
|
||||
if cpus < 1 {
|
||||
let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
|
||||
unsafe {
|
||||
libc::sysctl(
|
||||
mib.as_mut_ptr(),
|
||||
2,
|
||||
&mut cpus as *mut _ as *mut _,
|
||||
&mut cpus_size as *mut _ as *mut _,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
);
|
||||
}
|
||||
if cpus < 1 {
|
||||
cpus = 1;
|
||||
}
|
||||
}
|
||||
cpus as usize
|
||||
}
|
||||
} else if #[cfg(target_os = "openbsd")] {
|
||||
fn num_cpus() -> usize {
|
||||
use std::ptr;
|
||||
|
||||
let mut cpus: libc::c_uint = 0;
|
||||
let mut cpus_size = std::mem::size_of_val(&cpus);
|
||||
let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
|
||||
|
||||
unsafe {
|
||||
libc::sysctl(
|
||||
mib.as_mut_ptr(),
|
||||
2,
|
||||
&mut cpus as *mut _ as *mut _,
|
||||
&mut cpus_size as *mut _ as *mut _,
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
);
|
||||
}
|
||||
if cpus < 1 {
|
||||
cpus = 1;
|
||||
}
|
||||
cpus as usize
|
||||
}
|
||||
} else {
|
||||
// FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
|
||||
fn num_cpus() -> usize {
|
||||
1
|
||||
}
|
||||
Err(..) => thread::available_concurrency().map(|n| n.get()).unwrap_or(1),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#![feature(rustc_private)]
|
||||
#![feature(nll)]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(available_concurrency)]
|
||||
#![feature(set_stdio)]
|
||||
#![feature(panic_unwind)]
|
||||
#![feature(staged_api)]
|
||||
|
|
Loading…
Add table
Reference in a new issue