Files
gem5/src/mem/ruby/network/garnet/GarnetNetwork.cc
Daniel R. Carvalho 98ac080ec4 base-stats,misc: Rename Stats namespace as statistics
As part of recent decisions regarding namespace
naming conventions, all namespaces will be changed
to snake case.

::Stats became ::statistics.

"statistics" was chosen over "stats" to avoid generating
conflicts with the already existing variables (there are
way too many "stats" in the codebase), which would make
this patch even more disturbing for the users.

Change-Id: If877b12d7dac356f86e3b3d941bf7558a4fd8719
Signed-off-by: Daniel R. Carvalho <odanrc@yahoo.com.br>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/45421
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
2021-05-29 11:13:49 +00:00

616 lines
21 KiB
C++

/*
* Copyright (c) 2020 Advanced Micro Devices, Inc.
* 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.
*/
#include "mem/ruby/network/garnet/GarnetNetwork.hh"
#include <cassert>
#include "base/cast.hh"
#include "base/compiler.hh"
#include "debug/RubyNetwork.hh"
#include "mem/ruby/common/NetDest.hh"
#include "mem/ruby/network/MessageBuffer.hh"
#include "mem/ruby/network/garnet/CommonTypes.hh"
#include "mem/ruby/network/garnet/CreditLink.hh"
#include "mem/ruby/network/garnet/GarnetLink.hh"
#include "mem/ruby/network/garnet/NetworkInterface.hh"
#include "mem/ruby/network/garnet/NetworkLink.hh"
#include "mem/ruby/network/garnet/Router.hh"
#include "mem/ruby/system/RubySystem.hh"
/*
* 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_max_vcs_per_vnet = 0;
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 (std::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 (std::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);
}
// Print Garnet version
inform("Garnet version %s\n", garnetVersion);
}
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 (std::vector<Router*>::const_iterator i= m_routers.begin();
i != m_routers.end(); ++i) {
Router* router = safe_cast<Router*>(*i);
GEM5_VAR_USED int router_id =
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(std::cout);
router->printFaultVector(std::cout);
}
}
}
/*
* 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 global_src, SwitchID dest, BasicLink* link,
std::vector<NetDest>& routing_table_entry)
{
NodeID local_src = getLocalNodeID(global_src);
assert(local_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_max_vcs_per_vnet = std::max(m_max_vcs_per_vnet,
m_routers[dest]->get_vc_per_vnet());
/*
* We check if a bridge was enabled at any end of the link.
* The bridge is enabled if either of clock domain
* crossing (CDC) or Serializer-Deserializer(SerDes) unit is
* enabled for the link at each end. The bridge encapsulates
* the functionality for both CDC and SerDes and is a Consumer
* object similiar to a NetworkLink.
*
* If a bridge was enabled we connect the NI and Routers to
* bridge before connecting the link. Example, if an external
* bridge is enabled, we would connect:
* NI--->NetworkBridge--->GarnetExtLink---->Router
*/
if (garnet_link->extBridgeEn) {
DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
garnet_link->name());
m_nis[local_src]->
addOutPort(garnet_link->extNetBridge[LinkDirection_In],
garnet_link->extCredBridge[LinkDirection_In],
dest, m_routers[dest]->get_vc_per_vnet());
} else {
m_nis[local_src]->addOutPort(net_link, credit_link, dest,
m_routers[dest]->get_vc_per_vnet());
}
if (garnet_link->intBridgeEn) {
DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
garnet_link->name());
m_routers[dest]->
addInPort(dst_inport_dirn,
garnet_link->intNetBridge[LinkDirection_In],
garnet_link->intCredBridge[LinkDirection_In]);
} else {
m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
}
}
/*
* 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 global_dest,
BasicLink* link,
std::vector<NetDest>& routing_table_entry)
{
NodeID local_dest = getLocalNodeID(global_dest);
assert(local_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_max_vcs_per_vnet = std::max(m_max_vcs_per_vnet,
m_routers[src]->get_vc_per_vnet());
/*
* We check if a bridge was enabled at any end of the link.
* The bridge is enabled if either of clock domain
* crossing (CDC) or Serializer-Deserializer(SerDes) unit is
* enabled for the link at each end. The bridge encapsulates
* the functionality for both CDC and SerDes and is a Consumer
* object similiar to a NetworkLink.
*
* If a bridge was enabled we connect the NI and Routers to
* bridge before connecting the link. Example, if an external
* bridge is enabled, we would connect:
* NI<---NetworkBridge<---GarnetExtLink<----Router
*/
if (garnet_link->extBridgeEn) {
DPRINTF(RubyNetwork, "Enable external bridge for %s\n",
garnet_link->name());
m_nis[local_dest]->
addInPort(garnet_link->extNetBridge[LinkDirection_Out],
garnet_link->extCredBridge[LinkDirection_Out]);
} else {
m_nis[local_dest]->addInPort(net_link, credit_link);
}
if (garnet_link->intBridgeEn) {
DPRINTF(RubyNetwork, "Enable internal bridge for %s\n",
garnet_link->name());
m_routers[src]->
addOutPort(src_outport_dirn,
garnet_link->intNetBridge[LinkDirection_Out],
routing_table_entry, link->m_weight,
garnet_link->intCredBridge[LinkDirection_Out],
m_routers[src]->get_vc_per_vnet());
} else {
m_routers[src]->
addOutPort(src_outport_dirn, net_link,
routing_table_entry,
link->m_weight, credit_link,
m_routers[src]->get_vc_per_vnet());
}
}
/*
* 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,
std::vector<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_max_vcs_per_vnet = std::max(m_max_vcs_per_vnet,
std::max(m_routers[dest]->get_vc_per_vnet(),
m_routers[src]->get_vc_per_vnet()));
/*
* We check if a bridge was enabled at any end of the link.
* The bridge is enabled if either of clock domain
* crossing (CDC) or Serializer-Deserializer(SerDes) unit is
* enabled for the link at each end. The bridge encapsulates
* the functionality for both CDC and SerDes and is a Consumer
* object similiar to a NetworkLink.
*
* If a bridge was enabled we connect the NI and Routers to
* bridge before connecting the link. Example, if a source
* bridge is enabled, we would connect:
* Router--->NetworkBridge--->GarnetIntLink---->Router
*/
if (garnet_link->dstBridgeEn) {
DPRINTF(RubyNetwork, "Enable destination bridge for %s\n",
garnet_link->name());
m_routers[dest]->addInPort(dst_inport_dirn,
garnet_link->dstNetBridge, garnet_link->dstCredBridge);
} else {
m_routers[dest]->addInPort(dst_inport_dirn, net_link, credit_link);
}
if (garnet_link->srcBridgeEn) {
DPRINTF(RubyNetwork, "Enable source bridge for %s\n",
garnet_link->name());
m_routers[src]->
addOutPort(src_outport_dirn, garnet_link->srcNetBridge,
routing_table_entry,
link->m_weight, garnet_link->srcCredBridge,
m_routers[dest]->get_vc_per_vnet());
} else {
m_routers[src]->addOutPort(src_outport_dirn, net_link,
routing_table_entry,
link->m_weight, credit_link,
m_routers[dest]->get_vc_per_vnet());
}
}
// 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 global_ni, int vnet)
{
NodeID local_ni = getLocalNodeID(global_ni);
return m_nis[local_ni]->get_router_id(vnet);
}
void
GarnetNetwork::regStats()
{
Network::regStats();
// Packets
m_packets_received
.init(m_virtual_networks)
.name(name() + ".packets_received")
.flags(statistics::pdf | statistics::total | statistics::nozero |
statistics::oneline)
;
m_packets_injected
.init(m_virtual_networks)
.name(name() + ".packets_injected")
.flags(statistics::pdf | statistics::total | statistics::nozero |
statistics::oneline)
;
m_packet_network_latency
.init(m_virtual_networks)
.name(name() + ".packet_network_latency")
.flags(statistics::oneline)
;
m_packet_queueing_latency
.init(m_virtual_networks)
.name(name() + ".packet_queueing_latency")
.flags(statistics::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(statistics::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(statistics::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(statistics::pdf | statistics::total | statistics::nozero |
statistics::oneline)
;
m_flits_injected
.init(m_virtual_networks)
.name(name() + ".flits_injected")
.flags(statistics::pdf | statistics::total | statistics::nozero |
statistics::oneline)
;
m_flit_network_latency
.init(m_virtual_networks)
.name(name() + ".flit_network_latency")
.flags(statistics::oneline)
;
m_flit_queueing_latency
.init(m_virtual_networks)
.name(name() + ".flit_queueing_latency")
.flags(statistics::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(statistics::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(statistics::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_max_vcs_per_vnet)
.name(name() + ".avg_vc_load")
.flags(statistics::pdf | statistics::total | statistics::nozero |
statistics::oneline)
;
// Traffic distribution
for (int source = 0; source < m_routers.size(); ++source) {
m_data_traffic_distribution.push_back(
std::vector<statistics::Scalar *>());
m_ctrl_traffic_distribution.push_back(
std::vector<statistics::Scalar *>());
for (int dest = 0; dest < m_routers.size(); ++dest) {
statistics::Scalar *data_packets = new statistics::Scalar();
statistics::Scalar *ctrl_packets = new statistics::Scalar();
data_packets->name(name() + ".data_traffic_distribution." + "n" +
std::to_string(source) + "." + "n" + std::to_string(dest));
m_data_traffic_distribution[source].push_back(data_packets);
ctrl_packets->name(name() + ".ctrl_traffic_distribution." + "n" +
std::to_string(source) + "." + "n" + std::to_string(dest));
m_ctrl_traffic_distribution[source].push_back(ctrl_packets);
}
}
}
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);
std::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::resetStats()
{
for (int i = 0; i < m_routers.size(); i++) {
m_routers[i]->resetStats();
}
for (int i = 0; i < m_networklinks.size(); i++) {
m_networklinks[i]->resetStats();
}
for (int i = 0; i < m_creditlinks.size(); i++) {
m_creditlinks[i]->resetStats();
}
}
void
GarnetNetwork::print(std::ostream& out) const
{
out << "[GarnetNetwork]";
}
void
GarnetNetwork::update_traffic_distribution(RouteInfo route)
{
int src_node = route.src_router;
int dest_node = route.dest_router;
int vnet = route.vnet;
if (m_vnet_type[vnet] == DATA_VNET_)
(*m_data_traffic_distribution[src_node][dest_node])++;
else
(*m_ctrl_traffic_distribution[src_node][dest_node])++;
}
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;
}