pub mod basic;
pub mod input_output;
use std::rc::{Rc};
use std::cell::RefCell;
use std::collections::VecDeque;
use std::mem::{size_of};
use std::collections::{BTreeMap};
use ::rand::{Rng,rngs::StdRng};
use quantifiable_derive::Quantifiable;
use crate::{Phit,Packet,Plugs,error,source_location};
use self::basic::Basic;
use self::input_output::InputOutput;
use crate::config_parser::ConfigurationValue;
use crate::topology::{Topology};
use crate::event::{Eventful,Time,EventGeneration};
use crate::quantify::Quantifiable;
use crate::error::{Error,SourceLocation};
pub mod prelude
{
pub use super::{Router,StatusAtEmissor,SpaceAtReceptor,AcknowledgeMessage,Buffer,RouterBuilderArgument,TransmissionFromOblivious,TransmissionMechanism};
pub use crate::quantify::Quantifiable;
pub use crate::event::{Eventful,EventGeneration,Event,Time};
pub use crate::{SimulationShared,SimulationMut};
pub use crate::topology::Topology;
pub use crate::config_parser::ConfigurationValue;
pub use crate::packet::{Phit,Packet};
pub use crate::router;
}
pub trait Router: Eventful + Quantifiable
{
fn insert(&mut self, current_cycle:Time, phit:Rc<Phit>, port:usize, rng: &mut StdRng) -> Vec<EventGeneration>;
fn acknowledge(&mut self, current_cycle:Time, port:usize, ack_message:AcknowledgeMessage) -> Vec<EventGeneration>;
fn num_virtual_channels(&self) -> usize;
fn virtual_port_size(&self, port:usize, virtual_channel:usize) -> usize;
fn iter_phits(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>;
fn get_status_at_emisor(&self, port:usize) -> Option<&dyn StatusAtEmissor>;
fn get_maximum_credits_towards(&self, port:usize, virtual_channel:usize) -> Option<usize>;
fn get_index(&self)->Option<usize>;
fn aggregate_statistics(&self, statistics:Option<ConfigurationValue>, router_index:usize, total_routers:usize, cycle:Time) -> Option<ConfigurationValue>;
fn reset_statistics(&mut self,next_cycle:Time);
fn build_emissor_status(&self, port:usize, topology:&dyn Topology) -> Box<dyn StatusAtEmissor+'static>;
}
#[non_exhaustive]
pub struct RouterBuilderArgument<'a>
{
pub router_index: usize,
pub cv: &'a ConfigurationValue,
pub plugs: &'a Plugs,
pub topology: &'a dyn Topology,
pub maximum_packet_size: usize,
pub general_frequency_divisor: Time,
pub statistics_temporal_step: Time,
pub rng: &'a mut StdRng,
}
pub fn new_router(arg:RouterBuilderArgument) -> Rc<RefCell<dyn Router>>
{
if let &ConfigurationValue::Object(ref cv_name, ref _cv_pairs)=arg.cv
{
if let Some(builder) = arg.plugs.routers.get(cv_name)
{
return builder(arg);
}
match cv_name.as_ref()
{
"Basic" => Basic::new(arg),
"InputOutput" | "InputOutputMonocycle" => InputOutput::new(arg),
_ => panic!("Unknown router {}",cv_name),
}
}
else
{
panic!("Trying to create a Router from a non-Object");
}
}
pub struct Buffer
{
pub phits: VecDeque<Rc<Phit>>,
}
impl Buffer
{
#[allow(dead_code)]
pub fn new() -> Buffer
{
Buffer{ phits: VecDeque::new() }
}
pub fn push(&mut self, phit:Rc<Phit>)
{
self.phits.push_back(phit);
}
pub fn pop(&mut self) -> Option<Rc<Phit>>
{
self.phits.pop_front()
}
pub fn front(&self) -> Option<Rc<Phit>>
{
self.phits.front().cloned()
}
pub fn len(&self) -> usize
{
self.phits.len()
}
pub fn iter_phits(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
Box::new(self.phits.iter().cloned().collect::<Vec<_>>().into_iter())
}
}
impl Quantifiable for Buffer
{
fn total_memory(&self) -> usize
{
return size_of::<Buffer>() + (self.phits.capacity()+1)*size_of::<Rc<Phit>>();
}
fn print_memory_breakdown(&self)
{
unimplemented!();
}
fn forecast_total_memory(&self) -> usize
{
unimplemented!();
}
}
struct AugmentedBuffer<ExtraInfo>
{
phits: VecDeque<(Rc<Phit>,ExtraInfo)>,
}
impl<ExtraInfo> AugmentedBuffer<ExtraInfo>
{
fn new() -> AugmentedBuffer<ExtraInfo>
{
AugmentedBuffer{ phits: VecDeque::new() }
}
fn push(&mut self, phit:Rc<Phit>, extra: ExtraInfo)
{
self.phits.push_back((phit,extra));
}
fn pop(&mut self) -> Option<(Rc<Phit>,ExtraInfo)>
{
self.phits.pop_front()
}
fn front(&self) -> Option<(Rc<Phit>,ExtraInfo)> where ExtraInfo:Clone
{
self.phits.front().cloned()
}
fn len(&self) -> usize
{
self.phits.len()
}
#[allow(dead_code)]
fn iter_phits(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
Box::new(self.phits.iter().map(|p|p.0.clone()).collect::<Vec<_>>().into_iter())
}
}
impl<ExtraInfo> Quantifiable for AugmentedBuffer<ExtraInfo>
{
fn total_memory(&self) -> usize
{
return size_of::<AugmentedBuffer<ExtraInfo>>() + (self.phits.capacity()+1)*size_of::<(Rc<Phit>,ExtraInfo)>();
}
fn print_memory_breakdown(&self)
{
unimplemented!();
}
fn forecast_total_memory(&self) -> usize
{
unimplemented!();
}
}
pub trait StatusAtEmissor : Quantifiable
{
fn num_virtual_channels(&self)->usize;
fn acknowledge(&mut self, message:AcknowledgeMessage);
fn notify_outcoming_phit(&mut self, virtual_channel: usize, cycle:Time);
fn can_transmit(&self, phit:&Rc<Phit>, virtual_channel:usize)->bool;
fn can_transmit_whole_packet(&self, phit:&Rc<Phit>, virtual_channel:usize)->bool;
fn known_available_space_for_virtual_channel(&self,virtual_channel:usize)->Option<usize>;
fn get_last_transmission(&self)->Time;
}
pub trait SpaceAtReceptor
{
fn insert(&mut self, phit:Rc<Phit>, rng: &mut StdRng) -> Result<(),Error>;
fn front_iter(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>;
fn front_virtual_channel(&self,virtual_channel:usize) -> Option<Rc<Phit>>;
fn extract(&mut self, virtual_channel:usize) -> Result<(Rc<Phit>,Option<AcknowledgeMessage>),Error>;
fn iter_phits(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>;
fn available_dedicated_space(&self, virtual_channel:usize) -> Option<usize>;
fn occupied_dedicated_space(&self, virtual_channel:usize) -> Option<usize>;
}
#[derive(Clone,Debug)]
pub struct AcknowledgeMessage
{
virtual_channel: Option<usize>,
set_available_size: Option<usize>,
}
impl AcknowledgeMessage
{
pub fn ack_empty()->AcknowledgeMessage
{
AcknowledgeMessage{
virtual_channel: None,
set_available_size: None,
}
}
pub fn ack_phit_clear_from_virtual_channel(virtual_channel:usize)->AcknowledgeMessage
{
AcknowledgeMessage{
virtual_channel: Some(virtual_channel),
set_available_size: None,
}
}
pub fn ack_fix_available_size(amount:usize)->AcknowledgeMessage
{
AcknowledgeMessage{
virtual_channel: None,
set_available_size: Some(amount),
}
}
}
pub trait TransmissionMechanism
{
type StatusAtEmissor: StatusAtEmissor;
type SpaceAtReceptor: SpaceAtReceptor;
fn new_status_at_emissor(&self)-> Self::StatusAtEmissor;
fn new_space_at_receptor(&self)-> Self::SpaceAtReceptor;
}
pub trait AbstractTransmissionMechanism
{
fn new_status_at_emissor(&self)-> Box<dyn StatusAtEmissor>;
fn new_space_at_receptor(&self)-> Box<dyn SpaceAtReceptor>;
}
impl<E:StatusAtEmissor+'static,R:SpaceAtReceptor+'static,T:TransmissionMechanism<StatusAtEmissor=E,SpaceAtReceptor=R>> AbstractTransmissionMechanism for T
{
fn new_status_at_emissor(&self)-> Box<dyn StatusAtEmissor>
{
Box::new(self.new_status_at_emissor())
}
fn new_space_at_receptor(&self)-> Box<dyn SpaceAtReceptor>
{
Box::new(self.new_space_at_receptor())
}
}
#[derive(Debug)]
pub struct TransmissionMechanismBuilderArgument<'a>
{
name: &'a str,
virtual_channels: usize,
buffer_size: usize,
size_to_send: usize,
}
pub fn new_transmission_mechanism(arg:TransmissionMechanismBuilderArgument) -> Box<dyn AbstractTransmissionMechanism>
{
match arg.name
{
"SimpleVirtualChannels" => Box::new(SimpleVirtualChannels::new(arg.virtual_channels, arg.buffer_size, arg.size_to_send)),
"TransmissionToServer" => Box::new(TransmissionToServer() ),
"TransmissionFromOblivious" => Box::new(TransmissionFromOblivious::new(arg.virtual_channels, arg.buffer_size, arg.size_to_send)),
x => panic!("Unknown transission mechanism {}",x),
}
}
#[derive(Quantifiable)]
struct CreditCounterVector
{
pub neighbour_credits: Vec<usize>,
last_transmission:Time,
flit_size: usize,
}
impl StatusAtEmissor for CreditCounterVector
{
fn num_virtual_channels(&self)->usize
{
self.neighbour_credits.len()
}
fn acknowledge(&mut self, message:AcknowledgeMessage)
{
self.neighbour_credits[message.virtual_channel.expect("there is no virtual channel in the message")]+=1;
}
fn notify_outcoming_phit(&mut self, virtual_channel: usize, cycle:Time)
{
self.neighbour_credits[virtual_channel]-=1;
self.last_transmission=cycle;
}
fn can_transmit(&self, phit:&Rc<Phit>, virtual_channel:usize)->bool
{
let mut necessary_credits=1;
if phit.is_begin()
{
necessary_credits=self.flit_size;
}
self.neighbour_credits[virtual_channel]>=necessary_credits
}
fn can_transmit_whole_packet(&self, phit:&Rc<Phit>, virtual_channel:usize)->bool
{
let necessary_credits=phit.packet.size - phit.index;
self.neighbour_credits[virtual_channel]>=necessary_credits
}
fn known_available_space_for_virtual_channel(&self,virtual_channel:usize)->Option<usize>
{
Some(self.neighbour_credits[virtual_channel])
}
fn get_last_transmission(&self)->Time
{
self.last_transmission
}
}
pub struct ParallelBuffers
{
buffers: Vec<Buffer>,
input_virtual_channel_choices: BTreeMap<*const Packet,usize>,
}
impl SpaceAtReceptor for ParallelBuffers
{
fn insert(&mut self, phit:Rc<Phit>, rng: &mut StdRng) -> Result<(),Error>
{
let current_vc=*phit.virtual_channel.borrow();
let vc=match current_vc
{
None =>
{
let packet=phit.packet.clone();
let packet_ptr=packet.as_ref() as *const Packet;
let vc={
if phit.is_begin()
{
let r=rng.gen_range(0..self.buffers.len()); self.input_virtual_channel_choices.insert(packet_ptr,r);
r
}
else
{
match self.input_virtual_channel_choices.get(&packet_ptr)
{
Some ( x ) => *x,
None =>
{
panic!("Cannot assign a virtual channel if it is not the first phit.\n\tphit index={}\n\tpacket size={}\n\tpacket index={}\n\trouting info hops={}\n",phit.index,packet.size,packet.index,packet.routing_info.borrow().hops);
}
}
}
};
if phit.is_end()
{
self.input_virtual_channel_choices.remove(&packet_ptr);
}
*phit.virtual_channel.borrow_mut()=Some(vc);
vc
}
Some(vc) => vc,
};
self.buffers[vc].push(phit);
Ok(())
}
fn front_iter(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
Box::new(self.buffers.iter().filter_map(|b|b.front()).collect::<Vec<_>>().into_iter())
}
fn front_virtual_channel(&self,virtual_channel:usize) -> Option<Rc<Phit>>
{
self.buffers[virtual_channel].front()
}
fn extract(&mut self, virtual_channel:usize) -> Result<(Rc<Phit>,Option<AcknowledgeMessage>),Error>
{
match self.buffers[virtual_channel].pop()
{
Some(phit) =>
{
let message=AcknowledgeMessage::ack_phit_clear_from_virtual_channel(virtual_channel);
Ok((phit,Some(message)))
},
_ => Err(error!(undetermined)),
}
}
fn iter_phits(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
Box::new(self.buffers.iter().flat_map(|buffer|buffer.iter_phits()).collect::<Vec<_>>().into_iter())
}
fn available_dedicated_space(&self, _virtual_channel:usize) -> Option<usize>
{
None
}
fn occupied_dedicated_space(&self, virtual_channel:usize) -> Option<usize>
{
Some(self.buffers[virtual_channel].len())
}
}
struct SimpleVirtualChannels
{
virtual_channels: usize,
buffer_size: usize,
flit_size: usize,
}
impl SimpleVirtualChannels
{
fn new(virtual_channels: usize, buffer_size: usize, flit_size:usize) -> SimpleVirtualChannels
{
SimpleVirtualChannels{virtual_channels, buffer_size, flit_size}
}
}
impl TransmissionMechanism for SimpleVirtualChannels
{
type StatusAtEmissor = CreditCounterVector;
type SpaceAtReceptor = ParallelBuffers;
fn new_status_at_emissor(&self)-> CreditCounterVector
{
CreditCounterVector{
neighbour_credits: vec![self.buffer_size;self.virtual_channels],
last_transmission: 0,
flit_size: self.flit_size,
}
}
fn new_space_at_receptor(&self)-> ParallelBuffers
{
ParallelBuffers{
buffers: (0..self.virtual_channels).map(|_|Buffer{phits: VecDeque::new()}).collect(),
input_virtual_channel_choices: BTreeMap::new(),
}
}
}
#[derive(Quantifiable)]
struct EmptyStatus();
struct NoSpace();
impl StatusAtEmissor for EmptyStatus
{
fn num_virtual_channels(&self)->usize
{
1
}
fn acknowledge(&mut self, _message:AcknowledgeMessage)
{
}
fn notify_outcoming_phit(&mut self, _virtual_channel: usize, _cycle:Time)
{
}
fn can_transmit(&self, _phit:&Rc<Phit>, _virtual_channel:usize)->bool
{
true
}
fn can_transmit_whole_packet(&self, _phit:&Rc<Phit>, _virtual_channel:usize)->bool
{
true
}
fn known_available_space_for_virtual_channel(&self,_virtual_channel:usize)->Option<usize>
{
Some(1000)
}
fn get_last_transmission(&self)->Time
{
0
}
}
impl SpaceAtReceptor for NoSpace
{
fn insert(&mut self, _phit:Rc<Phit>, _rng: &mut StdRng) -> Result<(),Error>
{
unimplemented!()
}
fn front_iter(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
unimplemented!()
}
fn front_virtual_channel(&self,_virtual_channel:usize) -> Option<Rc<Phit>>
{
unimplemented!()
}
fn extract(&mut self, _virtual_channel:usize) -> Result<(Rc<Phit>,Option<AcknowledgeMessage>),Error>
{
unimplemented!()
}
fn iter_phits(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
unimplemented!()
}
fn available_dedicated_space(&self, _virtual_channel:usize) -> Option<usize>
{
Some(0)
}
fn occupied_dedicated_space(&self, _virtual_channel:usize) -> Option<usize>
{
Some(0)
}
}
struct TransmissionToServer();
impl TransmissionMechanism for TransmissionToServer
{
type StatusAtEmissor = EmptyStatus;
type SpaceAtReceptor = NoSpace;
fn new_status_at_emissor(&self)-> EmptyStatus
{
EmptyStatus()
}
fn new_space_at_receptor(&self)-> NoSpace
{
NoSpace()
}
}
#[derive(Clone,Quantifiable)]
pub struct StatusAtServer
{
available_size: usize,
size_to_send: usize,
}
impl StatusAtEmissor for StatusAtServer
{
fn num_virtual_channels(&self)->usize
{
1
}
fn acknowledge(&mut self, message:AcknowledgeMessage)
{
let new_available_size=message.set_available_size.expect("there is no set_avilable_size in the message");
self.available_size = self.available_size.max(new_available_size);
}
fn notify_outcoming_phit(&mut self, _virtual_channel: usize, _cycle:Time)
{
self.available_size-=1;
}
fn can_transmit(&self, phit:&Rc<Phit>, _virtual_channel:usize)->bool
{
if phit.is_begin()
{
self.available_size>=self.size_to_send
}
else
{
true
}
}
fn can_transmit_whole_packet(&self, _phit:&Rc<Phit>, _virtual_channel:usize)->bool
{
false
}
fn known_available_space_for_virtual_channel(&self,_virtual_channel:usize)->Option<usize>
{
Some(self.available_size)
}
fn get_last_transmission(&self)->Time
{
unimplemented!()
}
}
pub struct TransmissionFromOblivious
{
buffer_amount: usize,
buffer_size: usize,
size_to_send: usize,
}
impl TransmissionFromOblivious
{
pub fn new(buffer_amount:usize, buffer_size:usize, size_to_send:usize) -> TransmissionFromOblivious
{
TransmissionFromOblivious{
buffer_amount,
buffer_size,
size_to_send,
}
}
}
pub struct AgnosticParallelBuffers
{
buffers: Vec<Buffer>,
buffer_size: usize,
currently_selected: usize,
}
impl SpaceAtReceptor for AgnosticParallelBuffers
{
fn insert(&mut self, phit:Rc<Phit>, rng: &mut StdRng) -> Result<(),Error>
{
if phit.is_begin()
{
let good:Vec<usize>=self.buffers.iter().enumerate().filter_map(|(index,buffer)|{
let available = self.buffer_size - buffer.len();
if available >= phit.packet.size
{
Some(index)
}
else
{
None
}
}).collect();
if good.is_empty()
{
panic!("There is no space for the packet. packet.size={} available={:?}",phit.packet.size,self.buffers.iter().map(|buffer|self.buffer_size-buffer.len()).collect::<Vec<usize>>());
}
let r=rng.gen_range(0..good.len());
self.currently_selected=good[r]
}
let index = self.currently_selected;
*phit.virtual_channel.borrow_mut()=Some(index);
self.buffers[index].push(phit);
Ok(())
}
fn front_iter(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
Box::new(self.buffers.iter().filter_map(|b|b.front()).collect::<Vec<_>>().into_iter())
}
fn front_virtual_channel(&self,virtual_channel:usize) -> Option<Rc<Phit>>
{
self.buffers[virtual_channel].front()
}
fn extract(&mut self, virtual_channel:usize) -> Result<(Rc<Phit>,Option<AcknowledgeMessage>),Error>
{
match self.buffers[virtual_channel].pop()
{
Some(phit) =>
{
let available_size = self.buffers.iter().map(|b|self.buffer_size - b.len()).max().expect("no buffers");
let available_size = if available_size>=1
{
available_size.saturating_sub(2)
}
else
{
0
};
let message=AcknowledgeMessage::ack_fix_available_size(available_size);
Ok((phit,Some(message)))
},
_ => Err(error!(undetermined)),
}
}
fn iter_phits(&self) -> Box<dyn Iterator<Item=Rc<Phit>>>
{
Box::new(self.buffers.iter().flat_map(|buffer|buffer.iter_phits()).collect::<Vec<_>>().into_iter())
}
fn available_dedicated_space(&self, virtual_channel:usize) -> Option<usize>
{
Some(self.buffer_size - self.buffers[virtual_channel].len())
}
fn occupied_dedicated_space(&self, virtual_channel:usize) -> Option<usize>
{
Some(self.buffers[virtual_channel].len())
}
}
impl TransmissionMechanism for TransmissionFromOblivious
{
type StatusAtEmissor = StatusAtServer;
type SpaceAtReceptor = AgnosticParallelBuffers;
fn new_status_at_emissor(&self)-> StatusAtServer
{
StatusAtServer{
available_size: self.buffer_size,
size_to_send: self.size_to_send,
}
}
fn new_space_at_receptor(&self)-> AgnosticParallelBuffers
{
AgnosticParallelBuffers{
buffers: (0..self.buffer_amount).map(|_|Buffer{phits: VecDeque::new()}).collect(),
buffer_size: self.buffer_size,
currently_selected:0,
}
}
}