Topology.cc revision 6879
16899SN/A
26899SN/A/*
36899SN/A * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
46899SN/A * All rights reserved.
56899SN/A *
66899SN/A * Redistribution and use in source and binary forms, with or without
76899SN/A * modification, are permitted provided that the following conditions are
86899SN/A * met: redistributions of source code must retain the above copyright
96899SN/A * notice, this list of conditions and the following disclaimer;
106899SN/A * redistributions in binary form must reproduce the above copyright
116899SN/A * notice, this list of conditions and the following disclaimer in the
126899SN/A * documentation and/or other materials provided with the distribution;
136899SN/A * neither the name of the copyright holders nor the names of its
146899SN/A * contributors may be used to endorse or promote products derived from
156899SN/A * this software without specific prior written permission.
166899SN/A *
176899SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
186899SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
196899SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
206899SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
216899SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
226899SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
236899SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
246899SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
256899SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
266899SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
276899SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
286899SN/A */
296899SN/A
307056SN/A/*
317632SBrad.Beckmann@amd.com * Topology.cc
327632SBrad.Beckmann@amd.com *
337632SBrad.Beckmann@amd.com * Description: See Topology.hh
346899SN/A *
356899SN/A * $Id$
367053SN/A *
376899SN/A * */
387053SN/A
397053SN/A#include "mem/ruby/network/simple/Topology.hh"
406899SN/A#include "mem/ruby/common/NetDest.hh"
417053SN/A#include "mem/ruby/network/Network.hh"
427053SN/A#include "mem/ruby/slicc_interface/AbstractController.hh"
436899SN/A#include "mem/protocol/TopologyType.hh"
447053SN/A#include "mem/gems_common/util.hh"
457053SN/A#include "mem/protocol/MachineType.hh"
467053SN/A#include "mem/protocol/Protocol.hh"
477053SN/A#include "mem/ruby/system/System.hh"
487053SN/A#include <string>
497053SN/A
507053SN/Astatic const int INFINITE_LATENCY = 10000; // Yes, this is a big hack
517053SN/Astatic const int DEFAULT_BW_MULTIPLIER = 1;  // Just to be consistent with above :)
526899SN/A
537053SN/A// Note: In this file, we use the first 2*m_nodes SwitchIDs to
547053SN/A// represent the input and output endpoint links.  These really are
557053SN/A// not 'switches', as they will not have a Switch object allocated for
567053SN/A// them. The first m_nodes SwitchIDs are the links into the network,
577053SN/A// the second m_nodes set of SwitchIDs represent the the output queues
587053SN/A// of the network.
597053SN/A
607053SN/A// Helper functions based on chapter 29 of Cormen et al.
617053SN/Astatic void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches);
626899SN/Astatic Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches);
637053SN/Astatic bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, const Matrix& weights, const Matrix& dist);
647053SN/Astatic NetDest shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights, const Matrix& dist);
657053SN/A
667053SN/ATopology::Topology(const Params *p)
677053SN/A    : SimObject(p)
687053SN/A{
697053SN/A    m_print_config = p->print_config;
706899SN/A    m_number_of_switches = p->num_int_nodes;
716899SN/A  // initialize component latencies record
726899SN/A  m_component_latencies.setSize(0);
736899SN/A  m_component_inter_switches.setSize(0);
747053SN/A}
757053SN/A
767053SN/Avoid Topology::init()
776899SN/A{
786899SN/A    // need to defer this until init, to guarantee that constructors
797053SN/A    // for all the controller objects have been called.
807053SN/A    m_nodes = MachineType_base_number(MachineType_NUM);
816899SN/A}
827056SN/A
837053SN/Avoid Topology::makeTopology()
847053SN/A{
857053SN/A    if (m_nodes != params()->ext_links.size()) {
866899SN/A        fatal("m_nodes (%d) != ext_links vector length (%d)\n",
876899SN/A              m_nodes != params()->ext_links.size());
887053SN/A    }
897455SN/A
907053SN/A
917053SN/A
927053SN/A  /*
937053SN/A  if (m_nodes == 1) {
946899SN/A    SwitchID id = newSwitchID();
956899SN/A    addLink(0, id, m_network_ptr->getOffChipLinkLatency());
967053SN/A    addLink(id, 1, m_network_ptr->getOffChipLinkLatency());
977053SN/A    return;
987053SN/A  }
997053SN/A  */
1007455SN/A  assert(m_nodes > 1);
1017053SN/A
1027454SN/A  Vector< Vector < SwitchID > > nodePairs;  // node pairs extracted from the file
1036899SN/A  Vector<int> latencies;  // link latencies for each link extracted
1046899SN/A  Vector<int> bw_multis;  // bw multipliers for each link extracted
1057053SN/A  Vector<int> weights;  // link weights used to enfore e-cube deadlock free routing
1067053SN/A  Vector< SwitchID > int_network_switches;  // internal switches extracted from the file
1076899SN/A  Vector<bool> endpointConnectionExist;  // used to ensure all endpoints are connected to the network
1087053SN/A
1096899SN/A  for (vector<ExtLink*>::const_iterator i = params()->ext_links.begin();
1106899SN/A       i != params()->ext_links.end(); ++i)
1117053SN/A  {
1127053SN/A      const ExtLinkParams *p = (*i)->params();
1136899SN/A      AbstractController *c = p->ext_node;
1147780Snilay@cs.wisc.edu      int ext_idx1 =
1156899SN/A          MachineType_base_number(c->getMachineType()) + c->getVersion();
1167455SN/A      int ext_idx2 = ext_idx1 + m_nodes;
1177455SN/A      int int_idx = p->int_node + 2*m_nodes;
1187455SN/A
1197053SN/A      addLink(ext_idx1, int_idx, p->latency, p->bw_multiplier, p->weight);
1207455SN/A      addLink(int_idx, ext_idx2, p->latency, p->bw_multiplier, p->weight);
1217455SN/A  }
1227455SN/A
1237455SN/A  for (vector<IntLink*>::const_iterator i = params()->int_links.begin();
1246899SN/A       i != params()->int_links.end(); ++i)
1256899SN/A  {
1267053SN/A      const IntLinkParams *p = (*i)->params();
1277055SN/A      int a = p->node_a + 2*m_nodes;
1286899SN/A      int b = p->node_b + 2*m_nodes;
1296899SN/A      addLink(a, b, p->latency, p->bw_multiplier, p->weight);
130      addLink(b, a, p->latency, p->bw_multiplier, p->weight);
131  }
132}
133
134
135void Topology::createLinks(Network *net, bool isReconfiguration)
136{
137  // Find maximum switchID
138
139  SwitchID max_switch_id = 0;
140  for (int i=0; i<m_links_src_vector.size(); i++) {
141    max_switch_id = max(max_switch_id, m_links_src_vector[i]);
142    max_switch_id = max(max_switch_id, m_links_dest_vector[i]);
143  }
144
145  // Initialize weight vector
146  Matrix topology_weights;
147  Matrix topology_latency;
148  Matrix topology_bw_multis;
149  int num_switches = max_switch_id+1;
150  topology_weights.setSize(num_switches);
151  topology_latency.setSize(num_switches);
152  topology_bw_multis.setSize(num_switches);
153  m_component_latencies.setSize(num_switches);  // FIXME setting the size of a member variable here is a HACK!
154  m_component_inter_switches.setSize(num_switches);  // FIXME setting the size of a member variable here is a HACK!
155  for(int i=0; i<topology_weights.size(); i++) {
156    topology_weights[i].setSize(num_switches);
157    topology_latency[i].setSize(num_switches);
158    topology_bw_multis[i].setSize(num_switches);
159    m_component_latencies[i].setSize(num_switches);
160    m_component_inter_switches[i].setSize(num_switches);  // FIXME setting the size of a member variable here is a HACK!
161    for(int j=0; j<topology_weights[i].size(); j++) {
162      topology_weights[i][j] = INFINITE_LATENCY;
163      topology_latency[i][j] = -1;  // initialize to an invalid value
164      topology_bw_multis[i][j] = -1;  // initialize to an invalid value
165      m_component_latencies[i][j] = -1; // initialize to an invalid value
166      m_component_inter_switches[i][j] = 0;  // initially assume direct connections / no intermediate switches between components
167    }
168  }
169
170  // Set identity weights to zero
171  for(int i=0; i<topology_weights.size(); i++) {
172    topology_weights[i][i] = 0;
173  }
174
175  // Fill in the topology weights and bandwidth multipliers
176  for (int i=0; i<m_links_src_vector.size(); i++) {
177    topology_weights[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_weight_vector[i];
178    topology_latency[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_latency_vector[i];
179    m_component_latencies[m_links_src_vector[i]][m_links_dest_vector[i]] = m_links_latency_vector[i];  // initialize to latency vector
180    topology_bw_multis[m_links_src_vector[i]][m_links_dest_vector[i]] = m_bw_multiplier_vector[i];
181  }
182
183  // Walk topology and hookup the links
184  Matrix dist = shortest_path(topology_weights, m_component_latencies, m_component_inter_switches);
185  for(int i=0; i<topology_weights.size(); i++) {
186    for(int j=0; j<topology_weights[i].size(); j++) {
187      int weight = topology_weights[i][j];
188      int bw_multiplier = topology_bw_multis[i][j];
189      int latency = topology_latency[i][j];
190      if (weight > 0 && weight != INFINITE_LATENCY) {
191        NetDest destination_set = shortest_path_to_node(i, j, topology_weights, dist);
192        assert(latency != -1);
193        makeLink(net, i, j, destination_set, latency, weight, bw_multiplier, isReconfiguration);
194      }
195    }
196  }
197}
198
199SwitchID Topology::newSwitchID()
200{
201  m_number_of_switches++;
202  return m_number_of_switches-1+m_nodes+m_nodes;
203}
204
205void Topology::addLink(SwitchID src, SwitchID dest, int link_latency)
206{
207  addLink(src, dest, link_latency, DEFAULT_BW_MULTIPLIER, link_latency);
208}
209
210void Topology::addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier)
211{
212  addLink(src, dest, link_latency, bw_multiplier, link_latency);
213}
214
215void Topology::addLink(SwitchID src, SwitchID dest, int link_latency, int bw_multiplier, int link_weight)
216{
217  ASSERT(src <= m_number_of_switches+m_nodes+m_nodes);
218  ASSERT(dest <= m_number_of_switches+m_nodes+m_nodes);
219  m_links_src_vector.insertAtBottom(src);
220  m_links_dest_vector.insertAtBottom(dest);
221  m_links_latency_vector.insertAtBottom(link_latency);
222  m_links_weight_vector.insertAtBottom(link_weight);
223  m_bw_multiplier_vector.insertAtBottom(bw_multiplier);
224}
225
226void Topology::makeLink(Network *net, SwitchID src, SwitchID dest, const NetDest& routing_table_entry, int link_latency, int link_weight, int bw_multiplier, bool isReconfiguration)
227{
228  // Make sure we're not trying to connect two end-point nodes directly together
229  assert((src >= 2*m_nodes) || (dest >= 2*m_nodes));
230
231  if (src < m_nodes) {
232    net->makeInLink(src, dest-(2*m_nodes), routing_table_entry, link_latency, bw_multiplier, isReconfiguration);
233  } else if (dest < 2*m_nodes) {
234    assert(dest >= m_nodes);
235    NodeID node = dest-m_nodes;
236    net->makeOutLink(src-(2*m_nodes), node, routing_table_entry, link_latency, link_weight, bw_multiplier, isReconfiguration);
237  } else {
238    assert((src >= 2*m_nodes) && (dest >= 2*m_nodes));
239    net->makeInternalLink(src-(2*m_nodes), dest-(2*m_nodes), routing_table_entry, link_latency, link_weight, bw_multiplier, isReconfiguration);
240  }
241}
242
243void Topology::printConfig(ostream& out) const
244{
245  if (m_print_config == false) return;
246
247  assert(m_component_latencies.size() > 0);
248
249  out << "--- Begin Topology Print ---" << endl;
250  out << endl;
251  out << "Topology print ONLY indicates the _NETWORK_ latency between two machines" << endl;
252  out << "It does NOT include the latency within the machines" << endl;
253  out << endl;
254  for (int m=0; m<MachineType_NUM; m++) {
255    for (int i=0; i<MachineType_base_count((MachineType)m); i++) {
256      MachineID cur_mach = {(MachineType)m, i};
257      out << cur_mach << " Network Latencies" << endl;
258      for (int n=0; n<MachineType_NUM; n++) {
259        for (int j=0; j<MachineType_base_count((MachineType)n); j++) {
260          MachineID dest_mach = {(MachineType)n, j};
261          if (cur_mach != dest_mach) {
262            int link_latency = m_component_latencies[MachineType_base_number((MachineType)m)+i][MachineType_base_number(MachineType_NUM)+MachineType_base_number((MachineType)n)+j];
263            int intermediate_switches = m_component_inter_switches[MachineType_base_number((MachineType)m)+i][MachineType_base_number(MachineType_NUM)+MachineType_base_number((MachineType)n)+j];
264            out << "  " << cur_mach << " -> " << dest_mach << " net_lat: "
265                << link_latency+intermediate_switches << endl;  // NOTE switches are assumed to have single cycle latency
266          }
267        }
268      }
269      out << endl;
270    }
271  }
272
273  out << "--- End Topology Print ---" << endl;
274}
275
276/**************************************************************************/
277
278// The following all-pairs shortest path algorithm is based on the
279// discussion from Cormen et al., Chapter 26.1.
280
281static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches)
282{
283  bool change = true;
284  int nodes = current_dist.size();
285
286  while (change) {
287    change = false;
288    for (int i=0; i<nodes; i++) {
289      for (int j=0; j<nodes; j++) {
290        int minimum = current_dist[i][j];
291        int previous_minimum = minimum;
292        int intermediate_switch = -1;
293        for (int k=0; k<nodes; k++) {
294          minimum = min(minimum, current_dist[i][k] + current_dist[k][j]);
295          if (previous_minimum != minimum) {
296            intermediate_switch = k;
297            inter_switches[i][j] = inter_switches[i][k] + inter_switches[k][j] + 1;
298          }
299          previous_minimum = minimum;
300        }
301        if (current_dist[i][j] != minimum) {
302          change = true;
303          current_dist[i][j] = minimum;
304          assert(intermediate_switch >= 0);
305          assert(intermediate_switch < latencies[i].size());
306          latencies[i][j] = latencies[i][intermediate_switch] + latencies[intermediate_switch][j];
307        }
308      }
309    }
310  }
311}
312
313static Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches)
314{
315  Matrix dist = weights;
316  extend_shortest_path(dist, latencies, inter_switches);
317  return dist;
318}
319
320static bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final,
321                                          const Matrix& weights, const Matrix& dist)
322{
323  return (weights[src][next] + dist[next][final] == dist[src][final]);
324}
325
326static NetDest shortest_path_to_node(SwitchID src, SwitchID next,
327                                     const Matrix& weights, const Matrix& dist)
328{
329  NetDest result;
330  int d = 0;
331  int machines;
332  int max_machines;
333
334  machines = MachineType_NUM;
335  max_machines = MachineType_base_number(MachineType_NUM);
336
337  for (int m=0; m<machines; m++) {
338    for (int i=0; i<MachineType_base_count((MachineType)m); i++) {
339      // we use "d+max_machines" below since the "destination" switches for the machines are numbered
340      // [MachineType_base_number(MachineType_NUM)...2*MachineType_base_number(MachineType_NUM)-1]
341      // for the component network
342      if (link_is_shortest_path_to_node(src, next,
343                                        d+max_machines,
344                                        weights, dist)) {
345        MachineID mach = {(MachineType)m, i};
346        result.add(mach);
347      }
348      d++;
349    }
350  }
351
352  DEBUG_MSG(NETWORK_COMP, MedPrio, "returning shortest path");
353  DEBUG_EXPR(NETWORK_COMP, MedPrio, (src-(2*max_machines)));
354  DEBUG_EXPR(NETWORK_COMP, MedPrio, (next-(2*max_machines)));
355  DEBUG_EXPR(NETWORK_COMP, MedPrio, src);
356  DEBUG_EXPR(NETWORK_COMP, MedPrio, next);
357  DEBUG_EXPR(NETWORK_COMP, MedPrio, result);
358  DEBUG_NEWLINE(NETWORK_COMP, MedPrio);
359
360  return result;
361}
362
363Topology *
364TopologyParams::create()
365{
366    return new Topology(this);
367}
368
369Link *
370LinkParams::create()
371{
372    return new Link(this);
373}
374
375ExtLink *
376ExtLinkParams::create()
377{
378    return new ExtLink(this);
379}
380
381IntLink *
382IntLinkParams::create()
383{
384    return new IntLink(this);
385}
386