pub use quantifiable_derive::Quantifiable;
pub mod config_parser;
pub mod topology;
pub mod traffic;
pub mod pattern;
pub mod router;
pub mod routing;
pub mod event;
pub mod matrix;
mod output;
pub mod quantify;
pub mod policies;
pub mod experiments;
pub mod config;
use std::rc::Rc;
use std::boxed::Box;
use std::cell::{RefCell};
use std::env;
use std::fs::{File};
use std::io::prelude::*;
use std::io::{stdout};
use std::collections::{VecDeque,BTreeMap};
use std::ops::DerefMut;
use std::path::{Path};
use std::mem::{size_of};
use std::fmt::Debug;
use rand::{StdRng,SeedableRng};
use config_parser::{ConfigurationValue};
use topology::{Topology,new_topology,TopologyBuilderArgument,Location,
multistage::{Stage,StageBuilderArgument}};
use traffic::{Traffic,new_traffic,TrafficBuilderArgument,TrafficError};
use router::{Router,new_router,RouterBuilderArgument,TransmissionFromServer,TransmissionMechanism,StatusAtEmissor};
use routing::{RoutingInfo,Routing,new_routing,RoutingBuilderArgument};
use event::{EventQueue,Event};
use quantify::Quantifiable;
use experiments::{Experiment,Action,ExperimentOptions};
use policies::{VirtualChannelPolicy,VCPolicyBuilderArgument};
use pattern::{Pattern,PatternBuilderArgument};
use config::flatten_configuration_value;
#[derive(Clone,Quantifiable)]
struct ServerStatistics
{
created_phits: usize,
consumed_phits: usize,
consumed_messages: usize,
total_message_delay: usize,
}
impl ServerStatistics
{
fn new()->ServerStatistics
{
ServerStatistics{
created_phits:0,
consumed_phits:0,
consumed_messages:0,
total_message_delay:0,
}
}
fn reset(&mut self)
{
self.created_phits=0;
self.consumed_phits=0;
self.consumed_messages=0;
self.total_message_delay=0;
}
}
#[derive(Clone,Quantifiable)]
pub struct Server
{
index: usize,
port: (Location,usize),
router_status: router::StatusAtServer,
stored_messages: VecDeque<Rc<Message>>,
stored_packets: VecDeque<Rc<Packet>>,
stored_phits: VecDeque<Rc<Phit>>,
consumed_phits: BTreeMap<*const Message,usize>,
statistics: ServerStatistics,
}
impl Server
{
fn consume(&mut self, phit:Rc<Phit>, traffic:&mut dyn Traffic, statistics:&mut Statistics, cycle:usize, topology:&Box<dyn Topology>, rng: &RefCell<StdRng>)
{
self.statistics.consumed_phits+=1;
statistics.consumed_phits+=1;
let message=phit.packet.message.clone();
let message_ptr=message.as_ref() as *const Message;
let cp=match self.consumed_phits.get(&message_ptr)
{
None => 1,
Some(x) => x+1,
};
if cp==message.size
{
self.statistics.consumed_messages+=1;
statistics.consumed_messages+=1;
self.statistics.total_message_delay+=cycle-message.creation_cycle;
statistics.total_message_delay+=cycle-message.creation_cycle;
self.consumed_phits.remove(&message_ptr);
if !traffic.try_consume(message,cycle,topology,rng)
{
panic!("The traffic could not consume its own message.");
}
if !phit.is_end()
{
panic!("message was consumed by a non-ending phit.");
}
}
else
{
self.consumed_phits.insert(message_ptr,cp);
}
if phit.is_end()
{
statistics.consumed_packets+=1;
let hops=phit.packet.routing_info.borrow().hops;
statistics.total_packet_hops+=hops;
if statistics.total_packet_per_hop_count.len() <= hops
{
statistics.total_packet_per_hop_count.resize( hops+1, 0 );
}
statistics.total_packet_per_hop_count[hops]+=1;
if cp < phit.packet.size
{
println!("phit tail has been consuming without haing consumed a whole packet.");
}
}
}
}
pub struct Network
{
pub topology: Box<dyn Topology>,
pub routers: Vec<Rc<RefCell<dyn Router>>>,
pub servers: Vec<Server>,
}
impl Quantifiable for Network
{
fn total_memory(&self) -> usize
{
let mut total=size_of::<Box<dyn Topology>>() + self.topology.total_memory() + self.routers.total_memory() + self.servers.total_memory();
for router in self.routers.iter()
{
total+=router.as_ref().total_memory();
let rb=router.borrow();
for phit in rb.iter_phits()
{
total+=phit.as_ref().total_memory();
if phit.is_end()
{
let packet=phit.packet.as_ref();
total+=packet.total_memory();
}
}
}
for server in self.servers.iter()
{
for phit in server.stored_phits.iter()
{
total+=phit.as_ref().total_memory();
}
for packet in server.stored_packets.iter()
{
total+=packet.as_ref().total_memory();
}
for message in server.stored_messages.iter()
{
total+=message.as_ref().total_memory();
}
for (_message_ptr,_) in server.consumed_phits.iter()
{
total+=size_of::<Message>();
}
}
total
}
fn print_memory_breakdown(&self)
{
unimplemented!();
}
fn forecast_total_memory(&self) -> usize
{
unimplemented!();
}
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Phit
{
pub packet: Rc<Packet>,
pub index: usize,
pub virtual_channel: RefCell<Option<usize>>,
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Packet
{
pub size: usize,
pub routing_info: RefCell<RoutingInfo>,
pub message: Rc<Message>,
pub index: usize,
}
#[derive(Quantifiable)]
#[derive(Debug)]
pub struct Message
{
pub origin: usize,
pub destination: usize,
pub size: usize,
pub creation_cycle: usize,
}
impl Phit
{
pub fn is_begin(&self) -> bool
{
self.index==0
}
pub fn is_end(&self) -> bool
{
self.index==self.packet.size-1
}
}
pub struct LinkClass
{
pub delay: usize,
}
impl LinkClass
{
fn new(cv:&ConfigurationValue) -> LinkClass
{
let mut delay=None;
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=cv
{
if cv_name!="LinkClass"
{
panic!("A LinkClass must be created from a `LinkClass` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match name.as_ref()
{
"delay" => match value
{
&ConfigurationValue::Number(f) => delay=Some(f as usize),
_ => panic!("bad value for delay"),
},
"transference_speed" => (), _ => panic!("Nothing to do with field {} in LinkClass",name),
}
}
}
else
{
panic!("Trying to create a LinkClass from a non-Object");
}
let delay=delay.expect("There were no delay");
LinkClass{
delay,
}
}
}
#[derive(Debug)]
struct LinkStatistics
{
phit_arrivals: usize,
}
impl LinkStatistics
{
fn new() -> LinkStatistics
{
LinkStatistics{
phit_arrivals: 0,
}
}
fn reset(&mut self)
{
self.phit_arrivals=0;
}
}
#[derive(Debug)]
pub struct Statistics
{
begin_cycle: usize,
created_phits: usize,
consumed_phits: usize,
consumed_packets: usize,
consumed_messages: usize,
total_message_delay: usize,
total_packet_hops: usize,
total_packet_per_hop_count: Vec<usize>,
link_statistics: Vec<Vec<LinkStatistics>>,
columns: Vec<ReportColumn>,
}
impl Statistics
{
fn new(topology: &dyn Topology)->Statistics
{
Statistics{
begin_cycle:0,
created_phits:0,
consumed_phits:0,
consumed_packets:0,
consumed_messages:0,
total_message_delay:0,
total_packet_hops:0,
total_packet_per_hop_count:Vec::new(),
link_statistics: (0..topology.num_routers()).map(|i| (0..topology.ports(i)).map(|_|LinkStatistics::new()).collect() ).collect(),
columns: vec![
ReportColumnKind::BeginEndCycle.into(),
ReportColumnKind::InjectedLoad.into(),
ReportColumnKind::AcceptedLoad.into(),
ReportColumnKind::AveragePacketHops.into(),
ReportColumnKind::AverageLinkUtilization.into(),
ReportColumnKind::AverageMessageDelay.into(),
ReportColumnKind::ServerConsumptionJainIndex.into(),
],
}
}
fn jain_server_created_phits(&self, network:&Network) -> f64
{
let mut count=0.0;
let mut count2=0.0;
for server in network.servers.iter()
{
let x=server.statistics.created_phits as f64;
count+=x;
count2+=x*x;
}
count*count/count2/network.servers.len() as f64
}
fn jain_server_consumed_phits(&self, network:&Network) -> f64
{
let mut count=0.0;
let mut count2=0.0;
for server in network.servers.iter()
{
let x=server.statistics.consumed_phits as f64;
count+=x;
count2+=x*x;
}
count*count/count2/network.servers.len() as f64
}
fn print_header(&self)
{
let report:String = self.columns.iter().map(|c|c.header()).collect();
println!("{}",report);
}
fn print(&self, next_cycle:usize, network:&Network)
{
let report:String = self.columns.iter().map(|c|c.format(self,next_cycle,network)).collect();
println!("{}",report);
}
fn reset(&mut self,next_cycle:usize, network:&mut Network)
{
self.begin_cycle=next_cycle;
self.created_phits=0;
self.consumed_phits=0;
self.consumed_packets=0;
self.consumed_messages=0;
self.total_message_delay=0;
self.total_packet_hops=0;
self.total_packet_per_hop_count=Vec::new();
for server in network.servers.iter_mut()
{
server.statistics.reset();
}
for router in network.routers.iter()
{
router.borrow_mut().reset_statistics(next_cycle);
}
for router_links in self.link_statistics.iter_mut()
{
for link in router_links.iter_mut()
{
link.reset();
}
}
}
}
#[derive(Debug)]
#[allow(dead_code)]
enum ReportColumnKind
{
BeginEndCycle,
InjectedLoad,
AcceptedLoad,
ServerGenerationJainIndex,
ServerConsumptionJainIndex,
AverageMessageDelay,
AveragePacketHops,
AverageLinkUtilization,
MaximumLinkUtilization,
}
impl ReportColumnKind
{
fn name(&self) -> &str
{
match self
{
ReportColumnKind::BeginEndCycle => "cycle_begin-cycle_end",
ReportColumnKind::InjectedLoad => "injected_load",
ReportColumnKind::AcceptedLoad => "accepted_load",
ReportColumnKind::ServerGenerationJainIndex => "server_generation_jain_index",
ReportColumnKind::ServerConsumptionJainIndex => "server_consumption_jain_index",
ReportColumnKind::AverageMessageDelay => "average_message_delay",
ReportColumnKind::AveragePacketHops => "average_packet_hops",
ReportColumnKind::AverageLinkUtilization => "average_link_utilization",
ReportColumnKind::MaximumLinkUtilization => "maximum_link_utilization",
}
}
}
#[derive(Debug)]
struct ReportColumn
{
kind: ReportColumnKind,
width: usize,
}
impl ReportColumn
{
fn header(&self) -> String
{
let base = self.kind.name();
format!("{name:width$}",name=base,width=self.width)
}
fn format(&self, statistics: &Statistics, next_cycle:usize, network:&Network) -> String
{
let cycles=next_cycle-statistics.begin_cycle+1;
let value = match self.kind
{
ReportColumnKind::BeginEndCycle => format!("{:>11}-{}",statistics.begin_cycle,next_cycle-1),
ReportColumnKind::InjectedLoad => format!{"{}",statistics.created_phits as f32/cycles as f32/network.servers.len() as f32},
ReportColumnKind::AcceptedLoad => format!{"{}",statistics.consumed_phits as f32/cycles as f32/network.servers.len() as f32},
ReportColumnKind::ServerGenerationJainIndex => format!{"{}",statistics.jain_server_created_phits(network)},
ReportColumnKind::ServerConsumptionJainIndex => format!{"{}",statistics.jain_server_consumed_phits(network)},
ReportColumnKind::AverageMessageDelay => format!("{}",statistics.total_message_delay as f64/statistics.consumed_messages as f64),
ReportColumnKind::AveragePacketHops => format!("{}",statistics.total_packet_hops as f64 / statistics.consumed_packets as f64),
ReportColumnKind::AverageLinkUtilization =>
{
let total_arrivals:usize = (0..network.topology.num_routers()).map(|i|(0..network.topology.degree(i)).map(|j|statistics.link_statistics[i][j].phit_arrivals).sum::<usize>()).sum();
let total_links: usize = (0..network.topology.num_routers()).map(|i|network.topology.degree(i)).sum();
format!("{}",total_arrivals as f64 / cycles as f64 / total_links as f64)
},
ReportColumnKind::MaximumLinkUtilization =>
{
let maximum_arrivals:usize = statistics.link_statistics.iter().map(|rls|rls.iter().map(|ls|ls.phit_arrivals).max().unwrap()).max().unwrap();
format!("{}",maximum_arrivals as f64 / cycles as f64)
},
};
format!("{value:width$}",value=value,width=self.width)
}
}
impl From<ReportColumnKind> for ReportColumn
{
fn from(kind:ReportColumnKind) -> ReportColumn
{
let width = 1+kind.name().len();
ReportColumn{
kind,
width,
}
}
}
pub struct Simulation<'a>
{
#[allow(dead_code)]
pub configuration: ConfigurationValue,
#[allow(dead_code)]
pub seed: usize,
pub rng: RefCell<StdRng>,
pub warmup: usize,
pub measured: usize,
pub network: Network,
pub traffic: Box<dyn Traffic>,
pub maximum_packet_size: usize,
pub routing: Box<dyn Routing>,
pub link_classes: Vec<LinkClass>,
pub event_queue: EventQueue,
pub cycle:usize,
pub statistics: Statistics,
#[allow(dead_code)]
pub launch_configurations: Vec<ConfigurationValue>,
pub plugs: &'a Plugs,
}
impl<'a> Simulation<'a>
{
fn new(cv: &ConfigurationValue, plugs:&'a Plugs) -> Simulation<'a>
{
let mut seed: Option<usize> = None;
let mut topology =None;
let mut traffic =None;
let mut router_cfg: Option<&ConfigurationValue> =None;
let mut warmup = None;
let mut measured = None;
let mut maximum_packet_size=None;
let mut routing=None;
let mut link_classes = None;
let mut launch_configurations: Vec<ConfigurationValue> = vec![];
if let &ConfigurationValue::Object(ref cv_name, ref cv_pairs)=cv
{
if cv_name!="Configuration"
{
panic!("A simulation must be created from a `Configuration` object not `{}`",cv_name);
}
for &(ref name,ref value) in cv_pairs
{
match name.as_ref()
{
"random_seed" => match value
{
&ConfigurationValue::Number(f) => seed=Some(f as usize),
_ => panic!("bad value for random_seed"),
}
"warmup" => match value
{
&ConfigurationValue::Number(f) => warmup=Some(f as usize),
_ => panic!("bad value for warmup"),
}
"measured" => match value
{
&ConfigurationValue::Number(f) => measured=Some(f as usize),
_ => panic!("bad value for measured"),
}
"topology" => topology=Some(value),
"traffic" =>
{
traffic=Some(value);
},
"maximum_packet_size" => match value
{
&ConfigurationValue::Number(f) => maximum_packet_size=Some(f as usize),
_ => panic!("bad value for maximum_packet_size"),
}
"router" => router_cfg=Some(&value),
"routing" => routing=Some(new_routing(RoutingBuilderArgument{cv:value,plugs})),
"link_classes" => match value
{
&ConfigurationValue::Array(ref l) => link_classes=Some(l.iter().map(|v|LinkClass::new(v)).collect()),
_ => panic!("bad value for link_classes"),
}
"launch_configurations" => match value
{
&ConfigurationValue::Array(ref l) => launch_configurations=l.clone(),
_ => panic!("bad value for launch_configurations"),
}
"legend_name" => (),
_ => panic!("Nothing to do with field {} in Configuration",name),
}
}
}
else
{
panic!("Trying to create a simulation from a non-Object");
}
let seed=seed.expect("There were no random_seed");
let warmup=warmup.expect("There were no warmup");
let measured=measured.expect("There were no measured");
let topology=topology.expect("There were no topology");
let traffic=traffic.expect("There were no traffic");
let maximum_packet_size=maximum_packet_size.expect("There were no maximum_packet_size");
let router_cfg=router_cfg.expect("There were no router");
let mut routing=routing.expect("There were no routing");
let link_classes:Vec<LinkClass>=link_classes.expect("There were no link_classes");
let rng=RefCell::new(StdRng::from_seed(&[seed]));
let topology=new_topology(TopologyBuilderArgument{
cv:topology,
plugs,
rng:&rng,
});
topology.check_adjacency_consistency(Some(link_classes.len()));
routing.initialize(&topology,&rng);
let num_routers=topology.num_routers();
let num_servers=topology.num_servers();
let routers: Vec<Rc<RefCell<dyn Router>>>=(0..num_routers).map(|index|new_router(router::RouterBuilderArgument{
router_index:index,
cv:router_cfg,
plugs,
topology:topology.as_ref(),
maximum_packet_size
})).collect();
let servers=(0..num_servers).map(|index|{
let port=topology.server_neighbour(index);
let router_status=match port.0
{
Location::RouterPort{
router_index,
router_port
} => {
let router=routers[router_index].borrow();
let nvc=router.num_virtual_channels();
let buffer_amount=nvc;
let buffer_size=(0..nvc).map(|vc|router.virtual_port_size(router_port,vc)).sum::<usize>();
let size_to_send=maximum_packet_size;
let from_server_mechanism = TransmissionFromServer::new(buffer_amount,buffer_size,size_to_send);
from_server_mechanism.new_status_at_emissor()
}
_ => panic!("Server is not connected to router"),
};
Server{
index,
port,
router_status,
stored_messages:VecDeque::new(),
stored_packets:VecDeque::new(),
stored_phits:VecDeque::new(),
consumed_phits: BTreeMap::new(),
statistics: ServerStatistics::new(),
}
}).collect();
let traffic=new_traffic(TrafficBuilderArgument{
cv:traffic,
plugs,
topology:&topology,
rng:&rng,
});
let statistics=Statistics::new(topology.as_ref());
Simulation{
configuration: cv.clone(),
seed,
rng,
warmup,
measured,
network: Network{
topology,
routers,
servers,
},
traffic,
maximum_packet_size,
routing,
link_classes,
event_queue: EventQueue::new(1000),
cycle:0,
statistics,
launch_configurations,
plugs,
}
}
fn run(&mut self)
{
self.print_memory_breakdown();
self.statistics.print_header();
while self.cycle < self.warmup+self.measured
{
self.advance();
if self.cycle==self.warmup
{
self.statistics.reset(self.cycle,&mut self.network);
self.routing.reset_statistics(self.cycle);
}
if self.traffic.is_finished()
{
println!("Traffic consumed before cycle {}",self.cycle);
break;
}
}
}
fn advance(&mut self)
{
let mut ievent=0;
loop
{
let event=if let Some(event) = self.event_queue.access_begin(ievent)
{
event.clone()
}
else
{
break;
};
match event
{
Event::PhitToLocation{
ref phit,
ref previous,
ref new,
} =>
{
match new
{
&Location::RouterPort{router_index:router,router_port:port} =>
{
self.statistics.link_statistics[router][port].phit_arrivals+=1;
let mut brouter=self.network.routers[router].borrow_mut();
brouter.insert(phit.clone(),port,&self.rng);
if brouter.pending_events()==0
{
brouter.add_pending_event();
self.event_queue.enqueue_end(Event::Generic(brouter.as_eventful().upgrade().expect("missing router")),0);
}
match previous
{
&Location::ServerPort(_server_index) => if phit.is_begin()
{
self.routing.initialize_routing_info(&phit.packet.routing_info, self.network.topology.as_ref(), router, phit.packet.message.destination,&self.rng);
},
&Location::RouterPort{..} => if phit.is_begin()
{
phit.packet.routing_info.borrow_mut().hops+=1;
self.routing.update_routing_info(&phit.packet.routing_info, self.network.topology.as_ref(), router, port, phit.packet.message.destination,&self.rng);
},
_ => (),
};
},
&Location::ServerPort(server) =>
{
if server!=phit.packet.message.destination
{
panic!("Packet reached wrong server, {} instead of {}!\n",server,phit.packet.message.destination);
}
self.network.servers[server].consume(phit.clone(),self.traffic.deref_mut(),&mut self.statistics,self.cycle,&self.network.topology,&self.rng);
}
&Location::None => panic!("Phit went nowhere previous={:?}",previous),
};
},
Event::Acknowledge{
location,
message: ack_message,
} => match location
{
Location::RouterPort{
router_index,
router_port,
} =>
{
let mut brouter=self.network.routers[router_index].borrow_mut();
brouter.acknowledge(router_port,ack_message);
if brouter.pending_events()==0
{
brouter.add_pending_event();
self.event_queue.enqueue_end(Event::Generic(brouter.as_eventful().upgrade().expect("missing router")),0);
}
},
Location::ServerPort(server) => self.network.servers[server].router_status.acknowledge(ack_message),
_ => (),
},
Event::Generic(ref _element) => unimplemented!(),
};
ievent+=1;
}
ievent=0;
loop
{
let event=if let Some(event) = self.event_queue.access_end(ievent)
{
event.clone()
}
else
{
break;
};
match event
{
Event::PhitToLocation{
..
} => panic!("Phits should not arrive at the end of a cycle"),
Event::Acknowledge{
..
} => panic!("Phit Acknowledgements should not arrive at the end of a cycle"),
Event::Generic(ref element) =>
{
let new_events=element.borrow_mut().process(self);
for ge in new_events.into_iter()
{
self.event_queue.enqueue(ge);
}
},
};
ievent+=1;
}
let num_servers=self.network.servers.len();
for (iserver,server) in self.network.servers.iter_mut().enumerate()
{
if let (Location::RouterPort{router_index: index,router_port: port},link_class)=server.port
{
if server.stored_messages.len()<20 && self.traffic.should_generate(iserver,&self.rng)
{
match self.traffic.generate_message(iserver,self.cycle,&self.network.topology,&self.rng)
{
Ok(message) =>
{
if message.destination>=num_servers
{
panic!("Message sent to outside the network unexpectedly.");
}
if message.destination==iserver
{
panic!("Generated message to self unexpectedly.");
}
server.stored_messages.push_back(message);
},
Err(TrafficError::OriginOutsideTraffic) => (),
Err(TrafficError::SelfMessage) => (),
};
}
if server.stored_packets.len()==0 && server.stored_messages.len()>0
{
let message=server.stored_messages.pop_front().expect("There are not messages in queue");
let mut size=message.size;
while size>0
{
let ps=if size>self.maximum_packet_size
{
self.maximum_packet_size
}
else
{
size
};
server.stored_packets.push_back(Rc::new(Packet{
size:ps,
routing_info: RefCell::new(RoutingInfo::new()),
message:message.clone(),
index:0,
}));
size-=ps;
}
}
if server.stored_phits.len()==0 && server.stored_packets.len()>0
{
let packet=server.stored_packets.pop_front().expect("There are not packets in queue");
for index in 0..packet.size
{
server.stored_phits.push_back(Rc::new(Phit{
packet:packet.clone(),
index,
virtual_channel: RefCell::new(None),
}));
}
}
if server.stored_phits.len()>0
{
let phit=server.stored_phits.front().expect("There are not phits");
if server.router_status.can_transmit(&phit,0)
{
let phit=server.stored_phits.pop_front().expect("There are not phits");
let event=Event::PhitToLocation{
phit,
previous: Location::ServerPort(iserver),
new: Location::RouterPort{router_index:index,router_port:port},
};
self.statistics.created_phits+=1;
server.statistics.created_phits+=1;
self.event_queue.enqueue_begin(event,self.link_classes[link_class].delay);
server.router_status.notify_outcoming_phit(0,self.cycle);
}
}
}
else
{
panic!("Where goes this port?");
}
}
self.event_queue.advance();
self.cycle+=1;
if self.cycle%1000==0
{
self.statistics.print(self.cycle,&self.network);
}
}
fn write_result(&self,output:&mut dyn Write)
{
let cycles=self.cycle-self.statistics.begin_cycle;
let num_servers=self.network.servers.len();
let injected_load=self.statistics.created_phits as f64/cycles as f64/num_servers as f64;
let accepted_load=self.statistics.consumed_phits as f64/cycles as f64/num_servers as f64;
let average_message_delay=self.statistics.total_message_delay as f64/self.statistics.consumed_messages as f64;
let jscp=self.statistics.jain_server_consumed_phits(&self.network);
let jsgp=self.statistics.jain_server_created_phits(&self.network);
let average_packet_hops=self.statistics.total_packet_hops as f64 / self.statistics.consumed_packets as f64;
let total_packet_per_hop_count=self.statistics.total_packet_per_hop_count.iter().map(|&count|ConfigurationValue::Number(count as f64)).collect();
let total_arrivals:usize = (0..self.network.topology.num_routers()).map(|i|(0..self.network.topology.degree(i)).map(|j|self.statistics.link_statistics[i][j].phit_arrivals).sum::<usize>()).sum();
let total_links: usize = (0..self.network.topology.num_routers()).map(|i|self.network.topology.degree(i)).sum();
let average_link_utilization = total_arrivals as f64 / cycles as f64 / total_links as f64;
let maximum_arrivals:usize = self.statistics.link_statistics.iter().map(|rls|rls.iter().map(|ls|ls.phit_arrivals).max().unwrap()).max().unwrap();
let maximum_link_utilization = maximum_arrivals as f64 / cycles as f64;
let git_id=get_git_id();
let mut result_content = vec![
(String::from("cycle"),ConfigurationValue::Number(self.cycle as f64)),
(String::from("injected_load"),ConfigurationValue::Number(injected_load)),
(String::from("accepted_load"),ConfigurationValue::Number(accepted_load)),
(String::from("average_message_delay"),ConfigurationValue::Number(average_message_delay)),
(String::from("server_generation_jain_index"),ConfigurationValue::Number(jsgp)),
(String::from("server_consumption_jain_index"),ConfigurationValue::Number(jscp)),
(String::from("average_packet_hops"),ConfigurationValue::Number(average_packet_hops)),
(String::from("total_packet_per_hop_count"),ConfigurationValue::Array(total_packet_per_hop_count)),
(String::from("average_link_utilization"),ConfigurationValue::Number(average_link_utilization)),
(String::from("maximum_link_utilization"),ConfigurationValue::Number(maximum_link_utilization)),
(String::from("git_id"),ConfigurationValue::Literal(format!("{}",git_id))),
];
if let Some(content)=self.routing.statistics(self.cycle)
{
result_content.push((String::from("routing_statistics"),content));
}
if let Some(content) = self.network.routers.iter().enumerate().fold(None,|maybe_stat,(index,router)|router.borrow().aggregate_statistics(maybe_stat,index,self.network.routers.len(),self.cycle))
{
result_content.push((String::from("router_aggregated_statistics"),content));
}
if let Ok(linux_process) = procfs::process::Process::myself()
{
let status = linux_process.status().expect("failed to get status of the self process");
if let Some(peak_memory)=status.vmhwm
{
result_content.push((String::from("linux_high_water_mark"),ConfigurationValue::Number(peak_memory as f64)));
}
let stat = linux_process.stat().expect("failed to get stat of the self process");
let tps = procfs::ticks_per_second().expect("could not get the number of ticks per second.") as f64;
result_content.push((String::from("user_time"),ConfigurationValue::Number(stat.utime as f64/tps)));
result_content.push((String::from("system_time"),ConfigurationValue::Number(stat.stime as f64/tps)));
}
let result=ConfigurationValue::Object(String::from("Result"),result_content);
writeln!(output,"{}",result).unwrap();
}
}
impl<'a> Quantifiable for Simulation<'a>
{
fn total_memory(&self) -> usize
{
unimplemented!();
}
fn print_memory_breakdown(&self)
{
println!("\nBegin memory report");
println!("self : {}",size_of::<Self>());
println!("phit : {}",size_of::<Phit>());
println!("packet : {}",size_of::<Packet>());
println!("message : {}",size_of::<Message>());
println!("server : {}",size_of::<Server>());
println!("event : {}",size_of::<Event>());
println!("network total : {}",quantify::human_bytes(self.network.total_memory()));
println!("traffic total : {}",quantify::human_bytes(self.traffic.total_memory()));
println!("event_queue total : {}",quantify::human_bytes(self.event_queue.total_memory()));
println!("End memory report\n");
}
fn forecast_total_memory(&self) -> usize
{
unimplemented!();
}
}
#[derive(Default)]
pub struct Plugs
{
routers: BTreeMap<String, fn(RouterBuilderArgument) -> Rc<RefCell<dyn Router>> >,
topologies: BTreeMap<String, fn(TopologyBuilderArgument) -> Box<dyn Topology> >,
stages: BTreeMap<String, fn(StageBuilderArgument) -> Box<dyn Stage> >,
routings: BTreeMap<String,fn(RoutingBuilderArgument) -> Box<dyn Routing>>,
traffics: BTreeMap<String,fn(TrafficBuilderArgument) -> Box<dyn Traffic> >,
patterns: BTreeMap<String, fn(PatternBuilderArgument) -> Box<dyn Pattern> >,
policies: BTreeMap<String, fn(VCPolicyBuilderArgument) -> Box<dyn VirtualChannelPolicy> >,
}
impl Plugs
{
pub fn add_router(&mut self, key:String, builder:fn(RouterBuilderArgument) -> Rc<RefCell<dyn Router>>)
{
self.routers.insert(key,builder);
}
pub fn add_topology(&mut self, key:String, builder:fn(TopologyBuilderArgument) -> Box<dyn Topology>)
{
self.topologies.insert(key,builder);
}
pub fn add_stage(&mut self, key:String, builder:fn(StageBuilderArgument) -> Box<dyn Stage>)
{
self.stages.insert(key,builder);
}
pub fn add_traffic(&mut self, key:String, builder:fn(TrafficBuilderArgument) -> Box<dyn Traffic>)
{
self.traffics.insert(key,builder);
}
pub fn add_routing(&mut self, key:String, builder:fn(RoutingBuilderArgument) -> Box<dyn Routing>)
{
self.routings.insert(key,builder);
}
pub fn add_policy(&mut self, key:String, builder: fn(VCPolicyBuilderArgument) -> Box<dyn VirtualChannelPolicy>)
{
self.policies.insert(key,builder);
}
pub fn add_pattern(&mut self, key:String, builder: fn(PatternBuilderArgument) -> Box<dyn Pattern>)
{
self.patterns.insert(key,builder);
}
}
impl Debug for Plugs
{
fn fmt(&self,f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>
{
write!(f,"{};",self.routers.keys().map(|s|s.to_string()).collect::<Vec<String>>().join(","))?;
write!(f,"{};",self.topologies.keys().map(|s|s.to_string()).collect::<Vec<String>>().join(","))?;
write!(f,"{};",self.stages.keys().map(|s|s.to_string()).collect::<Vec<String>>().join(","))?;
write!(f,"{};",self.routings.keys().map(|s|s.to_string()).collect::<Vec<String>>().join(","))?;
write!(f,"{};",self.traffics.keys().map(|s|s.to_string()).collect::<Vec<String>>().join(","))?;
write!(f,"{};",self.patterns.keys().map(|s|s.to_string()).collect::<Vec<String>>().join(","))?;
write!(f,"{};",self.policies.keys().map(|s|s.to_string()).collect::<Vec<String>>().join(","))?;
Ok(())
}
}
pub fn file_main(file:&mut File, plugs:&Plugs, mut results_file:Option<File>)
{
let mut contents = String::new();
file.read_to_string(&mut contents).expect("something went wrong reading the file");
match config_parser::parse(&contents)
{
Err(x) => println!("error parsing configuration file: {:?}",x),
Ok(x) =>
{
println!("parsed correctly: {:?}",x);
match x
{
config_parser::Token::Value(ref value) =>
{
let flat=flatten_configuration_value(value);
if let ConfigurationValue::Experiments(ref experiments)=flat
{
for (i,experiment) in experiments.iter().enumerate()
{
println!("experiment {} of {} is {:?}",i,experiments.len(),experiment);
let mut simulation=Simulation::new(&experiment,plugs);
simulation.run();
match results_file
{
Some(ref mut f) => simulation.write_result(f),
None => simulation.write_result(&mut stdout()),
};
}
}
else
{
panic!("there are not experiments");
}
},
_ => panic!("Not a value"),
};
},
};
}
pub fn directory_main(path:&Path, binary:&str, plugs:&Plugs, action:Action, options: ExperimentOptions)
{
let binary_path=Path::new(binary);
let mut experiment=Experiment::new(binary_path,path,plugs,options);
experiment.execute_action(action);
}
pub fn get_git_id() -> &'static str
{
include_str!(concat!(env!("OUT_DIR"), "/generated_git_id"))
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}