From 0b9641d66f8768f82f7cc09c8c8ee7d3750c8a29 Mon Sep 17 00:00:00 2001 From: Cameron Elliott <868689+cameronelliott@users.noreply.github.com> Date: Sun, 8 May 2022 18:59:21 -0700 Subject: [PATCH 1/5] explain macos support --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 3e68d43..5f2eb4e 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,28 @@ Complete example [here](https://github.com/elast0ny/affinity-rs/blob/master/exam Currently only tested on : - Windows - Linux (Arch x64) +- macOS (see note below) + +## macOS Caveats + +macOS doesn't allow setting thread or process affinities in the same way as Linux and Windows. +The set_thread_affinity(&cores) call on macOS will only take a single value, +and it is not a core number, but rather a macOS-specific "affinity tag". +The following text may be helpful. + +From the file + +This policy is experimental. + +This may be used to express affinity relationships between threads in +the task. Threads with the same affinity tag will be scheduled to +share an L2 cache if possible. That is, affinity tags are a hint to +the scheduler for thread placement. + +The namespace of affinity tags is generally local to one task. +However, a child task created after the assignment of affinity tags by +its parent will share that namespace. In particular, a family of +forked processes may be created with a shared affinity namespace. ## License From 6b840c365b1e05ee17e33399776f5d029d229b62 Mon Sep 17 00:00:00 2001 From: Cameron Elliott <868689+cameronelliott@users.noreply.github.com> Date: Sun, 8 May 2022 18:59:45 -0700 Subject: [PATCH 2/5] initial macos support --- src/macos.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/macos.rs diff --git a/src/macos.rs b/src/macos.rs new file mode 100644 index 0000000..ff5290e --- /dev/null +++ b/src/macos.rs @@ -0,0 +1,84 @@ +use crate::Result; +use libc::*; + +pub fn set_thread_affinity(core_ids: &[usize]) -> Result<()> { + if core_ids.len() != 1 { + return Err(From::from( + "Can only accept a single value/affinity_tag for set_thread_affinity on macos", + )); + } + + if let Err(e) = _sched_setaffinity(core_ids[0] as i32) { + return Err(From::from(format!( + "sched_setaffinity failed with errno {}", + e + ))); + } + Ok(()) +} + +pub fn get_thread_affinity() -> Result> { + let mut affinity = Vec::new(); + // let mut set: cpu_set_t = unsafe { zeroed() }; + + let x = _sched_getaffinity(); + if let Err(e) = x { + return Err(From::from(format!( + "sched_getaffinity failed with errno {}", + e + ))); + } + + affinity.push(x.unwrap() as usize); + + Ok(affinity) +} + +/* Wrappers around unsafe OS calls */ +fn _sched_setaffinity(affinity_tag: i32) -> std::result::Result<(), i32> { + let mut policy_data = thread_affinity_policy_data_t { + affinity_tag: affinity_tag, + }; + + let tid = unsafe { mach_thread_self() }; + + let res = unsafe { + thread_policy_set( + tid, + THREAD_AFFINITY_POLICY as u32, + (&mut policy_data) as *mut _ as thread_policy_t, + 1, + ) + }; + if res != 0 { + return Err(errno::errno().into()); + } + Ok(()) +} + +fn _sched_getaffinity() -> std::result::Result { + let mut policy_data = thread_affinity_policy_data_t { affinity_tag: -1 }; + + let tid = unsafe { mach_thread_self() }; + + // false: we want to get the current value, not the default value. If this is `false` after + // returning, it means there are no current settings because of other factor, and the + // default was returned instead. + let mut get_default: boolean_t = 0; + + let mut count: mach_msg_type_number_t = 1; + let res = unsafe { + thread_policy_get( + tid, + THREAD_AFFINITY_POLICY as u32, + (&mut policy_data) as *mut _ as thread_policy_t, + &mut count, + &mut get_default, + ) + }; + if res != 0 { + return Err(errno::errno().into()); + } + + Ok(policy_data.affinity_tag) +} From 181a6c7379c4bd67f12debb0cfd866d8b65541be Mon Sep 17 00:00:00 2001 From: Cameron Elliott <868689+cameronelliott@users.noreply.github.com> Date: Sun, 8 May 2022 19:04:51 -0700 Subject: [PATCH 3/5] Add macos support back --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 895b9b9..cb8ef17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "linux")] { mod linux; use linux as os; + } else if #[cfg(target_os = "macos")] { + mod macos; + use macos as os; } else { unimplemented!("This crate does not support your OS yet !"); } From 10701b82edc93bed241069812f41046bc244903e Mon Sep 17 00:00:00 2001 From: Cameron Elliott <868689+cameronelliott@users.noreply.github.com> Date: Sun, 8 May 2022 19:05:42 -0700 Subject: [PATCH 4/5] add macos example --- examples/main.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/examples/main.rs b/examples/main.rs index 09e4033..f87df7b 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -13,6 +13,7 @@ fn bind_process() -> Result<(), Box> { Ok(()) } +#[cfg(not(target_os = "macos"))] pub fn main() -> Result<(), Box> { println!("Total cores : {}", get_core_num()); @@ -31,3 +32,23 @@ pub fn main() -> Result<(), Box> { Ok(()) } + +#[cfg(target_os = "macos")] +pub fn main() -> Result<(), Box> { + println!("Total cores : {}", get_core_num()); + + let cores = vec![42]; //42 is an affinity tag, see the readme + println!("Binding thread to cores : {:?}", &cores); + set_thread_affinity(&cores)?; + + let bound_cores = get_thread_affinity()?; + println!("\tCurrent thread affinity : {:?}", bound_cores); + println!("\tTotal cores : {}", get_core_num()); + + assert_eq!(bound_cores, cores.as_slice()); + + #[cfg(target_os = "windows")] + bind_process()?; + + Ok(()) +} From 67b925db00575a35d839455964baea494ac86ec2 Mon Sep 17 00:00:00 2001 From: Cameron Elliott <868689+cameronelliott@users.noreply.github.com> Date: Sun, 8 May 2022 19:14:19 -0700 Subject: [PATCH 5/5] improve readme macos quote on macos operation --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 5f2eb4e..d9b6e30 100644 --- a/README.md +++ b/README.md @@ -48,17 +48,17 @@ The following text may be helpful. From the file -This policy is experimental. - -This may be used to express affinity relationships between threads in -the task. Threads with the same affinity tag will be scheduled to -share an L2 cache if possible. That is, affinity tags are a hint to -the scheduler for thread placement. - -The namespace of affinity tags is generally local to one task. -However, a child task created after the assignment of affinity tags by -its parent will share that namespace. In particular, a family of -forked processes may be created with a shared affinity namespace. +> This policy is experimental. +> +> This may be used to express affinity relationships between threads in +> the task. Threads with the same affinity tag will be scheduled to +> share an L2 cache if possible. That is, affinity tags are a hint to +> the scheduler for thread placement. +> +> The namespace of affinity tags is generally local to one task. +> However, a child task created after the assignment of affinity tags by +> its parent will share that namespace. In particular, a family of +> forked processes may be created with a shared affinity namespace. ## License