From dbe8892b761067c5c1e828f889a513ea085b044f Mon Sep 17 00:00:00 2001 From: Tushar Krishna Date: Thu, 6 Oct 2016 14:35:22 -0400 Subject: [PATCH] ruby: garnet2.0 Revamped version of garnet with more optimized single-cycle routers, more configurability, and cleaner code. --- configs/network/Network.py | 55 ++- configs/topologies/Crossbar.py | 15 +- configs/topologies/MeshDirCorners_XY.py | 41 +- configs/topologies/Mesh_XY.py | 21 +- configs/topologies/Mesh_westfirst.py | 20 +- configs/topologies/Pt2Pt.py | 20 +- src/base/statistics.cc | 4 +- src/mem/ruby/network/BasicRouter.py | 2 + src/mem/ruby/network/garnet2.0/CommonTypes.hh | 65 +++ src/mem/ruby/network/garnet2.0/Credit.cc | 46 ++ src/mem/ruby/network/garnet2.0/Credit.hh | 60 +++ src/mem/ruby/network/garnet2.0/CreditLink.hh | 47 ++ .../ruby/network/garnet2.0/CrossbarSwitch.cc | 112 +++++ .../ruby/network/garnet2.0/CrossbarSwitch.hh | 72 +++ src/mem/ruby/network/garnet2.0/GarnetLink.cc | 94 ++++ src/mem/ruby/network/garnet2.0/GarnetLink.hh | 97 ++++ src/mem/ruby/network/garnet2.0/GarnetLink.py | 79 +++ .../ruby/network/garnet2.0/GarnetNetwork.cc | 460 ++++++++++++++++++ .../ruby/network/garnet2.0/GarnetNetwork.hh | 208 ++++++++ .../ruby/network/garnet2.0/GarnetNetwork.py | 68 +++ src/mem/ruby/network/garnet2.0/InputUnit.cc | 171 +++++++ src/mem/ruby/network/garnet2.0/InputUnit.hh | 170 +++++++ .../network/garnet2.0/NetworkInterface.cc | 443 +++++++++++++++++ .../network/garnet2.0/NetworkInterface.hh | 108 ++++ src/mem/ruby/network/garnet2.0/NetworkLink.cc | 94 ++++ src/mem/ruby/network/garnet2.0/NetworkLink.hh | 88 ++++ src/mem/ruby/network/garnet2.0/OutVcState.cc | 65 +++ src/mem/ruby/network/garnet2.0/OutVcState.hh | 70 +++ src/mem/ruby/network/garnet2.0/OutputUnit.cc | 168 +++++++ src/mem/ruby/network/garnet2.0/OutputUnit.hh | 113 +++++ src/mem/ruby/network/garnet2.0/README.txt | 71 +++ src/mem/ruby/network/garnet2.0/Router.cc | 296 +++++++++++ src/mem/ruby/network/garnet2.0/Router.hh | 140 ++++++ src/mem/ruby/network/garnet2.0/RoutingUnit.cc | 241 +++++++++ src/mem/ruby/network/garnet2.0/RoutingUnit.hh | 89 ++++ src/mem/ruby/network/garnet2.0/SConscript | 53 ++ .../ruby/network/garnet2.0/SwitchAllocator.cc | 389 +++++++++++++++ .../ruby/network/garnet2.0/SwitchAllocator.hh | 88 ++++ .../ruby/network/garnet2.0/VirtualChannel.cc | 85 ++++ .../ruby/network/garnet2.0/VirtualChannel.hh | 101 ++++ src/mem/ruby/network/garnet2.0/flit.cc | 85 ++++ src/mem/ruby/network/garnet2.0/flit.hh | 122 +++++ src/mem/ruby/network/garnet2.0/flitBuffer.cc | 93 ++++ src/mem/ruby/network/garnet2.0/flitBuffer.hh | 93 ++++ 44 files changed, 4982 insertions(+), 40 deletions(-) create mode 100644 src/mem/ruby/network/garnet2.0/CommonTypes.hh create mode 100644 src/mem/ruby/network/garnet2.0/Credit.cc create mode 100644 src/mem/ruby/network/garnet2.0/Credit.hh create mode 100644 src/mem/ruby/network/garnet2.0/CreditLink.hh create mode 100644 src/mem/ruby/network/garnet2.0/CrossbarSwitch.cc create mode 100644 src/mem/ruby/network/garnet2.0/CrossbarSwitch.hh create mode 100644 src/mem/ruby/network/garnet2.0/GarnetLink.cc create mode 100644 src/mem/ruby/network/garnet2.0/GarnetLink.hh create mode 100644 src/mem/ruby/network/garnet2.0/GarnetLink.py create mode 100644 src/mem/ruby/network/garnet2.0/GarnetNetwork.cc create mode 100644 src/mem/ruby/network/garnet2.0/GarnetNetwork.hh create mode 100644 src/mem/ruby/network/garnet2.0/GarnetNetwork.py create mode 100644 src/mem/ruby/network/garnet2.0/InputUnit.cc create mode 100644 src/mem/ruby/network/garnet2.0/InputUnit.hh create mode 100644 src/mem/ruby/network/garnet2.0/NetworkInterface.cc create mode 100644 src/mem/ruby/network/garnet2.0/NetworkInterface.hh create mode 100644 src/mem/ruby/network/garnet2.0/NetworkLink.cc create mode 100644 src/mem/ruby/network/garnet2.0/NetworkLink.hh create mode 100644 src/mem/ruby/network/garnet2.0/OutVcState.cc create mode 100644 src/mem/ruby/network/garnet2.0/OutVcState.hh create mode 100644 src/mem/ruby/network/garnet2.0/OutputUnit.cc create mode 100644 src/mem/ruby/network/garnet2.0/OutputUnit.hh create mode 100644 src/mem/ruby/network/garnet2.0/README.txt create mode 100644 src/mem/ruby/network/garnet2.0/Router.cc create mode 100644 src/mem/ruby/network/garnet2.0/Router.hh create mode 100644 src/mem/ruby/network/garnet2.0/RoutingUnit.cc create mode 100644 src/mem/ruby/network/garnet2.0/RoutingUnit.hh create mode 100644 src/mem/ruby/network/garnet2.0/SConscript create mode 100644 src/mem/ruby/network/garnet2.0/SwitchAllocator.cc create mode 100644 src/mem/ruby/network/garnet2.0/SwitchAllocator.hh create mode 100644 src/mem/ruby/network/garnet2.0/VirtualChannel.cc create mode 100644 src/mem/ruby/network/garnet2.0/VirtualChannel.hh create mode 100644 src/mem/ruby/network/garnet2.0/flit.cc create mode 100644 src/mem/ruby/network/garnet2.0/flit.hh create mode 100644 src/mem/ruby/network/garnet2.0/flitBuffer.cc create mode 100644 src/mem/ruby/network/garnet2.0/flitBuffer.hh diff --git a/configs/network/Network.py b/configs/network/Network.py index 871682ff1..3c15a4f79 100644 --- a/configs/network/Network.py +++ b/configs/network/Network.py @@ -38,25 +38,44 @@ def define_options(parser): parser.add_option("--topology", type="string", default="Crossbar", help="check configs/topologies for complete set") - parser.add_option("--mesh-rows", type="int", default=1, + parser.add_option("--mesh-rows", type="int", default=0, help="the number of rows in the mesh topology") - parser.add_option("--garnet-network", type="choice", - choices=['fixed', 'flexible'], help="'fixed'|'flexible'") - parser.add_option("--network-fault-model", action="store_true", default=False, - help="enable network fault model: see src/mem/ruby/network/fault_model/") + parser.add_option("--network", type="choice", default="simple", + choices=['simple', 'garnet2.0'], + help="'simple'|'garnet2.0'") + parser.add_option("--router-latency", action="store", type="int", + default=1, + help="""number of pipeline stages in the garnet router. + Has to be >= 1. + Can be over-ridden on a per router basis + in the topology file.""") + parser.add_option("--link-latency", action="store", type="int", default=1, + help="""latency of each link the simple/garnet networks. + Has to be >= 1. + Can be over-ridden on a per link basis + in the topology file.""") + parser.add_option("--link-width-bits", action="store", type="int", + default=128, + help="width in bits for all links inside garnet.") + parser.add_option("--vcs-per-vnet", action="store", type="int", default=4, + help="""number of virtual channels per virtual network + inside garnet network.""") + parser.add_option("--routing-algorithm", action="store", type="int", + default=0, + help="""routing algorithm in network. + 0: weight-based table + 1: XY (for Mesh. see garnet2.0/RoutingUnit.cc) + 2: Custom (see garnet2.0/RoutingUnit.cc""") + parser.add_option("--network-fault-model", action="store_true", + default=False, + help="""enable network fault model: + see src/mem/ruby/network/fault_model/""") def create_network(options, ruby): # Set the network classes based on the command line options - if options.garnet_network == "fixed": - NetworkClass = GarnetNetwork_d - IntLinkClass = GarnetIntLink_d - ExtLinkClass = GarnetExtLink_d - RouterClass = GarnetRouter_d - InterfaceClass = GarnetNetworkInterface_d - - elif options.garnet_network == "flexible": + if options.network == "garnet2.0": NetworkClass = GarnetNetwork IntLinkClass = GarnetIntLink ExtLinkClass = GarnetExtLink @@ -79,7 +98,13 @@ def create_network(options, ruby): def init_network(options, network, InterfaceClass): - if options.garnet_network is None: + if options.network == "garnet2.0": + network.num_rows = options.mesh_rows + network.vcs_per_vnet = options.vcs_per_vnet + network.ni_flit_size = options.link_width_bits / 8 + network.routing_algorithm = options.routing_algorithm + + if options.network == "simple": network.setup_buffers() if InterfaceClass != None: @@ -88,6 +113,6 @@ def init_network(options, network, InterfaceClass): network.netifs = netifs if options.network_fault_model: - assert(options.garnet_network == "fixed") + assert(options.network == "garnet2.0") network.enable_fault_model = True network.fault_model = FaultModel() diff --git a/configs/topologies/Crossbar.py b/configs/topologies/Crossbar.py index 35d20de34..447b1c597 100644 --- a/configs/topologies/Crossbar.py +++ b/configs/topologies/Crossbar.py @@ -35,6 +35,12 @@ class Crossbar(SimpleTopology): description='Crossbar' def makeTopology(self, options, network, IntLink, ExtLink, Router): + + # default values for link latency and router latency. + # Can be over-ridden on a per link/router basis + link_latency = options.link_latency # used by simple and garnet + router_latency = options.router_latency # only used by garnet + # Create an individual router for each controller plus one more for # the centralized crossbar. The large numbers of routers are needed # because external links do not model outgoing bandwidth in the @@ -45,7 +51,8 @@ class Crossbar(SimpleTopology): xbar = routers[len(self.nodes)] # the crossbar router is the last router created network.routers = routers - ext_links = [ExtLink(link_id=i, ext_node=n, int_node=routers[i]) + ext_links = [ExtLink(link_id=i, ext_node=n, int_node=routers[i], + latency = link_latency) for (i, n) in enumerate(self.nodes)] network.ext_links = ext_links @@ -55,13 +62,15 @@ class Crossbar(SimpleTopology): for i in range(len(self.nodes)): int_links.append(IntLink(link_id=(link_count+i), src_node=routers[i], - dst_node=xbar)) + dst_node=xbar, + latency = link_latency)) link_count += len(self.nodes) for i in range(len(self.nodes)): int_links.append(IntLink(link_id=(link_count+i), src_node=xbar, - dst_node=routers[i])) + dst_node=routers[i], + latency = link_latency)) network.int_links = int_links diff --git a/configs/topologies/MeshDirCorners_XY.py b/configs/topologies/MeshDirCorners_XY.py index 47eb48086..46f3c6fdd 100644 --- a/configs/topologies/MeshDirCorners_XY.py +++ b/configs/topologies/MeshDirCorners_XY.py @@ -47,6 +47,12 @@ class MeshDirCorners_XY(SimpleTopology): num_routers = options.num_cpus num_rows = options.mesh_rows + # default values for link latency and router latency. + # Can be over-ridden on a per link/router basis + link_latency = options.link_latency # used by simple and garnet + router_latency = options.router_latency # only used by garnet + + # First determine which nodes are cache cntrls vs. dirs vs. dma cache_nodes = [] dir_nodes = [] @@ -64,7 +70,7 @@ class MeshDirCorners_XY(SimpleTopology): # and evenly divisible. Also the number of caches must be a # multiple of the number of routers and the number of directories # must be four. - assert(num_rows <= num_routers) + assert(num_rows > 0 and num_rows <= num_routers) num_columns = int(num_routers / num_rows) assert(num_columns * num_rows == num_routers) caches_per_router, remainder = divmod(len(cache_nodes), num_routers) @@ -72,7 +78,8 @@ class MeshDirCorners_XY(SimpleTopology): assert(len(dir_nodes) == 4) # Create the routers in the mesh - routers = [Router(router_id=i) for i in range(num_routers)] + routers = [Router(router_id=i, latency = router_latency) \ + for i in range(num_routers)] network.routers = routers # link counter to set unique link ids @@ -84,28 +91,34 @@ class MeshDirCorners_XY(SimpleTopology): cntrl_level, router_id = divmod(i, num_routers) assert(cntrl_level < caches_per_router) ext_links.append(ExtLink(link_id=link_count, ext_node=n, - int_node=routers[router_id])) + int_node=routers[router_id], + latency = link_latency)) link_count += 1 # Connect the dir nodes to the corners. ext_links.append(ExtLink(link_id=link_count, ext_node=dir_nodes[0], - int_node=routers[0])) + int_node=routers[0], + latency = link_latency)) link_count += 1 ext_links.append(ExtLink(link_id=link_count, ext_node=dir_nodes[1], - int_node=routers[num_columns - 1])) + int_node=routers[num_columns - 1], + latency = link_latency)) link_count += 1 ext_links.append(ExtLink(link_id=link_count, ext_node=dir_nodes[2], - int_node=routers[num_routers - num_columns])) + int_node=routers[num_routers - num_columns], + latency = link_latency)) link_count += 1 ext_links.append(ExtLink(link_id=link_count, ext_node=dir_nodes[3], - int_node=routers[num_routers - 1])) + int_node=routers[num_routers - 1], + latency = link_latency)) link_count += 1 # Connect the dma nodes to router 0. These should only be DMA nodes. for (i, node) in enumerate(dma_nodes): assert(node.type == 'DMA_Controller') ext_links.append(ExtLink(link_id=link_count, ext_node=node, - int_node=routers[0])) + int_node=routers[0], + latency = link_latency)) network.ext_links = ext_links @@ -121,6 +134,9 @@ class MeshDirCorners_XY(SimpleTopology): int_links.append(IntLink(link_id=link_count, src_node=routers[east_out], dst_node=routers[west_in], + src_outport="East", + dst_inport="West", + latency = link_latency, weight=1)) link_count += 1 @@ -133,6 +149,9 @@ class MeshDirCorners_XY(SimpleTopology): int_links.append(IntLink(link_id=link_count, src_node=routers[west_out], dst_node=routers[east_in], + src_outport="West", + dst_inport="East", + latency = link_latency, weight=1)) link_count += 1 @@ -145,6 +164,9 @@ class MeshDirCorners_XY(SimpleTopology): int_links.append(IntLink(link_id=link_count, src_node=routers[north_out], dst_node=routers[south_in], + src_outport="North", + dst_inport="South", + latency = link_latency, weight=2)) link_count += 1 @@ -157,6 +179,9 @@ class MeshDirCorners_XY(SimpleTopology): int_links.append(IntLink(link_id=link_count, src_node=routers[south_out], dst_node=routers[north_in], + src_outport="South", + dst_inport="North", + latency = link_latency, weight=2)) link_count += 1 diff --git a/configs/topologies/Mesh_XY.py b/configs/topologies/Mesh_XY.py index 134a5c07d..652ac16d8 100644 --- a/configs/topologies/Mesh_XY.py +++ b/configs/topologies/Mesh_XY.py @@ -53,15 +53,22 @@ class Mesh_XY(SimpleTopology): num_routers = options.num_cpus num_rows = options.mesh_rows + # default values for link latency and router latency. + # Can be over-ridden on a per link/router basis + link_latency = options.link_latency # used by simple and garnet + router_latency = options.router_latency # only used by garnet + + # There must be an evenly divisible number of cntrls to routers # Also, obviously the number or rows must be <= the number of routers cntrls_per_router, remainder = divmod(len(nodes), num_routers) - assert(num_rows <= num_routers) + assert(num_rows > 0 and num_rows <= num_routers) num_columns = int(num_routers / num_rows) assert(num_columns * num_rows == num_routers) # Create the routers in the mesh - routers = [Router(router_id=i) for i in range(num_routers)] + routers = [Router(router_id=i, latency = router_latency) \ + for i in range(num_routers)] network.routers = routers # link counter to set unique link ids @@ -83,7 +90,8 @@ class Mesh_XY(SimpleTopology): cntrl_level, router_id = divmod(i, num_routers) assert(cntrl_level < cntrls_per_router) ext_links.append(ExtLink(link_id=link_count, ext_node=n, - int_node=routers[router_id])) + int_node=routers[router_id], + latency = link_latency)) link_count += 1 # Connect the remainding nodes to router 0. These should only be @@ -92,7 +100,8 @@ class Mesh_XY(SimpleTopology): assert(node.type == 'DMA_Controller') assert(i < remainder) ext_links.append(ExtLink(link_id=link_count, ext_node=node, - int_node=routers[0])) + int_node=routers[0], + latency = link_latency)) link_count += 1 network.ext_links = ext_links @@ -111,6 +120,7 @@ class Mesh_XY(SimpleTopology): dst_node=routers[west_in], src_outport="East", dst_inport="West", + latency = link_latency, weight=1)) link_count += 1 @@ -125,6 +135,7 @@ class Mesh_XY(SimpleTopology): dst_node=routers[east_in], src_outport="West", dst_inport="East", + latency = link_latency, weight=1)) link_count += 1 @@ -139,6 +150,7 @@ class Mesh_XY(SimpleTopology): dst_node=routers[south_in], src_outport="North", dst_inport="South", + latency = link_latency, weight=2)) link_count += 1 @@ -153,6 +165,7 @@ class Mesh_XY(SimpleTopology): dst_node=routers[north_in], src_outport="South", dst_inport="North", + latency = link_latency, weight=2)) link_count += 1 diff --git a/configs/topologies/Mesh_westfirst.py b/configs/topologies/Mesh_westfirst.py index 3af894f93..6139f6742 100644 --- a/configs/topologies/Mesh_westfirst.py +++ b/configs/topologies/Mesh_westfirst.py @@ -58,15 +58,21 @@ class Mesh_westfirst(SimpleTopology): num_routers = options.num_cpus num_rows = options.mesh_rows + # default values for link latency and router latency. + # Can be over-ridden on a per link/router basis + link_latency = options.link_latency # used by simple and garnet + router_latency = options.router_latency # only used by garnet + # There must be an evenly divisible number of cntrls to routers # Also, obviously the number or rows must be <= the number of routers cntrls_per_router, remainder = divmod(len(nodes), num_routers) - assert(num_rows <= num_routers) + assert(num_rows > 0 and num_rows <= num_routers) num_columns = int(num_routers / num_rows) assert(num_columns * num_rows == num_routers) # Create the routers in the mesh - routers = [Router(router_id=i) for i in range(num_routers)] + routers = [Router(router_id=i, latency=router_latency) \ + for i in range(num_routers)] network.routers = routers # link counter to set unique link ids @@ -88,7 +94,8 @@ class Mesh_westfirst(SimpleTopology): cntrl_level, router_id = divmod(i, num_routers) assert(cntrl_level < cntrls_per_router) ext_links.append(ExtLink(link_id=link_count, ext_node=n, - int_node=routers[router_id])) + int_node=routers[router_id], + latency = link_latency)) link_count += 1 # Connect the remainding nodes to router 0. These should only be @@ -97,7 +104,8 @@ class Mesh_westfirst(SimpleTopology): assert(node.type == 'DMA_Controller') assert(i < remainder) ext_links.append(ExtLink(link_id=link_count, ext_node=node, - int_node=routers[0])) + int_node=routers[0], + latency = link_latency)) link_count += 1 network.ext_links = ext_links @@ -114,6 +122,7 @@ class Mesh_westfirst(SimpleTopology): int_links.append(IntLink(link_id=link_count, src_node=routers[east_out], dst_node=routers[west_in], + latency = link_latency, weight=2)) link_count += 1 @@ -126,6 +135,7 @@ class Mesh_westfirst(SimpleTopology): int_links.append(IntLink(link_id=link_count, src_node=routers[west_out], dst_node=routers[east_in], + latency = link_latency, weight=1)) link_count += 1 @@ -139,6 +149,7 @@ class Mesh_westfirst(SimpleTopology): int_links.append(IntLink(link_id=link_count, src_node=routers[north_out], dst_node=routers[south_in], + latency = link_latency, weight=2)) link_count += 1 @@ -151,6 +162,7 @@ class Mesh_westfirst(SimpleTopology): int_links.append(IntLink(link_id=link_count, src_node=routers[south_out], dst_node=routers[north_in], + latency = link_latency, weight=2)) link_count += 1 diff --git a/configs/topologies/Pt2Pt.py b/configs/topologies/Pt2Pt.py index 006d00c2f..6cbf5ad85 100644 --- a/configs/topologies/Pt2Pt.py +++ b/configs/topologies/Pt2Pt.py @@ -42,11 +42,22 @@ class Pt2Pt(SimpleTopology): def makeTopology(self, options, network, IntLink, ExtLink, Router): nodes = self.nodes - # Create an individual router for each controller, and connect all to all. - routers = [Router(router_id=i) for i in range(len(nodes))] + # default values for link latency and router latency. + # Can be over-ridden on a per link/router basis + link_latency = options.link_latency # used by simple and garnet + router_latency = options.router_latency # only used by garnet + + # Create an individual router for each controller, + # and connect all to all. + # Since this is a high-radix router, router_latency should + # accordingly be set to a higher value than the default + # (which is 1 for mesh routers) + routers = [Router(router_id=i, latency = router_latency) \ + for i in range(len(nodes))] network.routers = routers - ext_links = [ExtLink(link_id=i, ext_node=n, int_node=routers[i]) + ext_links = [ExtLink(link_id=i, ext_node=n, int_node=routers[i], + latency = link_latency) for (i, n) in enumerate(nodes)] network.ext_links = ext_links @@ -58,6 +69,7 @@ class Pt2Pt(SimpleTopology): link_count += 1 int_links.append(IntLink(link_id=link_count, src_node=routers[i], - dst_node=routers[j])) + dst_node=routers[j], + latency = link_latency)) network.int_links = int_links diff --git a/src/base/statistics.cc b/src/base/statistics.cc index b32dafb8c..4c14bc522 100644 --- a/src/base/statistics.cc +++ b/src/base/statistics.cc @@ -180,8 +180,8 @@ Info::setName(const string &name) bool result = p.second; if (!result) { - // using other->name instead of just name to avoid a compiler - // warning. They should be the same. + // using other->name instead of just name to avoid a compiler + // warning. They should be the same. panic("same statistic name used twice! name=%s\n", other->name); } diff --git a/src/mem/ruby/network/BasicRouter.py b/src/mem/ruby/network/BasicRouter.py index 28fcdc47e..68a7b1d8b 100644 --- a/src/mem/ruby/network/BasicRouter.py +++ b/src/mem/ruby/network/BasicRouter.py @@ -34,4 +34,6 @@ class BasicRouter(ClockedObject): type = 'BasicRouter' cxx_header = "mem/ruby/network/BasicRouter.hh" router_id = Param.Int("ID in relation to other routers") + + # only used by garnet latency = Param.Cycles(1, "number of cycles inside router") diff --git a/src/mem/ruby/network/garnet2.0/CommonTypes.hh b/src/mem/ruby/network/garnet2.0/CommonTypes.hh new file mode 100644 index 000000000..63fc464a6 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/CommonTypes.hh @@ -0,0 +1,65 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_COMMONTYPES_HH__ +#define __MEM_RUBY_NETWORK_GARNET_COMMONTYPES_HH__ + +#include "mem/ruby/common/NetDest.hh" + +// All common enums and typedefs go here + +enum flit_type {HEAD_, BODY_, TAIL_, HEAD_TAIL_, NUM_FLIT_TYPE_}; +enum VC_state_type {IDLE_, VC_AB_, ACTIVE_, NUM_VC_STATE_TYPE_}; +enum VNET_type {CTRL_VNET_, DATA_VNET_, NULL_VNET_, NUM_VNET_TYPE_}; +enum flit_stage {I_, VA_, SA_, ST_, LT_, NUM_FLIT_STAGE_}; +enum link_type { EXT_IN_, EXT_OUT_, INT_, NUM_LINK_TYPES_ }; +enum RoutingAlgorithm { TABLE_ = 0, XY_ = 1, CUSTOM_ = 2, + NUM_ROUTING_ALGORITHM_}; + +struct RouteInfo +{ + // destination format for table-based routing + int vnet; + NetDest net_dest; + + // src and dest format for topology-specific routing + int src_ni; + int src_router; + int dest_ni; + int dest_router; + int hops_traversed; +}; + +#define INFINITE_ 10000 + +#endif // __MEM_RUBY_NETWORK_GARNET_COMMONTYPES_HH__ diff --git a/src/mem/ruby/network/garnet2.0/Credit.cc b/src/mem/ruby/network/garnet2.0/Credit.cc new file mode 100644 index 000000000..6bc7ca209 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/Credit.cc @@ -0,0 +1,46 @@ +/* + * 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/Credit.hh" + +// Credit Signal for buffers inside VC +// Carries m_vc (inherits from flit.hh) +// and m_is_free_signal (whether VC is free or not) + +Credit::Credit(int vc, bool is_free_signal, Cycles curTime) +{ + m_id = 0; + m_vc = vc; + m_is_free_signal = is_free_signal; + m_time = curTime; +} diff --git a/src/mem/ruby/network/garnet2.0/Credit.hh b/src/mem/ruby/network/garnet2.0/Credit.hh new file mode 100644 index 000000000..c2984e9ee --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/Credit.hh @@ -0,0 +1,60 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_CREDIT_HH__ +#define __MEM_RUBY_NETWORK_GARNET_CREDIT_HH__ + +#include +#include + +#include "base/types.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/flit.hh" + +// Credit Signal for buffers inside VC +// Carries m_vc (inherits from flit.hh) +// and m_is_free_signal (whether VC is free or not) + +class Credit : public flit +{ + public: + Credit() {}; + Credit(int vc, bool is_free_signal, Cycles curTime); + + bool is_free_signal() { return m_is_free_signal; } + + private: + bool m_is_free_signal; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_CREDIT_HH__ diff --git a/src/mem/ruby/network/garnet2.0/CreditLink.hh b/src/mem/ruby/network/garnet2.0/CreditLink.hh new file mode 100644 index 000000000..207fb864d --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/CreditLink.hh @@ -0,0 +1,47 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_CREDIT_LINK_HH__ +#define __MEM_RUBY_NETWORK_GARNET_CREDIT_LINK_HH__ + +#include "mem/ruby/network/garnet2.0/NetworkLink.hh" +#include "params/CreditLink.hh" + +class CreditLink : public NetworkLink +{ + public: + typedef CreditLinkParams Params; + CreditLink(const Params *p) : NetworkLink(p) {} +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_CREDIT_LINK_HH__ diff --git a/src/mem/ruby/network/garnet2.0/CrossbarSwitch.cc b/src/mem/ruby/network/garnet2.0/CrossbarSwitch.cc new file mode 100644 index 000000000..340f56d61 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/CrossbarSwitch.cc @@ -0,0 +1,112 @@ +/* + * 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/CrossbarSwitch.hh" + +#include "base/stl_helpers.hh" +#include "debug/RubyNetwork.hh" +#include "mem/ruby/network/garnet2.0/OutputUnit.hh" +#include "mem/ruby/network/garnet2.0/Router.hh" + +using m5::stl_helpers::deletePointers; + +CrossbarSwitch::CrossbarSwitch(Router *router) + : Consumer(router) +{ + m_router = router; + m_num_vcs = m_router->get_num_vcs(); + m_crossbar_activity = 0; +} + +CrossbarSwitch::~CrossbarSwitch() +{ + deletePointers(m_switch_buffer); +} + +void +CrossbarSwitch::init() +{ + m_output_unit = m_router->get_outputUnit_ref(); + + m_num_inports = m_router->get_num_inports(); + m_switch_buffer.resize(m_num_inports); + for (int i = 0; i < m_num_inports; i++) { + m_switch_buffer[i] = new flitBuffer(); + } +} + +/* + * The wakeup function of the CrossbarSwitch loops through all input ports, + * and sends the winning flit (from SA) out of its output port on to the + * output link. The output link is scheduled for wakeup in the next cycle. + */ + +void +CrossbarSwitch::wakeup() +{ + DPRINTF(RubyNetwork, "CrossbarSwitch at Router %d woke up " + "at time: %lld\n", + m_router->get_id(), m_router->curCycle()); + + for (int inport = 0; inport < m_num_inports; inport++) { + if (!m_switch_buffer[inport]->isReady(m_router->curCycle())) + continue; + + flit *t_flit = m_switch_buffer[inport]->peekTopFlit(); + if (t_flit->is_stage(ST_, m_router->curCycle())) { + int outport = t_flit->get_outport(); + + // flit performs LT_ in the next cycle + t_flit->advance_stage(LT_, m_router->curCycle() + Cycles(1)); + t_flit->set_time(m_router->curCycle() + Cycles(1)); + + // This will take care of waking up the Network Link + // in the next cycle + m_output_unit[outport]->insert_flit(t_flit); + m_switch_buffer[inport]->getTopFlit(); + m_crossbar_activity++; + } + } +} + +uint32_t +CrossbarSwitch::functionalWrite(Packet *pkt) +{ + uint32_t num_functional_writes = 0; + + for (uint32_t i = 0; i < m_switch_buffer.size(); ++i) { + num_functional_writes += m_switch_buffer[i]->functionalWrite(pkt); + } + + return num_functional_writes; +} diff --git a/src/mem/ruby/network/garnet2.0/CrossbarSwitch.hh b/src/mem/ruby/network/garnet2.0/CrossbarSwitch.hh new file mode 100644 index 000000000..7aaeabf0c --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/CrossbarSwitch.hh @@ -0,0 +1,72 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_CROSSBAR_SWITCH_HH__ +#define __MEM_RUBY_NETWORK_GARNET_CROSSBAR_SWITCH_HH__ + +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/flitBuffer.hh" + +class Router; +class OutputUnit; + +class CrossbarSwitch : public Consumer +{ + public: + CrossbarSwitch(Router *router); + ~CrossbarSwitch(); + void wakeup(); + void init(); + void print(std::ostream& out) const {}; + + inline void update_sw_winner(int inport, flit *t_flit) + { m_switch_buffer[inport]->insert(t_flit); } + + inline double get_crossbar_activity() { return m_crossbar_activity; } + + uint32_t functionalWrite(Packet *pkt); + + private: + int m_num_vcs; + int m_num_inports; + double m_crossbar_activity; + Router *m_router; + std::vector m_switch_buffer; + std::vector m_output_unit; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_CROSSBAR_SWITCH_HH__ diff --git a/src/mem/ruby/network/garnet2.0/GarnetLink.cc b/src/mem/ruby/network/garnet2.0/GarnetLink.cc new file mode 100644 index 000000000..ac5386a52 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/GarnetLink.cc @@ -0,0 +1,94 @@ +/* + * 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/GarnetLink.hh" + +#include "mem/ruby/network/garnet2.0/CreditLink.hh" +#include "mem/ruby/network/garnet2.0/NetworkLink.hh" + +GarnetIntLink::GarnetIntLink(const Params *p) + : BasicLink(p) +{ + // Uni-directional + + m_network_link = p->network_link; + m_credit_link = p->credit_link; +} + +void +GarnetIntLink::init() +{ +} + +void +GarnetIntLink::print(std::ostream& out) const +{ + out << name(); +} + +GarnetIntLink * +GarnetIntLinkParams::create() +{ + return new GarnetIntLink(this); +} + +GarnetExtLink::GarnetExtLink(const Params *p) + : BasicLink(p) +{ + // Bi-directional + + // In + m_network_links[0] = p->network_links[0]; + m_credit_links[0] = p->credit_links[0]; + + // Out + m_network_links[1] = p->network_links[1]; + m_credit_links[1] = p->credit_links[1]; +} + +void +GarnetExtLink::init() +{ +} + +void +GarnetExtLink::print(std::ostream& out) const +{ + out << name(); +} + +GarnetExtLink * +GarnetExtLinkParams::create() +{ + return new GarnetExtLink(this); +} diff --git a/src/mem/ruby/network/garnet2.0/GarnetLink.hh b/src/mem/ruby/network/garnet2.0/GarnetLink.hh new file mode 100644 index 000000000..d7c582950 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/GarnetLink.hh @@ -0,0 +1,97 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_LINK_HH__ +#define __MEM_RUBY_NETWORK_GARNET_LINK_HH__ + +#include +#include +#include + +#include "mem/ruby/network/BasicLink.hh" +#include "mem/ruby/network/garnet2.0/CreditLink.hh" +#include "mem/ruby/network/garnet2.0/NetworkLink.hh" +#include "params/GarnetExtLink.hh" +#include "params/GarnetIntLink.hh" + +class GarnetIntLink : public BasicLink +{ + public: + typedef GarnetIntLinkParams Params; + GarnetIntLink(const Params *p); + + void init(); + + void print(std::ostream& out) const; + + friend class GarnetNetwork; + + protected: + NetworkLink* m_network_link; + CreditLink* m_credit_link; +}; + +inline std::ostream& +operator<<(std::ostream& out, const GarnetIntLink& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +class GarnetExtLink : public BasicLink +{ + public: + typedef GarnetExtLinkParams Params; + GarnetExtLink(const Params *p); + + void init(); + + void print(std::ostream& out) const; + + friend class GarnetNetwork; + + protected: + NetworkLink* m_network_links[2]; + CreditLink* m_credit_links[2]; +}; + +inline std::ostream& +operator<<(std::ostream& out, const GarnetExtLink& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __MEM_RUBY_NETWORK_GARNET_LINK_HH__ diff --git a/src/mem/ruby/network/garnet2.0/GarnetLink.py b/src/mem/ruby/network/garnet2.0/GarnetLink.py new file mode 100644 index 000000000..fc5632d49 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/GarnetLink.py @@ -0,0 +1,79 @@ +# Copyright (c) 2008 Princeton University +# Copyright (c) 2009 Advanced Micro Devices, Inc. +# 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: Steve Reinhardt +# Brad Beckmann + +from m5.params import * +from m5.proxy import * +from ClockedObject import ClockedObject +from BasicLink import BasicIntLink, BasicExtLink + +class NetworkLink(ClockedObject): + type = 'NetworkLink' + cxx_header = "mem/ruby/network/garnet2.0/NetworkLink.hh" + link_id = Param.Int(Parent.link_id, "link id") + link_latency = Param.Cycles(Parent.latency, "link latency") + vcs_per_vnet = Param.Int(Parent.vcs_per_vnet, + "virtual channels per virtual network") + virt_nets = Param.Int(Parent.number_of_virtual_networks, + "number of virtual networks") + +class CreditLink(NetworkLink): + type = 'CreditLink' + cxx_header = "mem/ruby/network/garnet2.0/CreditLink.hh" + +# Interior fixed pipeline links between routers +class GarnetIntLink(BasicIntLink): + type = 'GarnetIntLink' + cxx_header = "mem/ruby/network/garnet2.0/GarnetLink.hh" + # The internal link includes one forward link (for flit) + # and one backward flow-control link (for credit) + network_link = Param.NetworkLink(NetworkLink(), "forward link") + credit_link = Param.CreditLink(CreditLink(), "backward flow-control link") + +# Exterior fixed pipeline links between a router and a controller +class GarnetExtLink(BasicExtLink): + type = 'GarnetExtLink' + cxx_header = "mem/ruby/network/garnet2.0/GarnetLink.hh" + # The external link is bi-directional. + # It includes two forward links (for flits) + # and two backward flow-control links (for credits), + # one per direction + _nls = [] + # In uni-directional link + _nls.append(NetworkLink()); + # Out uni-directional link + _nls.append(NetworkLink()); + network_links = VectorParam.NetworkLink(_nls, "forward links") + + _cls = [] + # In uni-directional link + _cls.append(CreditLink()); + # Out uni-directional link + _cls.append(CreditLink()); + credit_links = VectorParam.CreditLink(_cls, "backward flow-control links") diff --git a/src/mem/ruby/network/garnet2.0/GarnetNetwork.cc b/src/mem/ruby/network/garnet2.0/GarnetNetwork.cc new file mode 100644 index 000000000..5fa764457 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/GarnetNetwork.cc @@ -0,0 +1,460 @@ +/* + * 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 + +#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::const_iterator i = p->routers.begin(); + i != p->routers.end(); ++i) { + Router* router = safe_cast(*i); + m_routers.push_back(router); + + // initialize the router's network pointers + router->init_net_ptr(this); + } + + // record the network interfaces + for (vector::const_iterator i = p->netifs.begin(); + i != p->netifs.end(); ++i) { + NetworkInterface *ni = safe_cast(*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::const_iterator i= m_routers.begin(); + i != m_routers.end(); ++i) { + Router* router = safe_cast(*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(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(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(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 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; +} diff --git a/src/mem/ruby/network/garnet2.0/GarnetNetwork.hh b/src/mem/ruby/network/garnet2.0/GarnetNetwork.hh new file mode 100644 index 000000000..3ced88740 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/GarnetNetwork.hh @@ -0,0 +1,208 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_NETWORK_HH__ +#define __MEM_RUBY_NETWORK_GARNET_NETWORK_HH__ + +#include +#include + +#include "mem/ruby/network/Network.hh" +#include "mem/ruby/network/fault_model/FaultModel.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "params/GarnetNetwork.hh" + +class FaultModel; +class NetworkInterface; +class Router; +class NetDest; +class NetworkLink; +class CreditLink; + +class GarnetNetwork : public Network +{ + public: + typedef GarnetNetworkParams Params; + GarnetNetwork(const Params *p); + + ~GarnetNetwork(); + void init(); + + // Configuration (set externally) + + // for 2D topology + int getNumRows() const { return m_num_rows; } + int getNumCols() { return m_num_cols; } + + // for network + uint32_t getNiFlitSize() const { return m_ni_flit_size; } + uint32_t getVCsPerVnet() const { return m_vcs_per_vnet; } + uint32_t getBuffersPerDataVC() { return m_buffers_per_data_vc; } + uint32_t getBuffersPerCtrlVC() { return m_buffers_per_ctrl_vc; } + int getRoutingAlgorithm() const { return m_routing_algorithm; } + + bool isFaultModelEnabled() const { return m_enable_fault_model; } + FaultModel* fault_model; + + + // Internal configuration + bool isVNetOrdered(int vnet) const { return m_ordered[vnet]; } + VNET_type + get_vnet_type(int vc) + { + int vnet = vc/getVCsPerVnet(); + return m_vnet_type[vnet]; + } + int getNumRouters(); + int get_router_id(int ni); + + + // Methods used by Topology to setup the network + void makeExtOutLink(SwitchID src, NodeID dest, BasicLink* link, + const NetDest& routing_table_entry); + void makeExtInLink(NodeID src, SwitchID dest, BasicLink* link, + const NetDest& routing_table_entry); + void makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link, + const NetDest& routing_table_entry, + PortDirection src_outport_dirn, + PortDirection dest_inport_dirn); + + //! Function for performing a functional write. The return value + //! indicates the number of messages that were written. + uint32_t functionalWrite(Packet *pkt); + + // Stats + void collateStats(); + void regStats(); + void print(std::ostream& out) const; + + // increment counters + void increment_injected_packets(int vnet) { m_packets_injected[vnet]++; } + void increment_received_packets(int vnet) { m_packets_received[vnet]++; } + + void + increment_packet_network_latency(Cycles latency, int vnet) + { + m_packet_network_latency[vnet] += latency; + } + + void + increment_packet_queueing_latency(Cycles latency, int vnet) + { + m_packet_queueing_latency[vnet] += latency; + } + + void increment_injected_flits(int vnet) { m_flits_injected[vnet]++; } + void increment_received_flits(int vnet) { m_flits_received[vnet]++; } + + void + increment_flit_network_latency(Cycles latency, int vnet) + { + m_flit_network_latency[vnet] += latency; + } + + void + increment_flit_queueing_latency(Cycles latency, int vnet) + { + m_flit_queueing_latency[vnet] += latency; + } + + void + increment_total_hops(int hops) + { + m_total_hops += hops; + } + + protected: + // Configuration + int m_num_rows; + int m_num_cols; + uint32_t m_ni_flit_size; + uint32_t m_vcs_per_vnet; + uint32_t m_buffers_per_ctrl_vc; + uint32_t m_buffers_per_data_vc; + int m_routing_algorithm; + bool m_enable_fault_model; + + // Statistical variables + Stats::Vector m_packets_received; + Stats::Vector m_packets_injected; + Stats::Vector m_packet_network_latency; + Stats::Vector m_packet_queueing_latency; + + Stats::Formula m_avg_packet_vnet_latency; + Stats::Formula m_avg_packet_vqueue_latency; + Stats::Formula m_avg_packet_network_latency; + Stats::Formula m_avg_packet_queueing_latency; + Stats::Formula m_avg_packet_latency; + + Stats::Vector m_flits_received; + Stats::Vector m_flits_injected; + Stats::Vector m_flit_network_latency; + Stats::Vector m_flit_queueing_latency; + + Stats::Formula m_avg_flit_vnet_latency; + Stats::Formula m_avg_flit_vqueue_latency; + Stats::Formula m_avg_flit_network_latency; + Stats::Formula m_avg_flit_queueing_latency; + Stats::Formula m_avg_flit_latency; + + Stats::Scalar m_total_ext_in_link_utilization; + Stats::Scalar m_total_ext_out_link_utilization; + Stats::Scalar m_total_int_link_utilization; + Stats::Scalar m_average_link_utilization; + Stats::Vector m_average_vc_load; + + Stats::Scalar m_total_hops; + Stats::Formula m_avg_hops; + + private: + GarnetNetwork(const GarnetNetwork& obj); + GarnetNetwork& operator=(const GarnetNetwork& obj); + + std::vector m_vnet_type; + std::vector m_routers; // All Routers in Network + std::vector m_networklinks; // All flit links in the network + std::vector m_creditlinks; // All credit links in the network + std::vector m_nis; // All NI's in Network +}; + +inline std::ostream& +operator<<(std::ostream& out, const GarnetNetwork& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __MEM_RUBY_NETWORK_GARNET_NETWORK_HH__ diff --git a/src/mem/ruby/network/garnet2.0/GarnetNetwork.py b/src/mem/ruby/network/garnet2.0/GarnetNetwork.py new file mode 100644 index 000000000..704532782 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/GarnetNetwork.py @@ -0,0 +1,68 @@ +# Copyright (c) 2008 Princeton University +# Copyright (c) 2009 Advanced Micro Devices, Inc. +# 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. +# +# Author: Tushar Krishna +# + +from m5.params import * +from m5.proxy import * +from Network import RubyNetwork +from BasicRouter import BasicRouter +from ClockedObject import ClockedObject + +class GarnetNetwork(RubyNetwork): + type = 'GarnetNetwork' + cxx_header = "mem/ruby/network/garnet2.0/GarnetNetwork.hh" + num_rows = Param.Int(0, "number of rows if 2D (mesh/torus/..) topology"); + ni_flit_size = Param.UInt32(16, "network interface flit size in bytes") + vcs_per_vnet = Param.UInt32(4, "virtual channels per virtual network"); + buffers_per_data_vc = Param.UInt32(4, "buffers per data virtual channel"); + buffers_per_ctrl_vc = Param.UInt32(1, "buffers per ctrl virtual channel"); + routing_algorithm = Param.Int(0, + "0: Weight-based Table, 1: XY, 2: Custom"); + enable_fault_model = Param.Bool(False, "enable network fault model"); + fault_model = Param.FaultModel(NULL, "network fault model"); + +class GarnetNetworkInterface(ClockedObject): + type = 'GarnetNetworkInterface' + cxx_class = 'NetworkInterface' + cxx_header = "mem/ruby/network/garnet2.0/NetworkInterface.hh" + + id = Param.UInt32("ID in relation to other network interfaces") + vcs_per_vnet = Param.UInt32(Parent.vcs_per_vnet, + "virtual channels per virtual network") + virt_nets = Param.UInt32(Parent.number_of_virtual_networks, + "number of virtual networks") + +class GarnetRouter(BasicRouter): + type = 'GarnetRouter' + cxx_class = 'Router' + cxx_header = "mem/ruby/network/garnet2.0/Router.hh" + vcs_per_vnet = Param.UInt32(Parent.vcs_per_vnet, + "virtual channels per virtual network") + virt_nets = Param.UInt32(Parent.number_of_virtual_networks, + "number of virtual networks") diff --git a/src/mem/ruby/network/garnet2.0/InputUnit.cc b/src/mem/ruby/network/garnet2.0/InputUnit.cc new file mode 100644 index 000000000..c03bf2a09 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/InputUnit.cc @@ -0,0 +1,171 @@ +/* + * 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/InputUnit.hh" + +#include "base/stl_helpers.hh" +#include "debug/RubyNetwork.hh" +#include "mem/ruby/network/garnet2.0/Credit.hh" +#include "mem/ruby/network/garnet2.0/Router.hh" + +using namespace std; +using m5::stl_helpers::deletePointers; + +InputUnit::InputUnit(int id, PortDirection direction, Router *router) + : Consumer(router) +{ + m_id = id; + m_direction = direction; + m_router = router; + m_num_vcs = m_router->get_num_vcs(); + m_vc_per_vnet = m_router->get_vc_per_vnet(); + + m_num_buffer_reads.resize(m_num_vcs/m_vc_per_vnet); + m_num_buffer_writes.resize(m_num_vcs/m_vc_per_vnet); + for (int i = 0; i < m_num_buffer_reads.size(); i++) { + m_num_buffer_reads[i] = 0; + m_num_buffer_writes[i] = 0; + } + + creditQueue = new flitBuffer(); + // Instantiating the virtual channels + m_vcs.resize(m_num_vcs); + for (int i=0; i < m_num_vcs; i++) { + m_vcs[i] = new VirtualChannel(i); + } +} + +InputUnit::~InputUnit() +{ + delete creditQueue; + deletePointers(m_vcs); +} + +/* + * The InputUnit wakeup function reads the input flit from its input link. + * Each flit arrives with an input VC. + * For HEAD/HEAD_TAIL flits, performs route computation, + * and updates route in the input VC. + * The flit is buffered for (m_latency - 1) cycles in the input VC + * and marked as valid for SwitchAllocation starting that cycle. + * + */ + +void +InputUnit::wakeup() +{ + flit *t_flit; + if (m_in_link->isReady(m_router->curCycle())) { + + t_flit = m_in_link->consumeLink(); + int vc = t_flit->get_vc(); + t_flit->increment_hops(); // for stats + + if ((t_flit->get_type() == HEAD_) || + (t_flit->get_type() == HEAD_TAIL_)) { + + assert(m_vcs[vc]->get_state() == IDLE_); + set_vc_active(vc, m_router->curCycle()); + + // Route computation for this vc + int outport = m_router->route_compute(t_flit->get_route(), + m_id, m_direction); + + // Update output port in VC + // All flits in this packet will use this output port + // The output port field in the flit is updated after it wins SA + grant_outport(vc, outport); + + } else { + assert(m_vcs[vc]->get_state() == ACTIVE_); + } + + + // Buffer the flit + m_vcs[vc]->insertFlit(t_flit); + + int vnet = vc/m_vc_per_vnet; + // number of writes same as reads + // any flit that is written will be read only once + m_num_buffer_writes[vnet]++; + m_num_buffer_reads[vnet]++; + + Cycles pipe_stages = m_router->get_pipe_stages(); + if (pipe_stages == 1) { + // 1-cycle router + // Flit goes for SA directly + t_flit->advance_stage(SA_, m_router->curCycle()); + } else { + assert(pipe_stages > 1); + // Router delay is modeled by making flit wait in buffer for + // (pipe_stages cycles - 1) cycles before going for SA + + Cycles wait_time = pipe_stages - Cycles(1); + t_flit->advance_stage(SA_, m_router->curCycle() + wait_time); + + // Wakeup the router in that cycle to perform SA + m_router->schedule_wakeup(Cycles(wait_time)); + } + } +} + +// Send a credit back to upstream router for this VC. +// Called by SwitchAllocator when the flit in this VC wins the Switch. +void +InputUnit::increment_credit(int in_vc, bool free_signal, Cycles curTime) +{ + Credit *t_credit = new Credit(in_vc, free_signal, curTime); + creditQueue->insert(t_credit); + m_credit_link->scheduleEventAbsolute(m_router->clockEdge(Cycles(1))); +} + + +uint32_t +InputUnit::functionalWrite(Packet *pkt) +{ + uint32_t num_functional_writes = 0; + for (int i=0; i < m_num_vcs; i++) { + num_functional_writes += m_vcs[i]->functionalWrite(pkt); + } + + return num_functional_writes; +} + +void +InputUnit::resetStats() +{ + for (int j = 0; j < m_num_buffer_reads.size(); j++) { + m_num_buffer_reads[j] = 0; + m_num_buffer_writes[j] = 0; + } +} diff --git a/src/mem/ruby/network/garnet2.0/InputUnit.hh b/src/mem/ruby/network/garnet2.0/InputUnit.hh new file mode 100644 index 000000000..26803ed86 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/InputUnit.hh @@ -0,0 +1,170 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_INPUT_UNIT_HH__ +#define __MEM_RUBY_NETWORK_GARNET_INPUT_UNIT_HH__ + +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/CreditLink.hh" +#include "mem/ruby/network/garnet2.0/NetworkLink.hh" +#include "mem/ruby/network/garnet2.0/Router.hh" +#include "mem/ruby/network/garnet2.0/VirtualChannel.hh" +#include "mem/ruby/network/garnet2.0/flitBuffer.hh" + +class InputUnit : public Consumer +{ + public: + InputUnit(int id, PortDirection direction, Router *router); + ~InputUnit(); + + void wakeup(); + void print(std::ostream& out) const {}; + + inline PortDirection get_direction() { return m_direction; } + + inline void + set_vc_idle(int vc, Cycles curTime) + { + m_vcs[vc]->set_idle(curTime); + } + + inline void + set_vc_active(int vc, Cycles curTime) + { + m_vcs[vc]->set_active(curTime); + } + + inline void + grant_outport(int vc, int outport) + { + m_vcs[vc]->set_outport(outport); + } + + inline void + grant_outvc(int vc, int outvc) + { + m_vcs[vc]->set_outvc(outvc); + } + + inline int + get_outport(int invc) + { + return m_vcs[invc]->get_outport(); + } + + inline int + get_outvc(int invc) + { + return m_vcs[invc]->get_outvc(); + } + + inline Cycles + get_enqueue_time(int invc) + { + return m_vcs[invc]->get_enqueue_time(); + } + + void increment_credit(int in_vc, bool free_signal, Cycles curTime); + + inline flit* + peekTopFlit(int vc) + { + return m_vcs[vc]->peekTopFlit(); + } + + inline flit* + getTopFlit(int vc) + { + return m_vcs[vc]->getTopFlit(); + } + + inline bool + need_stage(int vc, flit_stage stage, Cycles time) + { + return m_vcs[vc]->need_stage(stage, time); + } + + inline bool + isReady(int invc, Cycles curTime) + { + return m_vcs[invc]->isReady(curTime); + } + + flitBuffer* getCreditQueue() { return creditQueue; } + + inline void + set_in_link(NetworkLink *link) + { + m_in_link = link; + } + + inline int get_inlink_id() { return m_in_link->get_id(); } + + inline void + set_credit_link(CreditLink *credit_link) + { + m_credit_link = credit_link; + } + + double get_buf_read_activity(unsigned int vnet) const + { return m_num_buffer_reads[vnet]; } + double get_buf_write_activity(unsigned int vnet) const + { return m_num_buffer_writes[vnet]; } + + uint32_t functionalWrite(Packet *pkt); + void resetStats(); + + private: + int m_id; + PortDirection m_direction; + int m_num_vcs; + int m_vc_per_vnet; + + Router *m_router; + NetworkLink *m_in_link; + CreditLink *m_credit_link; + flitBuffer *creditQueue; + + // Input Virtual channels + std::vector m_vcs; + + // Statistical variables + std::vector m_num_buffer_writes; + std::vector m_num_buffer_reads; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_INPUT_UNIT_HH__ diff --git a/src/mem/ruby/network/garnet2.0/NetworkInterface.cc b/src/mem/ruby/network/garnet2.0/NetworkInterface.cc new file mode 100644 index 000000000..6bdaf39af --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/NetworkInterface.cc @@ -0,0 +1,443 @@ +/* + * 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/NetworkInterface.hh" + +#include +#include + +#include "base/cast.hh" +#include "base/stl_helpers.hh" +#include "debug/RubyNetwork.hh" +#include "mem/ruby/network/MessageBuffer.hh" +#include "mem/ruby/network/garnet2.0/Credit.hh" +#include "mem/ruby/network/garnet2.0/flitBuffer.hh" +#include "mem/ruby/slicc_interface/Message.hh" + +using namespace std; +using m5::stl_helpers::deletePointers; + +NetworkInterface::NetworkInterface(const Params *p) + : ClockedObject(p), Consumer(this), m_id(p->id), + m_virtual_networks(p->virt_nets), m_vc_per_vnet(p->vcs_per_vnet), + m_num_vcs(m_vc_per_vnet * m_virtual_networks) +{ + m_router_id = -1; + m_vc_round_robin = 0; + m_ni_out_vcs.resize(m_num_vcs); + m_ni_out_vcs_enqueue_time.resize(m_num_vcs); + outCreditQueue = new flitBuffer(); + + // instantiating the NI flit buffers + for (int i = 0; i < m_num_vcs; i++) { + m_ni_out_vcs[i] = new flitBuffer(); + m_ni_out_vcs_enqueue_time[i] = Cycles(INFINITE_); + } + + m_vc_allocator.resize(m_virtual_networks); // 1 allocator per vnet + for (int i = 0; i < m_virtual_networks; i++) { + m_vc_allocator[i] = 0; + } +} + +void +NetworkInterface::init() +{ + for (int i = 0; i < m_num_vcs; i++) { + m_out_vc_state.push_back(new OutVcState(i, m_net_ptr)); + } +} + +NetworkInterface::~NetworkInterface() +{ + deletePointers(m_out_vc_state); + deletePointers(m_ni_out_vcs); + delete outCreditQueue; + delete outFlitQueue; +} + +void +NetworkInterface::addInPort(NetworkLink *in_link, + CreditLink *credit_link) +{ + inNetLink = in_link; + in_link->setLinkConsumer(this); + outCreditLink = credit_link; + credit_link->setSourceQueue(outCreditQueue); +} + +void +NetworkInterface::addOutPort(NetworkLink *out_link, + CreditLink *credit_link, + SwitchID router_id) +{ + inCreditLink = credit_link; + credit_link->setLinkConsumer(this); + + outNetLink = out_link; + outFlitQueue = new flitBuffer(); + out_link->setSourceQueue(outFlitQueue); + + m_router_id = router_id; +} + +void +NetworkInterface::addNode(vector& in, + vector& out) +{ + inNode_ptr = in; + outNode_ptr = out; + + for (auto& it : in) { + if (it != nullptr) { + it->setConsumer(this); + } + } +} + + +/* + * The NI wakeup checks whether there are any ready messages in the protocol + * buffer. If yes, it picks that up, flitisizes it into a number of flits and + * puts it into an output buffer and schedules the output link. On a wakeup + * it also checks whether there are flits in the input link. If yes, it picks + * them up and if the flit is a tail, the NI inserts the corresponding message + * into the protocol buffer. It also checks for credits being sent by the + * downstream router. + */ + +void +NetworkInterface::wakeup() +{ + DPRINTF(RubyNetwork, "Network Interface %d connected to router %d " + "woke up at time: %lld\n", m_id, m_router_id, curCycle()); + + MsgPtr msg_ptr; + Tick curTime = clockEdge(); + + // Checking for messages coming from the protocol + // can pick up a message/cycle for each virtual net + for (int vnet = 0; vnet < inNode_ptr.size(); ++vnet) { + MessageBuffer *b = inNode_ptr[vnet]; + if (b == nullptr) { + continue; + } + + if (b->isReady(curTime)) { // Is there a message waiting + msg_ptr = b->peekMsgPtr(); + if (flitisizeMessage(msg_ptr, vnet)) { + b->dequeue(curTime); + } else { + break; + } + } + } + + scheduleOutputLink(); + checkReschedule(); + + /*********** Check the incoming flit link **********/ + + if (inNetLink->isReady(curCycle())) { + flit *t_flit = inNetLink->consumeLink(); + bool free_signal = false; + if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) { + free_signal = true; + + // enqueue into the protocol buffers + outNode_ptr[t_flit->get_vnet()]->enqueue( + t_flit->get_msg_ptr(), curTime, cyclesToTicks(Cycles(1))); + } + // Simply send a credit back since we are not buffering + // this flit in the NI + Credit *t_credit = new Credit(t_flit->get_vc(), free_signal, + curCycle()); + outCreditQueue->insert(t_credit); + outCreditLink-> + scheduleEventAbsolute(clockEdge(Cycles(1))); + + int vnet = t_flit->get_vnet(); + + // Update Stats + + // Latency + m_net_ptr->increment_received_flits(vnet); + Cycles network_delay = curCycle() - t_flit->get_enqueue_time(); + Cycles queueing_delay = t_flit->get_src_delay(); + + m_net_ptr->increment_flit_network_latency(network_delay, vnet); + m_net_ptr->increment_flit_queueing_latency(queueing_delay, vnet); + + if (t_flit->get_type() == TAIL_ || t_flit->get_type() == HEAD_TAIL_) { + m_net_ptr->increment_received_packets(vnet); + m_net_ptr->increment_packet_network_latency(network_delay, vnet); + m_net_ptr->increment_packet_queueing_latency(queueing_delay, vnet); + } + + // Hops + m_net_ptr->increment_total_hops(t_flit->get_route().hops_traversed); + + delete t_flit; + } + + /****************** Check the incoming credit link *******/ + + if (inCreditLink->isReady(curCycle())) { + Credit *t_credit = (Credit*) inCreditLink->consumeLink(); + m_out_vc_state[t_credit->get_vc()]->increment_credit(); + if (t_credit->is_free_signal()) { + m_out_vc_state[t_credit->get_vc()]->setState(IDLE_, curCycle()); + } + delete t_credit; + } +} + + +// Embed the protocol message into flits +bool +NetworkInterface::flitisizeMessage(MsgPtr msg_ptr, int vnet) +{ + Message *net_msg_ptr = msg_ptr.get(); + NetDest net_msg_dest = net_msg_ptr->getDestination(); + + // gets all the destinations associated with this message. + vector dest_nodes = net_msg_dest.getAllDest(); + + // Number of flits is dependent on the link bandwidth available. + // This is expressed in terms of bytes/cycle or the flit size + int num_flits = (int) ceil((double) m_net_ptr->MessageSizeType_to_int( + net_msg_ptr->getMessageSize())/m_net_ptr->getNiFlitSize()); + + // loop to convert all multicast messages into unicast messages + for (int ctr = 0; ctr < dest_nodes.size(); ctr++) { + + // this will return a free output virtual channel + int vc = calculateVC(vnet); + + if (vc == -1) { + return false ; + } + MsgPtr new_msg_ptr = msg_ptr->clone(); + NodeID destID = dest_nodes[ctr]; + + Message *new_net_msg_ptr = new_msg_ptr.get(); + if (dest_nodes.size() > 1) { + NetDest personal_dest; + for (int m = 0; m < (int) MachineType_NUM; m++) { + if ((destID >= MachineType_base_number((MachineType) m)) && + destID < MachineType_base_number((MachineType) (m+1))) { + // calculating the NetDest associated with this destID + personal_dest.clear(); + personal_dest.add((MachineID) {(MachineType) m, (destID - + MachineType_base_number((MachineType) m))}); + new_net_msg_ptr->getDestination() = personal_dest; + break; + } + } + net_msg_dest.removeNetDest(personal_dest); + // removing the destination from the original message to reflect + // that a message with this particular destination has been + // flitisized and an output vc is acquired + net_msg_ptr->getDestination().removeNetDest(personal_dest); + } + + // Embed Route into the flits + // NetDest format is used by the routing table + // Custom routing algorithms just need destID + RouteInfo route; + route.vnet = vnet; + route.net_dest = new_net_msg_ptr->getDestination(); + route.src_ni = m_id; + route.src_router = m_router_id; + route.dest_ni = destID; + route.dest_router = m_net_ptr->get_router_id(destID); + + // initialize hops_traversed to -1 + // so that the first router increments it to 0 + route.hops_traversed = -1; + + m_net_ptr->increment_injected_packets(vnet); + for (int i = 0; i < num_flits; i++) { + m_net_ptr->increment_injected_flits(vnet); + flit *fl = new flit(i, vc, vnet, route, num_flits, new_msg_ptr, + curCycle()); + + fl->set_src_delay(curCycle() - ticksToCycles(msg_ptr->getTime())); + m_ni_out_vcs[vc]->insert(fl); + } + + m_ni_out_vcs_enqueue_time[vc] = curCycle(); + m_out_vc_state[vc]->setState(ACTIVE_, curCycle()); + } + return true ; +} + +// Looking for a free output vc +int +NetworkInterface::calculateVC(int vnet) +{ + for (int i = 0; i < m_vc_per_vnet; i++) { + int delta = m_vc_allocator[vnet]; + m_vc_allocator[vnet]++; + if (m_vc_allocator[vnet] == m_vc_per_vnet) + m_vc_allocator[vnet] = 0; + + if (m_out_vc_state[(vnet*m_vc_per_vnet) + delta]->isInState( + IDLE_, curCycle())) { + return ((vnet*m_vc_per_vnet) + delta); + } + } + return -1; +} + + +/** This function looks at the NI buffers + * if some buffer has flits which are ready to traverse the link in the next + * cycle, and the downstream output vc associated with this flit has buffers + * left, the link is scheduled for the next cycle + */ + +void +NetworkInterface::scheduleOutputLink() +{ + int vc = m_vc_round_robin; + m_vc_round_robin++; + if (m_vc_round_robin == m_num_vcs) + m_vc_round_robin = 0; + + for (int i = 0; i < m_num_vcs; i++) { + vc++; + if (vc == m_num_vcs) + vc = 0; + + // model buffer backpressure + if (m_ni_out_vcs[vc]->isReady(curCycle()) && + m_out_vc_state[vc]->has_credit()) { + + bool is_candidate_vc = true; + int t_vnet = get_vnet(vc); + int vc_base = t_vnet * m_vc_per_vnet; + + if (m_net_ptr->isVNetOrdered(t_vnet)) { + for (int vc_offset = 0; vc_offset < m_vc_per_vnet; + vc_offset++) { + int t_vc = vc_base + vc_offset; + if (m_ni_out_vcs[t_vc]->isReady(curCycle())) { + if (m_ni_out_vcs_enqueue_time[t_vc] < + m_ni_out_vcs_enqueue_time[vc]) { + is_candidate_vc = false; + break; + } + } + } + } + if (!is_candidate_vc) + continue; + + m_out_vc_state[vc]->decrement_credit(); + // Just removing the flit + flit *t_flit = m_ni_out_vcs[vc]->getTopFlit(); + t_flit->set_time(curCycle() + Cycles(1)); + outFlitQueue->insert(t_flit); + // schedule the out link + outNetLink->scheduleEventAbsolute(clockEdge(Cycles(1))); + + if (t_flit->get_type() == TAIL_ || + t_flit->get_type() == HEAD_TAIL_) { + m_ni_out_vcs_enqueue_time[vc] = Cycles(INFINITE_); + } + return; + } + } +} + +int +NetworkInterface::get_vnet(int vc) +{ + for (int i = 0; i < m_virtual_networks; i++) { + if (vc >= (i*m_vc_per_vnet) && vc < ((i+1)*m_vc_per_vnet)) { + return i; + } + } + fatal("Could not determine vc"); +} + + +// Wakeup the NI in the next cycle if there are waiting +// messages in the protocol buffer, or waiting flits in the +// output VC buffer +void +NetworkInterface::checkReschedule() +{ + for (const auto& it : inNode_ptr) { + if (it == nullptr) { + continue; + } + + while (it->isReady(clockEdge())) { // Is there a message waiting + scheduleEvent(Cycles(1)); + return; + } + } + + for (int vc = 0; vc < m_num_vcs; vc++) { + if (m_ni_out_vcs[vc]->isReady(curCycle() + Cycles(1))) { + scheduleEvent(Cycles(1)); + return; + } + } +} + +void +NetworkInterface::print(std::ostream& out) const +{ + out << "[Network Interface]"; +} + +uint32_t +NetworkInterface::functionalWrite(Packet *pkt) +{ + uint32_t num_functional_writes = 0; + for (unsigned int i = 0; i < m_num_vcs; ++i) { + num_functional_writes += m_ni_out_vcs[i]->functionalWrite(pkt); + } + + num_functional_writes += outFlitQueue->functionalWrite(pkt); + return num_functional_writes; +} + +NetworkInterface * +GarnetNetworkInterfaceParams::create() +{ + return new NetworkInterface(this); +} diff --git a/src/mem/ruby/network/garnet2.0/NetworkInterface.hh b/src/mem/ruby/network/garnet2.0/NetworkInterface.hh new file mode 100644 index 000000000..85e0145af --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/NetworkInterface.hh @@ -0,0 +1,108 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_NETWORK_INTERFACE_HH__ +#define __MEM_RUBY_NETWORK_GARNET_NETWORK_INTERFACE_HH__ + +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/CreditLink.hh" +#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh" +#include "mem/ruby/network/garnet2.0/NetworkLink.hh" +#include "mem/ruby/network/garnet2.0/OutVcState.hh" +#include "mem/ruby/slicc_interface/Message.hh" +#include "params/GarnetNetworkInterface.hh" + +class MessageBuffer; +class flitBuffer; + +class NetworkInterface : public ClockedObject, public Consumer +{ + public: + typedef GarnetNetworkInterfaceParams Params; + NetworkInterface(const Params *p); + ~NetworkInterface(); + + void init(); + + void addInPort(NetworkLink *in_link, CreditLink *credit_link); + void addOutPort(NetworkLink *out_link, CreditLink *credit_link, + SwitchID router_id); + + void wakeup(); + void addNode(std::vector &inNode, + std::vector &outNode); + + void print(std::ostream& out) const; + int get_vnet(int vc); + int get_router_id() { return m_router_id; } + void init_net_ptr(GarnetNetwork *net_ptr) { m_net_ptr = net_ptr; } + + uint32_t functionalWrite(Packet *); + + private: + GarnetNetwork *m_net_ptr; + const NodeID m_id; + const int m_virtual_networks, m_vc_per_vnet, m_num_vcs; + int m_router_id; // id of my router + std::vector m_out_vc_state; + std::vector m_vc_allocator; + int m_vc_round_robin; // For round robin scheduling + flitBuffer *outFlitQueue; // For modeling link contention + flitBuffer *outCreditQueue; + + NetworkLink *inNetLink; + NetworkLink *outNetLink; + CreditLink *inCreditLink; + CreditLink *outCreditLink; + + // Input Flit Buffers + // The flit buffers which will serve the Consumer + std::vector m_ni_out_vcs; + std::vector m_ni_out_vcs_enqueue_time; + + // The Message buffers that takes messages from the protocol + std::vector inNode_ptr; + // The Message buffers that provides messages to the protocol + std::vector outNode_ptr; + + bool flitisizeMessage(MsgPtr msg_ptr, int vnet); + int calculateVC(int vnet); + void scheduleOutputLink(); + void checkReschedule(); +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_NETWORK_INTERFACE_HH__ diff --git a/src/mem/ruby/network/garnet2.0/NetworkLink.cc b/src/mem/ruby/network/garnet2.0/NetworkLink.cc new file mode 100644 index 000000000..6010071f0 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/NetworkLink.cc @@ -0,0 +1,94 @@ +/* + * 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/NetworkLink.hh" + +#include "mem/ruby/network/garnet2.0/CreditLink.hh" + +NetworkLink::NetworkLink(const Params *p) + : ClockedObject(p), Consumer(this), m_id(p->link_id), + m_type(NUM_LINK_TYPES_), + m_latency(p->link_latency), + linkBuffer(new flitBuffer()), link_consumer(nullptr), + link_srcQueue(nullptr), m_link_utilized(0), + m_vc_load(p->vcs_per_vnet * p->virt_nets) +{ +} + +NetworkLink::~NetworkLink() +{ + delete linkBuffer; +} + +void +NetworkLink::setLinkConsumer(Consumer *consumer) +{ + link_consumer = consumer; +} + +void +NetworkLink::setSourceQueue(flitBuffer *srcQueue) +{ + link_srcQueue = srcQueue; +} + +void +NetworkLink::wakeup() +{ + if (link_srcQueue->isReady(curCycle())) { + flit *t_flit = link_srcQueue->getTopFlit(); + t_flit->set_time(curCycle() + m_latency); + linkBuffer->insert(t_flit); + link_consumer->scheduleEventAbsolute(clockEdge(m_latency)); + m_link_utilized++; + m_vc_load[t_flit->get_vc()]++; + } +} + +NetworkLink * +NetworkLinkParams::create() +{ + return new NetworkLink(this); +} + +CreditLink * +CreditLinkParams::create() +{ + return new CreditLink(this); +} + +uint32_t +NetworkLink::functionalWrite(Packet *pkt) +{ + return linkBuffer->functionalWrite(pkt); +} diff --git a/src/mem/ruby/network/garnet2.0/NetworkLink.hh b/src/mem/ruby/network/garnet2.0/NetworkLink.hh new file mode 100644 index 000000000..cb69b39ad --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/NetworkLink.hh @@ -0,0 +1,88 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_NETWORK_LINK_HH__ +#define __MEM_RUBY_NETWORK_GARNET_NETWORK_LINK_HH__ + +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/flitBuffer.hh" +#include "params/NetworkLink.hh" +#include "sim/clocked_object.hh" + +class GarnetNetwork; + +class NetworkLink : public ClockedObject, public Consumer +{ + public: + typedef NetworkLinkParams Params; + NetworkLink(const Params *p); + ~NetworkLink(); + + void setLinkConsumer(Consumer *consumer); + void setSourceQueue(flitBuffer *srcQueue); + void setType(link_type type) { m_type = type; } + link_type getType() { return m_type; } + void print(std::ostream& out) const {} + int get_id() const { return m_id; } + void wakeup(); + + unsigned int getLinkUtilization() const { return m_link_utilized; } + const std::vector & getVcLoad() const { return m_vc_load; } + + inline bool isReady(Cycles curTime) + { return linkBuffer->isReady(curTime); } + + inline flit* peekLink() { return linkBuffer->peekTopFlit(); } + inline flit* consumeLink() { return linkBuffer->getTopFlit(); } + + uint32_t functionalWrite(Packet *); + + private: + const int m_id; + link_type m_type; + const Cycles m_latency; + + flitBuffer *linkBuffer; + Consumer *link_consumer; + flitBuffer *link_srcQueue; + + // Statistical variables + unsigned int m_link_utilized; + std::vector m_vc_load; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_NETWORK_LINK_HH__ diff --git a/src/mem/ruby/network/garnet2.0/OutVcState.cc b/src/mem/ruby/network/garnet2.0/OutVcState.cc new file mode 100644 index 000000000..1ad65ecd0 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/OutVcState.cc @@ -0,0 +1,65 @@ +/* + * 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/OutVcState.hh" + +#include "mem/ruby/system/RubySystem.hh" + +OutVcState::OutVcState(int id, GarnetNetwork *network_ptr) + : m_time(0) +{ + m_id = id; + m_vc_state = IDLE_; + + if (network_ptr->get_vnet_type(id) == DATA_VNET_) + m_max_credit_count = network_ptr->getBuffersPerDataVC(); + else + m_max_credit_count = network_ptr->getBuffersPerCtrlVC(); + + m_credit_count = m_max_credit_count; + assert(m_credit_count >= 1); +} + +void +OutVcState::increment_credit() +{ + m_credit_count++; + assert(m_credit_count <= m_max_credit_count); +} + +void +OutVcState::decrement_credit() +{ + m_credit_count--; + assert(m_credit_count >= 0); +} diff --git a/src/mem/ruby/network/garnet2.0/OutVcState.hh b/src/mem/ruby/network/garnet2.0/OutVcState.hh new file mode 100644 index 000000000..b9c008df6 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/OutVcState.hh @@ -0,0 +1,70 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_OUTVC_STATE_HH__ +#define __MEM_RUBY_NETWORK_GARNET_OUTVC_STATE_HH__ + +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh" + +class OutVcState +{ + public: + OutVcState(int id, GarnetNetwork *network_ptr); + + int get_credit_count() { return m_credit_count; } + inline bool has_credit() { return (m_credit_count > 0); } + void increment_credit(); + void decrement_credit(); + + inline bool + isInState(VC_state_type state, Cycles request_time) + { + return ((m_vc_state == state) && (request_time >= m_time) ); + } + inline void + setState(VC_state_type state, Cycles time) + { + m_vc_state = state; + m_time = time; + } + + private: + int m_id ; + Cycles m_time; + VC_state_type m_vc_state; + int m_credit_count; + int m_max_credit_count; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_OUTVC_STATE_HH__ diff --git a/src/mem/ruby/network/garnet2.0/OutputUnit.cc b/src/mem/ruby/network/garnet2.0/OutputUnit.cc new file mode 100644 index 000000000..85fef5e53 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/OutputUnit.cc @@ -0,0 +1,168 @@ +/* + * 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/OutputUnit.hh" + +#include "base/stl_helpers.hh" +#include "debug/RubyNetwork.hh" +#include "mem/ruby/network/garnet2.0/Credit.hh" +#include "mem/ruby/network/garnet2.0/Router.hh" + +using namespace std; +using m5::stl_helpers::deletePointers; + +OutputUnit::OutputUnit(int id, PortDirection direction, Router *router) + : Consumer(router) +{ + m_id = id; + m_direction = direction; + m_router = router; + m_num_vcs = m_router->get_num_vcs(); + m_vc_per_vnet = m_router->get_vc_per_vnet(); + m_out_buffer = new flitBuffer(); + + for (int i = 0; i < m_num_vcs; i++) { + m_outvc_state.push_back(new OutVcState(i, m_router->get_net_ptr())); + } +} + +OutputUnit::~OutputUnit() +{ + delete m_out_buffer; + deletePointers(m_outvc_state); +} + +void +OutputUnit::decrement_credit(int out_vc) +{ + DPRINTF(RubyNetwork, "Router %d OutputUnit %d decrementing credit for " + "outvc %d at time: %lld\n", + m_router->get_id(), m_id, out_vc, m_router->curCycle()); + + m_outvc_state[out_vc]->decrement_credit(); +} + +void +OutputUnit::increment_credit(int out_vc) +{ + DPRINTF(RubyNetwork, "Router %d OutputUnit %d incrementing credit for " + "outvc %d at time: %lld\n", + m_router->get_id(), m_id, out_vc, m_router->curCycle()); + + m_outvc_state[out_vc]->increment_credit(); +} + +// Check if the output VC (i.e., input VC at next router) +// has free credits (i..e, buffer slots). +// This is tracked by OutVcState +bool +OutputUnit::has_credit(int out_vc) +{ + assert(m_outvc_state[out_vc]->isInState(ACTIVE_, m_router->curCycle())); + return m_outvc_state[out_vc]->has_credit(); +} + + +// Check if the output port (i.e., input port at next router) has free VCs. +bool +OutputUnit::has_free_vc(int vnet) +{ + int vc_base = vnet*m_vc_per_vnet; + for (int vc = vc_base; vc < vc_base + m_vc_per_vnet; vc++) { + if (is_vc_idle(vc, m_router->curCycle())) + return true; + } + + return false; +} + +// Assign a free output VC to the winner of Switch Allocation +int +OutputUnit::select_free_vc(int vnet) +{ + int vc_base = vnet*m_vc_per_vnet; + for (int vc = vc_base; vc < vc_base + m_vc_per_vnet; vc++) { + if (is_vc_idle(vc, m_router->curCycle())) { + m_outvc_state[vc]->setState(ACTIVE_, m_router->curCycle()); + return vc; + } + } + + return -1; +} + +/* + * The wakeup function of the OutputUnit reads the credit signal from the + * downstream router for the output VC (i.e., input VC at downstream router). + * It increments the credit count in the appropriate output VC state. + * If the credit carries is_free_signal as true, + * the output VC is marked IDLE. + */ + +void +OutputUnit::wakeup() +{ + if (m_credit_link->isReady(m_router->curCycle())) { + Credit *t_credit = (Credit*) m_credit_link->consumeLink(); + increment_credit(t_credit->get_vc()); + + if (t_credit->is_free_signal()) + set_vc_state(IDLE_, t_credit->get_vc(), m_router->curCycle()); + + delete t_credit; + } +} + +flitBuffer* +OutputUnit::getOutQueue() +{ + return m_out_buffer; +} + +void +OutputUnit::set_out_link(NetworkLink *link) +{ + m_out_link = link; +} + +void +OutputUnit::set_credit_link(CreditLink *credit_link) +{ + m_credit_link = credit_link; +} + +uint32_t +OutputUnit::functionalWrite(Packet *pkt) +{ + return m_out_buffer->functionalWrite(pkt); +} diff --git a/src/mem/ruby/network/garnet2.0/OutputUnit.hh b/src/mem/ruby/network/garnet2.0/OutputUnit.hh new file mode 100644 index 000000000..7b6d5497c --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/OutputUnit.hh @@ -0,0 +1,113 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_OUTPUT_UNIT_HH__ +#define __MEM_RUBY_NETWORK_GARNET_OUTPUT_UNIT_HH__ + +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/CreditLink.hh" +#include "mem/ruby/network/garnet2.0/NetworkLink.hh" +#include "mem/ruby/network/garnet2.0/OutVcState.hh" +#include "mem/ruby/network/garnet2.0/Router.hh" +#include "mem/ruby/network/garnet2.0/flitBuffer.hh" + +class OutputUnit : public Consumer +{ + public: + OutputUnit(int id, PortDirection direction, Router *router); + ~OutputUnit(); + void set_out_link(NetworkLink *link); + void set_credit_link(CreditLink *credit_link); + void wakeup(); + flitBuffer* getOutQueue(); + void print(std::ostream& out) const {}; + void decrement_credit(int out_vc); + void increment_credit(int out_vc); + bool has_credit(int out_vc); + bool has_free_vc(int vnet); + int select_free_vc(int vnet); + + inline PortDirection get_direction() { return m_direction; } + + int + get_credit_count(int vc) + { + return m_outvc_state[vc]->get_credit_count(); + } + + inline int + get_outlink_id() + { + return m_out_link->get_id(); + } + + inline void + set_vc_state(VC_state_type state, int vc, Cycles curTime) + { + m_outvc_state[vc]->setState(state, curTime); + } + + inline bool + is_vc_idle(int vc, Cycles curTime) + { + return (m_outvc_state[vc]->isInState(IDLE_, curTime)); + } + + inline void + insert_flit(flit *t_flit) + { + m_out_buffer->insert(t_flit); + m_out_link->scheduleEventAbsolute(m_router->clockEdge(Cycles(1))); + } + + uint32_t functionalWrite(Packet *pkt); + + private: + int m_id; + PortDirection m_direction; + int m_num_vcs; + int m_vc_per_vnet; + Router *m_router; + NetworkLink *m_out_link; + CreditLink *m_credit_link; + + flitBuffer *m_out_buffer; // This is for the network link to consume + std::vector m_outvc_state; // vc state of downstream router + +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_OUTPUT_UNIT_HH__ diff --git a/src/mem/ruby/network/garnet2.0/README.txt b/src/mem/ruby/network/garnet2.0/README.txt new file mode 100644 index 000000000..817b1d48d --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/README.txt @@ -0,0 +1,71 @@ +README for Garnet2.0 +Written By: Tushar Krishna (tushar@ece.gatech.edu) +Last Updated: Jul 9, 2016 +------------------------------------------------------- + +Garnet Network Parameters and Setup: +- GarnetNetwork.py + * defaults can be overwritten from command line (see configs/network/Network.py) +- GarnetNetwork.hh/cc + * sets up the routers and links + * collects stats + + +CODE FLOW +- NetworkInterface.cc::wakeup() + * Every NI connected to one coherence protocol controller on one end, and one router on the other. + * receives messages from coherence protocol buffer in appropriate vnet and converts them into network packets and sends them into the network. + * garnet2.0 adds the ability to capture a network trace at this point. + * receives flits from the network, extracts the protocol message and sends it to the coherence protocol buffer in appropriate vnet. + * manages flow-control (i.e., credits) with its attached router. + * The consuming flit/credit output link of the NI is put in the global event queue with a timestamp set to next cycle. + The eventqueue calls the wakeup function in the consumer. + +- NetworkLink.cc::wakeup() + * receives flits from NI/router and sends it to NI/router after m_latency cycles delay + * Default latency value for every link can be set from command line (see configs/network/Network.py) + * Per link latency can be overwritten in the topology file + * The consumer of the link (NI/router) is put in the global event queue with a timestamp set after m_latency cycles. + The eventqueue calls the wakeup function in the consumer. + +- Router.cc::wakeup() + * Loop through all InputUnits and call their wakeup() + * Loop through all OutputUnits and call their wakeup() + * Call SwitchAllocator's wakeup() + * Call CrossbarSwitch's wakeup() + * The router's wakeup function is called whenever any of its modules (InputUnit, OutputUnit, SwitchAllocator, CrossbarSwitch) have + a ready flit/credit to act upon this cycle. + +- InputUnit.cc::wakeup() + * Read input flit from upstream router if it is ready for this cycle + * For HEAD/HEAD_TAIL flits, perform route computation, and update route in the VC. + * Buffer the flit for (m_latency - 1) cycles and mark it valid for SwitchAllocation starting that cycle. + * Default latency for every router can be set from command line (see configs/network/Network.py) + * Per router latency (i.e., num pipeline stages) can be set in the topology file + +- OutputUnit.cc::wakeup() + * Read input credit from downstream router if it is ready for this cycle + * Increment the credit in the appropriate output VC state. + * Mark output VC as free if the credit carries is_free_signal as true + +- SwitchAllocator.cc::wakeup() + * Note: SwitchAllocator performs VC arbitration and selection within it. + * SA-I (or SA-i): Loop through all input VCs at every input port, and select one in a round robin manner. + * For HEAD/HEAD_TAIL flits only select an input VC whose output port has at least one free output VC. + * For BODY/TAIL flits, only select an input VC that has credits in its output VC. + * Place a request for the output port from this VC. + * SA-II (or SA-o): Loop through all output ports, and select one input VC (that placed a request during SA-I) as the winner for this output port in a round robin manner. + * For HEAD/HEAD_TAIL flits, perform outvc allocation (i.e., select a free VC from the output port). + * For BODY/TAIL flits, decrement a credit in the output vc. + * Read the flit out from the input VC, and send it to the CrossbarSwitch + * Send a increment_credit signal to the upstream router for this input VC. + * for HEAD_TAIL/TAIL flits, mark is_free_signal as true in the credit. + * The input unit sends the credit out on the credit link to the upstream router. + * Reschedule the Router to wakeup next cycle for any flits ready for SA next cycle. + +- CrossbarSwitch.cc::wakeup() + * Loop through all input ports, and send the winning flit out of its output port onto the output link. + * The consuming flit output link of the router is put in the global event queue with a timestamp set to next cycle. + The eventqueue calls the wakeup function in the consumer. + + diff --git a/src/mem/ruby/network/garnet2.0/Router.cc b/src/mem/ruby/network/garnet2.0/Router.cc new file mode 100644 index 000000000..65a730096 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/Router.cc @@ -0,0 +1,296 @@ +/* + * 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/Router.hh" + +#include "base/stl_helpers.hh" +#include "debug/RubyNetwork.hh" +#include "mem/ruby/network/garnet2.0/CreditLink.hh" +#include "mem/ruby/network/garnet2.0/CrossbarSwitch.hh" +#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh" +#include "mem/ruby/network/garnet2.0/InputUnit.hh" +#include "mem/ruby/network/garnet2.0/NetworkLink.hh" +#include "mem/ruby/network/garnet2.0/OutputUnit.hh" +#include "mem/ruby/network/garnet2.0/RoutingUnit.hh" +#include "mem/ruby/network/garnet2.0/SwitchAllocator.hh" + +using namespace std; +using m5::stl_helpers::deletePointers; + +Router::Router(const Params *p) + : BasicRouter(p), Consumer(this) +{ + m_latency = p->latency; + m_virtual_networks = p->virt_nets; + m_vc_per_vnet = p->vcs_per_vnet; + m_num_vcs = m_virtual_networks * m_vc_per_vnet; + + m_routing_unit = new RoutingUnit(this); + m_sw_alloc = new SwitchAllocator(this); + m_switch = new CrossbarSwitch(this); + + m_input_unit.clear(); + m_output_unit.clear(); +} + +Router::~Router() +{ + deletePointers(m_input_unit); + deletePointers(m_output_unit); + delete m_routing_unit; + delete m_sw_alloc; + delete m_switch; +} + +void +Router::init() +{ + BasicRouter::init(); + + m_sw_alloc->init(); + m_switch->init(); +} + +void +Router::wakeup() +{ + DPRINTF(RubyNetwork, "Router %d woke up\n", m_id); + + // check for incoming flits + for (int inport = 0; inport < m_input_unit.size(); inport++) { + m_input_unit[inport]->wakeup(); + } + + // check for incoming credits + // Note: the credit update is happening before SA + // buffer turnaround time = + // credit traversal (1-cycle) + SA (1-cycle) + Link Traversal (1-cycle) + // if we want the credit update to take place after SA, this loop should + // be moved after the SA request + for (int outport = 0; outport < m_output_unit.size(); outport++) { + m_output_unit[outport]->wakeup(); + } + + // Switch Allocation + m_sw_alloc->wakeup(); + + // Switch Traversal + m_switch->wakeup(); +} + +void +Router::addInPort(PortDirection inport_dirn, + NetworkLink *in_link, CreditLink *credit_link) +{ + int port_num = m_input_unit.size(); + InputUnit *input_unit = new InputUnit(port_num, inport_dirn, this); + + input_unit->set_in_link(in_link); + input_unit->set_credit_link(credit_link); + in_link->setLinkConsumer(this); + credit_link->setSourceQueue(input_unit->getCreditQueue()); + + m_input_unit.push_back(input_unit); + + m_routing_unit->addInDirection(inport_dirn, port_num); +} + +void +Router::addOutPort(PortDirection outport_dirn, + NetworkLink *out_link, + const NetDest& routing_table_entry, int link_weight, + CreditLink *credit_link) +{ + int port_num = m_output_unit.size(); + OutputUnit *output_unit = new OutputUnit(port_num, outport_dirn, this); + + output_unit->set_out_link(out_link); + output_unit->set_credit_link(credit_link); + credit_link->setLinkConsumer(this); + out_link->setSourceQueue(output_unit->getOutQueue()); + + m_output_unit.push_back(output_unit); + + m_routing_unit->addRoute(routing_table_entry); + m_routing_unit->addWeight(link_weight); + m_routing_unit->addOutDirection(outport_dirn, port_num); +} + +PortDirection +Router::getOutportDirection(int outport) +{ + return m_output_unit[outport]->get_direction(); +} + +PortDirection +Router::getInportDirection(int inport) +{ + return m_input_unit[inport]->get_direction(); +} + +int +Router::route_compute(RouteInfo route, int inport, PortDirection inport_dirn) +{ + return m_routing_unit->outportCompute(route, inport, inport_dirn); +} + +void +Router::grant_switch(int inport, flit *t_flit) +{ + m_switch->update_sw_winner(inport, t_flit); +} + +void +Router::schedule_wakeup(Cycles time) +{ + // wake up after time cycles + scheduleEvent(time); +} + +std::string +Router::getPortDirectionName(PortDirection direction) +{ + // PortDirection is actually a string + // If not, then this function should add a switch + // statement to convert direction to a string + // that can be printed out + return direction; +} + +void +Router::regStats() +{ + BasicRouter::regStats(); + + m_buffer_reads + .name(name() + ".buffer_reads") + .flags(Stats::nozero) + ; + + m_buffer_writes + .name(name() + ".buffer_writes") + .flags(Stats::nozero) + ; + + m_crossbar_activity + .name(name() + ".crossbar_activity") + .flags(Stats::nozero) + ; + + m_sw_input_arbiter_activity + .name(name() + ".sw_input_arbiter_activity") + .flags(Stats::nozero) + ; + + m_sw_output_arbiter_activity + .name(name() + ".sw_output_arbiter_activity") + .flags(Stats::nozero) + ; +} + +void +Router::collateStats() +{ + for (int j = 0; j < m_virtual_networks; j++) { + for (int i = 0; i < m_input_unit.size(); i++) { + m_buffer_reads += m_input_unit[i]->get_buf_read_activity(j); + m_buffer_writes += m_input_unit[i]->get_buf_write_activity(j); + } + } + + m_sw_input_arbiter_activity = m_sw_alloc->get_input_arbiter_activity(); + m_sw_output_arbiter_activity = m_sw_alloc->get_output_arbiter_activity(); + m_crossbar_activity = m_switch->get_crossbar_activity(); +} + +void +Router::resetStats() +{ + for (int j = 0; j < m_virtual_networks; j++) { + for (int i = 0; i < m_input_unit.size(); i++) { + m_input_unit[i]->resetStats(); + } + } +} + +void +Router::printFaultVector(ostream& out) +{ + int temperature_celcius = BASELINE_TEMPERATURE_CELCIUS; + int num_fault_types = m_network_ptr->fault_model->number_of_fault_types; + float fault_vector[num_fault_types]; + get_fault_vector(temperature_celcius, fault_vector); + out << "Router-" << m_id << " fault vector: " << endl; + for (int fault_type_index = 0; fault_type_index < num_fault_types; + fault_type_index++) { + out << " - probability of ("; + out << + m_network_ptr->fault_model->fault_type_to_string(fault_type_index); + out << ") = "; + out << fault_vector[fault_type_index] << endl; + } +} + +void +Router::printAggregateFaultProbability(std::ostream& out) +{ + int temperature_celcius = BASELINE_TEMPERATURE_CELCIUS; + float aggregate_fault_prob; + get_aggregate_fault_probability(temperature_celcius, + &aggregate_fault_prob); + out << "Router-" << m_id << " fault probability: "; + out << aggregate_fault_prob << endl; +} + +uint32_t +Router::functionalWrite(Packet *pkt) +{ + uint32_t num_functional_writes = 0; + num_functional_writes += m_switch->functionalWrite(pkt); + + for (uint32_t i = 0; i < m_input_unit.size(); i++) { + num_functional_writes += m_input_unit[i]->functionalWrite(pkt); + } + + for (uint32_t i = 0; i < m_output_unit.size(); i++) { + num_functional_writes += m_output_unit[i]->functionalWrite(pkt); + } + + return num_functional_writes; +} + +Router * +GarnetRouterParams::create() +{ + return new Router(this); +} diff --git a/src/mem/ruby/network/garnet2.0/Router.hh b/src/mem/ruby/network/garnet2.0/Router.hh new file mode 100644 index 000000000..a9ce5f80e --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/Router.hh @@ -0,0 +1,140 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_ROUTER_HH__ +#define __MEM_RUBY_NETWORK_GARNET_ROUTER_HH__ + +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/common/NetDest.hh" +#include "mem/ruby/network/BasicRouter.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh" +#include "mem/ruby/network/garnet2.0/flit.hh" +#include "params/GarnetRouter.hh" + +class NetworkLink; +class CreditLink; +class InputUnit; +class OutputUnit; +class RoutingUnit; +class SwitchAllocator; +class CrossbarSwitch; +class FaultModel; + +class Router : public BasicRouter, public Consumer +{ + public: + typedef GarnetRouterParams Params; + Router(const Params *p); + + ~Router(); + + void wakeup(); + void print(std::ostream& out) const {}; + + void init(); + void addInPort(PortDirection inport_dirn, NetworkLink *link, + CreditLink *credit_link); + void addOutPort(PortDirection outport_dirn, NetworkLink *link, + const NetDest& routing_table_entry, + int link_weight, CreditLink *credit_link); + + Cycles get_pipe_stages(){ return m_latency; } + int get_num_vcs() { return m_num_vcs; } + int get_num_vnets() { return m_virtual_networks; } + int get_vc_per_vnet() { return m_vc_per_vnet; } + int get_num_inports() { return m_input_unit.size(); } + int get_num_outports() { return m_output_unit.size(); } + int get_id() { return m_id; } + + void init_net_ptr(GarnetNetwork* net_ptr) + { + m_network_ptr = net_ptr; + } + + GarnetNetwork* get_net_ptr() { return m_network_ptr; } + std::vector& get_inputUnit_ref() { return m_input_unit; } + std::vector& get_outputUnit_ref() { return m_output_unit; } + PortDirection getOutportDirection(int outport); + PortDirection getInportDirection(int inport); + + int route_compute(RouteInfo route, int inport, PortDirection direction); + void grant_switch(int inport, flit *t_flit); + void schedule_wakeup(Cycles time); + + std::string getPortDirectionName(PortDirection direction); + void printFaultVector(std::ostream& out); + void printAggregateFaultProbability(std::ostream& out); + + void regStats(); + void collateStats(); + void resetStats(); + + // For Fault Model: + bool get_fault_vector(int temperature, float fault_vector[]) { + return m_network_ptr->fault_model->fault_vector(m_id, temperature, + fault_vector); + } + bool get_aggregate_fault_probability(int temperature, + float *aggregate_fault_prob) { + return m_network_ptr->fault_model->fault_prob(m_id, temperature, + aggregate_fault_prob); + } + + uint32_t functionalWrite(Packet *); + + private: + Cycles m_latency; + int m_virtual_networks, m_num_vcs, m_vc_per_vnet; + GarnetNetwork *m_network_ptr; + + std::vector m_input_unit; + std::vector m_output_unit; + RoutingUnit *m_routing_unit; + SwitchAllocator *m_sw_alloc; + CrossbarSwitch *m_switch; + + // Statistical variables required for power computations + Stats::Scalar m_buffer_reads; + Stats::Scalar m_buffer_writes; + + Stats::Scalar m_sw_input_arbiter_activity; + Stats::Scalar m_sw_output_arbiter_activity; + + Stats::Scalar m_crossbar_activity; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_ROUTER_HH__ diff --git a/src/mem/ruby/network/garnet2.0/RoutingUnit.cc b/src/mem/ruby/network/garnet2.0/RoutingUnit.cc new file mode 100644 index 000000000..aa5ff53c1 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/RoutingUnit.cc @@ -0,0 +1,241 @@ +/* + * 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/RoutingUnit.hh" + +#include "base/cast.hh" +#include "mem/ruby/network/garnet2.0/InputUnit.hh" +#include "mem/ruby/network/garnet2.0/Router.hh" +#include "mem/ruby/slicc_interface/Message.hh" + +RoutingUnit::RoutingUnit(Router *router) +{ + m_router = router; + m_routing_table.clear(); + m_weight_table.clear(); +} + +void +RoutingUnit::addRoute(const NetDest& routing_table_entry) +{ + m_routing_table.push_back(routing_table_entry); +} + +void +RoutingUnit::addWeight(int link_weight) +{ + m_weight_table.push_back(link_weight); +} + +/* + * This is the default routing algorithm in garnet. + * The routing table is populated during topology creation. + * Routes can be biased via weight assignments in the topology file. + * Correct weight assignments are critical to provide deadlock avoidance. + */ + +int +RoutingUnit::lookupRoutingTable(int vnet, NetDest msg_destination) +{ + // First find all possible output link candidates + // For ordered vnet, just choose the first + // (to make sure different packets don't choose different routes) + // For unordered vnet, randomly choose any of the links + // To have a strict ordering between links, they should be given + // different weights in the topology file + + int output_link = -1; + int min_weight = INFINITE_; + std::vector output_link_candidates; + int num_candidates = 0; + + // Identify the minimum weight among the candidate output links + for (int link = 0; link < m_routing_table.size(); link++) { + if (msg_destination.intersectionIsNotEmpty(m_routing_table[link])) { + + if (m_weight_table[link] <= min_weight) + min_weight = m_weight_table[link]; + } + } + + // Collect all candidate output links with this minimum weight + for (int link = 0; link < m_routing_table.size(); link++) { + if (msg_destination.intersectionIsNotEmpty(m_routing_table[link])) { + + if (m_weight_table[link] == min_weight) { + + num_candidates++; + output_link_candidates.push_back(link); + } + } + } + + if (output_link_candidates.size() == 0) { + fatal("Fatal Error:: No Route exists from this Router."); + exit(0); + } + + // Randomly select any candidate output link + int candidate = 0; + if (!(m_router->get_net_ptr())->isVNetOrdered(vnet)) + candidate = rand() % num_candidates; + + output_link = output_link_candidates.at(candidate); + return output_link; +} + + +void +RoutingUnit::addInDirection(PortDirection inport_dirn, int inport_idx) +{ + m_inports_dirn2idx[inport_dirn] = inport_idx; + m_inports_idx2dirn[inport_idx] = inport_dirn; +} + +void +RoutingUnit::addOutDirection(PortDirection outport_dirn, int outport_idx) +{ + m_outports_dirn2idx[outport_dirn] = outport_idx; + m_outports_idx2dirn[outport_idx] = outport_dirn; +} + +// outportCompute() is called by the InputUnit +// It calls the routing table by default. +// A template for adaptive topology-specific routing algorithm +// implementations using port directions rather than a static routing +// table is provided here. + +int +RoutingUnit::outportCompute(RouteInfo route, int inport, + PortDirection inport_dirn) +{ + int outport = -1; + + if (route.dest_router == m_router->get_id()) { + + // Multiple NIs may be connected to this router, + // all with output port direction = "Local" + // Get exact outport id from table + outport = lookupRoutingTable(route.vnet, route.net_dest); + return outport; + } + + // Routing Algorithm set in GarnetNetwork.py + // Can be over-ridden from command line using --routing-algorithm = 1 + RoutingAlgorithm routing_algorithm = + (RoutingAlgorithm) m_router->get_net_ptr()->getRoutingAlgorithm(); + + switch (routing_algorithm) { + case TABLE_: outport = + lookupRoutingTable(route.vnet, route.net_dest); break; + case XY_: outport = + outportComputeXY(route, inport, inport_dirn); break; + // any custom algorithm + case CUSTOM_: outport = + outportComputeCustom(route, inport, inport_dirn); break; + default: outport = + lookupRoutingTable(route.vnet, route.net_dest); break; + } + + assert(outport != -1); + return outport; +} + +// XY routing implemented using port directions +// Only for reference purpose in a Mesh +// By default Garnet uses the routing table +int +RoutingUnit::outportComputeXY(RouteInfo route, + int inport, + PortDirection inport_dirn) +{ + PortDirection outport_dirn = "Unknown"; + + int num_rows = m_router->get_net_ptr()->getNumRows(); + int num_cols = m_router->get_net_ptr()->getNumCols(); + assert(num_rows > 0 && num_cols > 0); + + int my_id = m_router->get_id(); + int my_x = my_id % num_cols; + int my_y = my_id / num_cols; + + int dest_id = route.dest_router; + int dest_x = dest_id % num_cols; + int dest_y = dest_id / num_cols; + + int x_hops = abs(dest_x - my_x); + int y_hops = abs(dest_y - my_y); + + bool x_dirn = (dest_x >= my_x); + bool y_dirn = (dest_y >= my_y); + + // already checked that in outportCompute() function + assert(!(x_hops == 0 && y_hops == 0)); + + if (x_hops > 0) { + if (x_dirn) { + assert(inport_dirn == "Local" || inport_dirn == "West"); + outport_dirn = "East"; + } else { + assert(inport_dirn == "Local" || inport_dirn == "East"); + outport_dirn = "West"; + } + } else if (y_hops > 0) { + if (y_dirn) { + // "Local" or "South" or "West" or "East" + assert(inport_dirn != "North"); + outport_dirn = "North"; + } else { + // "Local" or "North" or "West" or "East" + assert(inport_dirn != "South"); + outport_dirn = "South"; + } + } else { + // x_hops == 0 and y_hops == 0 + // this is not possible + // already checked that in outportCompute() function + assert(0); + } + + return m_outports_dirn2idx[outport_dirn]; +} + +// Template for implementing custom routing algorithm +// using port directions. (Example adaptive) +int +RoutingUnit::outportComputeCustom(RouteInfo route, + int inport, + PortDirection inport_dirn) +{ + assert(0); +} diff --git a/src/mem/ruby/network/garnet2.0/RoutingUnit.hh b/src/mem/ruby/network/garnet2.0/RoutingUnit.hh new file mode 100644 index 000000000..46b0969f3 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/RoutingUnit.hh @@ -0,0 +1,89 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_ROUTING_UNIT_HH__ +#define __MEM_RUBY_NETWORK_GARNET_ROUTING_UNIT_HH__ + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/common/NetDest.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh" +#include "mem/ruby/network/garnet2.0/flit.hh" + +class InputUnit; +class Router; + +class RoutingUnit +{ + public: + RoutingUnit(Router *router); + int outportCompute(RouteInfo route, + int inport, + PortDirection inport_dirn); + + // Topology-agnostic Routing Table based routing (default) + void addRoute(const NetDest& routing_table_entry); + void addWeight(int link_weight); + + // get output port from routing table + int lookupRoutingTable(int vnet, NetDest net_dest); + + // Topology-specific direction based routing + void addInDirection(PortDirection inport_dirn, int inport); + void addOutDirection(PortDirection outport_dirn, int outport); + + // Routing for Mesh + int outportComputeXY(RouteInfo route, + int inport, + PortDirection inport_dirn); + + // Custom Routing Algorithm using Port Directions + int outportComputeCustom(RouteInfo route, + int inport, + PortDirection inport_dirn); + + private: + Router *m_router; + + // Routing Table + std::vector m_routing_table; + std::vector m_weight_table; + + // Inport and Outport direction to idx maps + std::map m_inports_dirn2idx; + std::map m_inports_idx2dirn; + std::map m_outports_idx2dirn; + std::map m_outports_dirn2idx; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_ROUTING_UNIT_HH__ diff --git a/src/mem/ruby/network/garnet2.0/SConscript b/src/mem/ruby/network/garnet2.0/SConscript new file mode 100644 index 000000000..866bab9ac --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/SConscript @@ -0,0 +1,53 @@ +# -*- mode:python -*- + +# 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: Tushar Krishna + +Import('*') + +if env['PROTOCOL'] == 'None': + Return() + +SimObject('GarnetLink.py') +SimObject('GarnetNetwork.py') + +Source('GarnetLink.cc') +Source('GarnetNetwork.cc') +Source('InputUnit.cc') +Source('NetworkInterface.cc') +Source('NetworkLink.cc') +Source('OutVcState.cc') +Source('OutputUnit.cc') +Source('Router.cc') +Source('RoutingUnit.cc') +Source('SwitchAllocator.cc') +Source('CrossbarSwitch.cc') +Source('VirtualChannel.cc') +Source('flitBuffer.cc') +Source('flit.cc') +Source('Credit.cc') diff --git a/src/mem/ruby/network/garnet2.0/SwitchAllocator.cc b/src/mem/ruby/network/garnet2.0/SwitchAllocator.cc new file mode 100644 index 000000000..7916802a5 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/SwitchAllocator.cc @@ -0,0 +1,389 @@ +/* + * 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/SwitchAllocator.hh" + +#include "debug/RubyNetwork.hh" +#include "mem/ruby/network/garnet2.0/GarnetNetwork.hh" +#include "mem/ruby/network/garnet2.0/InputUnit.hh" +#include "mem/ruby/network/garnet2.0/OutputUnit.hh" +#include "mem/ruby/network/garnet2.0/Router.hh" + +SwitchAllocator::SwitchAllocator(Router *router) + : Consumer(router) +{ + m_router = router; + m_num_vcs = m_router->get_num_vcs(); + m_vc_per_vnet = m_router->get_vc_per_vnet(); + + m_input_arbiter_activity = 0; + m_output_arbiter_activity = 0; +} + +void +SwitchAllocator::init() +{ + m_input_unit = m_router->get_inputUnit_ref(); + m_output_unit = m_router->get_outputUnit_ref(); + + m_num_inports = m_router->get_num_inports(); + m_num_outports = m_router->get_num_outports(); + m_round_robin_inport.resize(m_num_outports); + m_round_robin_invc.resize(m_num_inports); + m_port_requests.resize(m_num_outports); + m_vc_winners.resize(m_num_outports); + + for (int i = 0; i < m_num_inports; i++) { + m_round_robin_invc[i] = 0; + } + + for (int i = 0; i < m_num_outports; i++) { + m_port_requests[i].resize(m_num_inports); + m_vc_winners[i].resize(m_num_inports); + + m_round_robin_inport[i] = 0; + + for (int j = 0; j < m_num_inports; j++) { + m_port_requests[i][j] = false; // [outport][inport] + } + } +} + +/* + * The wakeup function of the SwitchAllocator performs a 2-stage + * seperable switch allocation. At the end of the 2nd stage, a free + * output VC is assigned to the winning flits of each output port. + * There is no separate VCAllocator stage like the one in garnet1.0. + * At the end of this function, the router is rescheduled to wakeup + * next cycle for peforming SA for any flits ready next cycle. + */ + +void +SwitchAllocator::wakeup() +{ + arbitrate_inports(); // First stage of allocation + arbitrate_outports(); // Second stage of allocation + + clear_request_vector(); + check_for_wakeup(); +} + +/* + * SA-I (or SA-i) loops through all input VCs at every input port, + * and selects one in a round robin manner. + * - For HEAD/HEAD_TAIL flits only selects an input VC whose output port + * has at least one free output VC. + * - For BODY/TAIL flits, only selects an input VC that has credits + * in its output VC. + * Places a request for the output port from this input VC. + */ + +void +SwitchAllocator::arbitrate_inports() +{ + // Select a VC from each input in a round robin manner + // Independent arbiter at each input port + for (int inport = 0; inport < m_num_inports; inport++) { + int invc = m_round_robin_invc[inport]; + + // Select next round robin vc candidate within valid vnet + int next_round_robin_invc = invc; + next_round_robin_invc++; + if (next_round_robin_invc >= m_num_vcs) + next_round_robin_invc = 0; + m_round_robin_invc[inport] = next_round_robin_invc; + + for (int invc_iter = 0; invc_iter < m_num_vcs; invc_iter++) { + + if (m_input_unit[inport]->need_stage(invc, SA_, + m_router->curCycle())) { + + // This flit is in SA stage + + int outport = m_input_unit[inport]->get_outport(invc); + int outvc = m_input_unit[inport]->get_outvc(invc); + + // check if the flit in this InputVC is allowed to be sent + // send_allowed conditions described in that function. + bool make_request = + send_allowed(inport, invc, outport, outvc); + + if (make_request) { + m_input_arbiter_activity++; + m_port_requests[outport][inport] = true; + m_vc_winners[outport][inport]= invc; + break; // got one vc winner for this port + } + } + + invc++; + if (invc >= m_num_vcs) + invc = 0; + } + } +} + +/* + * SA-II (or SA-o) loops through all output ports, + * and selects one input VC (that placed a request during SA-I) + * as the winner for this output port in a round robin manner. + * - For HEAD/HEAD_TAIL flits, performs simplified outvc allocation. + * (i.e., select a free VC from the output port). + * - For BODY/TAIL flits, decrement a credit in the output vc. + * The winning flit is read out from the input VC and sent to the + * CrossbarSwitch. + * An increment_credit signal is sent from the InputUnit + * to the upstream router. For HEAD_TAIL/TAIL flits, is_free_signal in the + * credit is set to true. + */ + +void +SwitchAllocator::arbitrate_outports() +{ + // Now there are a set of input vc requests for output vcs. + // Again do round robin arbitration on these requests + // Independent arbiter at each output port + for (int outport = 0; outport < m_num_outports; outport++) { + int inport = m_round_robin_inport[outport]; + m_round_robin_inport[outport]++; + + if (m_round_robin_inport[outport] >= m_num_inports) + m_round_robin_inport[outport] = 0; + + for (int inport_iter = 0; inport_iter < m_num_inports; + inport_iter++) { + + // inport has a request this cycle for outport + if (m_port_requests[outport][inport]) { + + // grant this outport to this inport + int invc = m_vc_winners[outport][inport]; + + int outvc = m_input_unit[inport]->get_outvc(invc); + if (outvc == -1) { + // VC Allocation - select any free VC from outport + outvc = vc_allocate(outport, inport, invc); + } + + // remove flit from Input VC + flit *t_flit = m_input_unit[inport]->getTopFlit(invc); + + DPRINTF(RubyNetwork, "SwitchAllocator at Router %d " + "granted outvc %d at outport %d " + "to invc %d at inport %d to flit %s at " + "time: %lld\n", + m_router->get_id(), outvc, + m_router->getPortDirectionName( + m_output_unit[outport]->get_direction()), + invc, + m_router->getPortDirectionName( + m_input_unit[inport]->get_direction()), + *t_flit, + m_router->curCycle()); + + + // Update outport field in the flit since this is + // used by CrossbarSwitch code to send it out of + // correct outport. + // Note: post route compute in InputUnit, + // outport is updated in VC, but not in flit + t_flit->set_outport(outport); + + // set outvc (i.e., invc for next hop) in flit + // (This was updated in VC by vc_allocate, but not in flit) + t_flit->set_vc(outvc); + + // decrement credit in outvc + m_output_unit[outport]->decrement_credit(outvc); + + // flit ready for Switch Traversal + t_flit->advance_stage(ST_, m_router->curCycle()); + m_router->grant_switch(inport, t_flit); + m_output_arbiter_activity++; + + if ((t_flit->get_type() == TAIL_) || + t_flit->get_type() == HEAD_TAIL_) { + + // This Input VC should now be empty + assert(!(m_input_unit[inport]->isReady(invc, + m_router->curCycle()))); + + // Free this VC + m_input_unit[inport]->set_vc_idle(invc, + m_router->curCycle()); + + // Send a credit back + // along with the information that this VC is now idle + m_input_unit[inport]->increment_credit(invc, true, + m_router->curCycle()); + } else { + // Send a credit back + // but do not indicate that the VC is idle + m_input_unit[inport]->increment_credit(invc, false, + m_router->curCycle()); + } + + // remove this request + m_port_requests[outport][inport] = false; + + break; // got a input winner for this outport + } + + inport++; + if (inport >= m_num_inports) + inport = 0; + } + } +} + +/* + * A flit can be sent only if + * (1) there is at least one free output VC at the + * output port (for HEAD/HEAD_TAIL), + * or + * (2) if there is at least one credit (i.e., buffer slot) + * within the VC for BODY/TAIL flits of multi-flit packets. + * and + * (3) pt-to-pt ordering is not violated in ordered vnets, i.e., + * there should be no other flit in this input port + * within an ordered vnet + * that arrived before this flit and is requesting the same output port. + */ + +bool +SwitchAllocator::send_allowed(int inport, int invc, int outport, int outvc) +{ + // Check if outvc needed + // Check if credit needed (for multi-flit packet) + // Check if ordering violated (in ordered vnet) + + int vnet = get_vnet(invc); + bool has_outvc = (outvc != -1); + bool has_credit = false; + + if (!has_outvc) { + + // needs outvc + // this is only true for HEAD and HEAD_TAIL flits. + + if (m_output_unit[outport]->has_free_vc(vnet)) { + + has_outvc = true; + + // each VC has at least one buffer, + // so no need for additional credit check + has_credit = true; + } + } else { + has_credit = m_output_unit[outport]->has_credit(outvc); + } + + // cannot send if no outvc or no credit. + if (!has_outvc || !has_credit) + return false; + + + // protocol ordering check + if ((m_router->get_net_ptr())->isVNetOrdered(vnet)) { + + // enqueue time of this flit + Cycles t_enqueue_time = m_input_unit[inport]->get_enqueue_time(invc); + + // check if any other flit is ready for SA and for same output port + // and was enqueued before this flit + int vc_base = vnet*m_vc_per_vnet; + for (int vc_offset = 0; vc_offset < m_vc_per_vnet; vc_offset++) { + int temp_vc = vc_base + vc_offset; + if (m_input_unit[inport]->need_stage(temp_vc, SA_, + m_router->curCycle()) && + (m_input_unit[inport]->get_outport(temp_vc) == outport) && + (m_input_unit[inport]->get_enqueue_time(temp_vc) < + t_enqueue_time)) { + return false; + } + } + } + + return true; +} + +// Assign a free VC to the winner of the output port. +int +SwitchAllocator::vc_allocate(int outport, int inport, int invc) +{ + // Select a free VC from the output port + int outvc = m_output_unit[outport]->select_free_vc(get_vnet(invc)); + + // has to get a valid VC since it checked before performing SA + assert(outvc != -1); + m_input_unit[inport]->grant_outvc(invc, outvc); + return outvc; +} + +// Wakeup the router next cycle to perform SA again +// if there are flits ready. +void +SwitchAllocator::check_for_wakeup() +{ + Cycles nextCycle = m_router->curCycle() + Cycles(1); + + for (int i = 0; i < m_num_inports; i++) { + for (int j = 0; j < m_num_vcs; j++) { + if (m_input_unit[i]->need_stage(j, SA_, nextCycle)) { + m_router->schedule_wakeup(Cycles(1)); + return; + } + } + } +} + +int +SwitchAllocator::get_vnet(int invc) +{ + int vnet = invc/m_vc_per_vnet; + assert(vnet < m_router->get_num_vnets()); + return vnet; +} + + +// Clear the request vector within the allocator at end of SA-II. +// Was populated by SA-I. +void +SwitchAllocator::clear_request_vector() +{ + for (int i = 0; i < m_num_outports; i++) { + for (int j = 0; j < m_num_inports; j++) { + m_port_requests[i][j] = false; + } + } +} diff --git a/src/mem/ruby/network/garnet2.0/SwitchAllocator.hh b/src/mem/ruby/network/garnet2.0/SwitchAllocator.hh new file mode 100644 index 000000000..162264e85 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/SwitchAllocator.hh @@ -0,0 +1,88 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_SWITCH_ALLOCATOR_HH__ +#define __MEM_RUBY_NETWORK_GARNET_SWITCH_ALLOCATOR_HH__ + +#include +#include + +#include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" + +class Router; +class InputUnit; +class OutputUnit; + +class SwitchAllocator : public Consumer +{ + public: + SwitchAllocator(Router *router); + void wakeup(); + void init(); + void clear_request_vector(); + void check_for_wakeup(); + int get_vnet (int invc); + void print(std::ostream& out) const {}; + void arbitrate_inports(); + void arbitrate_outports(); + bool send_allowed(int inport, int invc, int outport, int outvc); + int vc_allocate(int outport, int inport, int invc); + + inline double + get_input_arbiter_activity() + { + return m_input_arbiter_activity; + } + inline double + get_output_arbiter_activity() + { + return m_output_arbiter_activity; + } + + private: + int m_num_inports, m_num_outports; + int m_num_vcs, m_vc_per_vnet; + + double m_input_arbiter_activity, m_output_arbiter_activity; + + Router *m_router; + std::vector m_round_robin_invc; + std::vector m_round_robin_inport; + std::vector> m_port_requests; + std::vector> m_vc_winners; // a list for each outport + std::vector m_input_unit; + std::vector m_output_unit; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_SWITCH_ALLOCATOR_HH__ diff --git a/src/mem/ruby/network/garnet2.0/VirtualChannel.cc b/src/mem/ruby/network/garnet2.0/VirtualChannel.cc new file mode 100644 index 000000000..55f2a874c --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/VirtualChannel.cc @@ -0,0 +1,85 @@ +/* + * 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/VirtualChannel.hh" + +VirtualChannel::VirtualChannel(int id) + : m_enqueue_time(INFINITE_) +{ + m_id = id; + m_input_buffer = new flitBuffer(); + m_vc_state.first = IDLE_; + m_vc_state.second = Cycles(0); + m_output_vc = -1; + m_output_port = -1; +} + +VirtualChannel::~VirtualChannel() +{ + delete m_input_buffer; +} + +void +VirtualChannel::set_idle(Cycles curTime) +{ + m_vc_state.first = IDLE_; + m_vc_state.second = curTime; + m_enqueue_time = Cycles(INFINITE_); + m_output_port = -1; + m_output_vc = -1; +} + +void +VirtualChannel::set_active(Cycles curTime) +{ + m_vc_state.first = ACTIVE_; + m_vc_state.second = curTime; + m_enqueue_time = curTime; +} + +bool +VirtualChannel::need_stage(flit_stage stage, Cycles time) +{ + if (m_input_buffer->isReady(time)) { + assert(m_vc_state.first == ACTIVE_ && m_vc_state.second <= time); + flit *t_flit = m_input_buffer->peekTopFlit(); + return(t_flit->is_stage(stage, time)); + } + return false; +} + +uint32_t +VirtualChannel::functionalWrite(Packet *pkt) +{ + return m_input_buffer->functionalWrite(pkt); +} diff --git a/src/mem/ruby/network/garnet2.0/VirtualChannel.hh b/src/mem/ruby/network/garnet2.0/VirtualChannel.hh new file mode 100644 index 000000000..d5f7687dc --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/VirtualChannel.hh @@ -0,0 +1,101 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_VIRTUAL_CHANNEL_HH__ +#define __MEM_RUBY_NETWORK_GARNET_VIRTUAL_CHANNEL_HH__ + +#include + +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/flitBuffer.hh" + +class VirtualChannel +{ + public: + VirtualChannel(int id); + ~VirtualChannel(); + + bool need_stage(flit_stage stage, Cycles time); + void set_idle(Cycles curTime); + void set_active(Cycles curTime); + void set_outvc(int outvc) { m_output_vc = outvc; } + inline int get_outvc() { return m_output_vc; } + void set_outport(int outport) { m_output_port = outport; }; + inline int get_outport() { return m_output_port; } + + inline Cycles get_enqueue_time() { return m_enqueue_time; } + inline void set_enqueue_time(Cycles time) { m_enqueue_time = time; } + inline VC_state_type get_state() { return m_vc_state.first; } + + inline bool isReady(Cycles curTime) + { + return m_input_buffer->isReady(curTime); + } + + inline void + insertFlit(flit *t_flit) + { + m_input_buffer->insert(t_flit); + } + + inline void + set_state(VC_state_type m_state, Cycles curTime) + { + m_vc_state.first = m_state; + m_vc_state.second = curTime; + } + + inline flit* + peekTopFlit() + { + return m_input_buffer->peekTopFlit(); + } + + inline flit* + getTopFlit() + { + return m_input_buffer->getTopFlit(); + } + + uint32_t functionalWrite(Packet *pkt); + + private: + int m_id; + flitBuffer *m_input_buffer; + std::pair m_vc_state; + int m_output_port; + Cycles m_enqueue_time; + int m_output_vc; +}; + +#endif // __MEM_RUBY_NETWORK_GARNET_VIRTUAL_CHANNEL_HH__ diff --git a/src/mem/ruby/network/garnet2.0/flit.cc b/src/mem/ruby/network/garnet2.0/flit.cc new file mode 100644 index 000000000..e507ea442 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/flit.cc @@ -0,0 +1,85 @@ +/* + * 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/flit.hh" + +// Constructor for the flit +flit::flit(int id, int vc, int vnet, RouteInfo route, int size, + MsgPtr msg_ptr, Cycles curTime) +{ + m_size = size; + m_msg_ptr = msg_ptr; + m_enqueue_time = curTime; + m_time = curTime; + m_id = id; + m_vnet = vnet; + m_vc = vc; + m_route = route; + m_stage.first = I_; + m_stage.second = m_time; + + if (size == 1) { + m_type = HEAD_TAIL_; + return; + } + if (id == 0) + m_type = HEAD_; + else if (id == (size - 1)) + m_type = TAIL_; + else + m_type = BODY_; +} + +// Flit can be printed out for debugging purposes +void +flit::print(std::ostream& out) const +{ + out << "[flit:: "; + out << "Id=" << m_id << " "; + out << "Type=" << m_type << " "; + out << "Vnet=" << m_vnet << " "; + out << "VC=" << m_vc << " "; + out << "Src NI=" << m_route.src_ni << " "; + out << "Src Router=" << m_route.src_router << " "; + out << "Dest NI=" << m_route.dest_ni << " "; + out << "Dest Router=" << m_route.dest_router << " "; + out << "Enqueue Time=" << m_enqueue_time << " "; + out << "]"; +} + +bool +flit::functionalWrite(Packet *pkt) +{ + Message *msg = m_msg_ptr.get(); + return msg->functionalWrite(pkt); +} diff --git a/src/mem/ruby/network/garnet2.0/flit.hh b/src/mem/ruby/network/garnet2.0/flit.hh new file mode 100644 index 000000000..3e30ec98c --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/flit.hh @@ -0,0 +1,122 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_FLIT_HH__ +#define __MEM_RUBY_NETWORK_GARNET_FLIT_HH__ + +#include +#include + +#include "base/types.hh" +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/slicc_interface/Message.hh" + +class flit +{ + public: + flit() {} + flit(int id, int vc, int vnet, RouteInfo route, int size, + MsgPtr msg_ptr, Cycles curTime); + + int get_outport() {return m_outport; } + int get_size() { return m_size; } + Cycles get_enqueue_time() { return m_enqueue_time; } + int get_id() { return m_id; } + Cycles get_time() { return m_time; } + int get_vnet() { return m_vnet; } + int get_vc() { return m_vc; } + RouteInfo get_route() { return m_route; } + MsgPtr& get_msg_ptr() { return m_msg_ptr; } + flit_type get_type() { return m_type; } + std::pair get_stage() { return m_stage; } + Cycles get_src_delay() { return src_delay; } + + void set_outport(int port) { m_outport = port; } + void set_time(Cycles time) { m_time = time; } + void set_vc(int vc) { m_vc = vc; } + void set_route(RouteInfo route) { m_route = route; } + void set_src_delay(Cycles delay) { src_delay = delay; } + + void increment_hops() { m_route.hops_traversed++; } + void print(std::ostream& out) const; + + bool + is_stage(flit_stage stage, Cycles time) + { + return (stage == m_stage.first && + time >= m_stage.second); + } + + void + advance_stage(flit_stage t_stage, Cycles newTime) + { + m_stage.first = t_stage; + m_stage.second = newTime; + } + + static bool + greater(flit* n1, flit* n2) + { + if (n1->get_time() == n2->get_time()) { + //assert(n1->flit_id != n2->flit_id); + return (n1->get_id() > n2->get_id()); + } else { + return (n1->get_time() > n2->get_time()); + } + } + + bool functionalWrite(Packet *pkt); + + protected: + int m_id; + int m_vnet; + int m_vc; + RouteInfo m_route; + int m_size; + Cycles m_enqueue_time, m_time; + flit_type m_type; + MsgPtr m_msg_ptr; + int m_outport; + Cycles src_delay; + std::pair m_stage; +}; + +inline std::ostream& +operator<<(std::ostream& out, const flit& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __MEM_RUBY_NETWORK_GARNET_FLIT_HH__ diff --git a/src/mem/ruby/network/garnet2.0/flitBuffer.cc b/src/mem/ruby/network/garnet2.0/flitBuffer.cc new file mode 100644 index 000000000..1a089936e --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/flitBuffer.cc @@ -0,0 +1,93 @@ +/* + * 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/flitBuffer.hh" + +flitBuffer::flitBuffer() +{ + max_size = INFINITE_; +} + +flitBuffer::flitBuffer(int maximum_size) +{ + max_size = maximum_size; +} + +bool +flitBuffer::isEmpty() +{ + return (m_buffer.size() == 0); +} + +bool +flitBuffer::isReady(Cycles curTime) +{ + if (m_buffer.size() != 0 ) { + flit *t_flit = peekTopFlit(); + if (t_flit->get_time() <= curTime) + return true; + } + return false; +} + +void +flitBuffer::print(std::ostream& out) const +{ + out << "[flitBuffer: " << m_buffer.size() << "] " << std::endl; +} + +bool +flitBuffer::isFull() +{ + return (m_buffer.size() >= max_size); +} + +void +flitBuffer::setMaxSize(int maximum) +{ + max_size = maximum; +} + +uint32_t +flitBuffer::functionalWrite(Packet *pkt) +{ + uint32_t num_functional_writes = 0; + + for (unsigned int i = 0; i < m_buffer.size(); ++i) { + if (m_buffer[i]->functionalWrite(pkt)) { + num_functional_writes++; + } + } + + return num_functional_writes; +} diff --git a/src/mem/ruby/network/garnet2.0/flitBuffer.hh b/src/mem/ruby/network/garnet2.0/flitBuffer.hh new file mode 100644 index 000000000..eb6ad6167 --- /dev/null +++ b/src/mem/ruby/network/garnet2.0/flitBuffer.hh @@ -0,0 +1,93 @@ +/* + * 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 + */ + + +#ifndef __MEM_RUBY_NETWORK_GARNET_FLIT_BUFFER_HH__ +#define __MEM_RUBY_NETWORK_GARNET_FLIT_BUFFER_HH__ + +#include +#include +#include + +#include "mem/ruby/network/garnet2.0/CommonTypes.hh" +#include "mem/ruby/network/garnet2.0/flit.hh" + +class flitBuffer +{ + public: + flitBuffer(); + flitBuffer(int maximum_size); + + bool isReady(Cycles curTime); + bool isEmpty(); + void print(std::ostream& out) const; + bool isFull(); + void setMaxSize(int maximum); + + flit * + getTopFlit() + { + flit *f = m_buffer.front(); + std::pop_heap(m_buffer.begin(), m_buffer.end(), flit::greater); + m_buffer.pop_back(); + return f; + } + + flit * + peekTopFlit() + { + return m_buffer.front(); + } + + void + insert(flit *flt) + { + m_buffer.push_back(flt); + std::push_heap(m_buffer.begin(), m_buffer.end(), flit::greater); + } + + uint32_t functionalWrite(Packet *pkt); + + private: + std::vector m_buffer; + int max_size; +}; + +inline std::ostream& +operator<<(std::ostream& out, const flitBuffer& obj) +{ + obj.print(out); + out << std::flush; + return out; +} + +#endif // __MEM_RUBY_NETWORK_GARNET_FLIT_BUFFER_HH__