Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreeBSD: Add cpuset and physical core support #133

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
- msrv
- test-linux
- test-macos
- test-freebsd
- test-windows
- build-cross
- test-cgroups
Expand Down Expand Up @@ -150,6 +151,24 @@ jobs:
rustup target add ${{ matrix.target }}
cargo build --verbose --target ${{ matrix.target }}

test-freebsd:
runs-on: macos-12
Copy link
Owner

@seanmonstar seanmonstar Apr 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
runs-on: macos-12
runs-on: ubuntu-latest

Seems like the Ubuntu jobs are faster than mac (I assume there's a smaller quantity of them).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately VM Actions only supports macos-12, as nested virtualisation isn't available elsewhere (at least on the free tier).

steps:
- uses: actions/checkout@v3
- id: test-cpuset
uses: vmactions/freebsd-vm@v0
with:
envs: 'RUST_BACKTRACE CARGO_TERM_COLOR'
usesh: true
copyback: false
prepare: |
pkg install -y rust
run: |
cargo test --verbose
NUM_CPUS_TEST_GET=1 cpuset -l 0 cargo test --verbose
NUM_CPUS_TEST_GET=2 cpuset -l 0,1 cargo test --verbose


test-cgroups:
runs-on: ubuntu-latest

Expand Down
65 changes: 61 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! current system.
//!
//! Sometimes the CPU will exaggerate the number of CPUs it contains, because it can use
//! [processor tricks] to deliver increased performance when there are more threads. This
//! [processor tricks] to deliver increased performance when there are more threads. This
//! crate provides methods to get both the logical and physical numbers of cores.
//!
//! This information can be used as a guide to how many tasks can be run in parallel.
Expand Down Expand Up @@ -66,9 +66,12 @@ use linux::{get_num_cpus, get_num_physical_cpus};
///
/// This will also check [cgroups], frequently used in containers to constrain CPU usage.
///
/// Similarly on FreeBSD this will check the current [cpuset affinity].
///
/// [smt]: https://en.wikipedia.org/wiki/Simultaneous_multithreading
/// [sched affinity]: http://www.gnu.org/software/libc/manual/html_node/CPU-Affinity.html
/// [cgroups]: https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt
/// [cpuset affinity]: https://man.freebsd.org/cgi/man.cgi?query=cpuset&sektion=2
#[inline]
pub fn get() -> usize {
get_num_cpus()
Expand All @@ -80,7 +83,8 @@ pub fn get() -> usize {
///
/// # Note
///
/// Physical count is supported only on Linux, mac OS and Windows platforms.
/// Physical count is supported only on Linux, mac OS, FreeBSD, OpenBSD, and
/// Windows platforms.
/// On other platforms, or if the physical count fails on supported platforms,
/// this function returns the same as [`get()`], which is the number of logical
/// CPUS.
Expand All @@ -92,7 +96,7 @@ pub fn get() -> usize {
/// let physical_cpus = num_cpus::get_physical();
/// if logical_cpus > physical_cpus {
/// println!("We have simultaneous multithreading with about {:.2} \
/// logical cores to 1 physical core.",
/// logical cores to 1 physical core.",
/// (logical_cpus as f64) / (physical_cpus as f64));
/// } else if logical_cpus == physical_cpus {
/// println!("Either we don't have simultaneous multithreading, or our \
Expand All @@ -110,7 +114,7 @@ pub fn get_physical() -> usize {
}


#[cfg(not(any(target_os = "linux", target_os = "windows", target_os="macos", target_os="openbsd")))]
#[cfg(not(any(target_os = "linux", target_os = "windows", target_os="macos", target_os="openbsd", target_os="freebsd")))]
#[inline]
fn get_num_physical_cpus() -> usize {
// Not implemented, fall back
Expand Down Expand Up @@ -234,6 +238,13 @@ fn get_num_cpus() -> usize {
fn get_num_cpus() -> usize {
use std::ptr;

#[cfg(target_os = "freebsd")]
{
if let Some(cpus) = get_cpuset_cpus() {
return cpus;
}
seanmonstar marked this conversation as resolved.
Show resolved Hide resolved
}

let mut cpus: libc::c_uint = 0;
let mut cpus_size = std::mem::size_of_val(&cpus);

Expand All @@ -257,6 +268,52 @@ fn get_num_cpus() -> usize {
cpus as usize
}

#[cfg(target_os = "freebsd")]
fn get_cpuset_cpus() -> Option<usize> {
use std::mem;

let mut set: libc::cpuset_t = unsafe { mem::zeroed() };
if unsafe {
libc::cpuset_getaffinity(
libc::CPU_LEVEL_WHICH,
libc::CPU_WHICH_PID,
-1,
mem::size_of::<libc::cpuset_t>(),
&mut set,
)
} == 0
{
Some(unsafe { libc::CPU_COUNT(&set) as usize })
} else {
None
}
}

#[cfg(target_os = "freebsd")]
fn get_num_physical_cpus() -> usize {
use std::ptr;

let mut cpus: libc::c_uint = 0;
let mut cpus_size = std::mem::size_of_val(&cpus);
let rc: libc::c_int;

const MIB: &[u8] = b"kern.smp.cores\0";
unsafe {
rc = libc::sysctlbyname(
MIB.as_ptr() as *const _ as *const _,
&mut cpus as *mut _ as *mut _,
&mut cpus_size as *mut _ as *mut _,
ptr::null_mut(),
0,
);
}
if rc < 0 {
get_num_cpus()
} else {
cpus as usize
}
}

#[cfg(target_os = "openbsd")]
fn get_num_cpus() -> usize {
use std::ptr;
Expand Down