use std::cell::RefCell;
use std::any::Any;
use crate::routing::*;
use crate::match_object_panic;
#[derive(Debug)]
pub struct Polarized
{
include_labels: bool,
strong: bool,
panic_on_empty: bool,
enable_statistics: bool,
empty_count: Option<RefCell<u64>>,
best_count: Option<RefCell<[u64;3]>>,
}
impl Routing for Polarized
{
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
{
let r=(0..num_virtual_channels).map(|vc|CandidateEgress::new(i,vc)).collect();
return Ok(RoutingNextCandidates{candidates:r,idempotent:true});
}
}
}
unreachable!();
}
let source_router=if let Some(ref visited)=routing_info.visited_routers
{
visited[0]
}
else
{
panic!("Unknown source router");
};
let num_ports=topology.ports(current_router);
let mut r=Vec::with_capacity(num_ports*num_virtual_channels);
let a=topology.distance(source_router,current_router);
let b=topology.distance(current_router,target_router);
let weight:i32 = b as i32 - a as i32;
for port_index in 0..num_ports
{
if let (Location::RouterPort{router_index,router_port:_},_link_class)=topology.neighbour(current_router,port_index)
{
let new_a=topology.distance(source_router,router_index);
let new_b=topology.distance(router_index,target_router);
let new_weight:i32 = new_b as i32 - new_a as i32;
let condition = new_weight<weight || ( !self.strong
&& new_weight==weight && if a<b {a<new_a} else {new_b<b} );
if condition
{
let label=if self.include_labels {new_weight-weight} else {0}; r.extend((0..num_virtual_channels).map(|vc|CandidateEgress{port:port_index,virtual_channel:vc,label,..Default::default()}));
}
}
}
let call_count: Option<usize> = {
let mut auxiliar = routing_info.auxiliar.borrow_mut();
if let Some(any) = &mut *auxiliar {
let count : &mut usize = any.downcast_mut().expect("auxiliar failed to cast");
*count += 1;
Some(*count)
} else {
None
}
};
if r.is_empty()
{
if self.panic_on_empty
{
panic!("Polarized routing did not find any candidate output port for s={} c={} t={} a={} b={}",source_router,current_router,target_router,a,b);
}
if let Some(1) = call_count
{
if let Some( empty_count_refcell ) = self.empty_count.as_ref()
{
let mut empty_count = empty_count_refcell.borrow_mut();
*empty_count += 1;
}
}
}
if let Some(min_label)=r.iter().map(|ref e|e.label).min()
{
for ref mut e in r.iter_mut()
{
e.label-=min_label;
}
if let Some(1) = call_count
{
if let Some( best_count_refcell ) = self.best_count.as_ref()
{
let mut best_count = best_count_refcell.borrow_mut();
let index = (-min_label) as usize;
best_count[index] += 1;
}
}
}
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 self.enable_statistics
{
let any : Box<dyn Any> = Box::new(0usize);
routing_info.borrow_mut().auxiliar = RefCell::new(Some(any));
}
}
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();
if let Some(ref mut visited)=ri.visited_routers
{
visited.push(current_router);
}
if self.enable_statistics
{
let any : Box<dyn Any> = Box::new(0usize);
ri.auxiliar = RefCell::new(Some(any));
}
}
fn initialize(&mut self, topology:&dyn Topology, _rng: &mut StdRng)
{
let n=topology.num_routers();
let eccentricity_vector :Vec<usize> = (0..n).map(|vertex|topology.eccentricity(vertex)).collect();
let diam = topology.diameter();
let average_eccentricity = eccentricity_vector.iter().sum::<usize>() as f64 / n as f64;
let nf = n as f64;
let max_deg = topology.maximum_degree();
println!("INFO: n={n} d={max_deg} diameter={diam} average_eccentricity={average_eccentricity}");
let random_placid_value = (max_deg as f64) / nf.ln() * 2.0f64.ln()/2.0;
if random_placid_value >= 1.0 {
println!("INFO: d/ln n * ln 2/2 = {} > 1: In a RRG with these parameters Polarized routing should work.",random_placid_value);
} else if random_placid_value >= 0.5 {
println!("INFO: .5 < d/ln n * ln 2/2 = {} < 1: In a RRG with these parameters is not clear whether Polarized routing will have corners.",random_placid_value);
} else {
println!("INFO: d/ln n * ln 2/2 = {} < .5: In a RRG with these parameters Polarized routing is expected to have problematic corners.",random_placid_value);
}
}
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)
{
}
fn statistics(&self, _cycle:Time) -> Option<ConfigurationValue>
{
if self.enable_statistics{
let mut content = Vec::with_capacity(2);
if let Some(empty_count) = self.empty_count.as_ref()
{
content.push(
(String::from("empty_count"),ConfigurationValue::Number(*empty_count.borrow() as f64))
);
}
if let Some(best_count) = self.best_count.as_ref()
{
content.push(
(String::from("best_count"),ConfigurationValue::Array(
best_count.borrow().iter().map(|x|ConfigurationValue::Number(*x as f64)).collect()
))
);
}
Some(ConfigurationValue::Object(String::from("PolarizedStatistics"),content))
} else {
None
}
}
fn reset_statistics(&mut self, _next_cycle:Time)
{
if self.enable_statistics
{
self.empty_count = Some(RefCell::new(0));
self.best_count = Some(RefCell::new([0,0,0]));
}
}
}
impl Polarized
{
pub fn new(arg:RoutingBuilderArgument) -> Polarized
{
let mut include_labels = None;
let mut strong = None;
let mut panic_on_empty = true;
let mut enable_statistics = false;
match_object_panic!(arg.cv,"Polarized", value,
"include_labels" => include_labels=Some(value.as_bool().expect("bad value for include_labels")),
"strong" => strong=Some(value.as_bool().expect("bad value for strong")),
"panic_on_empty" => panic_on_empty=value.as_bool().expect("bad value for panic_on_empty"),
"enable_statistics" => enable_statistics=value.as_bool().expect("bad value for enable_statistics"),
);
let include_labels=include_labels.expect("There were no include_labels");
let strong=strong.unwrap_or_else(||false);
Polarized{
include_labels,
strong,
panic_on_empty,
enable_statistics,
empty_count: if enable_statistics {Some(RefCell::new(0))} else {None},
best_count: if enable_statistics {Some(RefCell::new([0,0,0]))} else {None},
}
}
}