use std::cell::RefCell;
use std::convert::TryFrom;
use ::rand::{rngs::StdRng,Rng};
use crate::match_object_panic;
use crate::config_parser::ConfigurationValue;
use crate::routing::*;
use crate::topology::{Topology,Location};
#[derive(Debug)]
pub enum SumRoutingPolicy
{
Random,
TryBoth,
Stubborn,
StubbornWhenSecond,
SecondWhenFirstEmpty,
EscapeToSecond,
}
pub fn new_sum_routing_policy(cv: &ConfigurationValue) -> SumRoutingPolicy
{
if let &ConfigurationValue::Object(ref cv_name, ref _cv_pairs)=cv
{
match cv_name.as_ref()
{
"Random" => SumRoutingPolicy::Random,
"TryBoth" => SumRoutingPolicy::TryBoth,
"Stubborn" => SumRoutingPolicy::Stubborn,
"StubbornWhenSecond" => SumRoutingPolicy::StubbornWhenSecond,
"SecondWhenFirstEmpty" => SumRoutingPolicy::SecondWhenFirstEmpty,
"EscapeToSecond" => SumRoutingPolicy::EscapeToSecond,
_ => panic!("Unknown sum routing policy {}",cv_name),
}
}
else
{
panic!("Trying to create a SumRoutingPolicy from a non-Object");
}
}
#[derive(Debug)]
pub struct SumRouting
{
policy:SumRoutingPolicy,
routing: [Box<dyn Routing>;2],
allowed_virtual_channels: [Vec<usize>;2],
extra_label: [i32;2],
enabled_statistics: bool,
tracked_hops: RefCell<[i64;2]>,
}
impl Routing for SumRouting
{
fn next(&self, routing_info:&RoutingInfo, topology:&dyn Topology, current_router:usize, target_router: usize, target_server:Option<usize>, num_virtual_channels:usize, rng: &mut StdRng) -> Result<RoutingNextCandidates,Error>
{
let distance=topology.distance(current_router,target_router);
if distance==0
{
let target_server = target_server.expect("target server was not given.");
for i in 0..topology.ports(current_router)
{
if let (Location::ServerPort(server),_link_class)=topology.neighbour(current_router,i)
{
if server==target_server
{
return Ok(RoutingNextCandidates{candidates:(0..num_virtual_channels).map(|vc|CandidateEgress::new(i,vc)).collect(),idempotent:true});
}
}
}
unreachable!();
}
let meta=routing_info.meta.as_ref().unwrap();
let r = match routing_info.selections
{
None =>
{
unreachable!();
}
Some(ref s) =>
{
if s.len()>=2
{
let avc0=&self.allowed_virtual_channels[0];
let el0=self.extra_label[0];
let r0=self.routing[0].next(&meta[0].borrow(),topology,current_router,target_router,target_server,avc0.len(),rng)?.into_iter().map( |candidate| CandidateEgress{virtual_channel:avc0[candidate.virtual_channel],label:candidate.label+el0,annotation:Some(RoutingAnnotation{values:vec![0],meta:vec![candidate.annotation]}),..candidate} );
let avc1=&self.allowed_virtual_channels[1];
let el1=self.extra_label[1];
let r1=self.routing[1].next(&meta[1].borrow(),topology,current_router,target_router,target_server,avc1.len(),rng)?.into_iter().map( |candidate| CandidateEgress{virtual_channel:avc1[candidate.virtual_channel],label:candidate.label+el1,annotation:Some(RoutingAnnotation{values:vec![1],meta:vec![candidate.annotation]}),..candidate} );
match self.policy
{
SumRoutingPolicy::SecondWhenFirstEmpty =>
{
let r : Vec<_> =r0.collect();
if r.is_empty() { r1.collect() } else { r }
}
_ => r0.chain(r1).collect()
}
}
else
{
let index=s[0] as usize;
let routing = &self.routing[index];
let allowed_virtual_channels = &self.allowed_virtual_channels[index];
let extra_label = self.extra_label[index];
let r=routing.next(&meta[index].borrow(),topology,current_router,target_router,target_server,allowed_virtual_channels.len(),rng)?;
r.into_iter()
.map( |candidate| CandidateEgress{virtual_channel:allowed_virtual_channels[candidate.virtual_channel],label:candidate.label+extra_label,annotation:Some(RoutingAnnotation{values:vec![s[0]],meta:vec![candidate.annotation]}),..candidate} ).collect()
}
}
};
Ok(RoutingNextCandidates{candidates:r,idempotent:false})
}
fn initialize_routing_info(&self, routing_info:&RefCell<RoutingInfo>, topology:&dyn Topology, current_router:usize, target_router:usize, target_server:Option<usize>, rng: &mut StdRng)
{
let all:Vec<i32> = match self.policy
{
SumRoutingPolicy::Random => vec![rng.gen_range(0..2)],
SumRoutingPolicy::TryBoth | SumRoutingPolicy::Stubborn | SumRoutingPolicy::StubbornWhenSecond
| SumRoutingPolicy::SecondWhenFirstEmpty | SumRoutingPolicy::EscapeToSecond => vec![0,1],
};
let mut bri=routing_info.borrow_mut();
bri.meta=Some(vec![RefCell::new(RoutingInfo::new()),RefCell::new(RoutingInfo::new())]);
for &s in all.iter()
{
let routing = &self.routing[s as usize];
routing.initialize_routing_info(&bri.meta.as_ref().unwrap()[s as usize],topology,current_router,target_router,target_server,rng)
}
bri.selections=Some(all);
}
fn update_routing_info(&self, routing_info:&RefCell<RoutingInfo>, topology:&dyn Topology, current_router:usize, current_port:usize, target_router:usize, target_server:Option<usize>, rng: &mut StdRng)
{
use SumRoutingPolicy::*;
let mut bri=routing_info.borrow_mut();
if self.enabled_statistics
{
if let Some(cs) = &bri.selections
{
let tracked_hops = &mut self.tracked_hops.borrow_mut();
let range = if cs.len()==3 { &cs[2..=2] } else { &cs[..] };
for &is in range.iter()
{
tracked_hops[is as usize] +=1;
}
}
}
let mut cs = match bri.selections
{
None => unreachable!(),
Some(ref t) =>
{
if t.len()==3 {
match self.policy
{
SecondWhenFirstEmpty => t.clone(),
_ => vec![t[2]],
}
} else { t.clone() }
},
};
for &is in cs.iter().take(2)
{
let s = is as usize;
let routing = &self.routing[s];
let meta=bri.meta.as_mut().unwrap();
meta[s].borrow_mut().hops+=1;
routing.update_routing_info(&meta[s],topology,current_router,current_port,target_router,target_server,rng);
}
if let EscapeToSecond = self.policy
{
if cs[0]==0
{
cs = vec![0,1];
let second_meta = RefCell::new(RoutingInfo::new());
self.routing[1].initialize_routing_info(&second_meta,topology,current_router,target_router,target_server,rng);
match bri.meta
{
Some(ref mut a) => a[1] = second_meta,
_ => panic!("No meta data for EscapeToSecond"),
};
}
}
bri.selections=Some(cs);
}
fn initialize(&mut self, topology:&dyn Topology, rng: &mut StdRng)
{
self.routing[0].initialize(topology,rng);
self.routing[1].initialize(topology,rng);
}
fn performed_request(&self, requested:&CandidateEgress, routing_info:&RefCell<RoutingInfo>, topology:&dyn Topology, current_router:usize, target_router:usize, target_server:Option<usize>, _num_virtual_channels:usize, rng:&mut StdRng)
{
use sum_routing_internal::{SumRoutingSelection,SumRoutingCase::*};
let mut bri=routing_info.borrow_mut();
if let DoubleChoice(..) = bri.selections.case()
{
let &CandidateEgress{ref annotation,..} = requested;
if let Some(annotation) = annotation.as_ref()
{
let s = annotation.values[0];
match self.policy
{
SumRoutingPolicy::Stubborn => bri.selections.set_single(s),
SumRoutingPolicy::StubbornWhenSecond => if s==1 {
bri.selections.set_single(1);
} else {
bri.selections.set_request(s);
},
_ => bri.selections.set_request(s),
}
}
}
let &CandidateEgress{ref annotation,..} = requested;
if let Some(annotation) = annotation.as_ref()
{
let meta=bri.meta.as_mut().unwrap();
let mut sub_requested = requested.clone();
let s = annotation.values[0] as usize;
let routing = &self.routing[s];
sub_requested.annotation = requested.annotation.as_ref().unwrap().meta[0].clone();
let sub_num_vc = self.allowed_virtual_channels[s].len();
routing.performed_request(&sub_requested,&meta[s],topology,current_router,target_router,target_server,sub_num_vc,rng);
}
}
fn statistics(&self, cycle:Time) -> Option<ConfigurationValue>
{
if self.enabled_statistics {
let tracked_hops = self.tracked_hops.borrow();
let mut content = vec![
(String::from("first_routing_hops"),ConfigurationValue::Number(tracked_hops[0] as f64)),
(String::from("second_routing_hops"),ConfigurationValue::Number(tracked_hops[1] as f64)),
];
if let Some(inner)=self.routing[0].statistics(cycle)
{
content.push( (String::from("first_statistics"),inner) );
}
if let Some(inner)=self.routing[1].statistics(cycle)
{
content.push( (String::from("second_statistics"),inner) );
}
Some(ConfigurationValue::Object(String::from("SumRoutingStatistics"),content))
} else {
None
}
}
fn reset_statistics(&mut self, _next_cycle:Time)
{
}
}
impl SumRouting
{
pub fn new(arg: RoutingBuilderArgument) -> SumRouting
{
let mut policy=None;
let mut first_routing=None;
let mut second_routing=None;
let mut first_allowed_virtual_channels=None;
let mut second_allowed_virtual_channels=None;
let mut first_extra_label=0i32;
let mut second_extra_label=0i32;
let mut enabled_statistics=false;
match_object_panic!(arg.cv,"Sum",value,
"policy" => policy=Some(new_sum_routing_policy(value)),
"first_routing" => first_routing=Some(new_routing(RoutingBuilderArgument{cv:value,..arg})),
"second_routing" => second_routing=Some(new_routing(RoutingBuilderArgument{cv:value,..arg})),
"first_allowed_virtual_channels" => first_allowed_virtual_channels = Some(value.as_array()
.expect("bad value for first_allowed_virtual_channels").iter()
.map(|v|v.as_f64().expect("bad value in first_allowed_virtual_channels") as usize).collect()),
"second_allowed_virtual_channels" => second_allowed_virtual_channels = Some(value.as_array()
.expect("bad value for second_allowed_virtual_channels").iter()
.map(|v|v.as_f64().expect("bad value in second_allowed_virtual_channels") as usize).collect()),
"first_extra_label" => first_extra_label = value.as_f64().expect("bad value for first_extra_label") as i32,
"second_extra_label" => second_extra_label = value.as_f64().expect("bad value for second_extra_label") as i32,
"enabled_statistics" => enabled_statistics = value.as_bool().expect("bad value for enabled_statistics"),
);
let policy=policy.expect("There were no policy");
let first_routing=first_routing.expect("There were no first_routing");
let second_routing=second_routing.expect("There were no second_routing");
let first_allowed_virtual_channels=first_allowed_virtual_channels.expect("There were no first_allowed_virtual_channels");
let second_allowed_virtual_channels=second_allowed_virtual_channels.expect("There were no second_allowed_virtual_channels");
SumRouting{
policy,
routing: [first_routing,second_routing],
allowed_virtual_channels: [first_allowed_virtual_channels, second_allowed_virtual_channels],
extra_label: [first_extra_label, second_extra_label],
enabled_statistics,
tracked_hops: RefCell::new([0,0]),
}
}
}
mod sum_routing_internal
{
pub trait SumRoutingSelection
{
fn case(&self) -> SumRoutingCase;
fn set_single(&mut self, selection:i32);
fn set_request(&mut self, request:i32);
}
use SumRoutingCase::*;
impl SumRoutingSelection for Option<Vec<i32>>
{
fn case(&self) -> SumRoutingCase
{
if let Some(s) = self {
if s.len()==1 {
SingleChoice(s[0])
} else {
DoubleChoice(s[0],s[1])
}
} else {
panic!("Invalid selections");
}
}
fn set_single(&mut self, selection:i32)
{
*self = Some(vec![selection]);
}
fn set_request(&mut self, request:i32)
{
if let Some(ref mut s) = self {
if s.len()>=2 {
*s = vec![s[0],s[1],request];
}
}
}
}
pub enum SumRoutingCase
{
SingleChoice(i32),
DoubleChoice(i32,i32),
}
}
#[derive(Debug)]
pub struct Stubborn
{
routing: Box<dyn Routing>,
}
impl Routing for Stubborn
{
fn next(&self, routing_info:&RoutingInfo, topology:&dyn Topology, current_router:usize, target_router: usize, target_server:Option<usize>, num_virtual_channels:usize, rng: &mut StdRng) -> Result<RoutingNextCandidates,Error>
{
if target_router==current_router
{
let target_server = target_server.expect("target server was not given.");
for i in 0..topology.ports(current_router)
{
if let (Location::ServerPort(server),_link_class)=topology.neighbour(current_router,i)
{
if server==target_server
{
return Ok(RoutingNextCandidates{candidates:(0..num_virtual_channels).map(|vc|CandidateEgress::new(i,vc)).collect(),idempotent:true});
}
}
}
unreachable!();
}
if let Some(ref sel)=routing_info.selections
{
return Ok(RoutingNextCandidates{candidates:vec![CandidateEgress{port:sel[0] as usize,virtual_channel:sel[1] as usize,label:sel[2],..Default::default()}],idempotent:false});
}
return Ok(RoutingNextCandidates{candidates:self.routing.next(&routing_info.meta.as_ref().unwrap()[0].borrow(),topology,current_router,target_router,target_server,num_virtual_channels,rng)?.into_iter().map(|candidate|CandidateEgress{annotation:Some(RoutingAnnotation{values:vec![candidate.label],meta:vec![candidate.annotation]}),..candidate}).collect(),idempotent:false})
}
fn initialize_routing_info(&self, routing_info:&RefCell<RoutingInfo>, topology:&dyn Topology, current_router:usize, target_router:usize, target_server:Option<usize>, rng: &mut StdRng)
{
let meta_routing_info=RefCell::new(RoutingInfo::new());
self.routing.initialize_routing_info(&meta_routing_info, topology, current_router, target_router, target_server, rng);
routing_info.borrow_mut().meta = Some(vec![meta_routing_info]);
}
fn update_routing_info(&self, routing_info:&RefCell<RoutingInfo>, topology:&dyn Topology, current_router:usize, current_port:usize, target_router:usize, target_server:Option<usize>, rng: &mut StdRng)
{
let mut bri=routing_info.borrow_mut();
bri.selections=None;
self.routing.update_routing_info(&bri.meta.as_mut().unwrap()[0],topology,current_router,current_port,target_router,target_server,rng);
}
fn initialize(&mut self, topology:&dyn Topology, rng: &mut StdRng)
{
self.routing.initialize(topology,rng);
}
fn performed_request(&self, requested:&CandidateEgress, routing_info:&RefCell<RoutingInfo>, topology:&dyn Topology, current_router:usize, target_router:usize, target_server:Option<usize>, num_virtual_channels:usize, rng:&mut StdRng)
{
let &CandidateEgress{port,virtual_channel,ref annotation,..} = requested;
if let Some(annotation) = annotation.as_ref()
{
let label = annotation.values[0];
let mut bri=routing_info.borrow_mut();
bri.selections=Some(vec![port as i32, virtual_channel as i32, label]);
let meta_requested = CandidateEgress{annotation:annotation.meta[0].clone(),..*requested};
let meta_info = &bri.meta.as_ref().unwrap()[0];
self.routing.performed_request(&meta_requested,meta_info,topology,current_router,target_router,target_server,num_virtual_channels,rng);
}
}
}
impl Stubborn
{
pub fn new(arg: RoutingBuilderArgument) -> Stubborn
{
let mut routing=None;
match_object_panic!(arg.cv,"Stubborn",value,
"routing" => routing=Some(new_routing(RoutingBuilderArgument{cv:value,..arg})),
);
let routing=routing.expect("There were no routing");
Stubborn{
routing,
}
}
}
#[derive(Debug)]
pub struct EachLengthSourceAdaptiveRouting
{
pub routing: Box<dyn InstantiableSourceRouting>,
}
impl Routing for EachLengthSourceAdaptiveRouting
{
fn next(&self, routing_info:&RoutingInfo, topology:&dyn Topology, current_router:usize, target_router: usize, target_server:Option<usize>, num_virtual_channels:usize, _rng: &mut StdRng) -> Result<RoutingNextCandidates,Error>
{
let distance=topology.distance(current_router,target_router);
if distance==0
{
let target_server = target_server.expect("target server was not given.");
for i in 0..topology.ports(current_router)
{
if let (Location::ServerPort(server),_link_class)=topology.neighbour(current_router,i)
{
if server==target_server
{
return Ok(RoutingNextCandidates{
candidates:(0..num_virtual_channels).map(|vc|CandidateEgress::new(i,vc)).collect(),
idempotent:true
});
}
}
}
unreachable!();
}
let source_router = routing_info.visited_routers.as_ref().unwrap()[0];
let num_ports=topology.ports(current_router);
let mut r=Vec::with_capacity(num_ports*num_virtual_channels);
let selections = routing_info.selections.as_ref().unwrap().clone();
for path_index in selections
{
let path = &self.routing.get_paths(source_router,target_router)[<usize>::try_from(path_index).unwrap()];
let next_router = path[routing_info.hops+1];
let length = path.len() - 1; let remain = length - routing_info.hops;
for i in 0..num_ports
{
if let (Location::RouterPort{router_index,router_port:_},_link_class)=topology.neighbour(current_router,i)
{
if router_index==next_router
{
r.extend((0..num_virtual_channels).map(|vc|{
let mut egress = CandidateEgress::new(i,vc);
egress.estimated_remaining_hops = Some(remain);
egress.label = i32::try_from(remain - distance).unwrap();
egress
}));
}
}
}
}
Ok(RoutingNextCandidates{candidates:r,idempotent:true})
}
fn initialize_routing_info(&self, routing_info:&RefCell<RoutingInfo>, _topology:&dyn Topology, current_router:usize, target_router:usize, _target_server:Option<usize>, rng: &mut StdRng)
{
routing_info.borrow_mut().visited_routers=Some(vec![current_router]);
if current_router!=target_router
{
let path_collection = self.routing.get_paths(current_router,target_router);
if path_collection.is_empty()
{
panic!("No path found from router {} to router {}",current_router,target_router);
}
let min_length:usize = path_collection.iter().map(|path|path.len()).min().unwrap();
let max_length:usize = path_collection.iter().map(|path|path.len()).max().unwrap();
let selected_indices : Vec<i32> = (min_length..=max_length).filter_map(|length|{
let candidates : Vec<usize> = (0..path_collection.len()).filter(|&index|path_collection[index].len()==length).collect();
if candidates.is_empty() {
None
} else {
let r = rng.gen_range(0..candidates.len());
Some(i32::try_from(candidates[r]).unwrap())
}
}).collect();
routing_info.borrow_mut().selections=Some(selected_indices);
}
}
fn update_routing_info(&self, routing_info:&RefCell<RoutingInfo>, _topology:&dyn Topology, current_router:usize, _current_port:usize, target_router:usize, _target_server:Option<usize>, _rng: &mut StdRng)
{
let mut ri=routing_info.borrow_mut();
let hops = ri.hops;
if let Some(ref mut visited)=ri.visited_routers
{
let source_router = visited[0];
visited.push(current_router);
let paths = &self.routing.get_paths(source_router,target_router);
if let Some(ref mut selections)=ri.selections
{
selections.retain(|path_index|{
let path = &paths[<usize>::try_from(*path_index).unwrap()];
path[hops]==current_router
});
if selections.is_empty()
{
panic!("No selections remaining.");
}
}
}
}
fn initialize(&mut self, topology:&dyn Topology, rng: &mut StdRng)
{
self.routing.initialize(topology,rng);
}
}