// $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 #include #include #include //this is a hack, I can't easily get the routing talbe out of the network map* 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 > >::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"<::iterator iter; for(iter = node_list.begin(); iter!=node_list.end(); iter++){ cout<<"Node "<first; cout<<"\tRouter "<second< > >::iterator iter3; cout<<"\n****************router to node listing*************\n"; for(iter3 = router_list[0].begin(); iter3!=router_list[0].end(); iter3++){ cout<<"Router "<first< >::iterator iter2; for(iter2 = iter3->second.begin(); iter2!=iter3->second.end(); iter2++){ cout<<"\t Node "<first<<" lat "<second.second<first< >::iterator iter2; if(iter3->second.size() == 0){ cout<<"Caution Router "<first <<" is not connected to any other Router\n"<second.begin(); iter2!=iter3->second.end(); iter2++){ cout<<"\t Router "<first<<" lat "<second.second< > >::iterator niter; for(niter = router_list[0].begin(); niter!=router_list[0].end(); niter++){ map > >::iterator riter = router_list[1].find(niter->first); //calculate radix int radix = niter->second.size()+riter->second.size(); int node = niter->first; cout<<"router "< >::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 "<second.first <<" lat "<second.second<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 > >::iterator riter = router_list[1].find(niter->first); int node = niter->first; map >::iterator rriter; cout<<"router "<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 "<second.first <<" lat "<second.second<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 rlist; for(int i = 0; i<_size; i++){ dist[i] = numeric_limits::max(); prev[i] = -1; rlist.insert(i); } dist[r_start] = 0; while(!rlist.empty()){ //find min int min_dist = numeric_limits::max(); int min_cand = -1; for(set::iterator i = rlist.begin(); i!=rlist.end(); i++){ if(dist[*i] >::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 >::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 "<first<<" port "<< iter->second.first<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 >::iterator iter = router_list[0][i].begin(); iter!=router_list[0][i].end(); iter++){ routing_table[r_start][iter->first]=port; //cout<<"node "<first<<" port "<< port<<" dist "< >(); } if(router_list[ROUTER].count(head_id) == 0){ router_list[ROUTER][head_id] = map >(); } 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 "< >(); } if(router_list[ROUTER].count(body_id) == 0){ router_list[ROUTER][body_id] = map >(); } } if(head_type==NODE && body_type==NODE){ cout<<"Anynet:Cannot connect node to node "<(-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 "<(-1,1); } else if(head_type==ROUTER && body_type==ROUTER){ router_list[ROUTER][head_id][body_id]=pair(-1,1); if(router_list[ROUTER][body_id].count(head_id)==0){ router_list[ROUTER][body_id][head_id]=pair(-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: "< node_check; for(map::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