Topology.cc revision 9109
1/* 2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <cassert> 30 31#include "debug/RubyNetwork.hh" 32#include "mem/protocol/MachineType.hh" 33#include "mem/protocol/TopologyType.hh" 34#include "mem/ruby/common/NetDest.hh" 35#include "mem/ruby/network/BasicLink.hh" 36#include "mem/ruby/network/BasicRouter.hh" 37#include "mem/ruby/network/Network.hh" 38#include "mem/ruby/network/Topology.hh" 39#include "mem/ruby/slicc_interface/AbstractController.hh" 40 41using namespace std; 42 43const int INFINITE_LATENCY = 10000; // Yes, this is a big hack 44 45class BasicRouter; 46 47// Note: In this file, we use the first 2*m_nodes SwitchIDs to 48// represent the input and output endpoint links. These really are 49// not 'switches', as they will not have a Switch object allocated for 50// them. The first m_nodes SwitchIDs are the links into the network, 51// the second m_nodes set of SwitchIDs represent the the output queues 52// of the network. 53 54// Helper functions based on chapter 29 of Cormen et al. 55void extend_shortest_path(Matrix& current_dist, Matrix& latencies, 56 Matrix& inter_switches); 57Matrix shortest_path(const Matrix& weights, Matrix& latencies, 58 Matrix& inter_switches); 59bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, 60 SwitchID final, const Matrix& weights, const Matrix& dist); 61NetDest shortest_path_to_node(SwitchID src, SwitchID next, 62 const Matrix& weights, const Matrix& dist); 63 64Topology::Topology(const Params *p) 65 : SimObject(p) 66{ 67 m_print_config = p->print_config; 68 m_number_of_switches = p->routers.size(); 69 70 // initialize component latencies record 71 m_component_latencies.resize(0); 72 m_component_inter_switches.resize(0); 73 74 // Total nodes/controllers in network 75 // Must make sure this is called after the State Machine constructors 76 m_nodes = MachineType_base_number(MachineType_NUM); 77 assert(m_nodes > 1); 78 79 if (m_nodes != params()->ext_links.size() && 80 m_nodes != params()->ext_links.size()) { 81 fatal("m_nodes (%d) != ext_links vector length (%d)\n", 82 m_nodes, params()->ext_links.size()); 83 } 84 85 // analyze both the internal and external links, create data structures 86 // Note that the python created links are bi-directional, but that the 87 // topology and networks utilize uni-directional links. Thus each 88 // BasicLink is converted to two calls to add link, on for each direction 89 for (vector<BasicExtLink*>::const_iterator i = params()->ext_links.begin(); 90 i != params()->ext_links.end(); ++i) { 91 BasicExtLink *ext_link = (*i); 92 AbstractController *abs_cntrl = ext_link->params()->ext_node; 93 BasicRouter *router = ext_link->params()->int_node; 94 95 // Store the controller and ExtLink pointers for later 96 m_controller_vector.push_back(abs_cntrl); 97 m_ext_link_vector.push_back(ext_link); 98 99 int ext_idx1 = abs_cntrl->params()->cntrl_id; 100 int ext_idx2 = ext_idx1 + m_nodes; 101 int int_idx = router->params()->router_id + 2*m_nodes; 102 103 // create the internal uni-directional links in both directions 104 // the first direction is marked: In 105 addLink(ext_idx1, int_idx, ext_link, LinkDirection_In); 106 // the first direction is marked: Out 107 addLink(int_idx, ext_idx2, ext_link, LinkDirection_Out); 108 } 109 110 for (vector<BasicIntLink*>::const_iterator i = params()->int_links.begin(); 111 i != params()->int_links.end(); ++i) { 112 BasicIntLink *int_link = (*i); 113 BasicRouter *router_a = int_link->params()->node_a; 114 BasicRouter *router_b = int_link->params()->node_b; 115 116 // Store the IntLink pointers for later 117 m_int_link_vector.push_back(int_link); 118 119 int a = router_a->params()->router_id + 2*m_nodes; 120 int b = router_b->params()->router_id + 2*m_nodes; 121 122 // create the internal uni-directional links in both directions 123 // the first direction is marked: In 124 addLink(a, b, int_link, LinkDirection_In); 125 // the second direction is marked: Out 126 addLink(b, a, int_link, LinkDirection_Out); 127 } 128} 129 130void 131Topology::init() 132{ 133} 134 135 136void 137Topology::initNetworkPtr(Network* net_ptr) 138{ 139 for (vector<BasicExtLink*>::const_iterator i = params()->ext_links.begin(); 140 i != params()->ext_links.end(); ++i) { 141 BasicExtLink *ext_link = (*i); 142 AbstractController *abs_cntrl = ext_link->params()->ext_node; 143 abs_cntrl->initNetworkPtr(net_ptr); 144 } 145} 146 147void 148Topology::createLinks(Network *net, bool isReconfiguration) 149{ 150 // Find maximum switchID 151 SwitchID max_switch_id = 0; 152 for (LinkMap::const_iterator i = m_link_map.begin(); 153 i != m_link_map.end(); ++i) { 154 std::pair<int, int> src_dest = (*i).first; 155 max_switch_id = max(max_switch_id, src_dest.first); 156 max_switch_id = max(max_switch_id, src_dest.second); 157 } 158 159 // Initialize weight, latency, and inter switched vectors 160 Matrix topology_weights; 161 int num_switches = max_switch_id+1; 162 topology_weights.resize(num_switches); 163 m_component_latencies.resize(num_switches); 164 m_component_inter_switches.resize(num_switches); 165 166 for (int i = 0; i < topology_weights.size(); i++) { 167 topology_weights[i].resize(num_switches); 168 m_component_latencies[i].resize(num_switches); 169 m_component_inter_switches[i].resize(num_switches); 170 171 for (int j = 0; j < topology_weights[i].size(); j++) { 172 topology_weights[i][j] = INFINITE_LATENCY; 173 174 // initialize to invalid values 175 m_component_latencies[i][j] = -1; 176 177 // initially assume direct connections / no intermediate 178 // switches between components 179 m_component_inter_switches[i][j] = 0; 180 } 181 } 182 183 // Set identity weights to zero 184 for (int i = 0; i < topology_weights.size(); i++) { 185 topology_weights[i][i] = 0; 186 } 187 188 // Fill in the topology weights and bandwidth multipliers 189 for (LinkMap::const_iterator i = m_link_map.begin(); 190 i != m_link_map.end(); ++i) { 191 std::pair<int, int> src_dest = (*i).first; 192 BasicLink* link = (*i).second.link; 193 int src = src_dest.first; 194 int dst = src_dest.second; 195 m_component_latencies[src][dst] = link->m_latency; 196 topology_weights[src][dst] = link->m_weight; 197 } 198 199 // Walk topology and hookup the links 200 Matrix dist = shortest_path(topology_weights, m_component_latencies, 201 m_component_inter_switches); 202 for (int i = 0; i < topology_weights.size(); i++) { 203 for (int j = 0; j < topology_weights[i].size(); j++) { 204 int weight = topology_weights[i][j]; 205 if (weight > 0 && weight != INFINITE_LATENCY) { 206 NetDest destination_set = shortest_path_to_node(i, j, 207 topology_weights, dist); 208 makeLink(net, i, j, destination_set, isReconfiguration); 209 } 210 } 211 } 212} 213 214void 215Topology::addLink(SwitchID src, SwitchID dest, BasicLink* link, 216 LinkDirection dir) 217{ 218 assert(src <= m_number_of_switches+m_nodes+m_nodes); 219 assert(dest <= m_number_of_switches+m_nodes+m_nodes); 220 221 std::pair<int, int> src_dest_pair; 222 LinkEntry link_entry; 223 224 src_dest_pair.first = src; 225 src_dest_pair.second = dest; 226 link_entry.direction = dir; 227 link_entry.link = link; 228 m_link_map[src_dest_pair] = link_entry; 229} 230 231void 232Topology::makeLink(Network *net, SwitchID src, SwitchID dest, 233 const NetDest& routing_table_entry, bool isReconfiguration) 234{ 235 // Make sure we're not trying to connect two end-point nodes 236 // directly together 237 assert(src >= 2 * m_nodes || dest >= 2 * m_nodes); 238 239 std::pair<int, int> src_dest; 240 LinkEntry link_entry; 241 242 if (src < m_nodes) { 243 src_dest.first = src; 244 src_dest.second = dest; 245 link_entry = m_link_map[src_dest]; 246 net->makeInLink(src, dest - (2 * m_nodes), link_entry.link, 247 link_entry.direction, 248 routing_table_entry, 249 isReconfiguration); 250 } else if (dest < 2*m_nodes) { 251 assert(dest >= m_nodes); 252 NodeID node = dest - m_nodes; 253 src_dest.first = src; 254 src_dest.second = dest; 255 link_entry = m_link_map[src_dest]; 256 net->makeOutLink(src - (2 * m_nodes), node, link_entry.link, 257 link_entry.direction, 258 routing_table_entry, 259 isReconfiguration); 260 } else { 261 assert((src >= 2 * m_nodes) && (dest >= 2 * m_nodes)); 262 src_dest.first = src; 263 src_dest.second = dest; 264 link_entry = m_link_map[src_dest]; 265 net->makeInternalLink(src - (2 * m_nodes), dest - (2 * m_nodes), 266 link_entry.link, link_entry.direction, 267 routing_table_entry, isReconfiguration); 268 } 269} 270 271void 272Topology::printStats(std::ostream& out) const 273{ 274 for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) { 275 m_controller_vector[cntrl]->printStats(out); 276 } 277} 278 279void 280Topology::clearStats() 281{ 282 for (int cntrl = 0; cntrl < m_controller_vector.size(); cntrl++) { 283 m_controller_vector[cntrl]->clearStats(); 284 } 285} 286 287void 288Topology::printConfig(std::ostream& out) const 289{ 290 if (m_print_config == false) 291 return; 292 293 assert(m_component_latencies.size() > 0); 294 295 out << "--- Begin Topology Print ---" << endl 296 << endl 297 << "Topology print ONLY indicates the _NETWORK_ latency between two " 298 << "machines" << endl 299 << "It does NOT include the latency within the machines" << endl 300 << endl; 301 302 for (int m = 0; m < MachineType_NUM; m++) { 303 int i_end = MachineType_base_count((MachineType)m); 304 for (int i = 0; i < i_end; i++) { 305 MachineID cur_mach = {(MachineType)m, i}; 306 out << cur_mach << " Network Latencies" << endl; 307 for (int n = 0; n < MachineType_NUM; n++) { 308 int j_end = MachineType_base_count((MachineType)n); 309 for (int j = 0; j < j_end; j++) { 310 MachineID dest_mach = {(MachineType)n, j}; 311 if (cur_mach == dest_mach) 312 continue; 313 314 int src = MachineType_base_number((MachineType)m) + i; 315 int dst = MachineType_base_number(MachineType_NUM) + 316 MachineType_base_number((MachineType)n) + j; 317 int link_latency = m_component_latencies[src][dst]; 318 int intermediate_switches = 319 m_component_inter_switches[src][dst]; 320 321 // NOTE switches are assumed to have single 322 // cycle latency 323 out << " " << cur_mach << " -> " << dest_mach 324 << " net_lat: " 325 << link_latency + intermediate_switches << endl; 326 } 327 } 328 out << endl; 329 } 330 } 331 332 out << "--- End Topology Print ---" << endl; 333} 334 335// The following all-pairs shortest path algorithm is based on the 336// discussion from Cormen et al., Chapter 26.1. 337void 338extend_shortest_path(Matrix& current_dist, Matrix& latencies, 339 Matrix& inter_switches) 340{ 341 bool change = true; 342 int nodes = current_dist.size(); 343 344 while (change) { 345 change = false; 346 for (int i = 0; i < nodes; i++) { 347 for (int j = 0; j < nodes; j++) { 348 int minimum = current_dist[i][j]; 349 int previous_minimum = minimum; 350 int intermediate_switch = -1; 351 for (int k = 0; k < nodes; k++) { 352 minimum = min(minimum, 353 current_dist[i][k] + current_dist[k][j]); 354 if (previous_minimum != minimum) { 355 intermediate_switch = k; 356 inter_switches[i][j] = 357 inter_switches[i][k] + 358 inter_switches[k][j] + 1; 359 } 360 previous_minimum = minimum; 361 } 362 if (current_dist[i][j] != minimum) { 363 change = true; 364 current_dist[i][j] = minimum; 365 assert(intermediate_switch >= 0); 366 assert(intermediate_switch < latencies[i].size()); 367 latencies[i][j] = latencies[i][intermediate_switch] + 368 latencies[intermediate_switch][j]; 369 } 370 } 371 } 372 } 373} 374 375Matrix 376shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches) 377{ 378 Matrix dist = weights; 379 extend_shortest_path(dist, latencies, inter_switches); 380 return dist; 381} 382 383bool 384link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, 385 const Matrix& weights, const Matrix& dist) 386{ 387 return weights[src][next] + dist[next][final] == dist[src][final]; 388} 389 390NetDest 391shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights, 392 const Matrix& dist) 393{ 394 NetDest result; 395 int d = 0; 396 int machines; 397 int max_machines; 398 399 machines = MachineType_NUM; 400 max_machines = MachineType_base_number(MachineType_NUM); 401 402 for (int m = 0; m < machines; m++) { 403 for (int i = 0; i < MachineType_base_count((MachineType)m); i++) { 404 // we use "d+max_machines" below since the "destination" 405 // switches for the machines are numbered 406 // [MachineType_base_number(MachineType_NUM)... 407 // 2*MachineType_base_number(MachineType_NUM)-1] for the 408 // component network 409 if (link_is_shortest_path_to_node(src, next, d + max_machines, 410 weights, dist)) { 411 MachineID mach = {(MachineType)m, i}; 412 result.add(mach); 413 } 414 d++; 415 } 416 } 417 418 DPRINTF(RubyNetwork, "Returning shortest path\n" 419 "(src-(2*max_machines)): %d, (next-(2*max_machines)): %d, " 420 "src: %d, next: %d, result: %s\n", 421 (src-(2*max_machines)), (next-(2*max_machines)), 422 src, next, result); 423 424 return result; 425} 426 427Topology * 428TopologyParams::create() 429{ 430 return new Topology(this); 431} 432 433