Topology.cc revision 6879
1
2/*
3 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * Topology.cc
32 *
33 * Description: See Topology.hh
34 *
35 * $Id$
36 *
37 * */
38
39#include "mem/ruby/network/simple/Topology.hh"
40#include "mem/ruby/common/NetDest.hh"
41#include "mem/ruby/network/Network.hh"
42#include "mem/ruby/slicc_interface/AbstractController.hh"
43#include "mem/protocol/TopologyType.hh"
44#include "mem/gems_common/util.hh"
45#include "mem/protocol/MachineType.hh"
46#include "mem/protocol/Protocol.hh"
47#include "mem/ruby/system/System.hh"
48#include <string>
49
50static const int INFINITE_LATENCY = 10000; // Yes, this is a big hack
51static const int DEFAULT_BW_MULTIPLIER = 1;  // Just to be consistent with above :)
52
53// Note: In this file, we use the first 2*m_nodes SwitchIDs to
54// represent the input and output endpoint links.  These really are
55// not 'switches', as they will not have a Switch object allocated for
56// them. The first m_nodes SwitchIDs are the links into the network,
57// the second m_nodes set of SwitchIDs represent the the output queues
58// of the network.
59
60// Helper functions based on chapter 29 of Cormen et al.
61static void extend_shortest_path(Matrix& current_dist, Matrix& latencies, Matrix& inter_switches);
62static Matrix shortest_path(const Matrix& weights, Matrix& latencies, Matrix& inter_switches);
63static bool link_is_shortest_path_to_node(SwitchID src, SwitchID next, SwitchID final, const Matrix& weights, const Matrix& dist);
64static NetDest shortest_path_to_node(SwitchID src, SwitchID next, const Matrix& weights, const Matrix& dist);
65
66Topology::Topology(const Params *p)
67    : SimObject(p)
68{
69    m_print_config = p->print_config;
70    m_number_of_switches = p->num_int_nodes;
71  // initialize component latencies record
72  m_component_latencies.setSize(0);
73  m_component_inter_switches.setSize(0);
74}
75
76void Topology::init()
77{
78    // need to defer this until init, to guarantee that constructors
79    // for all the controller objects have been called.
80    m_nodes = MachineType_base_number(MachineType_NUM);
81}
82
83void Topology::makeTopology()
84{
85    if (m_nodes != params()->ext_links.size()) {
86        fatal("m_nodes (%d) != ext_links vector length (%d)\n",
87              m_nodes != params()->ext_links.size());
88    }
89
90
91
92  /*
93  if (m_nodes == 1) {
94    SwitchID id = newSwitchID();
95    addLink(0, id, m_network_ptr->getOffChipLinkLatency());
96    addLink(id, 1, m_network_ptr->getOffChipLinkLatency());
97    return;
98  }
99  */
100  assert(m_nodes > 1);
101
102  Vector< Vector < SwitchID > > nodePairs;  // node pairs extracted from the file
103  Vector<int> latencies;  // link latencies for each link extracted
104  Vector<int> bw_multis;  // bw multipliers for each link extracted
105  Vector<int> weights;  // link weights used to enfore e-cube deadlock free routing
106  Vector< SwitchID > int_network_switches;  // internal switches extracted from the file
107  Vector<bool> endpointConnectionExist;  // used to ensure all endpoints are connected to the network
108
109  for (vector<ExtLink*>::const_iterator i = params()->ext_links.begin();
110       i != params()->ext_links.end(); ++i)
111  {
112      const ExtLinkParams *p = (*i)->params();
113      AbstractController *c = p->ext_node;
114      int ext_idx1 =
115          MachineType_base_number(c->getMachineType()) + c->getVersion();
116      int ext_idx2 = ext_idx1 + m_nodes;
117      int int_idx = p->int_node + 2*m_nodes;
118
119      addLink(ext_idx1, int_idx, p->latency, p->bw_multiplier, p->weight);
120      addLink(int_idx, ext_idx2, p->latency, p->bw_multiplier, p->weight);
121  }
122
123  for (vector<IntLink*>::const_iterator i = params()->int_links.begin();
124       i != params()->int_links.end(); ++i)
125  {
126      const IntLinkParams *p = (*i)->params();
127      int a = p->node_a + 2*m_nodes;
128      int b = p->node_b + 2*m_nodes;
129      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