ec733185191cda26a2b933f566909a138ed25883
[gem5.git] / src / mem / ruby / network / garnet / GarnetNetwork.cc
1 /*
2 * Copyright (c) 2020 Advanced Micro Devices, Inc.
3 * Copyright (c) 2008 Princeton University
4 * Copyright (c) 2016 Georgia Institute of Technology
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met: redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer;
11 * redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution;
14 * neither the name of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32 #include "mem/ruby/network/garnet/GarnetNetwork.hh"
33
34 #include <cassert>
35
36 #include "base/cast.hh"
37 #include "debug/RubyNetwork.hh"
38 #include "mem/ruby/common/NetDest.hh"
39 #include "mem/ruby/network/MessageBuffer.hh"
40 #include "mem/ruby/network/garnet/CommonTypes.hh"
41 #include "mem/ruby/network/garnet/CreditLink.hh"
42 #include "mem/ruby/network/garnet/GarnetLink.hh"
43 #include "mem/ruby/network/garnet/NetworkInterface.hh"
44 #include "mem/ruby/network/garnet/NetworkLink.hh"
45 #include "mem/ruby/network/garnet/Router.hh"
46 #include "mem/ruby/system/RubySystem.hh"
47
48 using namespace std;
49
50 /*
51 * GarnetNetwork sets up the routers and links and collects stats.
52 * Default parameters (GarnetNetwork.py) can be overwritten from command line
53 * (see configs/network/Network.py)
54 */
55
56 GarnetNetwork::GarnetNetwork(const Params &p)
57 : Network(p)
58 {
59 m_num_rows = p.num_rows;
60 m_ni_flit_size = p.ni_flit_size;
61 m_max_vcs_per_vnet = 0;
62 m_buffers_per_data_vc = p.buffers_per_data_vc;
63 m_buffers_per_ctrl_vc = p.buffers_per_ctrl_vc;
64 m_routing_algorithm = p.routing_algorithm;
65
66 m_enable_fault_model = p.enable_fault_model;
67 if (m_enable_fault_model)
68 fault_model = p.fault_model;
69
70 m_vnet_type.resize(m_virtual_networks);
71
72 for (int i = 0 ; i < m_virtual_networks ; i++) {
73 if (m_vnet_type_names[i] == "response")
74 m_vnet_type[i] = DATA_VNET_; // carries data (and ctrl) packets
75 else
76 m_vnet_type[i] = CTRL_VNET_; // carries only ctrl packets
77 }
78
79 // record the routers
80 for (vector<BasicRouter*>::const_iterator i = p.routers.begin();
81 i != p.routers.end(); ++i) {
82 Router* router = safe_cast<Router*>(*i);
83 m_routers.push_back(router);
84
85 // initialize the router's network pointers
86 router->init_net_ptr(this);
87 }
88
89 // record the network interfaces
90 for (vector<ClockedObject*>::const_iterator i = p.netifs.begin();
91 i != p.netifs.end(); ++i) {
92 NetworkInterface *ni = safe_cast<NetworkInterface *>(*i);
93 m_nis.push_back(ni);
94 ni->init_net_ptr(this);
95 }
96
97 // Print Garnet version
98 inform("Garnet version %s\n", garnetVersion);
99 }
100
101 void
102 GarnetNetwork::init()
103 {
104 Network::init();
105
106 for (int i=0; i < m_nodes; i++) {
107 m_nis[i]->addNode(m_toNetQueues[i], m_fromNetQueues[i]);
108 }
109
110 // The topology pointer should have already been initialized in the
111 // parent network constructor
112 assert(m_topology_ptr != NULL);
113 m_topology_ptr->createLinks(this);
114
115 // Initialize topology specific parameters
116 if (getNumRows() > 0) {
117 // Only for Mesh topology
118 // m_num_rows and m_num_cols are only used for
119 // implementing XY or custom routing in RoutingUnit.cc
120 m_num_rows = getNumRows();
121 m_num_cols = m_routers.size() / m_num_rows;
122 assert(m_num_rows * m_num_cols == m_routers.size());
123 } else {
124 m_num_rows = -1;
125 m_num_cols = -1;
126 }
127
128 // FaultModel: declare each router to the fault model
129 if (isFaultModelEnabled()) {
130 for (vector<Router*>::const_iterator i= m_routers.begin();
131 i != m_routers.end(); ++i) {
132 Router* router = safe_cast<Router*>(*i);
133 M5_VAR_USED int router_id =
134 fault_model->declare_router(router->get_num_inports(),
135 router->get_num_outports(),
136 router->get_vc_per_vnet(),
137 getBuffersPerDataVC(),
138 getBuffersPerCtrlVC());
139 assert(router_id == router->get_id());
140 router->printAggregateFaultProbability(cout);
141 router->printFaultVector(cout);
142 }
143 }
144 }
145
146 /*
147 * This function creates a link from the Network Interface (NI)
148 * into the Network.
149 * It creates a Network Link from the NI to a Router and a Credit Link from
150 * the Router to the NI
151 */
152
153 void
154 GarnetNetwork::makeExtInLink(NodeID global_src, SwitchID dest, BasicLink* link,
155 std::vector<NetDest>& routing_table_entry)
156 {
157 NodeID local_src = getLocalNodeID(global_src);
158 assert(local_src < m_nodes);
159
160 GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
161
162 // GarnetExtLink is bi-directional
163 NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_In];
164 net_link->setType(EXT_IN_);
165 CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_In];
166
167 m_networklinks.push_back(net_link);
168 m_creditlinks.push_back(credit_link);
169
170 PortDirection dst_inport_dirn = "Local";
171
172 m_max_vcs_per_vnet = std::max(m_max_vcs_per_vnet,
173 m_routers[dest]->get_vc_per_vnet());
174
175 /*
176 * We check if a bridge was enabled at any end of the link.
177 * The bridge is enabled if either of clock domain
178 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
179 * enabled for the link at each end. The bridge encapsulates
180 * the functionality for both CDC and SerDes and is a Consumer
181 * object similiar to a NetworkLink.
182 *
183 * If a bridge was enabled we connect the NI and Routers to
184 * bridge before connecting the link. Example, if an external
185 * bridge is enabled, we would connect:
186 * NI--->NetworkBridge--->GarnetExtLink---->Router
187 */
188 if (garnet_link->extBridgeEn) {
189 DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
190 garnet_link->name());
191 m_nis[local_src]->
192 addOutPort(garnet_link->extNetBridge[LinkDirection_In],
193 garnet_link->extCredBridge[LinkDirection_In],
194 dest, m_routers[dest]->get_vc_per_vnet());
195 } else {
196 m_nis[local_src]->addOutPort(net_link, credit_link, dest,
197 m_routers[dest]->get_vc_per_vnet());
198 }
199
200 if (garnet_link->intBridgeEn) {
201 DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
202 garnet_link->name());
203 m_routers[dest]->
204 addInPort(dst_inport_dirn,
205 garnet_link->intNetBridge[LinkDirection_In],
206 garnet_link->intCredBridge[LinkDirection_In]);
207 } else {
208 m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
209 }
210
211 }
212
213 /*
214 * This function creates a link from the Network to a NI.
215 * It creates a Network Link from a Router to the NI and
216 * a Credit Link from NI to the Router
217 */
218
219 void
220 GarnetNetwork::makeExtOutLink(SwitchID src, NodeID global_dest,
221 BasicLink* link,
222 std::vector<NetDest>& routing_table_entry)
223 {
224 NodeID local_dest = getLocalNodeID(global_dest);
225 assert(local_dest < m_nodes);
226 assert(src < m_routers.size());
227 assert(m_routers[src] != NULL);
228
229 GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
230
231 // GarnetExtLink is bi-directional
232 NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_Out];
233 net_link->setType(EXT_OUT_);
234 CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_Out];
235
236 m_networklinks.push_back(net_link);
237 m_creditlinks.push_back(credit_link);
238
239 PortDirection src_outport_dirn = "Local";
240
241 m_max_vcs_per_vnet = std::max(m_max_vcs_per_vnet,
242 m_routers[src]->get_vc_per_vnet());
243
244 /*
245 * We check if a bridge was enabled at any end of the link.
246 * The bridge is enabled if either of clock domain
247 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
248 * enabled for the link at each end. The bridge encapsulates
249 * the functionality for both CDC and SerDes and is a Consumer
250 * object similiar to a NetworkLink.
251 *
252 * If a bridge was enabled we connect the NI and Routers to
253 * bridge before connecting the link. Example, if an external
254 * bridge is enabled, we would connect:
255 * NI<---NetworkBridge<---GarnetExtLink<----Router
256 */
257 if (garnet_link->extBridgeEn) {
258 DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
259 garnet_link->name());
260 m_nis[local_dest]->
261 addInPort(garnet_link->extNetBridge[LinkDirection_Out],
262 garnet_link->extCredBridge[LinkDirection_Out]);
263 } else {
264 m_nis[local_dest]->addInPort(net_link, credit_link);
265 }
266
267 if (garnet_link->intBridgeEn) {
268 DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
269 garnet_link->name());
270 m_routers[src]->
271 addOutPort(src_outport_dirn,
272 garnet_link->intNetBridge[LinkDirection_Out],
273 routing_table_entry, link->m_weight,
274 garnet_link->intCredBridge[LinkDirection_Out],
275 m_routers[src]->get_vc_per_vnet());
276 } else {
277 m_routers[src]->
278 addOutPort(src_outport_dirn, net_link,
279 routing_table_entry,
280 link->m_weight, credit_link,
281 m_routers[src]->get_vc_per_vnet());
282 }
283 }
284
285 /*
286 * This function creates an internal network link between two routers.
287 * It adds both the network link and an opposite credit link.
288 */
289
290 void
291 GarnetNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
292 std::vector<NetDest>& routing_table_entry,
293 PortDirection src_outport_dirn,
294 PortDirection dst_inport_dirn)
295 {
296 GarnetIntLink* garnet_link = safe_cast<GarnetIntLink*>(link);
297
298 // GarnetIntLink is unidirectional
299 NetworkLink* net_link = garnet_link->m_network_link;
300 net_link->setType(INT_);
301 CreditLink* credit_link = garnet_link->m_credit_link;
302
303 m_networklinks.push_back(net_link);
304 m_creditlinks.push_back(credit_link);
305
306 m_max_vcs_per_vnet = std::max(m_max_vcs_per_vnet,
307 std::max(m_routers[dest]->get_vc_per_vnet(),
308 m_routers[src]->get_vc_per_vnet()));
309
310 /*
311 * We check if a bridge was enabled at any end of the link.
312 * The bridge is enabled if either of clock domain
313 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
314 * enabled for the link at each end. The bridge encapsulates
315 * the functionality for both CDC and SerDes and is a Consumer
316 * object similiar to a NetworkLink.
317 *
318 * If a bridge was enabled we connect the NI and Routers to
319 * bridge before connecting the link. Example, if a source
320 * bridge is enabled, we would connect:
321 * Router--->NetworkBridge--->GarnetIntLink---->Router
322 */
323 if (garnet_link->dstBridgeEn) {
324 DPRINTF(RubyNetwork, "Enable destination bridge for %s\n",
325 garnet_link->name());
326 m_routers[dest]->addInPort(dst_inport_dirn,
327 garnet_link->dstNetBridge, garnet_link->dstCredBridge);
328 } else {
329 m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
330 }
331
332 if (garnet_link->srcBridgeEn) {
333 DPRINTF(RubyNetwork, "Enable source bridge for %s\n",
334 garnet_link->name());
335 m_routers[src]->
336 addOutPort(src_outport_dirn, garnet_link->srcNetBridge,
337 routing_table_entry,
338 link->m_weight, garnet_link->srcCredBridge,
339 m_routers[dest]->get_vc_per_vnet());
340 } else {
341 m_routers[src]->addOutPort(src_outport_dirn, net_link,
342 routing_table_entry,
343 link->m_weight, credit_link,
344 m_routers[dest]->get_vc_per_vnet());
345 }
346 }
347
348 // Total routers in the network
349 int
350 GarnetNetwork::getNumRouters()
351 {
352 return m_routers.size();
353 }
354
355 // Get ID of router connected to a NI.
356 int
357 GarnetNetwork::get_router_id(int global_ni, int vnet)
358 {
359 NodeID local_ni = getLocalNodeID(global_ni);
360
361 return m_nis[local_ni]->get_router_id(vnet);
362 }
363
364 void
365 GarnetNetwork::regStats()
366 {
367 Network::regStats();
368
369 // Packets
370 m_packets_received
371 .init(m_virtual_networks)
372 .name(name() + ".packets_received")
373 .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
374 ;
375
376 m_packets_injected
377 .init(m_virtual_networks)
378 .name(name() + ".packets_injected")
379 .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
380 ;
381
382 m_packet_network_latency
383 .init(m_virtual_networks)
384 .name(name() + ".packet_network_latency")
385 .flags(Stats::oneline)
386 ;
387
388 m_packet_queueing_latency
389 .init(m_virtual_networks)
390 .name(name() + ".packet_queueing_latency")
391 .flags(Stats::oneline)
392 ;
393
394 for (int i = 0; i < m_virtual_networks; i++) {
395 m_packets_received.subname(i, csprintf("vnet-%i", i));
396 m_packets_injected.subname(i, csprintf("vnet-%i", i));
397 m_packet_network_latency.subname(i, csprintf("vnet-%i", i));
398 m_packet_queueing_latency.subname(i, csprintf("vnet-%i", i));
399 }
400
401 m_avg_packet_vnet_latency
402 .name(name() + ".average_packet_vnet_latency")
403 .flags(Stats::oneline);
404 m_avg_packet_vnet_latency =
405 m_packet_network_latency / m_packets_received;
406
407 m_avg_packet_vqueue_latency
408 .name(name() + ".average_packet_vqueue_latency")
409 .flags(Stats::oneline);
410 m_avg_packet_vqueue_latency =
411 m_packet_queueing_latency / m_packets_received;
412
413 m_avg_packet_network_latency
414 .name(name() + ".average_packet_network_latency");
415 m_avg_packet_network_latency =
416 sum(m_packet_network_latency) / sum(m_packets_received);
417
418 m_avg_packet_queueing_latency
419 .name(name() + ".average_packet_queueing_latency");
420 m_avg_packet_queueing_latency
421 = sum(m_packet_queueing_latency) / sum(m_packets_received);
422
423 m_avg_packet_latency
424 .name(name() + ".average_packet_latency");
425 m_avg_packet_latency
426 = m_avg_packet_network_latency + m_avg_packet_queueing_latency;
427
428 // Flits
429 m_flits_received
430 .init(m_virtual_networks)
431 .name(name() + ".flits_received")
432 .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
433 ;
434
435 m_flits_injected
436 .init(m_virtual_networks)
437 .name(name() + ".flits_injected")
438 .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
439 ;
440
441 m_flit_network_latency
442 .init(m_virtual_networks)
443 .name(name() + ".flit_network_latency")
444 .flags(Stats::oneline)
445 ;
446
447 m_flit_queueing_latency
448 .init(m_virtual_networks)
449 .name(name() + ".flit_queueing_latency")
450 .flags(Stats::oneline)
451 ;
452
453 for (int i = 0; i < m_virtual_networks; i++) {
454 m_flits_received.subname(i, csprintf("vnet-%i", i));
455 m_flits_injected.subname(i, csprintf("vnet-%i", i));
456 m_flit_network_latency.subname(i, csprintf("vnet-%i", i));
457 m_flit_queueing_latency.subname(i, csprintf("vnet-%i", i));
458 }
459
460 m_avg_flit_vnet_latency
461 .name(name() + ".average_flit_vnet_latency")
462 .flags(Stats::oneline);
463 m_avg_flit_vnet_latency = m_flit_network_latency / m_flits_received;
464
465 m_avg_flit_vqueue_latency
466 .name(name() + ".average_flit_vqueue_latency")
467 .flags(Stats::oneline);
468 m_avg_flit_vqueue_latency =
469 m_flit_queueing_latency / m_flits_received;
470
471 m_avg_flit_network_latency
472 .name(name() + ".average_flit_network_latency");
473 m_avg_flit_network_latency =
474 sum(m_flit_network_latency) / sum(m_flits_received);
475
476 m_avg_flit_queueing_latency
477 .name(name() + ".average_flit_queueing_latency");
478 m_avg_flit_queueing_latency =
479 sum(m_flit_queueing_latency) / sum(m_flits_received);
480
481 m_avg_flit_latency
482 .name(name() + ".average_flit_latency");
483 m_avg_flit_latency =
484 m_avg_flit_network_latency + m_avg_flit_queueing_latency;
485
486
487 // Hops
488 m_avg_hops.name(name() + ".average_hops");
489 m_avg_hops = m_total_hops / sum(m_flits_received);
490
491 // Links
492 m_total_ext_in_link_utilization
493 .name(name() + ".ext_in_link_utilization");
494 m_total_ext_out_link_utilization
495 .name(name() + ".ext_out_link_utilization");
496 m_total_int_link_utilization
497 .name(name() + ".int_link_utilization");
498 m_average_link_utilization
499 .name(name() + ".avg_link_utilization");
500 m_average_vc_load
501 .init(m_virtual_networks * m_max_vcs_per_vnet)
502 .name(name() + ".avg_vc_load")
503 .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
504 ;
505 }
506
507 void
508 GarnetNetwork::collateStats()
509 {
510 RubySystem *rs = params().ruby_system;
511 double time_delta = double(curCycle() - rs->getStartCycle());
512
513 for (int i = 0; i < m_networklinks.size(); i++) {
514 link_type type = m_networklinks[i]->getType();
515 int activity = m_networklinks[i]->getLinkUtilization();
516
517 if (type == EXT_IN_)
518 m_total_ext_in_link_utilization += activity;
519 else if (type == EXT_OUT_)
520 m_total_ext_out_link_utilization += activity;
521 else if (type == INT_)
522 m_total_int_link_utilization += activity;
523
524 m_average_link_utilization +=
525 (double(activity) / time_delta);
526
527 vector<unsigned int> vc_load = m_networklinks[i]->getVcLoad();
528 for (int j = 0; j < vc_load.size(); j++) {
529 m_average_vc_load[j] += ((double)vc_load[j] / time_delta);
530 }
531 }
532
533 // Ask the routers to collate their statistics
534 for (int i = 0; i < m_routers.size(); i++) {
535 m_routers[i]->collateStats();
536 }
537 }
538
539 void
540 GarnetNetwork::resetStats()
541 {
542 for (int i = 0; i < m_routers.size(); i++) {
543 m_routers[i]->resetStats();
544 }
545 for (int i = 0; i < m_networklinks.size(); i++) {
546 m_networklinks[i]->resetStats();
547 }
548 for (int i = 0; i < m_creditlinks.size(); i++) {
549 m_creditlinks[i]->resetStats();
550 }
551 }
552
553 void
554 GarnetNetwork::print(ostream& out) const
555 {
556 out << "[GarnetNetwork]";
557 }
558
559 GarnetNetwork *
560 GarnetNetworkParams::create() const
561 {
562 return new GarnetNetwork(*this);
563 }
564
565 uint32_t
566 GarnetNetwork::functionalWrite(Packet *pkt)
567 {
568 uint32_t num_functional_writes = 0;
569
570 for (unsigned int i = 0; i < m_routers.size(); i++) {
571 num_functional_writes += m_routers[i]->functionalWrite(pkt);
572 }
573
574 for (unsigned int i = 0; i < m_nis.size(); ++i) {
575 num_functional_writes += m_nis[i]->functionalWrite(pkt);
576 }
577
578 for (unsigned int i = 0; i < m_networklinks.size(); ++i) {
579 num_functional_writes += m_networklinks[i]->functionalWrite(pkt);
580 }
581
582 return num_functional_writes;
583 }