summaryrefslogtreecommitdiff
path: root/src/intersim2/networks/anynet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/intersim2/networks/anynet.cpp')
-rw-r--r--src/intersim2/networks/anynet.cpp501
1 files changed, 501 insertions, 0 deletions
diff --git a/src/intersim2/networks/anynet.cpp b/src/intersim2/networks/anynet.cpp
new file mode 100644
index 0000000..4db1dfb
--- /dev/null
+++ b/src/intersim2/networks/anynet.cpp
@@ -0,0 +1,501 @@
+// $Id: anynet.cpp 5354 2012-11-07 23:51:49Z qtedq $
+
+/*
+ Copyright (c) 2007-2012, Trustees of The Leland Stanford Junior University
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*anynet
+ *
+ *Network setup file format
+ *example 1:
+ *router 0 router 1 15 router 2
+ *
+ *Router 0 is connect to router 1 with a 15-cycle channel, and router 0 is connected to
+ * router 2 with a 1-cycle channel, the channels latency are unidirectional, so channel
+ * from router 1 back to router 0 is only single-cycle because it was not specified
+ *
+ *example 2:
+ *router 0 node 0 node 1 5 node 2 5
+ *
+ *Router 0 is directly connected to node 0-2. Channel latency is 5cycles for 1 and 2. In
+ * this case the latency specification is bidirectional, the injeciton and ejection lat
+ * for node 1 and 2 are 5-cycle
+ *
+ *other notes:
+ *
+ *Router and node numbers must be sequential starting with 0
+ *Credit channel latency follows the channel latency, even though it travels in revse
+ * direction this might not be desired
+ *
+ */
+
+#include "anynet.hpp"
+#include <fstream>
+#include <sstream>
+#include <limits>
+#include <algorithm>
+//this is a hack, I can't easily get the routing talbe out of the network
+map<int, int>* global_routing_table;
+
+AnyNet::AnyNet( const Configuration &config, const string & name )
+ : Network( config, name ){
+
+ router_list.resize(2);
+ _ComputeSize( config );
+ _Alloc( );
+ _BuildNet( config );
+}
+
+AnyNet::~AnyNet(){
+ for(int i = 0; i < 2; ++i) {
+ for(map<int, map<int, pair<int,int> > >::iterator iter = router_list[i].begin();
+ iter != router_list[i].end();
+ ++iter) {
+ iter->second.clear();
+ }
+ }
+}
+
+void AnyNet::_ComputeSize( const Configuration &config ){
+ file_name = config.GetStr("network_file");
+ if(file_name==""){
+ cout<<"No network file name provided"<<endl;
+ exit(-1);
+ }
+ //parse the network description file
+ readFile();
+
+ _channels =0;
+ cout<<"========================Network File Parsed=================\n";
+ cout<<"******************node listing**********************\n";
+ map<int, int >::iterator iter;
+ for(iter = node_list.begin(); iter!=node_list.end(); iter++){
+ cout<<"Node "<<iter->first;
+ cout<<"\tRouter "<<iter->second<<endl;
+ }
+
+ map<int, map<int, pair<int,int> > >::iterator iter3;
+ cout<<"\n****************router to node listing*************\n";
+ for(iter3 = router_list[0].begin(); iter3!=router_list[0].end(); iter3++){
+ cout<<"Router "<<iter3->first<<endl;
+ map<int, pair<int,int> >::iterator iter2;
+ for(iter2 = iter3->second.begin();
+ iter2!=iter3->second.end();
+ iter2++){
+ cout<<"\t Node "<<iter2->first<<" lat "<<iter2->second.second<<endl;
+ }
+ }
+
+ cout<<"\n*****************router to router listing************\n";
+ for(iter3 = router_list[1].begin(); iter3!=router_list[1].end(); iter3++){
+ cout<<"Router "<<iter3->first<<endl;
+ map<int, pair<int,int> >::iterator iter2;
+ if(iter3->second.size() == 0){
+ cout<<"Caution Router "<<iter3->first
+ <<" is not connected to any other Router\n"<<endl;
+ }
+ for(iter2 = iter3->second.begin();
+ iter2!=iter3->second.end();
+ iter2++){
+ cout<<"\t Router "<<iter2->first<<" lat "<<iter2->second.second<<endl;
+ _channels++;
+ }
+ }
+
+ _size = router_list[1].size();
+ _nodes = node_list.size();
+
+}
+
+
+
+void AnyNet::_BuildNet( const Configuration &config ){
+
+
+ //I need to keep track the output ports for each router during build
+ int * outport = (int*)malloc(sizeof(int)*_size);
+ for(int i = 0; i<_size; i++){outport[i] = 0;}
+
+ cout<<"==========================Node to Router =====================\n";
+ //adding the injection/ejection chanenls first
+ map<int, map<int, pair<int,int> > >::iterator niter;
+ for(niter = router_list[0].begin(); niter!=router_list[0].end(); niter++){
+ map<int, map<int, pair<int,int> > >::iterator riter = router_list[1].find(niter->first);
+ //calculate radix
+ int radix = niter->second.size()+riter->second.size();
+ int node = niter->first;
+ cout<<"router "<<node<<" radix "<<radix<<endl;
+ //decalre the routers
+ ostringstream router_name;
+ router_name << "router";
+ router_name << "_" << node ;
+ _routers[node] = Router::NewRouter( config, this, router_name.str( ),
+ node, radix, radix );
+ _timed_modules.push_back(_routers[node]);
+ //add injeciton ejection channels
+ map<int, pair<int,int> >::iterator nniter;
+ for(nniter = niter->second.begin();nniter!=niter->second.end(); nniter++){
+ int link = nniter->first;
+ //add the outport port assined to the map
+ (niter->second)[link].first = outport[node];
+ outport[node]++;
+ cout<<"\t connected to node "<<link<<" at outport "<<nniter->second.first
+ <<" lat "<<nniter->second.second<<endl;
+ _inject[link]->SetLatency(nniter->second.second);
+ _inject_cred[link]->SetLatency(nniter->second.second);
+ _eject[link]->SetLatency(nniter->second.second);
+ _eject_cred[link]->SetLatency(nniter->second.second);
+
+ _routers[node]->AddInputChannel( _inject[link], _inject_cred[link] );
+ _routers[node]->AddOutputChannel( _eject[link], _eject_cred[link] );
+ }
+
+ }
+
+ cout<<"==========================Router to Router =====================\n";
+ //add inter router channels
+ //since there is no way to systematically number the channels we just start from 0
+ //the map, is a mapping of output->input
+ int channel_count = 0;
+ for(niter = router_list[0].begin(); niter!=router_list[0].end(); niter++){
+ map<int, map<int, pair<int,int> > >::iterator riter = router_list[1].find(niter->first);
+ int node = niter->first;
+ map<int, pair<int,int> >::iterator rriter;
+ cout<<"router "<<node<<endl;
+ for(rriter = riter->second.begin();rriter!=riter->second.end(); rriter++){
+ int other_node = rriter->first;
+ int link = channel_count;
+ //add the outport port assined to the map
+ (riter->second)[other_node].first = outport[node];
+ outport[node]++;
+ cout<<"\t connected to router "<<other_node<<" using link "<<link
+ <<" at outport "<<rriter->second.first
+ <<" lat "<<rriter->second.second<<endl;
+
+ _chan[link]->SetLatency(rriter->second.second);
+ _chan_cred[link]->SetLatency(rriter->second.second);
+
+ _routers[node]->AddOutputChannel( _chan[link], _chan_cred[link] );
+ _routers[other_node]->AddInputChannel( _chan[link], _chan_cred[link]);
+ channel_count++;
+ }
+ }
+
+ buildRoutingTable();
+
+}
+
+
+void AnyNet::RegisterRoutingFunctions() {
+ gRoutingFunctionMap["min_anynet"] = &min_anynet;
+}
+
+void min_anynet( const Router *r, const Flit *f, int in_channel,
+ OutputSet *outputs, bool inject ){
+ int out_port=-1;
+ if(!inject){
+ assert(global_routing_table[r->GetID()].count(f->dest)!=0);
+ out_port=global_routing_table[r->GetID()][f->dest];
+ }
+
+
+ int vcBegin = 0, vcEnd = gNumVCs-1;
+ if ( f->type == Flit::READ_REQUEST ) {
+ vcBegin = gReadReqBeginVC;
+ vcEnd = gReadReqEndVC;
+ } else if ( f->type == Flit::WRITE_REQUEST ) {
+ vcBegin = gWriteReqBeginVC;
+ vcEnd = gWriteReqEndVC;
+ } else if ( f->type == Flit::READ_REPLY ) {
+ vcBegin = gReadReplyBeginVC;
+ vcEnd = gReadReplyEndVC;
+ } else if ( f->type == Flit::WRITE_REPLY ) {
+ vcBegin = gWriteReplyBeginVC;
+ vcEnd = gWriteReplyEndVC;
+ }
+
+ outputs->Clear( );
+
+ outputs->AddRange( out_port , vcBegin, vcEnd );
+}
+
+void AnyNet::buildRoutingTable(){
+ cout<<"========================== Routing table =====================\n";
+ routing_table.resize(_size);
+ for(int i = 0; i<_size; i++){
+ route(i);
+ }
+ global_routing_table = &routing_table[0];
+}
+
+
+//11/7/2012
+//basically djistra's, tested on a large dragonfly anynet configuration
+void AnyNet::route(int r_start){
+ int* dist = new int[_size];
+ int* prev = new int[_size];
+ set<int> rlist;
+ for(int i = 0; i<_size; i++){
+ dist[i] = numeric_limits<int>::max();
+ prev[i] = -1;
+ rlist.insert(i);
+ }
+ dist[r_start] = 0;
+ while(!rlist.empty()){
+ //find min
+ int min_dist = numeric_limits<int>::max();
+ int min_cand = -1;
+ for(set<int>::iterator i = rlist.begin();
+ i!=rlist.end();
+ i++){
+ if(dist[*i]<min_dist){
+ min_dist = dist[*i];
+ min_cand = *i;
+ }
+ }
+ rlist.erase(min_cand);
+
+ //neighbor
+ for(map<int,pair<int,int> >::iterator i = router_list[1][min_cand].begin();
+ i!=router_list[1][min_cand].end();
+ i++){
+ int new_dist = dist[min_cand] + i->second.second;//distance is hops not cycles
+ if(new_dist < dist[i->first]){
+ dist[i->first] = new_dist;
+ prev[i->first] = min_cand;
+ }
+ }
+ }
+
+ //post process from the prev list
+ for(int i = 0; i<_size; i++){
+ if(prev[i] ==-1){ //self
+ assert(i == r_start);
+ for(map<int, pair<int, int> >::iterator iter = router_list[0][i].begin();
+ iter!=router_list[0][i].end();
+ iter++){
+ routing_table[r_start][iter->first]=iter->second.first;
+ //cout<<"node "<<iter->first<<" port "<< iter->second.first<<endl;
+ }
+ } else {
+ int distance=0;
+ int neighbor=i;
+ while(prev[neighbor]!=r_start){
+ assert(router_list[1][neighbor].count(prev[neighbor])>0);
+ distance+=router_list[1][prev[neighbor]][neighbor].second;//REVERSE lat
+ neighbor= prev[neighbor];
+ }
+ distance+=router_list[1][prev[neighbor]][neighbor].second;//lat
+
+ assert( router_list[1][r_start].count(neighbor)!=0);
+ int port = router_list[1][r_start][neighbor].first;
+ for(map<int, pair<int,int> >::iterator iter = router_list[0][i].begin();
+ iter!=router_list[0][i].end();
+ iter++){
+ routing_table[r_start][iter->first]=port;
+ //cout<<"node "<<iter->first<<" port "<< port<<" dist "<<distance<<endl;
+ }
+ }
+ }
+}
+
+
+void AnyNet::readFile(){
+
+ ifstream network_list;
+ string line;
+ enum ParseState{HEAD_TYPE=0,
+ HEAD_ID,
+ BODY_TYPE,
+ BODY_ID,
+ LINK_WEIGHT};
+ enum ParseType{NODE=0,
+ ROUTER,
+ UNKNOWN};
+
+ network_list.open(file_name.c_str());
+ if(!network_list.is_open()){
+ cout<<"Anynet:can't open network file "<<file_name<<endl;
+ exit(-1);
+ }
+
+ //loop through the entire file
+ while(!network_list.eof()){
+ getline(network_list,line);
+ if(line==""){
+ continue;
+ }
+
+ ParseState state=HEAD_TYPE;
+ //position to parse out white sspace
+ int pos = 0;
+ int next_pos=-1;
+ string temp;
+ //the first node and its type
+ int head_id = -1;
+ ParseType head_type = UNKNOWN;
+ //stuff that head are linked to
+ ParseType body_type = UNKNOWN;
+ int body_id = -1;
+ int link_weight = 1;
+
+ do{
+
+ //skip empty spaces
+ next_pos = line.find(" ",pos);
+ temp = line.substr(pos,next_pos-pos);
+ pos = next_pos+1;
+ if(temp=="" || temp==" "){
+ continue;
+ }
+
+ switch(state){
+ case HEAD_TYPE:
+ if(temp=="router"){
+ head_type = ROUTER;
+ } else if (temp == "node"){
+ head_type = NODE;
+ } else {
+ cout<<"Anynet:Unknow head of line type "<<temp<<"\n";
+ assert(false);
+ }
+ state=HEAD_ID;
+ break;
+ case HEAD_ID:
+ //need better error check
+ head_id = atoi(temp.c_str());
+
+ //intialize router structures
+ if(router_list[NODE].count(head_id) == 0){
+ router_list[NODE][head_id] = map<int, pair<int,int> >();
+ }
+ if(router_list[ROUTER].count(head_id) == 0){
+ router_list[ROUTER][head_id] = map<int, pair<int,int> >();
+ }
+
+ state=BODY_TYPE;
+ break;
+ case LINK_WEIGHT:
+ if(temp=="router"||
+ temp == "node"){
+ //ignore
+ } else {
+ link_weight= atoi(temp.c_str());
+ router_list[head_type][head_id][body_id].second=link_weight;
+ break;
+ }
+ //intentionally letting it flow through
+ case BODY_TYPE:
+ if(temp=="router"){
+ body_type = ROUTER;
+ } else if (temp == "node"){
+ body_type = NODE;
+ } else {
+ cout<<"Anynet:Unknow body type "<<temp<<"\n";
+ assert(false);
+ }
+ state=BODY_ID;
+ break;
+ case BODY_ID:
+ body_id = atoi(temp.c_str());
+ //intialize router structures if necessary
+ if(body_type==ROUTER){
+ if(router_list[NODE].count(body_id) ==0){
+ router_list[NODE][body_id] = map<int, pair<int,int> >();
+ }
+ if(router_list[ROUTER].count(body_id) == 0){
+ router_list[ROUTER][body_id] = map<int, pair<int,int> >();
+ }
+ }
+
+ if(head_type==NODE && body_type==NODE){
+
+ cout<<"Anynet:Cannot connect node to node "<<temp<<"\n";
+ assert(false);
+
+ } else if(head_type==NODE && body_type==ROUTER){
+
+ if(node_list.count(head_id)!=0 &&
+ node_list[head_id]!=body_id){
+ cout<<"Anynet:Node "<<body_id<<" trying to connect to multiple router "
+ <<body_id<<" and "<<node_list[head_id]<<endl;
+ assert(false);
+ }
+ node_list[head_id]=body_id;
+ router_list[NODE][body_id][head_id]=pair<int, int>(-1,1);
+
+ } else if(head_type==ROUTER && body_type==NODE){
+ //insert and check node
+ if(node_list.count(body_id) != 0 &&
+ node_list[body_id]!=head_id){
+ cout<<"Anynet:Node "<<body_id<<" trying to connect to multiple router "
+ <<body_id<<" and "<<node_list[head_id]<<endl;
+ assert(false);
+ }
+ node_list[body_id] = head_id;
+ router_list[NODE][head_id][body_id]=pair<int, int>(-1,1);
+
+ } else if(head_type==ROUTER && body_type==ROUTER){
+ router_list[ROUTER][head_id][body_id]=pair<int, int>(-1,1);
+ if(router_list[ROUTER][body_id].count(head_id)==0){
+ router_list[ROUTER][body_id][head_id]=pair<int, int>(-1,1);
+ }
+ }
+ state=LINK_WEIGHT;
+ break ;
+ default:
+ cout<<"Anynet:Unknow parse state\n";
+ assert(false);
+ break;
+ }
+
+ } while(pos!=0);
+ if(state!=LINK_WEIGHT &&
+ state!=BODY_TYPE){
+ cout<<"Anynet:Incomplete parse of the line: "<<line<<endl;
+ }
+
+ }
+
+ //map verification, make sure the information contained in bother maps
+ //are the same
+ assert(router_list[0].size() == router_list[1].size());
+
+ //traffic generator assumes node list is sequenctial and starts at 0
+ vector<int> node_check;
+ for(map<int,int>::iterator i = node_list.begin();
+ i!=node_list.end();
+ i++){
+ node_check.push_back(i->first);
+ }
+ sort(node_check.begin(), node_check.end());
+ for(size_t i = 0; i<node_check.size(); i++){
+ if(node_check[i] != i){
+ cout<<"Anynet:booksim trafficmanager assumes sequential node numbering starting at 0\n";
+ assert(false);
+ }
+ }
+
+}
+