#[cfg(test)]
extern crate num_cpus;
pub fn get_core_ids() -> Option<Vec<CoreId>> {
get_core_ids_helper()
}
pub fn set_for_current(core_id: CoreId) {
set_for_current_helper(core_id);
}
#[derive(Copy, Clone)]
pub struct CoreId {
id: usize,
}
#[cfg(target_os = "linux")]
#[inline]
fn get_core_ids_helper() -> Option<Vec<CoreId>> {
linux::get_core_ids()
}
#[cfg(target_os = "linux")]
#[inline]
fn set_for_current_helper(core_id: CoreId) {
linux::set_for_current(core_id);
}
#[cfg(target_os = "linux")]
extern crate libc;
#[cfg(target_os = "linux")]
mod linux {
use std::mem;
use libc;
use super::CoreId;
pub fn get_core_ids() -> Option<Vec<CoreId>> {
if let Some(full_set) = get_affinity_mask() {
let mut core_ids: Vec<CoreId> = Vec::new();
for i in 0..libc::CPU_SETSIZE as usize {
if unsafe { libc::CPU_ISSET(i, &full_set) } {
core_ids.push(CoreId{ id: i });
}
}
Some(core_ids)
}
else {
None
}
}
pub fn set_for_current(core_id: CoreId) {
let mut set = new_cpu_set();
unsafe { libc::CPU_SET(core_id.id, &mut set) };
unsafe {
libc::sched_setaffinity(0, mem::size_of::<libc::cpu_set_t>(),
&set);
}
}
fn get_affinity_mask() -> Option<libc::cpu_set_t> {
let mut set = new_cpu_set();
let result = unsafe {
libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(),
&mut set)
};
if result == 0 {
Some(set)
}
else {
None
}
}
fn new_cpu_set() -> libc::cpu_set_t {
unsafe { mem::zeroed::<libc::cpu_set_t>() }
}
#[cfg(test)]
mod tests {
use num_cpus;
use super::*;
#[test]
fn test_linux_get_affinity_mask() {
match get_affinity_mask() {
Some(_) => {},
None => { assert!(false); },
}
}
#[test]
fn test_linux_get_core_ids() {
match get_core_ids() {
Some(set) => {
assert_eq!(set.len(), num_cpus::get());
},
None => { assert!(false); },
}
}
#[test]
fn test_linux_set_for_current() {
let ids = get_core_ids().unwrap();
assert!(ids.len() > 0);
set_for_current(ids[0]);
let mut core_mask = new_cpu_set();
unsafe { libc::CPU_SET(ids[0].id, &mut core_mask) };
let new_mask = get_affinity_mask().unwrap();
let mut is_equal = true;
for i in 0..libc::CPU_SETSIZE as usize {
let is_set1 = unsafe {
libc::CPU_ISSET(i, &core_mask)
};
let is_set2 = unsafe {
libc::CPU_ISSET(i, &new_mask)
};
if is_set1 != is_set2 {
is_equal = false;
}
}
assert!(is_equal);
}
}
}
#[cfg(target_os = "windows")]
#[inline]
fn get_core_ids_helper() -> Option<Vec<CoreId>> {
windows::get_core_ids()
}
#[cfg(target_os = "windows")]
#[inline]
fn set_for_current_helper(core_id: CoreId) {
windows::set_for_current(core_id);
}
#[cfg(target_os = "windows")]
extern crate winapi;
#[cfg(target_os = "windows")]
mod windows {
use std::mem;
use winapi;
use super::CoreId;
pub fn get_core_ids() -> Option<Vec<CoreId>> {
if let Some(mask) = get_affinity_mask() {
let mut core_ids: Vec<CoreId> = Vec::new();
for i in 0..64 as u64 {
let test_mask = 1 << i;
if (mask & test_mask) == test_mask {
core_ids.push(CoreId { id: i as usize });
}
}
Some(core_ids)
}
else {
None
}
}
pub fn set_for_current(core_id: CoreId) {
let mask: u64 = 1 << core_id.id;
let res = unsafe {
winapi::kernel32::SetThreadAffinityMask(
winapi::kernel32::GetCurrentThread(),
mask as winapi::basetsd::DWORD_PTR
)
};
}
fn get_affinity_mask() -> Option<u64> {
let mut process_mask: u64 = 0;
let mut system_mask: u64 = 0;
let res = unsafe {
winapi::kernel32::GetProcessAffinityMask(
winapi::kernel32::GetCurrentProcess(),
&process_mask as winapi::basetsd::PDWORD_PTR,
&system_mask as winapi::basetsd::PDWORD_PTR
)
};
if res != 0 {
Some(process_mask)
}
else {
None
}
}
}
#[cfg(not(any(target_os = "linux", target_os = "windows")))]
#[inline]
fn get_core_ids_helper() -> Option<Vec<CoreId>> {
None
}
#[cfg(not(any(target_os = "linux", target_os = "windows")))]
#[inline]
fn set_for_current_helper(core_id: CoreId) {
}
#[cfg(test)]
mod tests {
use num_cpus;
use super::*;
#[test]
fn test_num_cpus() {
println!("Num CPUs: {}", num_cpus::get());
println!("Num Physical CPUs: {}", num_cpus::get_physical());
}
#[test]
fn test_get_core_ids() {
match get_core_ids() {
Some(set) => {
assert_eq!(set.len(), num_cpus::get());
},
None => { assert!(false); },
}
}
#[test]
fn test_set_for_current() {
let ids = get_core_ids().unwrap();
assert!(ids.len() > 0);
set_for_current(ids[0]);
}
}