Daecheol You has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/40279 )
Change subject: python: Mesh topology with user-defined layout
......................................................................
python: Mesh topology with user-defined layout
There is a limitation on mesh configuration
with Mesh_XY since it requires an evenly divisible number of cache
and directory controllers. Mesh_layout enables to configure
mesh router nodes with the user-defined layout file.
A user can describe an attached controller list for each router node
manually
Change-Id: Iea99a01d6f100c36d4a08a8677cb64912d6117d0
---
M configs/network/Network.py
A configs/topologies/Mesh_layout.py
A configs/topologies/layout_example.txt
3 files changed, 345 insertions(+), 0 deletions(-)
diff --git a/configs/network/Network.py b/configs/network/Network.py
index 8690912..f63e27d 100644
--- a/configs/network/Network.py
+++ b/configs/network/Network.py
@@ -38,6 +38,8 @@
help="check configs/topologies for complete set")
parser.add_option("--mesh-rows", type="int", default=0,
help="the number of rows in the mesh topology")
+ parser.add_option("--layout-path", type="string",
+ help="Mesh layout file path")
parser.add_option("--network", type="choice", default="simple",
choices=['simple', 'garnet'],
help="""'simple'|'garnet' (garnet2.0 will be
diff --git a/configs/topologies/Mesh_layout.py
b/configs/topologies/Mesh_layout.py
new file mode 100644
index 0000000..773543d
--- /dev/null
+++ b/configs/topologies/Mesh_layout.py
@@ -0,0 +1,303 @@
+# Copyright (c) 2010 Advanced Micro Devices, Inc.
+# 2016 Georgia Institute of Technology
+# 2021 Samsung Electronics Co., Ltd.
+# 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.
+
+from __future__ import print_function
+from __future__ import absolute_import
+
+from collections import defaultdict
+from collections import deque
+
+import re
+
+from m5.params import *
+from m5.objects import *
+
+from common import FileSystemConfig
+
+from topologies.BaseTopology import SimpleTopology
+
+# Create a mesh as descirbed in a layout file.
+# The layout file descirbes the number of rows and columns,
+# and external controllers (caches and directoryies) attached to each node.
+# Please, see configs/topologies/layout_example.txt for further explanation
+
+# Same as Mesh_XY, XY routing is enforced (using link weights)
+# to guarantee deadlock freedom.
+
+class Mesh_layout(SimpleTopology):
+ description='Mesh_layout'
+
+ def __init__(self, controllers):
+ self.nodes = controllers
+ self.sep = ':'
+
+ # Parse each token in a layout file
+
+ def parse_layout(self, path):
+ with open(path, 'r') as f:
+ while True:
+ stream = f.readline()
+ if not stream:
+ break
+ elif stream[0] == '#':
+ continue
+
+ pos = 0
+ while True:
+ i = stream.find(self.sep, pos)
+ # no token in the stream
+ if i < 0:
+ break
+ token = stream[pos:i].strip()
+ yield token
+ pos = i + 1
+
+ # Make a mesh as described in a layout file
+
+ def makeTopology(self, options, network, IntLink, ExtLink, Router):
+ nodes = self.nodes
+ controllers = defaultdict(deque)
+ ctrl_type_list = set()
+ for ctrl in nodes:
+ controllers[ctrl.type].append(ctrl)
+ ctrl_type_list.add(ctrl.type)
+
+ # 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
+
+ # Get the number of rows and columns
+ # Assume the layout file descirbes 'rows' first, and then 'cols'
+ tokens = self.parse_layout(options.layout_path)
+ for token in tokens:
+ # First two attributes in layout file
+ # should be the number of rows and columns
+ assert(token == 'rows' or token == 'cols')
+
+ self.sep = ","
+ attribute = next(tokens)
+ self.sep = ":"
+ if token == 'rows':
+ num_rows = int(attribute)
+ elif token == 'cols':
+ num_columns = int(attribute)
+ break
+
+ # Create the routers in the mesh
+ routers = [Router(router_id=i, latency = router_latency) \
+ for i in range(num_rows*num_columns)]
+ network.routers = routers
+
+ # 'nodes' should be described in the layout file
+ # after 'rows' and 'cols'
+ token = next(tokens)
+ assert(token == 'nodes')
+
+ # Parse attatched controllers of each router node
+ # and make external links for each router
+ # Previously parsed controllers is applied to the nodes
+ # as long as the node's column index is smaller than or
+ # equal to the 'last_valid_index'
+ node_pattern = re.compile('\d+/\d+')
+ cache_pattern = re.compile('L\d+')
+ link_count = 0
+ ext_links = []
+ for row in range(num_rows):
+ last_valid_index = -1
+ for col in range(num_columns):
+ # Need to parse a new controller list
+ # for the current node
+ if col > last_valid_index:
+ token = next(tokens)
+
+ # Format of node name should be row/col
+ matched = node_pattern.search(token)
+ assert(matched)
+
+ row_col = token.split('/')
+ row_num = int(row_col[0])
+ col_num = int(row_col[1])
+
+ # row and column number of the node should be
incremental
+ assert(row_num == row)
+ assert(col_num > last_valid_index)
+
+ # Get the controllers attached to the node
+ self.sep = ","
+ attribute = next(tokens)
+ attached_ctrls = attribute.split()
+
+ # Apply this controller configuration
+ # until the column index of last_valid_index
+ last_valid_index = col_num
+ self.sep = ":"
+
+ for ctrl in attached_ctrls:
+ # Controller ID can be described
+ ctrl = ctrl.split('-')
+ ctrl_type = ctrl[0]
+ ctrl_id = -1
+
+ # Get a controller ID if it is described
+ if len(ctrl) == 2:
+ ctrl_id = int(ctrl[1])
+
+ # Controller should be cache (like L1, L2, etc)
+ # or directory (Dir) or none (no controllers are
attached)
+ cache_matched = cache_pattern.match(ctrl_type)
+ assert(matched or ctrl_type == 'Dir' or
+ ctrl_type == 'None')
+ if cache_matched:
+ ctrl_type += 'Cache_Controller'
+ elif ctrl_type == 'Dir':
+ ctrl_type = 'Directory_Controller'
+ # No controllers are attached
+ else:
+ break;
+
+ # If controller ID is not specified,
+ # use the controller in the order maded by the protocol
+ if ctrl_id == -1:
+ ctrl_obj = controllers[ctrl_type].popleft()
+ # If controller ID is specified in the layout file,
+ # pop the controller of specified ID
+ else:
+ for ctrl_obj in controllers[ctrl_type]:
+ if ctrl_obj.version.getValue() == ctrl_id:
+ controllers[ctrl_type].remove(ctrl_obj)
+ break
+ # The controller must be in the queue
+ assert(ctrl_obj.version.getValue() == ctrl_id)
+
+ router_id = col + (row * num_columns)
+ ext_links.append(ExtLink(link_id=link_count,
+ ext_node= ctrl_obj,
+ int_node=routers[router_id],
+ latency = link_latency))
+ link_count += 1
+
+ # If we have a remaining directory controller,
+ # it is a boot ROM directory and connected to router 0
+ ctrl_type = 'Directory_Controller'
+ if controllers[ctrl_type]:
+ ctrl_obj = controllers[ctrl_type].popleft()
+ ext_links.append(ExtLink(link_id=link_count,
+ ext_node= ctrl_obj,
+ int_node=routers[0],
+ latency = link_latency))
+ link_count += 1
+
+ # DMA nodes are connected to router 0
+ ctrl_type = 'DMA_Controller'
+ while controllers[ctrl_type]:
+ ctrl_obj = controllers[ctrl_type].popleft()
+ ext_links.append(ExtLink(link_id=link_count,
+ ext_node= ctrl_obj,
+ int_node=routers[0],
+ latency = link_latency))
+ link_count += 1
+
+ # All controllers generated by the protocol
+ # should be matched with the layout file
+ for ctrl_type in ctrl_type_list:
+ assert(not controllers[ctrl_type])
+
+ network.ext_links = ext_links
+
+ # Create the mesh links.
+ int_links = []
+
+ # East output to West input links (weight = 1)
+ for row in range(num_rows):
+ for col in range(num_columns):
+ if (col + 1 < num_columns):
+ east_out = col + (row * num_columns)
+ west_in = (col + 1) + (row * num_columns)
+ 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
+
+ # West output to East input links (weight = 1)
+ for row in range(num_rows):
+ for col in range(num_columns):
+ if (col + 1 < num_columns):
+ east_in = col + (row * num_columns)
+ west_out = (col + 1) + (row * num_columns)
+ 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
+
+ # North output to South input links (weight = 2)
+ for col in range(num_columns):
+ for row in range(num_rows):
+ if (row + 1 < num_rows):
+ north_out = col + (row * num_columns)
+ south_in = col + ((row + 1) * num_columns)
+ 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
+
+ # South output to North input links (weight = 2)
+ for col in range(num_columns):
+ for row in range(num_rows):
+ if (row + 1 < num_rows):
+ north_in = col + (row * num_columns)
+ south_out = col + ((row + 1) * num_columns)
+ 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
+
+
+ network.int_links = int_links
+
+ # Register nodes with filesystem
+ def registerTopology(self, options):
+ for i in range(options.num_cpus):
+ FileSystemConfig.register_node([i],
+ MemorySize(options.mem_size) // options.num_cpus, i)
diff --git a/configs/topologies/layout_example.txt
b/configs/topologies/layout_example.txt
new file mode 100644
index 0000000..98b5eae
--- /dev/null
+++ b/configs/topologies/layout_example.txt
@@ -0,0 +1,40 @@
+# This is an example of 6x8 mesh layout.
+# The example assumes that MESI_Three_Level protocol is used.
+# 64 CPUs (L0 and L1) shared caches (L2) are connected in 32 router nodes
+# and 8 directories are distributed on each right and left side of the
mesh.
+# 8 router nodes at four corners have no controllers attached.
+#
+# First two attribute should be number of rows and columns like below.
+# row: {number of rows}, cols: {number of columns}
+#
+# Then, external controllers attached to each router node are described.
+# The format is like below.
+# nodes: {row number}/{column number}: {attached controller list},
+# Each controller is separated with space.
+# A cache is described as 'L{cache level}'
+# and a directory is described as 'Dir'.
+# If no controllers are attatched, the controller list is described
as 'None'.
+#
+# Note that the same controller configuration is applied
+# until the router node of specified column nubmer.
+# For example, the routers in the first row of the example layout
+# have the controllers like below:
+# 0/0, 0/1: No controllers are attched
+# 0/2, 0/3, 0/4, 0/5: L0 L1 L2 L0 L1 L2
+# 0/6, 0/7: No controllers are attched
+#
+# When describing controller list for each router,
+# controller ID can be specified additionally.
+# The format is {controller type}-{controller ID}.
+# For instance, if you want to specify L0 and L1 cache with ID of 1,
+# and a directory with ID of 7, describtion is like below.
+# 0/0: L0-1 L1-1 Dir-7,
+
+rows: 6,
+cols: 8,
+nodes: 0/1: None, 0/5: L0 L1 L2 L0 L1 L2, 0/7: None,
+ 1/0: Dir, 1/6: L0 L1 L2 L0 L1 L2, 1/7: Dir,
+ 2/0: Dir, 2/6: L0 L1 L2 L0 L1 L2, 2/7: Dir,
+ 3/0: Dir, 3/6: L0 L1 L2 L0 L1 L2, 3/7: Dir,
+ 4/0: Dir, 4/6: L0 L1 L2 L0 L1 L2, 4/7: Dir,
+ 5/1: None, 5/5: L0 L1 L2 L0 L1 L2, 5/7: None,
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/40279
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: Iea99a01d6f100c36d4a08a8677cb64912d6117d0
Gerrit-Change-Number: 40279
Gerrit-PatchSet: 1
Gerrit-Owner: Daecheol You <daecheol....@samsung.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s