use std::cell::RefCell;
use std::rc::{Rc,Weak};
use std::ops::Deref;
use std::mem::size_of;
use ::rand::{Rng,rngs::StdRng};
use super::{Router,AbstractTransmissionMechanism,TransmissionMechanismBuilderArgument,new_transmission_mechanism,StatusAtEmissor,SpaceAtReceptor,AugmentedBuffer,AcknowledgeMessage};
use crate::allocator::{Allocator,VCARequest,AllocatorBuilderArgument, new_allocator};
use crate::config_parser::ConfigurationValue;
use crate::router::RouterBuilderArgument;
use crate::topology::{Location,Topology};
use crate::routing::CandidateEgress;
use crate::policies::{RequestInfo,VirtualChannelPolicy,new_virtual_channel_policy,VCPolicyBuilderArgument};
use crate::event::{self,Event,Eventful,EventGeneration,CyclePosition,Time};
use crate::{Phit,SimulationShared,SimulationMut};
use crate::quantify::Quantifiable;
use crate::match_object_panic;
enum OutputArbiter
{
#[allow(dead_code)]
Random,
Token{
port_token: Vec<usize>,
},
}
pub struct InputOutput
{
self_rc: Weak<RefCell<InputOutput>>,
next_events: Vec<Time>,
last_process_at_cycle: Option<Time>,
router_index: usize,
virtual_channel_policies: Vec<Box<dyn VirtualChannelPolicy>>,
bubble: bool,
flit_size: usize,
buffer_size: usize,
crossbar_delay: Time,
intransit_priority: bool,
allow_request_busy_port: bool,
neglect_busy_output: bool,
transmission_port_status: Vec<Box<dyn StatusAtEmissor>>,
reception_port_space: Vec<Box<dyn SpaceAtReceptor>>,
from_server_mechanism: Box<dyn AbstractTransmissionMechanism>,
output_buffer_size: usize,
output_buffers: Vec<Vec<AugmentedBuffer<(usize,usize)>>>,
output_buffer_phits_traversing_crossbar: Vec<Vec<usize>>,
output_schedulers: Vec<Rc<RefCell<internal::TryLinkTraversal>>>,
selected_input: Vec<Vec<Option<(usize,usize)>>>,
selected_output: Vec<Vec<Option<(usize,usize)>>>,
time_at_input_head: Vec<Vec<usize>>,
output_arbiter: OutputArbiter,
maximum_packet_size: usize,
crossbar_frequency_divisor: Time,
crossbar_allocator: Box<dyn Allocator>,
statistics_begin_cycle: Time,
statistics_output_buffer_occupation_per_vc: Vec<f64>,
statistics_reception_space_occupation_per_vc: Vec<f64>,
}
impl Router for InputOutput
{
fn insert(&mut self, current_cycle:Time, phit:Rc<Phit>, port:usize, rng: &mut StdRng) -> Vec<EventGeneration>
{
self.reception_port_space[port].insert(phit,rng).expect("there was some problem on the insertion");
if let Some(event) = self.schedule(current_cycle,0) {
vec![event]
} else {
vec![]
}
}
fn acknowledge(&mut self, current_cycle:Time, port:usize, ack_message:AcknowledgeMessage) -> Vec<EventGeneration>
{
self.transmission_port_status[port].acknowledge(ack_message);
let mut events = vec![];
if let Some(event) = self.schedule(current_cycle,0) {
events.push(event);
}
if let Some(event) = self.output_schedulers[port].borrow_mut().schedule(current_cycle,0) {
events.push(event);
}
events
}
fn num_virtual_channels(&self) -> usize
{
self.transmission_port_status[0].num_virtual_channels()
}
fn virtual_port_size(&self, _port:usize, _virtual_channel:usize) -> usize
{
self.buffer_size
}
fn iter_phits(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
Box::new(self.reception_port_space.iter().flat_map(|space|space.iter_phits()).collect::<Vec<_>>().into_iter())
}
fn get_status_at_emisor(&self, port:usize) -> Option<&dyn StatusAtEmissor>
{
Some(&*self.transmission_port_status[port])
}
fn get_maximum_credits_towards(&self, _port:usize, _virtual_channel:usize) -> Option<usize>
{
Some(self.buffer_size)
}
fn get_index(&self)->Option<usize>
{
Some(self.router_index)
}
fn aggregate_statistics(&self, statistics:Option<ConfigurationValue>, router_index:usize, total_routers:usize, cycle:Time) -> Option<ConfigurationValue>
{
let cycle_span = cycle - self.statistics_begin_cycle;
let mut reception_space_occupation_per_vc:Option<Vec<f64>> = Some(self.statistics_reception_space_occupation_per_vc.iter().map(|x|x/cycle_span as f64).collect());
let mut output_buffer_occupation_per_vc:Option<Vec<f64>> = Some(self.statistics_output_buffer_occupation_per_vc.iter().map(|x|x/cycle_span as f64).collect());
if let Some(previous)=statistics
{
if let ConfigurationValue::Object(cv_name,previous_pairs) = previous
{
if cv_name!="InputOutput"
{
panic!("incompatible statistics, should be `InputOutput` object not `{}`",cv_name);
}
for (ref name,ref value) in previous_pairs
{
match name.as_ref()
{
"average_output_buffer_occupation_per_vc" => match value
{
&ConfigurationValue::Array(ref prev_a) =>
{
if let Some(ref mut curr_a) = output_buffer_occupation_per_vc
{
for (c,p) in curr_a.iter_mut().zip(prev_a.iter())
{
if let ConfigurationValue::Number(x)=p
{
*c += x;
}
else
{
panic!("The non-number {:?} cannot be added",p);
}
}
}
else
{
println!("Ignoring average_output_buffer_occupation_per_vc.");
}
}
_ => panic!("bad value for average_output_buffer_occupation_per_vc"),
},
"average_reception_space_occupation_per_vc" => match value
{
&ConfigurationValue::Array(ref prev_a) =>
{
if let Some(ref mut curr_a) = reception_space_occupation_per_vc
{
for (c,p) in curr_a.iter_mut().zip(prev_a.iter())
{
if let ConfigurationValue::Number(x)=p
{
*c += x;
}
else
{
panic!("The non-number {:?} cannot be added",p);
}
}
}
else
{
println!("Ignoring average_output_buffer_occupation_per_vc.");
}
}
_ => panic!("bad value for average_output_buffer_occupation_per_vc"),
},
_ => panic!("Nothing to do with field {} in InputOutput statistics",name),
}
}
}
else
{
panic!("received incompatible statistics");
}
}
let mut result_content : Vec<(String,ConfigurationValue)> = vec![
];
let is_last = router_index+1==total_routers;
if let Some(ref mut content)=output_buffer_occupation_per_vc
{
if is_last
{
let factor=1f64 / total_routers as f64;
for x in content.iter_mut()
{
*x *= factor;
}
}
result_content.push((String::from("average_output_buffer_occupation_per_vc"),ConfigurationValue::Array(content.iter().map(|x|ConfigurationValue::Number(*x)).collect())));
}
if let Some(ref mut content)=reception_space_occupation_per_vc
{
if is_last
{
let factor=1f64 / total_routers as f64;
for x in content.iter_mut()
{
*x *= factor;
}
}
result_content.push((String::from("average_reception_space_occupation_per_vc"),ConfigurationValue::Array(content.iter().map(|x|ConfigurationValue::Number(*x)).collect())));
}
Some(ConfigurationValue::Object(String::from("InputOutput"),result_content))
}
fn reset_statistics(&mut self, next_cycle:Time)
{
self.statistics_begin_cycle=next_cycle;
for x in self.statistics_output_buffer_occupation_per_vc.iter_mut()
{
*x=0f64;
}
for x in self.statistics_reception_space_occupation_per_vc.iter_mut()
{
*x=0f64;
}
}
fn build_emissor_status(&self, port:usize, topology:&dyn Topology) -> Box<dyn StatusAtEmissor+'static>
{
if let (Location::ServerPort(_server),_link_class)=topology.neighbour(self.router_index,port)
{
self.from_server_mechanism.new_status_at_emissor()
}
else
{
unimplemented!()
}
}
}
impl InputOutput
{
pub fn new(arg:RouterBuilderArgument) -> Rc<RefCell<InputOutput>>
{
let RouterBuilderArgument{
router_index,
cv,
plugs,
topology,
maximum_packet_size,
general_frequency_divisor,
..
} = arg;
let mut virtual_channels=None;
let mut buffer_size=None;
let mut virtual_channel_policies=None;
let mut bubble=None;
let mut flit_size=None;
let mut intransit_priority=None;
let mut allow_request_busy_port=None;
let mut output_buffer_size=None;
let mut allocator_value=None;
let mut transmission_mechanism=None;
let mut to_server_mechanism=None;
let mut from_server_mechanism=None;
let mut crossbar_delay: Time =0;
let mut neglect_busy_output = false;
let mut crossbar_frequency_divisor = general_frequency_divisor;
match_object_panic!(cv,["InputOutput","InputOutputMonocycle"],value,
"virtual_channels" => match value
{
&ConfigurationValue::Number(f) => virtual_channels=Some(f as usize),
_ => panic!("bad value for virtual_channels"),
},
"virtual_channel_policies" => match value
{
&ConfigurationValue::Array(ref a) => virtual_channel_policies=Some(a.iter().map(
|cv|new_virtual_channel_policy(VCPolicyBuilderArgument{
cv,
plugs
})).collect()),
_ => panic!("bad value for permute"),
}
"crossbar_delay" | "delay" => crossbar_delay = value.as_time().expect("bad value for crossbar_delay"),
"buffer_size" => match value
{
&ConfigurationValue::Number(f) => buffer_size=Some(f as usize),
_ => panic!("bad value for buffer_size"),
},
"output_buffer_size" => match value
{
&ConfigurationValue::Number(f) => output_buffer_size=Some(f as usize),
_ => panic!("bad value for buffer_size"),
},
"bubble" => match value
{
&ConfigurationValue::True => bubble=Some(true),
&ConfigurationValue::False => bubble=Some(false),
_ => panic!("bad value for bubble"),
},
"flit_size" => match value
{
&ConfigurationValue::Number(f) => flit_size=Some(f as usize),
_ => panic!("bad value for flit_size"),
},
"intransit_priority" => match value
{
&ConfigurationValue::True => intransit_priority=Some(true),
&ConfigurationValue::False => intransit_priority=Some(false),
_ => panic!("bad value for intransit_priority"),
},
"allow_request_busy_port" => match value
{
&ConfigurationValue::True => allow_request_busy_port=Some(true),
&ConfigurationValue::False => allow_request_busy_port=Some(false),
_ => panic!("bad value for allow_request_busy_port"),
},
"neglect_busy_output" => neglect_busy_output = value.as_bool().expect("bad value for neglect_busy_output"),
"transmission_mechanism" => match value
{
&ConfigurationValue::Literal(ref s) => transmission_mechanism = Some(s.to_string()),
_ => panic!("bad value for transmission_mechanism"),
},
"to_server_mechanism" => match value
{
&ConfigurationValue::Literal(ref s) => to_server_mechanism = Some(s.to_string()),
_ => panic!("bad value for to_server_mechanism"),
},
"from_server_mechanism" => match value
{
&ConfigurationValue::Literal(ref s) => from_server_mechanism = Some(s.to_string()),
_ => panic!("bad value for from_server_mechanism"),
},
"allocator" => allocator_value=Some(value.clone()),
"crossbar_frequency_divisor" => crossbar_frequency_divisor = value.as_time().expect("bad value for crossbar_frequency_divisor"),
);
let virtual_channels=virtual_channels.expect("There were no virtual_channels");
let virtual_channel_policies=virtual_channel_policies.expect("There were no virtual_channel_policies");
let buffer_size=buffer_size.expect("There were no buffer_size");
let output_buffer_size=output_buffer_size.expect("There were no output_buffer_size");
let bubble=bubble.expect("There were no bubble");
let flit_size=flit_size.expect("There were no flit_size");
let intransit_priority=intransit_priority.expect("There were no intransit_priority");
let allow_request_busy_port=allow_request_busy_port.expect("There were no allow_request_busy_port");
let input_ports=topology.ports(router_index);
let allocator = new_allocator(AllocatorBuilderArgument{
cv:&allocator_value.expect("There were no allocator"),
num_clients:input_ports * virtual_channels,
num_resources:input_ports * virtual_channels,
plugs,
rng:arg.rng,
});
let selected_input=(0..input_ports).map(|_|
(0..virtual_channels).map(|_|None).collect()
).collect();
let selected_output=(0..input_ports).map(|_|
(0..virtual_channels).map(|_|None).collect()
).collect();
let time_at_input_head=(0..input_ports).map(|_|
(0..virtual_channels).map(|_|0).collect()
).collect();
let transmission_mechanism = transmission_mechanism.unwrap_or_else(||"SimpleVirtualChannels".to_string());
let from_server_mechanism = from_server_mechanism.unwrap_or_else(||"SimpleVirtualChannels".to_string());
let to_server_mechanism = to_server_mechanism.unwrap_or_else(||"TransmissionToServer".to_string());
let transmission_builder_argument = TransmissionMechanismBuilderArgument{name:"",virtual_channels,buffer_size,size_to_send:flit_size};
let transmission_mechanism = new_transmission_mechanism(TransmissionMechanismBuilderArgument{name:&transmission_mechanism,..transmission_builder_argument});
let to_server_mechanism = new_transmission_mechanism(TransmissionMechanismBuilderArgument{name:&to_server_mechanism,..transmission_builder_argument});
let from_server_mechanism = new_transmission_mechanism(TransmissionMechanismBuilderArgument{name:&from_server_mechanism,..transmission_builder_argument});
let transmission_port_status:Vec<Box<dyn StatusAtEmissor>> = (0..input_ports).map(|p|
if let (Location::ServerPort(_server),_link_class)=topology.neighbour(router_index,p)
{
to_server_mechanism.new_status_at_emissor()
}
else
{
transmission_mechanism.new_status_at_emissor()
}
).collect();
let reception_port_space = (0..input_ports).map(|p|
if let (Location::ServerPort(_server),_link_class)=topology.neighbour(router_index,p)
{
from_server_mechanism.new_space_at_receptor()
}
else
{
transmission_mechanism.new_space_at_receptor()
}
).collect();
let output_buffers= if output_buffer_size==0 {
panic!("output_buffer_size must be greater than 0");
} else {
(0..input_ports).map(|_|
(0..virtual_channels).map(|_|AugmentedBuffer::new()).collect()
).collect()
};
let output_buffer_phits_traversing_crossbar = vec![ vec![ 0 ; virtual_channels ] ; input_ports ];
let r=Rc::new(RefCell::new(InputOutput{
self_rc: Weak::new(),
next_events: vec![],
last_process_at_cycle: None,
router_index,
virtual_channel_policies,
bubble,
flit_size,
intransit_priority,
allow_request_busy_port,
neglect_busy_output,
buffer_size,
crossbar_delay,
transmission_port_status,
reception_port_space,
from_server_mechanism,
output_buffer_size,
output_buffers,
output_buffer_phits_traversing_crossbar,
output_schedulers: vec![],
selected_input,
selected_output,
time_at_input_head,
output_arbiter: OutputArbiter::Token{port_token: vec![0;input_ports]},
maximum_packet_size,
crossbar_frequency_divisor,
crossbar_allocator: allocator,
statistics_begin_cycle: 0,
statistics_output_buffer_occupation_per_vc: vec![0f64;virtual_channels],
statistics_reception_space_occupation_per_vc: vec![0f64;virtual_channels],
}));
r.borrow_mut().self_rc=Rc::<_>::downgrade(&r);
r
}
}
impl InputOutput
{
fn can_phit_advance(&self, phit:&Rc<Phit>, exit_port:usize, exit_vc:usize, bubble_in_use:bool)->bool
{
let available_internal_space = self.output_buffer_size-self.output_buffers[exit_port][exit_vc].len() - self.output_buffer_phits_traversing_crossbar[exit_port][exit_vc];
let mut necessary_credits=1;
if phit.is_begin()
{
necessary_credits=if bubble_in_use
{
phit.packet.size + self.maximum_packet_size
}
else
{
self.flit_size
}
}
available_internal_space >= necessary_credits
}
}
impl Eventful for InputOutput
{
fn process(&mut self, simulation:&SimulationShared, mutable:&mut SimulationMut) -> Vec<EventGeneration>
{
if self.output_schedulers.is_empty()
{
self.output_schedulers = (0..self.output_buffers.len()).map(|exit_port|{
let (_location,link_class)=simulation.network.topology.neighbour(self.router_index,exit_port);
let link = simulation.link_classes[link_class].clone();
internal::TryLinkTraversalArgument{
router:self,
exit_port,
link,
}.into()
}).collect();
}
let mut cycles_span = 1; if let Some(ref last)=self.last_process_at_cycle
{
cycles_span = simulation.cycle - *last;
if *last >= simulation.cycle
{
panic!("Trying to process at cycle {} a router::InputOutput already processed at {}",simulation.cycle,last);
}
}
self.last_process_at_cycle = Some(simulation.cycle);
assert!((simulation.cycle%self.crossbar_frequency_divisor) == 0, "Processing InputOutput router at a cycle ({cycle}) not multiple of crossbar_frequency_divisor ({divisor}). {cycle}%{divisor}={remainder}", cycle=simulation.cycle,divisor=self.crossbar_frequency_divisor,remainder=simulation.cycle%self.crossbar_frequency_divisor);
let mut request:Vec<VCARequest>=vec![];
let topology = simulation.network.topology.as_ref();
let amount_virtual_channels=self.num_virtual_channels();
for port_space in self.reception_port_space.iter()
{
for vc in 0..amount_virtual_channels
{
self.statistics_reception_space_occupation_per_vc[vc]+=(port_space.occupied_dedicated_space(vc).unwrap_or(0)*cycles_span as usize) as f64 / self.reception_port_space.len() as f64;
}
}
for output_port in self.output_buffers.iter()
{
for (vc,buffer) in output_port.iter().enumerate()
{
self.statistics_output_buffer_occupation_per_vc[vc]+=(buffer.len()*cycles_span as usize) as f64 / self.output_buffers.len() as f64;
}
}
let server_ports : Option<Vec<usize>> = if self.virtual_channel_policies.iter().any(|policy|policy.need_server_ports())
{
Some((0..topology.ports(self.router_index)).filter(|&p|
if let (Location::ServerPort(_server),_link_class)=topology.neighbour(self.router_index,p)
{
true
}
else
{
false
}
).collect())
}
else
{
None
};
let busy_ports:Vec<bool> = self.transmission_port_status.iter().enumerate().map(|(port,ref _status)|{
let mut is_busy = false;
for vc in 0..amount_virtual_channels
{
if let Some((selected_port,selected_virtual_channel))=self.selected_input[port][vc]
{
if let Some(phit)=self.reception_port_space[selected_port].front_virtual_channel(selected_virtual_channel)
{
if self.can_phit_advance(&phit,port,vc,false)
{
is_busy=true;
break;
}
}
}
}
is_busy
}).collect();
let port_last_transmission:Option<Vec<Time>> = if self.virtual_channel_policies.iter().any(|policy|policy.need_port_last_transmission())
{
Some(self.transmission_port_status.iter().map(|ref p|
p.get_last_transmission()
).collect())
}
else
{
None
};
let port_average_neighbour_queue_length:Option<Vec<f32>> = if self.virtual_channel_policies.iter().any(|policy|policy.need_port_average_queue_length())
{
Some(self.transmission_port_status.iter().map(|ref p|{
let total=(0..amount_virtual_channels).map(|vc|{
let available = p.known_available_space_for_virtual_channel(vc).expect("needs to know available space");
if available>self.buffer_size
{
0
}
else
{
self.buffer_size - available
}
}).sum::<usize>();
(total as f32) / (amount_virtual_channels as f32)
}).collect())
}
else
{
None
};
let port_occupied_output_space:Option<Vec<usize>> =
{
Some(self.output_buffers.iter().map(|p|
p.iter().map(|b|b.len()).sum()
).collect())
};
let port_available_output_space:Option<Vec<usize>> =
{
Some(self.output_buffers.iter().map(|p|
p.iter().map(|b|self.output_buffer_size - b.len()).sum()
).collect())
};
let virtual_channel_occupied_output_space:Option<Vec<Vec<usize>>> =
{
Some(self.output_buffers.iter().map(|p|
p.iter().map(|b|b.len()).collect()
).collect())
};
let virtual_channel_available_output_space:Option<Vec<Vec<usize>>> =
{
Some(self.output_buffers.iter().map(|p|
p.iter().map(|b|self.output_buffer_size-b.len()).collect()
).collect())
};
let mut undecided_channels=0; let mut moved_input_phits=0; for entry_port in 0..self.reception_port_space.len()
{
for phit in self.reception_port_space[entry_port].front_iter()
{
let entry_vc={
phit.virtual_channel.borrow().expect("it should have an associated virtual channel")
};
match self.selected_output[entry_port][entry_vc]
{
None =>
{
undecided_channels+=1;
let target_server=phit.packet.message.destination;
let (target_location,_link_class)=topology.server_neighbour(target_server);
let target_router=match target_location
{
Location::RouterPort{router_index,router_port:_} =>router_index,
_ => panic!("The server is not attached to a router"),
};
let routing_candidates=simulation.routing.next(phit.packet.routing_info.borrow().deref(),simulation.network.topology.as_ref(),self.router_index,target_router,Some(target_server),amount_virtual_channels,&mut mutable.rng).unwrap_or_else(|e|panic!("Error {} while routing.",e));
let routing_idempotent = routing_candidates.idempotent;
if routing_candidates.len()==0
{
if routing_idempotent
{
panic!("There are no choices for packet {:?} entry_port={} entry_vc={} in router {} towards server {}",phit.packet,entry_port,entry_vc,self.router_index,target_server);
}
continue;
}
let mut good_ports=routing_candidates.into_iter().filter_map(|candidate|{
let CandidateEgress{port:f_port,virtual_channel:f_virtual_channel,..} = candidate;
match self.selected_input[f_port][f_virtual_channel]
{
Some(_) => if self.neglect_busy_output {None} else {Some(CandidateEgress{router_allows:Some(false), ..candidate})},
None =>
{
let bubble_in_use= self.bubble && phit.is_begin() && simulation.network.topology.is_direction_change(self.router_index,entry_port,f_port);
let allowed = if self.can_phit_advance(&phit,f_port,f_virtual_channel,bubble_in_use)
{
if self.allow_request_busy_port
{
true
}
else
{
!busy_ports[f_port]
}
}
else
{
false
};
Some(CandidateEgress{router_allows:Some(allowed), ..candidate})
}
}
}).collect::<Vec<_>>();
let performed_hops=phit.packet.routing_info.borrow().hops;
let request_info=RequestInfo{
target_router_index: target_router,
entry_port,
entry_virtual_channel: entry_vc,
performed_hops,
server_ports: server_ports.as_ref(),
port_average_neighbour_queue_length: port_average_neighbour_queue_length.as_ref(),
port_last_transmission: port_last_transmission.as_ref(),
port_occupied_output_space: port_occupied_output_space.as_ref(),
port_available_output_space: port_available_output_space.as_ref(),
virtual_channel_occupied_output_space: virtual_channel_occupied_output_space.as_ref(),
virtual_channel_available_output_space: virtual_channel_available_output_space.as_ref(),
time_at_front: Some(self.time_at_input_head[entry_port][entry_vc]),
current_cycle: simulation.cycle,
phit: phit.clone(),
};
for vcp in self.virtual_channel_policies.iter()
{
good_ports=vcp.filter(good_ports,self,&request_info,topology,&mut mutable.rng);
if good_ports.len()==0
{
break; }
}
if good_ports.len()==0
{
continue; }
for candidate in good_ports
{
simulation.routing.performed_request(&candidate,&phit.packet.routing_info,simulation.network.topology.as_ref(),self.router_index,target_router,Some(target_server),amount_virtual_channels,&mut mutable.rng);
let CandidateEgress{port:requested_port,virtual_channel:requested_vc,label,..} = candidate;
request.push( VCARequest{entry_port,entry_vc,requested_port,requested_vc,label});
}
},
Some((_port,_vc)) => (), };
self.time_at_input_head[entry_port][entry_vc]+=1;
}
}
let captured_intransit_priority=self.intransit_priority;
if captured_intransit_priority {
if !self.crossbar_allocator.support_intransit_priority() {
panic!("Current crossbar allocator does not support intransit priority option");
}
request = request.into_iter().map(|mut req|{
if let (Location::RouterPort { .. },_) = simulation.network.topology.neighbour(self.router_index,req.entry_port)
{
req.label = 0;
}
req
}).collect();
}
request.iter_mut().for_each(|pr| {
self.crossbar_allocator.add_request(pr.to_allocator_request(amount_virtual_channels));
});
let mut requests_granted : Vec<VCARequest> = Vec::new();
for gr in self.crossbar_allocator.perform_allocation(&mut mutable.rng) {
requests_granted.push(gr.to_port_request(amount_virtual_channels));
}
let request_it = requests_granted.into_iter();
for VCARequest{entry_port,entry_vc,requested_port,requested_vc,..} in request_it
{
self.selected_input[requested_port][requested_vc]=Some((entry_port,entry_vc));
self.selected_output[entry_port][entry_vc]=Some((requested_port,requested_vc));
}
let mut events=vec![];
for exit_port in 0..self.transmission_port_status.len()
{
let nvc=amount_virtual_channels;
for exit_vc in 0..nvc
{
if let Some((entry_port,entry_vc))=self.selected_input[exit_port][exit_vc]
{
if let Ok((phit,ack_message)) = self.reception_port_space[entry_port].extract(entry_vc)
{
if self.output_buffers[exit_port][exit_vc].len()>=self.output_buffer_size
{
panic!("Trying to move into a full output buffer.");
}
moved_input_phits+=1;
self.time_at_input_head[entry_port][entry_vc]=0;
*phit.virtual_channel.borrow_mut()=Some(exit_vc);
if let Some(message)=ack_message
{
let (previous_location,previous_link_class)=simulation.network.topology.neighbour(self.router_index,entry_port);
let event = Event::Acknowledge{location:previous_location,message};
events.push(simulation.schedule_link_arrival( previous_link_class, event ));
}
if phit.is_end()
{
self.selected_input[exit_port][exit_vc]=None;
self.selected_output[entry_port][entry_vc]=None;
}
else
{
self.selected_output[entry_port][entry_vc]=Some((exit_port,exit_vc));
}
if self.crossbar_delay==0 {
self.output_buffers[exit_port][exit_vc].push(phit,(entry_port,entry_vc));
let mut output_scheduler = self.output_schedulers[exit_port].borrow_mut();
if let Some(event) = output_scheduler.schedule(simulation.cycle,0) {
events.push(event);
}
} else {
let event = Rc::<RefCell<internal::PhitToOutput>>::from(internal::PhitToOutputArgument{
router: self,
exit_port,
exit_vc,
entry_port,
entry_vc,
phit,
});
events.push(EventGeneration{
delay: self.crossbar_delay,
position:CyclePosition::Begin,
event: Event::Generic(event),
});
}
}
else
{
if self.flit_size>1
{
}
}
}
}
}
self.next_events.pop(); let recheck_crossbar = undecided_channels>0 || moved_input_phits>0 || request.len()>0; if recheck_crossbar {
let next_delay = event::round_to_multiple(simulation.cycle+1,self.crossbar_frequency_divisor) - simulation.cycle;
if let Some(event) = self.schedule(simulation.cycle,next_delay)
{
events.push(event);
}
}
events
}
fn as_eventful(&self)->Weak<RefCell<dyn Eventful>>
{
self.self_rc.clone()
}
fn schedule(&mut self, current_cycle:Time, delay:Time) -> Option<EventGeneration>
{
let target = current_cycle+delay;
let target = event::round_to_multiple(target,self.crossbar_frequency_divisor);
if self.next_events.is_empty() || target<*self.next_events.last().unwrap() {
self.next_events.push(target);
let event = Event::Generic(self.as_eventful().upgrade().expect("missing component"));
Some(EventGeneration{
delay: target-current_cycle,
position: CyclePosition::End,
event,
})
} else {
None
}
}
}
impl Quantifiable for InputOutput
{
fn total_memory(&self) -> usize
{
return size_of::<InputOutput>();
}
fn print_memory_breakdown(&self)
{
unimplemented!();
}
fn forecast_total_memory(&self) -> usize
{
unimplemented!();
}
}
mod internal
{
use super::*;
pub struct PhitToOutput
{
self_rc: Weak<RefCell<PhitToOutput>>,
router: Rc<RefCell<InputOutput>>,
exit_port: usize,
exit_vc: usize,
entry_port: usize,
entry_vc: usize,
phit: Rc<Phit>,
}
pub struct PhitToOutputArgument<'a>
{
pub router: &'a mut InputOutput,
pub exit_port: usize,
pub exit_vc: usize,
pub entry_port: usize,
pub entry_vc: usize,
pub phit: Rc<Phit>,
}
impl<'a> From<PhitToOutputArgument<'a>> for Rc<RefCell<PhitToOutput>>
{
fn from(arg:PhitToOutputArgument) -> Rc<RefCell<PhitToOutput>>
{
arg.router.output_buffer_phits_traversing_crossbar[arg.exit_port][arg.exit_vc]+=1;
let event = Rc::new(RefCell::new(PhitToOutput{
self_rc: Weak::new(),
router: arg.router.self_rc.upgrade().unwrap(),
exit_port: arg.exit_port,
exit_vc: arg.exit_vc,
entry_port: arg.entry_port,
entry_vc: arg.entry_vc,
phit: arg.phit,
}));
event.borrow_mut().self_rc=Rc::<_>::downgrade(&event);
event
}
}
impl Eventful for PhitToOutput
{
fn process(&mut self, simulation:&SimulationShared, _mutable:&mut SimulationMut) -> Vec<EventGeneration>
{
let mut router = self.router.borrow_mut();
if router.output_buffers[self.exit_port][self.exit_vc].len()>=router.output_buffer_size
{
panic!("(PhitToOutput) Trying to move into a full output buffer.");
}
router.output_buffer_phits_traversing_crossbar[self.exit_port][self.exit_vc]-=1;
router.output_buffers[self.exit_port][self.exit_vc].push(self.phit.clone(),(self.entry_port,self.entry_vc));
let mut output_scheduler = router.output_schedulers[self.exit_port].borrow_mut();
if let Some(event) = output_scheduler.schedule(simulation.cycle,0) {
vec![event]
} else {
vec![]
}
}
fn as_eventful(&self)->Weak<RefCell<dyn Eventful>>
{
self.self_rc.clone()
}
}
use crate::LinkClass;
pub struct TryLinkTraversal
{
self_rc: Weak<RefCell<TryLinkTraversal>>,
router: Rc<RefCell<InputOutput>>,
exit_port: usize,
link:LinkClass,
amount_virtual_channels: usize,
pending_event:bool,
}
pub struct TryLinkTraversalArgument<'a>
{
pub router: &'a mut InputOutput,
pub exit_port: usize,
pub link: LinkClass
}
impl<'a> From<TryLinkTraversalArgument<'a>> for Rc<RefCell<TryLinkTraversal>>
{
fn from(arg:TryLinkTraversalArgument) -> Rc<RefCell<TryLinkTraversal>>
{
let amount_virtual_channels = arg.router.num_virtual_channels();
let this = Rc::new(RefCell::new(TryLinkTraversal{
self_rc: Weak::new(),
router: arg.router.self_rc.upgrade().unwrap(),
exit_port: arg.exit_port,
link: arg.link,
amount_virtual_channels,
pending_event:false,
}));
this.borrow_mut().self_rc=Rc::<_>::downgrade(&this);
this
}
}
impl Eventful for TryLinkTraversal
{
fn process(&mut self, simulation:&SimulationShared, mutable:&mut SimulationMut) -> Vec<EventGeneration>
{
let mut events=vec![];
let mut router = self.router.borrow_mut();
let nvc= self.amount_virtual_channels;
let mut cand=Vec::with_capacity(nvc);
let mut cand_in_transit=false;
for exit_vc in 0..nvc
{
if let Some( (phit,(entry_port,_entry_vc))) = router.output_buffers[self.exit_port][exit_vc].front()
{
let bubble_in_use= router.bubble && phit.is_begin() && simulation.network.topology.is_direction_change(router.router_index,entry_port,self.exit_port);
let status=&router.transmission_port_status[self.exit_port];
let can_transmit = if bubble_in_use
{
if let Some(space)=status.known_available_space_for_virtual_channel(exit_vc)
{
status.can_transmit(&phit,exit_vc) && space>= phit.packet.size + router.maximum_packet_size
}
else
{
panic!("InputOutput router requires knowledge of available space to apply bubble.");
}
}
else
{
status.can_transmit(&phit,exit_vc)
};
if can_transmit
{
if cand_in_transit
{
if !phit.is_begin()
{
cand.push(exit_vc);
}
}
else
{
if phit.is_begin()
{
cand.push(exit_vc);
}
else
{
cand=vec![exit_vc];
cand_in_transit=true;
}
}
}
else
{
if 0<phit.index && phit.index<router.flit_size
{
panic!("cannot transmit phit (index={}) but it should (flit_size={})",phit.index,router.flit_size);
}
}
}
}
if !cand.is_empty()
{
let selected_virtual_channel = match router.output_arbiter
{
OutputArbiter::Random=> cand[mutable.rng.gen_range(0..cand.len())],
OutputArbiter::Token{ref mut port_token}=>
{
let nvc= self.amount_virtual_channels as i64;
let token= port_token[self.exit_port] as i64;
let mut best=0;
let mut bestd=nvc;
for vc in cand
{
let mut d:i64 = vc as i64 - token;
if d<0
{
d+=nvc;
}
if d<bestd
{
best=vc;
bestd=d;
}
}
port_token[self.exit_port]=best;
best
},
};
let (phit,original_port) =
{
let (phit,(entry_port,_entry_vc))=router.output_buffers[self.exit_port][selected_virtual_channel].pop().expect("incorrect selected_input");
(phit,entry_port)
};
let (new_location,_link_class)=simulation.network.topology.neighbour(router.router_index,self.exit_port);
events.push(EventGeneration{
delay: self.link.delay,
position:CyclePosition::Begin,
event:Event::PhitToLocation{
phit: phit.clone(),
previous: Location::RouterPort{
router_index: router.router_index,
router_port: original_port,
},
new: new_location,
},
});
router.transmission_port_status[self.exit_port].notify_outcoming_phit(selected_virtual_channel,simulation.cycle);
if phit.is_end()
{
if let OutputArbiter::Token{ref mut port_token}=router.output_arbiter
{
port_token[self.exit_port]=(port_token[self.exit_port]+1)% self.amount_virtual_channels;
}
}
}
drop(router); self.pending_event = false;
if !events.is_empty()
{
if let Some(event) = self.schedule(simulation.cycle,1)
{
events.push(event);
}
}
events
}
fn as_eventful(&self)->Weak<RefCell<dyn Eventful>>
{
self.self_rc.clone()
}
fn schedule(&mut self, current_cycle:Time, delay:Time) -> Option<EventGeneration>
{
if !self.pending_event {
self.pending_event=true;
let event = Event::Generic(self.as_eventful().upgrade().expect("missing component"));
let target = current_cycle+delay;
let target = event::round_to_multiple(target,self.link.frequency_divisor);
let delay = target - current_cycle;
Some(EventGeneration{
delay,
position: CyclePosition::End,
event,
})
} else {
None
}
}
}
}