2 * Copyright (c) 2020 Advanced Micro Devices, Inc.
3 * Copyright (c) 2008 Princeton University
4 * Copyright (c) 2016 Georgia Institute of Technology
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.
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.
32 #include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
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/garnet2.0/CommonTypes.hh"
41 #include "mem/ruby/network/garnet2.0/CreditLink.hh"
42 #include "mem/ruby/network/garnet2.0/GarnetLink.hh"
43 #include "mem/ruby/network/garnet2.0/NetworkInterface.hh"
44 #include "mem/ruby/network/garnet2.0/NetworkLink.hh"
45 #include "mem/ruby/network/garnet2.0/Router.hh"
46 #include "mem/ruby/system/RubySystem.hh"
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)
56 GarnetNetwork::GarnetNetwork(const Params
*p
)
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
;
66 m_enable_fault_model
= p
->enable_fault_model
;
67 if (m_enable_fault_model
)
68 fault_model
= p
->fault_model
;
70 m_vnet_type
.resize(m_virtual_networks
);
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
76 m_vnet_type
[i
] = CTRL_VNET_
; // carries only ctrl packets
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
);
85 // initialize the router's network pointers
86 router
->init_net_ptr(this);
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
);
94 ni
->init_net_ptr(this);
103 for (int i
=0; i
< m_nodes
; i
++) {
104 m_nis
[i
]->addNode(m_toNetQueues
[i
], m_fromNetQueues
[i
]);
107 // The topology pointer should have already been initialized in the
108 // parent network constructor
109 assert(m_topology_ptr
!= NULL
);
110 m_topology_ptr
->createLinks(this);
112 // Initialize topology specific parameters
113 if (getNumRows() > 0) {
114 // Only for Mesh topology
115 // m_num_rows and m_num_cols are only used for
116 // implementing XY or custom routing in RoutingUnit.cc
117 m_num_rows
= getNumRows();
118 m_num_cols
= m_routers
.size() / m_num_rows
;
119 assert(m_num_rows
* m_num_cols
== m_routers
.size());
125 // FaultModel: declare each router to the fault model
126 if (isFaultModelEnabled()) {
127 for (vector
<Router
*>::const_iterator i
= m_routers
.begin();
128 i
!= m_routers
.end(); ++i
) {
129 Router
* router
= safe_cast
<Router
*>(*i
);
130 int router_id M5_VAR_USED
=
131 fault_model
->declare_router(router
->get_num_inports(),
132 router
->get_num_outports(),
133 router
->get_vc_per_vnet(),
134 getBuffersPerDataVC(),
135 getBuffersPerCtrlVC());
136 assert(router_id
== router
->get_id());
137 router
->printAggregateFaultProbability(cout
);
138 router
->printFaultVector(cout
);
144 * This function creates a link from the Network Interface (NI)
146 * It creates a Network Link from the NI to a Router and a Credit Link from
147 * the Router to the NI
151 GarnetNetwork::makeExtInLink(NodeID global_src
, SwitchID dest
, BasicLink
* link
,
152 std::vector
<NetDest
>& routing_table_entry
)
154 NodeID local_src
= getLocalNodeID(global_src
);
155 assert(local_src
< m_nodes
);
157 GarnetExtLink
* garnet_link
= safe_cast
<GarnetExtLink
*>(link
);
159 // GarnetExtLink is bi-directional
160 NetworkLink
* net_link
= garnet_link
->m_network_links
[LinkDirection_In
];
161 net_link
->setType(EXT_IN_
);
162 CreditLink
* credit_link
= garnet_link
->m_credit_links
[LinkDirection_In
];
164 m_networklinks
.push_back(net_link
);
165 m_creditlinks
.push_back(credit_link
);
167 PortDirection dst_inport_dirn
= "Local";
169 m_max_vcs_per_vnet
= std::max(m_max_vcs_per_vnet
,
170 m_routers
[dest
]->get_vc_per_vnet());
173 * We check if a bridge was enabled at any end of the link.
174 * The bridge is enabled if either of clock domain
175 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
176 * enabled for the link at each end. The bridge encapsulates
177 * the functionality for both CDC and SerDes and is a Consumer
178 * object similiar to a NetworkLink.
180 * If a bridge was enabled we connect the NI and Routers to
181 * bridge before connecting the link. Example, if an external
182 * bridge is enabled, we would connect:
183 * NI--->NetworkBridge--->GarnetExtLink---->Router
185 if (garnet_link
->extBridgeEn
) {
186 DPRINTF(RubyNetwork
, "Enable external bridge for %s\n",
187 garnet_link
->name());
189 addOutPort(garnet_link
->extNetBridge
[LinkDirection_In
],
190 garnet_link
->extCredBridge
[LinkDirection_In
],
191 dest
, m_routers
[dest
]->get_vc_per_vnet());
193 m_nis
[local_src
]->addOutPort(net_link
, credit_link
, dest
,
194 m_routers
[dest
]->get_vc_per_vnet());
197 if (garnet_link
->intBridgeEn
) {
198 DPRINTF(RubyNetwork
, "Enable internal bridge for %s\n",
199 garnet_link
->name());
201 addInPort(dst_inport_dirn
,
202 garnet_link
->intNetBridge
[LinkDirection_In
],
203 garnet_link
->intCredBridge
[LinkDirection_In
]);
205 m_routers
[dest
]->addInPort(dst_inport_dirn
, net_link
, credit_link
);
211 * This function creates a link from the Network to a NI.
212 * It creates a Network Link from a Router to the NI and
213 * a Credit Link from NI to the Router
217 GarnetNetwork::makeExtOutLink(SwitchID src
, NodeID global_dest
,
219 std::vector
<NetDest
>& routing_table_entry
)
221 NodeID local_dest
= getLocalNodeID(global_dest
);
222 assert(local_dest
< m_nodes
);
223 assert(src
< m_routers
.size());
224 assert(m_routers
[src
] != NULL
);
226 GarnetExtLink
* garnet_link
= safe_cast
<GarnetExtLink
*>(link
);
228 // GarnetExtLink is bi-directional
229 NetworkLink
* net_link
= garnet_link
->m_network_links
[LinkDirection_Out
];
230 net_link
->setType(EXT_OUT_
);
231 CreditLink
* credit_link
= garnet_link
->m_credit_links
[LinkDirection_Out
];
233 m_networklinks
.push_back(net_link
);
234 m_creditlinks
.push_back(credit_link
);
236 PortDirection src_outport_dirn
= "Local";
238 m_max_vcs_per_vnet
= std::max(m_max_vcs_per_vnet
,
239 m_routers
[src
]->get_vc_per_vnet());
242 * We check if a bridge was enabled at any end of the link.
243 * The bridge is enabled if either of clock domain
244 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
245 * enabled for the link at each end. The bridge encapsulates
246 * the functionality for both CDC and SerDes and is a Consumer
247 * object similiar to a NetworkLink.
249 * If a bridge was enabled we connect the NI and Routers to
250 * bridge before connecting the link. Example, if an external
251 * bridge is enabled, we would connect:
252 * NI<---NetworkBridge<---GarnetExtLink<----Router
254 if (garnet_link
->extBridgeEn
) {
255 DPRINTF(RubyNetwork
, "Enable external bridge for %s\n",
256 garnet_link
->name());
258 addInPort(garnet_link
->extNetBridge
[LinkDirection_Out
],
259 garnet_link
->extCredBridge
[LinkDirection_Out
]);
261 m_nis
[local_dest
]->addInPort(net_link
, credit_link
);
264 if (garnet_link
->intBridgeEn
) {
265 DPRINTF(RubyNetwork
, "Enable internal bridge for %s\n",
266 garnet_link
->name());
268 addOutPort(src_outport_dirn
,
269 garnet_link
->intNetBridge
[LinkDirection_Out
],
270 routing_table_entry
, link
->m_weight
,
271 garnet_link
->intCredBridge
[LinkDirection_Out
],
272 m_routers
[src
]->get_vc_per_vnet());
275 addOutPort(src_outport_dirn
, net_link
,
277 link
->m_weight
, credit_link
,
278 m_routers
[src
]->get_vc_per_vnet());
283 * This function creates an internal network link between two routers.
284 * It adds both the network link and an opposite credit link.
288 GarnetNetwork::makeInternalLink(SwitchID src
, SwitchID dest
, BasicLink
* link
,
289 std::vector
<NetDest
>& routing_table_entry
,
290 PortDirection src_outport_dirn
,
291 PortDirection dst_inport_dirn
)
293 GarnetIntLink
* garnet_link
= safe_cast
<GarnetIntLink
*>(link
);
295 // GarnetIntLink is unidirectional
296 NetworkLink
* net_link
= garnet_link
->m_network_link
;
297 net_link
->setType(INT_
);
298 CreditLink
* credit_link
= garnet_link
->m_credit_link
;
300 m_networklinks
.push_back(net_link
);
301 m_creditlinks
.push_back(credit_link
);
303 m_max_vcs_per_vnet
= std::max(m_max_vcs_per_vnet
,
304 std::max(m_routers
[dest
]->get_vc_per_vnet(),
305 m_routers
[src
]->get_vc_per_vnet()));
308 * We check if a bridge was enabled at any end of the link.
309 * The bridge is enabled if either of clock domain
310 * crossing (CDC) or Serializer-Deserializer(SerDes) unit is
311 * enabled for the link at each end. The bridge encapsulates
312 * the functionality for both CDC and SerDes and is a Consumer
313 * object similiar to a NetworkLink.
315 * If a bridge was enabled we connect the NI and Routers to
316 * bridge before connecting the link. Example, if a source
317 * bridge is enabled, we would connect:
318 * Router--->NetworkBridge--->GarnetIntLink---->Router
320 if (garnet_link
->dstBridgeEn
) {
321 DPRINTF(RubyNetwork
, "Enable destination bridge for %s\n",
322 garnet_link
->name());
323 m_routers
[dest
]->addInPort(dst_inport_dirn
,
324 garnet_link
->dstNetBridge
, garnet_link
->dstCredBridge
);
326 m_routers
[dest
]->addInPort(dst_inport_dirn
, net_link
, credit_link
);
329 if (garnet_link
->srcBridgeEn
) {
330 DPRINTF(RubyNetwork
, "Enable source bridge for %s\n",
331 garnet_link
->name());
333 addOutPort(src_outport_dirn
, garnet_link
->srcNetBridge
,
335 link
->m_weight
, garnet_link
->srcCredBridge
,
336 m_routers
[dest
]->get_vc_per_vnet());
338 m_routers
[src
]->addOutPort(src_outport_dirn
, net_link
,
340 link
->m_weight
, credit_link
,
341 m_routers
[dest
]->get_vc_per_vnet());
345 // Total routers in the network
347 GarnetNetwork::getNumRouters()
349 return m_routers
.size();
352 // Get ID of router connected to a NI.
354 GarnetNetwork::get_router_id(int global_ni
, int vnet
)
356 NodeID local_ni
= getLocalNodeID(global_ni
);
358 return m_nis
[local_ni
]->get_router_id(vnet
);
362 GarnetNetwork::regStats()
368 .init(m_virtual_networks
)
369 .name(name() + ".packets_received")
370 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
374 .init(m_virtual_networks
)
375 .name(name() + ".packets_injected")
376 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
379 m_packet_network_latency
380 .init(m_virtual_networks
)
381 .name(name() + ".packet_network_latency")
382 .flags(Stats::oneline
)
385 m_packet_queueing_latency
386 .init(m_virtual_networks
)
387 .name(name() + ".packet_queueing_latency")
388 .flags(Stats::oneline
)
391 for (int i
= 0; i
< m_virtual_networks
; i
++) {
392 m_packets_received
.subname(i
, csprintf("vnet-%i", i
));
393 m_packets_injected
.subname(i
, csprintf("vnet-%i", i
));
394 m_packet_network_latency
.subname(i
, csprintf("vnet-%i", i
));
395 m_packet_queueing_latency
.subname(i
, csprintf("vnet-%i", i
));
398 m_avg_packet_vnet_latency
399 .name(name() + ".average_packet_vnet_latency")
400 .flags(Stats::oneline
);
401 m_avg_packet_vnet_latency
=
402 m_packet_network_latency
/ m_packets_received
;
404 m_avg_packet_vqueue_latency
405 .name(name() + ".average_packet_vqueue_latency")
406 .flags(Stats::oneline
);
407 m_avg_packet_vqueue_latency
=
408 m_packet_queueing_latency
/ m_packets_received
;
410 m_avg_packet_network_latency
411 .name(name() + ".average_packet_network_latency");
412 m_avg_packet_network_latency
=
413 sum(m_packet_network_latency
) / sum(m_packets_received
);
415 m_avg_packet_queueing_latency
416 .name(name() + ".average_packet_queueing_latency");
417 m_avg_packet_queueing_latency
418 = sum(m_packet_queueing_latency
) / sum(m_packets_received
);
421 .name(name() + ".average_packet_latency");
423 = m_avg_packet_network_latency
+ m_avg_packet_queueing_latency
;
427 .init(m_virtual_networks
)
428 .name(name() + ".flits_received")
429 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
433 .init(m_virtual_networks
)
434 .name(name() + ".flits_injected")
435 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
438 m_flit_network_latency
439 .init(m_virtual_networks
)
440 .name(name() + ".flit_network_latency")
441 .flags(Stats::oneline
)
444 m_flit_queueing_latency
445 .init(m_virtual_networks
)
446 .name(name() + ".flit_queueing_latency")
447 .flags(Stats::oneline
)
450 for (int i
= 0; i
< m_virtual_networks
; i
++) {
451 m_flits_received
.subname(i
, csprintf("vnet-%i", i
));
452 m_flits_injected
.subname(i
, csprintf("vnet-%i", i
));
453 m_flit_network_latency
.subname(i
, csprintf("vnet-%i", i
));
454 m_flit_queueing_latency
.subname(i
, csprintf("vnet-%i", i
));
457 m_avg_flit_vnet_latency
458 .name(name() + ".average_flit_vnet_latency")
459 .flags(Stats::oneline
);
460 m_avg_flit_vnet_latency
= m_flit_network_latency
/ m_flits_received
;
462 m_avg_flit_vqueue_latency
463 .name(name() + ".average_flit_vqueue_latency")
464 .flags(Stats::oneline
);
465 m_avg_flit_vqueue_latency
=
466 m_flit_queueing_latency
/ m_flits_received
;
468 m_avg_flit_network_latency
469 .name(name() + ".average_flit_network_latency");
470 m_avg_flit_network_latency
=
471 sum(m_flit_network_latency
) / sum(m_flits_received
);
473 m_avg_flit_queueing_latency
474 .name(name() + ".average_flit_queueing_latency");
475 m_avg_flit_queueing_latency
=
476 sum(m_flit_queueing_latency
) / sum(m_flits_received
);
479 .name(name() + ".average_flit_latency");
481 m_avg_flit_network_latency
+ m_avg_flit_queueing_latency
;
485 m_avg_hops
.name(name() + ".average_hops");
486 m_avg_hops
= m_total_hops
/ sum(m_flits_received
);
489 m_total_ext_in_link_utilization
490 .name(name() + ".ext_in_link_utilization");
491 m_total_ext_out_link_utilization
492 .name(name() + ".ext_out_link_utilization");
493 m_total_int_link_utilization
494 .name(name() + ".int_link_utilization");
495 m_average_link_utilization
496 .name(name() + ".avg_link_utilization");
498 .init(m_virtual_networks
* m_max_vcs_per_vnet
)
499 .name(name() + ".avg_vc_load")
500 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
505 GarnetNetwork::collateStats()
507 RubySystem
*rs
= params()->ruby_system
;
508 double time_delta
= double(curCycle() - rs
->getStartCycle());
510 for (int i
= 0; i
< m_networklinks
.size(); i
++) {
511 link_type type
= m_networklinks
[i
]->getType();
512 int activity
= m_networklinks
[i
]->getLinkUtilization();
515 m_total_ext_in_link_utilization
+= activity
;
516 else if (type
== EXT_OUT_
)
517 m_total_ext_out_link_utilization
+= activity
;
518 else if (type
== INT_
)
519 m_total_int_link_utilization
+= activity
;
521 m_average_link_utilization
+=
522 (double(activity
) / time_delta
);
524 vector
<unsigned int> vc_load
= m_networklinks
[i
]->getVcLoad();
525 for (int j
= 0; j
< vc_load
.size(); j
++) {
526 m_average_vc_load
[j
] += ((double)vc_load
[j
] / time_delta
);
530 // Ask the routers to collate their statistics
531 for (int i
= 0; i
< m_routers
.size(); i
++) {
532 m_routers
[i
]->collateStats();
537 GarnetNetwork::resetStats()
539 for (int i
= 0; i
< m_routers
.size(); i
++) {
540 m_routers
[i
]->resetStats();
542 for (int i
= 0; i
< m_networklinks
.size(); i
++) {
543 m_networklinks
[i
]->resetStats();
545 for (int i
= 0; i
< m_creditlinks
.size(); i
++) {
546 m_creditlinks
[i
]->resetStats();
551 GarnetNetwork::print(ostream
& out
) const
553 out
<< "[GarnetNetwork]";
557 GarnetNetworkParams::create()
559 return new GarnetNetwork(this);
563 GarnetNetwork::functionalWrite(Packet
*pkt
)
565 uint32_t num_functional_writes
= 0;
567 for (unsigned int i
= 0; i
< m_routers
.size(); i
++) {
568 num_functional_writes
+= m_routers
[i
]->functionalWrite(pkt
);
571 for (unsigned int i
= 0; i
< m_nis
.size(); ++i
) {
572 num_functional_writes
+= m_nis
[i
]->functionalWrite(pkt
);
575 for (unsigned int i
= 0; i
< m_networklinks
.size(); ++i
) {
576 num_functional_writes
+= m_networklinks
[i
]->functionalWrite(pkt
);
579 return num_functional_writes
;