#[doc(hidden)]
#[macro_export]
macro_rules! extend_dataframe {
(
$name:ident,
input {$($input: ident: $input_ty: ty)*},
input_vec {$($input_vec:ident: [$input_ty_vec:ty; $input_len: expr])*},
output [$($output: ident: $output_ty: ty)*]
) =>{
unsafe impl Equivalence for $name {
type Out = UserDatatype;
fn equivalent_datatype() -> Self::Out {
let v_in = count_tts!($($input)*);
let v_out = count_tts!($($output)*);
let v_vec_in = count_tts!($($input_vec)*);
let dim = v_in + v_out + v_vec_in + 4;
let mut vec = Vec::with_capacity(dim);
for i in 0..dim {
vec.push(1);
}
UserDatatype::structured(
vec.as_slice(),
&[
offset_of!($name, conf_num) as Address,
offset_of!($name, conf_rep) as Address,
$(
offset_of!($name, $input) as Address,
)*
$(
offset_of!($name, $input_vec) as Address,
)*
$(
offset_of!($name, $output) as Address,
)*
offset_of!($name, run_duration) as Address,
offset_of!($name, step_per_sec) as Address,
],
&[
u32::equivalent_datatype(),
u32::equivalent_datatype(),
$(
<$input_ty>::equivalent_datatype(),
)*
$(
UserDatatype::contiguous($input_len, &<$input_ty_vec>::equivalent_datatype()).as_ref(),
)*
$(
<$output_ty>::equivalent_datatype(),
)*
f32::equivalent_datatype(),
f32::equivalent_datatype(),
]
)
}
}
};
}
#[macro_export]
macro_rules! explore_distributed_mpi {
($nstep: expr, $rep_conf:expr, $state:ty,
input {$($input:ident: $input_ty: ty )*},
input_vec {$($input_vec:ident: [$input_ty_vec:ty; $input_len:expr])*},
output [$($output:ident: $output_ty: ty )*],
$mode: expr,
) => {{
let world = UNIVERSE.world();
let root_rank = 0;
let root_process = world.process_at_rank(root_rank);
let my_rank = world.rank();
let num_procs = world.size() as usize;
if world.rank() == root_rank {
println!("Running distributed (MPI) model exploration...");
}
let mut rep_conf = $rep_conf as usize;
let _nstep = $nstep as u32;
if rep_conf <= 0 { rep_conf = 1;}
build_dataframe!(FrameRow,
input { $($input:$input_ty)* },
input_vec { $($input_vec: [$input_ty_vec; $input_len] )* },
output[ $($output:$output_ty)*]
Copy);
extend_dataframe!(FrameRow,
input {$($input:$input_ty)* },
input_vec { $($input_vec: [$input_ty_vec; $input_len] )* },
output[ $( $output:$output_ty )*]
);
let mut n_conf:usize = 1;
let mut config_table_index: Vec<Vec<usize>> = Vec::new();
match $mode {
ExploreMode::Exaustive =>{
$( n_conf *= $input.len(); )*
$( n_conf *= $input_vec.len(); )*
config_table_index = build_configurations!(n_conf, $($input )* $($input_vec)*);
},
ExploreMode::Matched =>{
$( n_conf = $input.len(); )*
$( n_conf = $input_vec.len(); )*
},
}
let total_sim = n_conf*rep_conf;
if world.rank() == root_rank {
println!("Total simulations: {}", total_sim);
println!("Total configurations: {}", n_conf);
}
let mut local_conf_size: usize = n_conf/num_procs;
if (my_rank as usize) < n_conf%num_procs {
local_conf_size += 1;
}
println!("Processor {}: assigned {} configurations", my_rank, local_conf_size);
let mut dataframe: Vec<FrameRow> = Vec::new();
for i in 0..local_conf_size {
let mut state;
match $mode {
ExploreMode::Exaustive =>{
let mut row_count = -1.;
state = <$state>::new(
$(
$input[config_table_index[{row_count+=1.; row_count as usize}][i*num_procs + (my_rank as usize)]],
)*
$(
$input_vec[config_table_index[{row_count+=1.; row_count as usize}][i*num_procs + (my_rank as usize)]].clone(),
)*
);
},
ExploreMode::Matched =>{
state = <$state>::new(
$(
$input[i*num_procs + (my_rank as usize)],
)*
$(
$input_vec[i*num_procs + (my_rank as usize)].clone(),
)*
);
},
}
for j in 0..rep_conf{
println!("Running configuration #{} - Simulation #{} on processor #{}", i*num_procs + (my_rank as usize), j, my_rank);
let result = simulate_explore!($nstep, state);
$(
let mut $input_vec: [$input_ty_vec; $input_len] = [0; $input_len];
let slice = state.$input_vec.clone();
$input_vec.copy_from_slice(&slice[..]);
)*
dataframe.push(
FrameRow::new(i as u32, j as u32, $(state.$input,)* $($input_vec,)* $(state.$output,)* result[0].0, result[0].1)
);
}
}
if world.rank() == root_rank {
let mut samples_count: Vec<Count> = Vec::new();
for i in 0..num_procs {
if i < n_conf%num_procs || n_conf%num_procs == 0 {
let temp:usize = local_conf_size*(rep_conf as usize);
samples_count.push(temp as Count);
}
else {
let temp:usize = (local_conf_size-1)*(rep_conf as usize);
samples_count.push(temp as Count);
}
}
let displs: Vec<Count> = samples_count
.iter()
.scan(0, |acc, &x| {
let tmp = *acc;
*acc += x;
Some(tmp)
})
.collect();
let mut all_dataframe = vec![dataframe[0]; n_conf*$rep_conf];
let mut partition = PartitionMut::new(&mut all_dataframe[..], samples_count.clone(), &displs[..]);
root_process.gather_varcount_into_root(&dataframe[..], &mut partition);
all_dataframe
} else {
root_process.gather_varcount_into(&dataframe[..]);
dataframe = Vec::new();
dataframe
}
}};
($nstep: expr, $rep_conf:expr, $state_name:ty,
input {$($input:ident: $input_ty: ty )*,},
input_vec {$($input_vec:ident: [$input_vec_type:ty; $input_vec_len:expr])*},
$mode: expr,
) => {
explore_distributed_mpi!($nstep, $rep_conf, $state_name,
input { $($input: $input_ty)*},
input_vec { $($input_vec: [$input_vec_type; $input_vec_len])* },
output [],
$mode,)
};
($nstep: expr, $rep_conf:expr, $state_name:ty,
input {$($input:ident: $input_ty: ty )*,},
$mode: expr,
) => {
explore_distributed_mpi!($nstep, $rep_conf, $state_name,
input { $($input: $input_ty)*},
input_vec { },
output [],
$mode,)
};
($nstep: expr, $rep_conf:expr, $state_name:ty,
input_vec {$($input_vec:ident: [$input_vec_type:ty; $input_vec_len:expr])*},
$mode: expr,
) => {
explore_distributed_mpi!($nstep, $rep_conf, $state_name,
input { },
input_vec { $($input_vec: [$input_vec_type; $input_vec_len])* },
output [],
$mode,)
};
}