blob: 5fa76445792f9af29ac569fbcb5e4bc4e0b52766 [file] [log] [blame]
/*
* Copyright (c) 2008 Princeton University
* Copyright (c) 2016 Georgia Institute of Technology
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Niket Agarwal
* Tushar Krishna
*/
#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh"
#include <cassert>
#include "base/cast.hh"
#include "base/stl_helpers.hh"
#include "mem/ruby/common/NetDest.hh"
#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/garnet2.0/CommonTypes.hh"
#include "mem/ruby/network/garnet2.0/CreditLink.hh"
#include "mem/ruby/network/garnet2.0/GarnetLink.hh"
#include "mem/ruby/network/garnet2.0/NetworkInterface.hh"
#include "mem/ruby/network/garnet2.0/NetworkLink.hh"
#include "mem/ruby/network/garnet2.0/Router.hh"
#include "mem/ruby/system/RubySystem.hh"
using namespace std;
using m5::stl_helpers::deletePointers;
/*
* GarnetNetwork sets up the routers and links and collects stats.
* Default parameters (GarnetNetwork.py) can be overwritten from command line
* (see configs/network/Network.py)
*/
GarnetNetwork::GarnetNetwork(const Params *p)
: Network(p)
{
m_num_rows = p->num_rows;
m_ni_flit_size = p->ni_flit_size;
m_vcs_per_vnet = p->vcs_per_vnet;
m_buffers_per_data_vc = p->buffers_per_data_vc;
m_buffers_per_ctrl_vc = p->buffers_per_ctrl_vc;
m_routing_algorithm = p->routing_algorithm;
m_enable_fault_model = p->enable_fault_model;
if (m_enable_fault_model)
fault_model = p->fault_model;
m_vnet_type.resize(m_virtual_networks);
for (int i = 0 ; i < m_virtual_networks ; i++) {
if (m_vnet_type_names[i] == "response")
m_vnet_type[i] = DATA_VNET_; // carries data (and ctrl) packets
else
m_vnet_type[i] = CTRL_VNET_; // carries only ctrl packets
}
// record the routers
for (vector<BasicRouter*>::const_iterator i = p->routers.begin();
i != p->routers.end(); ++i) {
Router* router = safe_cast<Router*>(*i);
m_routers.push_back(router);
// initialize the router's network pointers
router->init_net_ptr(this);
}
// record the network interfaces
for (vector<ClockedObject*>::const_iterator i = p->netifs.begin();
i != p->netifs.end(); ++i) {
NetworkInterface *ni = safe_cast<NetworkInterface *>(*i);
m_nis.push_back(ni);
ni->init_net_ptr(this);
}
}
void
GarnetNetwork::init()
{
Network::init();
for (int i=0; i < m_nodes; i++) {
m_nis[i]->addNode(m_toNetQueues[i], m_fromNetQueues[i]);
}
// The topology pointer should have already been initialized in the
// parent network constructor
assert(m_topology_ptr != NULL);
m_topology_ptr->createLinks(this);
// Initialize topology specific parameters
if (getNumRows() > 0) {
// Only for Mesh topology
// m_num_rows and m_num_cols are only used for
// implementing XY or custom routing in RoutingUnit.cc
m_num_rows = getNumRows();
m_num_cols = m_routers.size() / m_num_rows;
assert(m_num_rows * m_num_cols == m_routers.size());
} else {
m_num_rows = -1;
m_num_cols = -1;
}
// FaultModel: declare each router to the fault model
if (isFaultModelEnabled()) {
for (vector<Router*>::const_iterator i= m_routers.begin();
i != m_routers.end(); ++i) {
Router* router = safe_cast<Router*>(*i);
int router_id M5_VAR_USED =
fault_model->declare_router(router->get_num_inports(),
router->get_num_outports(),
router->get_vc_per_vnet(),
getBuffersPerDataVC(),
getBuffersPerCtrlVC());
assert(router_id == router->get_id());
router->printAggregateFaultProbability(cout);
router->printFaultVector(cout);
}
}
}
GarnetNetwork::~GarnetNetwork()
{
deletePointers(m_routers);
deletePointers(m_nis);
deletePointers(m_networklinks);
deletePointers(m_creditlinks);
}
/*
* This function creates a link from the Network Interface (NI)
* into the Network.
* It creates a Network Link from the NI to a Router and a Credit Link from
* the Router to the NI
*/
void
GarnetNetwork::makeExtInLink(NodeID src, SwitchID dest, BasicLink* link,
const NetDest& routing_table_entry)
{
assert(src < m_nodes);
GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
// GarnetExtLink is bi-directional
NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_In];
net_link->setType(EXT_IN_);
CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_In];
m_networklinks.push_back(net_link);
m_creditlinks.push_back(credit_link);
PortDirection dst_inport_dirn = "Local";
m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
m_nis[src]->addOutPort(net_link, credit_link, dest);
}
/*
* This function creates a link from the Network to a NI.
* It creates a Network Link from a Router to the NI and
* a Credit Link from NI to the Router
*/
void
GarnetNetwork::makeExtOutLink(SwitchID src, NodeID dest, BasicLink* link,
const NetDest& routing_table_entry)
{
assert(dest < m_nodes);
assert(src < m_routers.size());
assert(m_routers[src] != NULL);
GarnetExtLink* garnet_link = safe_cast<GarnetExtLink*>(link);
// GarnetExtLink is bi-directional
NetworkLink* net_link = garnet_link->m_network_links[LinkDirection_Out];
net_link->setType(EXT_OUT_);
CreditLink* credit_link = garnet_link->m_credit_links[LinkDirection_Out];
m_networklinks.push_back(net_link);
m_creditlinks.push_back(credit_link);
PortDirection src_outport_dirn = "Local";
m_routers[src]->addOutPort(src_outport_dirn, net_link,
routing_table_entry,
link->m_weight, credit_link);
m_nis[dest]->addInPort(net_link, credit_link);
}
/*
* This function creates an internal network link between two routers.
* It adds both the network link and an opposite credit link.
*/
void
GarnetNetwork::makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link,
const NetDest& routing_table_entry,
PortDirection src_outport_dirn,
PortDirection dst_inport_dirn)
{
GarnetIntLink* garnet_link = safe_cast<GarnetIntLink*>(link);
// GarnetIntLink is unidirectional
NetworkLink* net_link = garnet_link->m_network_link;
net_link->setType(INT_);
CreditLink* credit_link = garnet_link->m_credit_link;
m_networklinks.push_back(net_link);
m_creditlinks.push_back(credit_link);
m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
m_routers[src]->addOutPort(src_outport_dirn, net_link,
routing_table_entry,
link->m_weight, credit_link);
}
// Total routers in the network
int
GarnetNetwork::getNumRouters()
{
return m_routers.size();
}
// Get ID of router connected to a NI.
int
GarnetNetwork::get_router_id(int ni)
{
return m_nis[ni]->get_router_id();
}
void
GarnetNetwork::regStats()
{
Network::regStats();
// Packets
m_packets_received
.init(m_virtual_networks)
.name(name() + ".packets_received")
.flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
;
m_packets_injected
.init(m_virtual_networks)
.name(name() + ".packets_injected")
.flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
;
m_packet_network_latency
.init(m_virtual_networks)
.name(name() + ".packet_network_latency")
.flags(Stats::oneline)
;
m_packet_queueing_latency
.init(m_virtual_networks)
.name(name() + ".packet_queueing_latency")
.flags(Stats::oneline)
;
for (int i = 0; i < m_virtual_networks; i++) {
m_packets_received.subname(i, csprintf("vnet-%i", i));
m_packets_injected.subname(i, csprintf("vnet-%i", i));
m_packet_network_latency.subname(i, csprintf("vnet-%i", i));
m_packet_queueing_latency.subname(i, csprintf("vnet-%i", i));
}
m_avg_packet_vnet_latency
.name(name() + ".average_packet_vnet_latency")
.flags(Stats::oneline);
m_avg_packet_vnet_latency =
m_packet_network_latency / m_packets_received;
m_avg_packet_vqueue_latency
.name(name() + ".average_packet_vqueue_latency")
.flags(Stats::oneline);
m_avg_packet_vqueue_latency =
m_packet_queueing_latency / m_packets_received;
m_avg_packet_network_latency
.name(name() + ".average_packet_network_latency");
m_avg_packet_network_latency =
sum(m_packet_network_latency) / sum(m_packets_received);
m_avg_packet_queueing_latency
.name(name() + ".average_packet_queueing_latency");
m_avg_packet_queueing_latency
= sum(m_packet_queueing_latency) / sum(m_packets_received);
m_avg_packet_latency
.name(name() + ".average_packet_latency");
m_avg_packet_latency
= m_avg_packet_network_latency + m_avg_packet_queueing_latency;
// Flits
m_flits_received
.init(m_virtual_networks)
.name(name() + ".flits_received")
.flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
;
m_flits_injected
.init(m_virtual_networks)
.name(name() + ".flits_injected")
.flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
;
m_flit_network_latency
.init(m_virtual_networks)
.name(name() + ".flit_network_latency")
.flags(Stats::oneline)
;
m_flit_queueing_latency
.init(m_virtual_networks)
.name(name() + ".flit_queueing_latency")
.flags(Stats::oneline)
;
for (int i = 0; i < m_virtual_networks; i++) {
m_flits_received.subname(i, csprintf("vnet-%i", i));
m_flits_injected.subname(i, csprintf("vnet-%i", i));
m_flit_network_latency.subname(i, csprintf("vnet-%i", i));
m_flit_queueing_latency.subname(i, csprintf("vnet-%i", i));
}
m_avg_flit_vnet_latency
.name(name() + ".average_flit_vnet_latency")
.flags(Stats::oneline);
m_avg_flit_vnet_latency = m_flit_network_latency / m_flits_received;
m_avg_flit_vqueue_latency
.name(name() + ".average_flit_vqueue_latency")
.flags(Stats::oneline);
m_avg_flit_vqueue_latency =
m_flit_queueing_latency / m_flits_received;
m_avg_flit_network_latency
.name(name() + ".average_flit_network_latency");
m_avg_flit_network_latency =
sum(m_flit_network_latency) / sum(m_flits_received);
m_avg_flit_queueing_latency
.name(name() + ".average_flit_queueing_latency");
m_avg_flit_queueing_latency =
sum(m_flit_queueing_latency) / sum(m_flits_received);
m_avg_flit_latency
.name(name() + ".average_flit_latency");
m_avg_flit_latency =
m_avg_flit_network_latency + m_avg_flit_queueing_latency;
// Hops
m_avg_hops.name(name() + ".average_hops");
m_avg_hops = m_total_hops / sum(m_flits_received);
// Links
m_total_ext_in_link_utilization
.name(name() + ".ext_in_link_utilization");
m_total_ext_out_link_utilization
.name(name() + ".ext_out_link_utilization");
m_total_int_link_utilization
.name(name() + ".int_link_utilization");
m_average_link_utilization
.name(name() + ".avg_link_utilization");
m_average_vc_load
.init(m_virtual_networks * m_vcs_per_vnet)
.name(name() + ".avg_vc_load")
.flags(Stats::pdf | Stats::total | Stats::nozero | Stats::oneline)
;
}
void
GarnetNetwork::collateStats()
{
RubySystem *rs = params()->ruby_system;
double time_delta = double(curCycle() - rs->getStartCycle());
for (int i = 0; i < m_networklinks.size(); i++) {
link_type type = m_networklinks[i]->getType();
int activity = m_networklinks[i]->getLinkUtilization();
if (type == EXT_IN_)
m_total_ext_in_link_utilization += activity;
else if (type == EXT_OUT_)
m_total_ext_out_link_utilization += activity;
else if (type == INT_)
m_total_int_link_utilization += activity;
m_average_link_utilization +=
(double(activity) / time_delta);
vector<unsigned int> vc_load = m_networklinks[i]->getVcLoad();
for (int j = 0; j < vc_load.size(); j++) {
m_average_vc_load[j] += ((double)vc_load[j] / time_delta);
}
}
// Ask the routers to collate their statistics
for (int i = 0; i < m_routers.size(); i++) {
m_routers[i]->collateStats();
}
}
void
GarnetNetwork::print(ostream& out) const
{
out << "[GarnetNetwork]";
}
GarnetNetwork *
GarnetNetworkParams::create()
{
return new GarnetNetwork(this);
}
uint32_t
GarnetNetwork::functionalWrite(Packet *pkt)
{
uint32_t num_functional_writes = 0;
for (unsigned int i = 0; i < m_routers.size(); i++) {
num_functional_writes += m_routers[i]->functionalWrite(pkt);
}
for (unsigned int i = 0; i < m_nis.size(); ++i) {
num_functional_writes += m_nis[i]->functionalWrite(pkt);
}
for (unsigned int i = 0; i < m_networklinks.size(); ++i) {
num_functional_writes += m_networklinks[i]->functionalWrite(pkt);
}
return num_functional_writes;
}