1/*
2 * Copyright (c) 2008 Princeton University
3 * Copyright (c) 2016 Georgia Institute of Technology
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 * Authors: Niket Agarwal
30 *          Tushar Krishna
31 */
32
33
34#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
35
36#include <cassert>
37
38#include "base/cast.hh"
39#include "base/stl_helpers.hh"
40#include "mem/ruby/common/NetDest.hh"
41#include "mem/ruby/network/MessageBuffer.hh"
42#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
43#include "mem/ruby/network/garnet2.0/CreditLink.hh"
44#include "mem/ruby/network/garnet2.0/GarnetLink.hh"
45#include "mem/ruby/network/garnet2.0/NetworkInterface.hh"
46#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
47#include "mem/ruby/network/garnet2.0/Router.hh"
48#include "mem/ruby/system/RubySystem.hh"
49
50using namespace std;
51using m5::stl_helpers::deletePointers;
52
53/*
54 * GarnetNetwork sets up the routers and links and collects stats.
55 * Default parameters (GarnetNetwork.py) can be overwritten from command line
56 * (see configs/network/Network.py)
57 */
58
59GarnetNetwork::GarnetNetwork(const Params *p)
60    : Network(p)
61{
62    m_num_rows = p->num_rows;
63    m_ni_flit_size = p->ni_flit_size;
64    m_vcs_per_vnet = p->vcs_per_vnet;
65    m_buffers_per_data_vc = p->buffers_per_data_vc;
66    m_buffers_per_ctrl_vc = p->buffers_per_ctrl_vc;
67    m_routing_algorithm = p->routing_algorithm;
68
69    m_enable_fault_model = p->enable_fault_model;
70    if (m_enable_fault_model)
71        fault_model = p->fault_model;
72
73    m_vnet_type.resize(m_virtual_networks);
74
75    for (int i = 0 ; i < m_virtual_networks ; i++) {
76        if (m_vnet_type_names[i] == "response")
77            m_vnet_type[i] = DATA_VNET_; // carries data (and ctrl) packets
78        else
79            m_vnet_type[i] = CTRL_VNET_; // carries only ctrl packets
80    }
81
82    // record the routers
83    for (vector<BasicRouter*>::const_iterator i =  p->routers.begin();
84         i != p->routers.end(); ++i) {
85        Router* router = safe_cast<Router*>(*i);
86        m_routers.push_back(router);
87
88        // initialize the router's network pointers
89        router->init_net_ptr(this);
90    }
91
92    // record the network interfaces
93    for (vector<ClockedObject*>::const_iterator i = p->netifs.begin();
94         i != p->netifs.end(); ++i) {
95        NetworkInterface *ni = safe_cast<NetworkInterface *>(*i);
96        m_nis.push_back(ni);
97        ni->init_net_ptr(this);
98    }
99}
100
101void
102GarnetNetwork::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            int router_id M5_VAR_USED =
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
146GarnetNetwork::~GarnetNetwork()
147{
148    deletePointers(m_routers);
149    deletePointers(m_nis);
150    deletePointers(m_networklinks);
151    deletePointers(m_creditlinks);
152}
153
154/*
155 * This function creates a link from the Network Interface (NI)
156 * into the Network.
157 * It creates a Network Link from the NI to a Router and a Credit Link from
158 * the Router to the NI
159*/
160
161void
162GarnetNetwork::makeExtInLink(NodeID src, SwitchID dest, BasicLink* link,
163                            const NetDest& routing_table_entry)
164{
165    assert(src < m_nodes);
166
167    GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
168
169    // GarnetExtLink is bi-directional
170    NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_In];
171    net_link->setType(EXT_IN_);
172    CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_In];
173
174    m_networklinks.push_back(net_link);
175    m_creditlinks.push_back(credit_link);
176
177    PortDirection dst_inport_dirn = "Local";
178    m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
179    m_nis[src]->addOutPort(net_link, credit_link, dest);
180}
181
182/*
183 * This function creates a link from the Network to a NI.
184 * It creates a Network Link from a Router to the NI and
185 * a Credit Link from NI to the Router
186*/
187
188void
189GarnetNetwork::makeExtOutLink(SwitchID src, NodeID dest, BasicLink* link,
190                             const NetDest& routing_table_entry)
191{
192    assert(dest < m_nodes);
193    assert(src < m_routers.size());
194    assert(m_routers[src] != NULL);
195
196    GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
197
198    // GarnetExtLink is bi-directional
199    NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_Out];
200    net_link->setType(EXT_OUT_);
201    CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_Out];
202
203    m_networklinks.push_back(net_link);
204    m_creditlinks.push_back(credit_link);
205
206    PortDirection src_outport_dirn = "Local";
207    m_routers[src]->addOutPort(src_outport_dirn, net_link,
208                               routing_table_entry,
209                               link->m_weight, credit_link);
210    m_nis[dest]->addInPort(net_link, credit_link);
211}
212
213/*
214 * This function creates an internal network link between two routers.
215 * It adds both the network link and an opposite credit link.
216*/
217
218void
219GarnetNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
220                                const NetDest& routing_table_entry,
221                                PortDirection src_outport_dirn,
222                                PortDirection dst_inport_dirn)
223{
224    GarnetIntLink* garnet_link = safe_cast<GarnetIntLink*>(link);
225
226    // GarnetIntLink is unidirectional
227    NetworkLink* net_link = garnet_link->m_network_link;
228    net_link->setType(INT_);
229    CreditLink* credit_link = garnet_link->m_credit_link;
230
231    m_networklinks.push_back(net_link);
232    m_creditlinks.push_back(credit_link);
233
234    m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
235    m_routers[src]->addOutPort(src_outport_dirn, net_link,
236                               routing_table_entry,
237                               link->m_weight, credit_link);
238}
239
240// Total routers in the network
241int
242GarnetNetwork::getNumRouters()
243{
244    return m_routers.size();
245}
246
247// Get ID of router connected to a NI.
248int
249GarnetNetwork::get_router_id(int ni)
250{
251    return m_nis[ni]->get_router_id();
252}
253
254void
255GarnetNetwork::regStats()
256{
257    Network::regStats();
258
259    // Packets
260    m_packets_received
261        .init(m_virtual_networks)
262        .name(name() + ".packets_received")
263        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
264        ;
265
266    m_packets_injected
267        .init(m_virtual_networks)
268        .name(name() + ".packets_injected")
269        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
270        ;
271
272    m_packet_network_latency
273        .init(m_virtual_networks)
274        .name(name() + ".packet_network_latency")
275        .flags(Stats::oneline)
276        ;
277
278    m_packet_queueing_latency
279        .init(m_virtual_networks)
280        .name(name() + ".packet_queueing_latency")
281        .flags(Stats::oneline)
282        ;
283
284    for (int i = 0; i < m_virtual_networks; i++) {
285        m_packets_received.subname(i, csprintf("vnet-%i", i));
286        m_packets_injected.subname(i, csprintf("vnet-%i", i));
287        m_packet_network_latency.subname(i, csprintf("vnet-%i", i));
288        m_packet_queueing_latency.subname(i, csprintf("vnet-%i", i));
289    }
290
291    m_avg_packet_vnet_latency
292        .name(name() + ".average_packet_vnet_latency")
293        .flags(Stats::oneline);
294    m_avg_packet_vnet_latency =
295        m_packet_network_latency / m_packets_received;
296
297    m_avg_packet_vqueue_latency
298        .name(name() + ".average_packet_vqueue_latency")
299        .flags(Stats::oneline);
300    m_avg_packet_vqueue_latency =
301        m_packet_queueing_latency / m_packets_received;
302
303    m_avg_packet_network_latency
304        .name(name() + ".average_packet_network_latency");
305    m_avg_packet_network_latency =
306        sum(m_packet_network_latency) / sum(m_packets_received);
307
308    m_avg_packet_queueing_latency
309        .name(name() + ".average_packet_queueing_latency");
310    m_avg_packet_queueing_latency
311        = sum(m_packet_queueing_latency) / sum(m_packets_received);
312
313    m_avg_packet_latency
314        .name(name() + ".average_packet_latency");
315    m_avg_packet_latency
316        = m_avg_packet_network_latency + m_avg_packet_queueing_latency;
317
318    // Flits
319    m_flits_received
320        .init(m_virtual_networks)
321        .name(name() + ".flits_received")
322        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
323        ;
324
325    m_flits_injected
326        .init(m_virtual_networks)
327        .name(name() + ".flits_injected")
328        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
329        ;
330
331    m_flit_network_latency
332        .init(m_virtual_networks)
333        .name(name() + ".flit_network_latency")
334        .flags(Stats::oneline)
335        ;
336
337    m_flit_queueing_latency
338        .init(m_virtual_networks)
339        .name(name() + ".flit_queueing_latency")
340        .flags(Stats::oneline)
341        ;
342
343    for (int i = 0; i < m_virtual_networks; i++) {
344        m_flits_received.subname(i, csprintf("vnet-%i", i));
345        m_flits_injected.subname(i, csprintf("vnet-%i", i));
346        m_flit_network_latency.subname(i, csprintf("vnet-%i", i));
347        m_flit_queueing_latency.subname(i, csprintf("vnet-%i", i));
348    }
349
350    m_avg_flit_vnet_latency
351        .name(name() + ".average_flit_vnet_latency")
352        .flags(Stats::oneline);
353    m_avg_flit_vnet_latency = m_flit_network_latency / m_flits_received;
354
355    m_avg_flit_vqueue_latency
356        .name(name() + ".average_flit_vqueue_latency")
357        .flags(Stats::oneline);
358    m_avg_flit_vqueue_latency =
359        m_flit_queueing_latency / m_flits_received;
360
361    m_avg_flit_network_latency
362        .name(name() + ".average_flit_network_latency");
363    m_avg_flit_network_latency =
364        sum(m_flit_network_latency) / sum(m_flits_received);
365
366    m_avg_flit_queueing_latency
367        .name(name() + ".average_flit_queueing_latency");
368    m_avg_flit_queueing_latency =
369        sum(m_flit_queueing_latency) / sum(m_flits_received);
370
371    m_avg_flit_latency
372        .name(name() + ".average_flit_latency");
373    m_avg_flit_latency =
374        m_avg_flit_network_latency + m_avg_flit_queueing_latency;
375
376
377    // Hops
378    m_avg_hops.name(name() + ".average_hops");
379    m_avg_hops = m_total_hops / sum(m_flits_received);
380
381    // Links
382    m_total_ext_in_link_utilization
383        .name(name() + ".ext_in_link_utilization");
384    m_total_ext_out_link_utilization
385        .name(name() + ".ext_out_link_utilization");
386    m_total_int_link_utilization
387        .name(name() + ".int_link_utilization");
388    m_average_link_utilization
389        .name(name() + ".avg_link_utilization");
390
391    m_average_vc_load
392        .init(m_virtual_networks * m_vcs_per_vnet)
393        .name(name() + ".avg_vc_load")
394        .flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
395        ;
396}
397
398void
399GarnetNetwork::collateStats()
400{
401    RubySystem *rs = params()->ruby_system;
402    double time_delta = double(curCycle() - rs->getStartCycle());
403
404    for (int i = 0; i < m_networklinks.size(); i++) {
405        link_type type = m_networklinks[i]->getType();
406        int activity = m_networklinks[i]->getLinkUtilization();
407
408        if (type == EXT_IN_)
409            m_total_ext_in_link_utilization += activity;
410        else if (type == EXT_OUT_)
411            m_total_ext_out_link_utilization += activity;
412        else if (type == INT_)
413            m_total_int_link_utilization += activity;
414
415        m_average_link_utilization +=
416            (double(activity) / time_delta);
417
418        vector<unsigned int> vc_load = m_networklinks[i]->getVcLoad();
419        for (int j = 0; j < vc_load.size(); j++) {
420            m_average_vc_load[j] += ((double)vc_load[j] / time_delta);
421        }
422    }
423
424    // Ask the routers to collate their statistics
425    for (int i = 0; i < m_routers.size(); i++) {
426        m_routers[i]->collateStats();
427    }
428}
429
430void
431GarnetNetwork::print(ostream& out) const
432{
433    out << "[GarnetNetwork]";
434}
435
436GarnetNetwork *
437GarnetNetworkParams::create()
438{
439    return new GarnetNetwork(this);
440}
441
442uint32_t
443GarnetNetwork::functionalWrite(Packet *pkt)
444{
445    uint32_t num_functional_writes = 0;
446
447    for (unsigned int i = 0; i < m_routers.size(); i++) {
448        num_functional_writes += m_routers[i]->functionalWrite(pkt);
449    }
450
451    for (unsigned int i = 0; i < m_nis.size(); ++i) {
452        num_functional_writes += m_nis[i]->functionalWrite(pkt);
453    }
454
455    for (unsigned int i = 0; i < m_networklinks.size(); ++i) {
456        num_functional_writes += m_networklinks[i]->functionalWrite(pkt);
457    }
458
459    return num_functional_writes;
460}
461