use std::env;
use core_affinity::CoreId;
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum Scheduling {
Dynamic,
Static,
}
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum WaitPolicy {
Active,
Passive,
}
pub struct Configuration {
max_cores: usize,
thread_mapping: Vec<CoreId>,
pinning: bool,
scheduling: Scheduling,
wait_policy: WaitPolicy,
}
fn parse_thread_mapping() -> Vec<CoreId> {
let mut env_mapping = Vec::new();
match env::var("PPL_THREAD_MAPPING") {
Ok(val) => {
let mapping: Vec<&str> = val.split(',').collect();
for core in mapping {
env_mapping.push(core.parse::<usize>().unwrap())
}
}
Err(_) => {
for i in 0..num_cpus::get() {
env_mapping.push(i);
}
}
}
let core_ids = core_affinity::get_core_ids().unwrap();
let mut threads_mapping = Vec::new();
for thread in env_mapping {
if thread >= core_ids.len() {
panic!("Error: The thread mapping is invalid");
}
threads_mapping.push(core_ids[thread]);
}
threads_mapping
}
impl Configuration {
pub fn new(
max_cores: usize,
pinning: bool,
scheduling: Scheduling,
wait_policy: WaitPolicy,
) -> Configuration {
let threads_mapping = parse_thread_mapping();
Configuration {
max_cores,
thread_mapping: threads_mapping,
pinning,
scheduling,
wait_policy,
}
}
pub fn new_default() -> Configuration {
let max_threads = match env::var("PPL_MAX_CORES") {
Ok(val) => val.parse::<usize>().unwrap(),
Err(_) => num_cpus::get(),
};
let pinning = match env::var("PPL_PINNING") {
Ok(val) => val.parse::<bool>().unwrap(),
Err(_) => false,
};
let scheduling = match env::var("PPL_SCHEDULE") {
Ok(val) => {
let value = val.to_lowercase();
if value == "static" {
Scheduling::Static
} else if value == "dynamic" {
Scheduling::Dynamic
} else {
panic!("{} is an invalid scheduling policy", value);
}
}
Err(_) => Scheduling::Static,
};
let wait_policy = match env::var("PPL_WAIT_POLICY") {
Ok(val) => {
let value = val.to_lowercase();
if value == "active" {
WaitPolicy::Active
} else if value == "passive" {
WaitPolicy::Passive
} else {
panic!("{} is an invalid threads wait policy", value);
}
}
Err(_) => WaitPolicy::Passive,
};
Configuration::new(max_threads, pinning, scheduling, wait_policy)
}
pub(crate) fn get_max_cores(&self) -> usize {
self.max_cores
}
pub(crate) fn get_thread_mapping(&self) -> &Vec<CoreId> {
&self.thread_mapping
}
pub(crate) fn get_pinning(&self) -> bool {
self.pinning
}
pub(crate) fn get_scheduling(&self) -> Scheduling {
self.scheduling
}
pub(crate) fn get_wait_policy(&self) -> WaitPolicy {
self.wait_policy
}
}
#[cfg(test)]
mod tests {
use super::*;
use ::serial_test::serial;
fn reset_env() {
env::remove_var("PPL_MAX_CORES");
env::remove_var("PPL_PINNING");
env::remove_var("PPL_WAIT_POLICY");
env::remove_var("PPL_THREAD_MAPPING");
env::remove_var("PPL_SCHEDULE");
}
#[test]
#[serial]
fn test_configuration() {
let conf = Configuration::new_default();
assert_eq!(conf.max_cores, num_cpus::get());
assert_eq!(conf.wait_policy, WaitPolicy::Passive);
assert_eq!(conf.scheduling, Scheduling::Static);
}
#[test]
#[serial]
fn test_configuration_with_env() {
env::set_var("PPL_MAX_CORES", "4");
env::set_var("PPL_PINNING", "true");
env::set_var("PPL_WAIT_POLICY", "PASSIVE");
env::set_var("PPL_SCHEDULE", "DYNAMIC");
let conf = Configuration::new_default();
assert_eq!(conf.max_cores, 4);
assert!(conf.pinning);
assert_eq!(conf.wait_policy, WaitPolicy::Passive);
assert_eq!(conf.scheduling, Scheduling::Dynamic);
reset_env();
}
}