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/garnet/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/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"
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);
97 // Print Garnet version
98 inform("Garnet version %s\n", garnetVersion
);
102 GarnetNetwork::init()
106 for (int i
=0; i
< m_nodes
; i
++) {
107 m_nis
[i
]->addNode(m_toNetQueues
[i
], m_fromNetQueues
[i
]);
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);
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());
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
);
147 * This function creates a link from the Network Interface (NI)
149 * It creates a Network Link from the NI to a Router and a Credit Link from
150 * the Router to the NI
154 GarnetNetwork::makeExtInLink(NodeID global_src
, SwitchID dest
, BasicLink
* link
,
155 std::vector
<NetDest
>& routing_table_entry
)
157 NodeID local_src
= getLocalNodeID(global_src
);
158 assert(local_src
< m_nodes
);
160 GarnetExtLink
* garnet_link
= safe_cast
<GarnetExtLink
*>(link
);
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
];
167 m_networklinks
.push_back(net_link
);
168 m_creditlinks
.push_back(credit_link
);
170 PortDirection dst_inport_dirn
= "Local";
172 m_max_vcs_per_vnet
= std::max(m_max_vcs_per_vnet
,
173 m_routers
[dest
]->get_vc_per_vnet());
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.
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
188 if (garnet_link
->extBridgeEn
) {
189 DPRINTF(RubyNetwork
, "Enable external bridge for %s\n",
190 garnet_link
->name());
192 addOutPort(garnet_link
->extNetBridge
[LinkDirection_In
],
193 garnet_link
->extCredBridge
[LinkDirection_In
],
194 dest
, m_routers
[dest
]->get_vc_per_vnet());
196 m_nis
[local_src
]->addOutPort(net_link
, credit_link
, dest
,
197 m_routers
[dest
]->get_vc_per_vnet());
200 if (garnet_link
->intBridgeEn
) {
201 DPRINTF(RubyNetwork
, "Enable internal bridge for %s\n",
202 garnet_link
->name());
204 addInPort(dst_inport_dirn
,
205 garnet_link
->intNetBridge
[LinkDirection_In
],
206 garnet_link
->intCredBridge
[LinkDirection_In
]);
208 m_routers
[dest
]->addInPort(dst_inport_dirn
, net_link
, credit_link
);
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
220 GarnetNetwork::makeExtOutLink(SwitchID src
, NodeID global_dest
,
222 std::vector
<NetDest
>& routing_table_entry
)
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
);
229 GarnetExtLink
* garnet_link
= safe_cast
<GarnetExtLink
*>(link
);
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
];
236 m_networklinks
.push_back(net_link
);
237 m_creditlinks
.push_back(credit_link
);
239 PortDirection src_outport_dirn
= "Local";
241 m_max_vcs_per_vnet
= std::max(m_max_vcs_per_vnet
,
242 m_routers
[src
]->get_vc_per_vnet());
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.
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
257 if (garnet_link
->extBridgeEn
) {
258 DPRINTF(RubyNetwork
, "Enable external bridge for %s\n",
259 garnet_link
->name());
261 addInPort(garnet_link
->extNetBridge
[LinkDirection_Out
],
262 garnet_link
->extCredBridge
[LinkDirection_Out
]);
264 m_nis
[local_dest
]->addInPort(net_link
, credit_link
);
267 if (garnet_link
->intBridgeEn
) {
268 DPRINTF(RubyNetwork
, "Enable internal bridge for %s\n",
269 garnet_link
->name());
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());
278 addOutPort(src_outport_dirn
, net_link
,
280 link
->m_weight
, credit_link
,
281 m_routers
[src
]->get_vc_per_vnet());
286 * This function creates an internal network link between two routers.
287 * It adds both the network link and an opposite credit link.
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
)
296 GarnetIntLink
* garnet_link
= safe_cast
<GarnetIntLink
*>(link
);
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
;
303 m_networklinks
.push_back(net_link
);
304 m_creditlinks
.push_back(credit_link
);
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()));
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.
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
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
);
329 m_routers
[dest
]->addInPort(dst_inport_dirn
, net_link
, credit_link
);
332 if (garnet_link
->srcBridgeEn
) {
333 DPRINTF(RubyNetwork
, "Enable source bridge for %s\n",
334 garnet_link
->name());
336 addOutPort(src_outport_dirn
, garnet_link
->srcNetBridge
,
338 link
->m_weight
, garnet_link
->srcCredBridge
,
339 m_routers
[dest
]->get_vc_per_vnet());
341 m_routers
[src
]->addOutPort(src_outport_dirn
, net_link
,
343 link
->m_weight
, credit_link
,
344 m_routers
[dest
]->get_vc_per_vnet());
348 // Total routers in the network
350 GarnetNetwork::getNumRouters()
352 return m_routers
.size();
355 // Get ID of router connected to a NI.
357 GarnetNetwork::get_router_id(int global_ni
, int vnet
)
359 NodeID local_ni
= getLocalNodeID(global_ni
);
361 return m_nis
[local_ni
]->get_router_id(vnet
);
365 GarnetNetwork::regStats()
371 .init(m_virtual_networks
)
372 .name(name() + ".packets_received")
373 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
377 .init(m_virtual_networks
)
378 .name(name() + ".packets_injected")
379 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
382 m_packet_network_latency
383 .init(m_virtual_networks
)
384 .name(name() + ".packet_network_latency")
385 .flags(Stats::oneline
)
388 m_packet_queueing_latency
389 .init(m_virtual_networks
)
390 .name(name() + ".packet_queueing_latency")
391 .flags(Stats::oneline
)
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
));
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
;
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
;
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
);
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
);
424 .name(name() + ".average_packet_latency");
426 = m_avg_packet_network_latency
+ m_avg_packet_queueing_latency
;
430 .init(m_virtual_networks
)
431 .name(name() + ".flits_received")
432 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
436 .init(m_virtual_networks
)
437 .name(name() + ".flits_injected")
438 .flags(Stats::pdf
| Stats::total
| Stats::nozero
| Stats::oneline
)
441 m_flit_network_latency
442 .init(m_virtual_networks
)
443 .name(name() + ".flit_network_latency")
444 .flags(Stats::oneline
)
447 m_flit_queueing_latency
448 .init(m_virtual_networks
)
449 .name(name() + ".flit_queueing_latency")
450 .flags(Stats::oneline
)
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
));
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
;
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
;
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
);
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
);
482 .name(name() + ".average_flit_latency");
484 m_avg_flit_network_latency
+ m_avg_flit_queueing_latency
;
488 m_avg_hops
.name(name() + ".average_hops");
489 m_avg_hops
= m_total_hops
/ sum(m_flits_received
);
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");
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
)
508 GarnetNetwork::collateStats()
510 RubySystem
*rs
= params().ruby_system
;
511 double time_delta
= double(curCycle() - rs
->getStartCycle());
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();
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
;
524 m_average_link_utilization
+=
525 (double(activity
) / time_delta
);
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
);
533 // Ask the routers to collate their statistics
534 for (int i
= 0; i
< m_routers
.size(); i
++) {
535 m_routers
[i
]->collateStats();
540 GarnetNetwork::resetStats()
542 for (int i
= 0; i
< m_routers
.size(); i
++) {
543 m_routers
[i
]->resetStats();
545 for (int i
= 0; i
< m_networklinks
.size(); i
++) {
546 m_networklinks
[i
]->resetStats();
548 for (int i
= 0; i
< m_creditlinks
.size(); i
++) {
549 m_creditlinks
[i
]->resetStats();
554 GarnetNetwork::print(ostream
& out
) const
556 out
<< "[GarnetNetwork]";
560 GarnetNetworkParams::create() const
562 return new GarnetNetwork(*this);
566 GarnetNetwork::functionalWrite(Packet
*pkt
)
568 uint32_t num_functional_writes
= 0;
570 for (unsigned int i
= 0; i
< m_routers
.size(); i
++) {
571 num_functional_writes
+= m_routers
[i
]->functionalWrite(pkt
);
574 for (unsigned int i
= 0; i
< m_nis
.size(); ++i
) {
575 num_functional_writes
+= m_nis
[i
]->functionalWrite(pkt
);
578 for (unsigned int i
= 0; i
< m_networklinks
.size(); ++i
) {
579 num_functional_writes
+= m_networklinks
[i
]->functionalWrite(pkt
);
582 return num_functional_writes
;