From b9db0976ca2116d111b3af2eb78d549df22ce0a6 Mon Sep 17 00:00:00 2001 From: Hoa Nguyen Date: Tue, 13 Jun 2023 21:04:30 +0000 Subject: [PATCH] stdlib: Add a prebuilt MESI_Three_Level cache The cache is modeled after an AMD EPYC cache, but not exactly like AMD EPYC cache. - K cores per core complex (CCD), each core has one private split L1, and one private L2. - K cores in the same CCD share 1 slice of L3 cache, which is not a victim cache. - There can be multiple CCDs, which communicate with each other via Cross-CCD router. The Cross-CCD rounter is also connected to directory controllers and dma controllers. - All links latency are set to 1. Change-Id: Ib64248bed9155b8e48e5158ffdeebf1f2d770754 Signed-off-by: Hoa Nguyen Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/71598 Maintainer: Jason Lowe-Power Tested-by: kokoro Reviewed-by: Jason Lowe-Power --- src/python/SConscript | 12 + .../caches/prebuilt/octopi_cache/__init__.py | 25 ++ .../prebuilt/octopi_cache/core_complex.py | 245 +++++++++++++++++ .../caches/prebuilt/octopi_cache/octopi.py | 257 ++++++++++++++++++ .../prebuilt/octopi_cache/octopi_network.py | 67 +++++ .../octopi_cache/ruby_network_components.py | 111 ++++++++ 6 files changed, 717 insertions(+) create mode 100644 src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/__init__.py create mode 100644 src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/core_complex.py create mode 100644 src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/octopi.py create mode 100644 src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/octopi_network.py create mode 100644 src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/ruby_network_components.py diff --git a/src/python/SConscript b/src/python/SConscript index f98b5700c7..ea9d3d4021 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -154,6 +154,18 @@ PySource('gem5.components.cachehierarchies.ruby.caches.mesi_three_level', PySource('gem5.components.cachehierarchies.ruby.caches.mesi_three_level', 'gem5/components/cachehierarchies/ruby/caches/mesi_three_level/' 'l3_cache.py') +PySource('gem5.components.cachehierarchies.ruby.caches.mesi_three_level', + 'gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/' + 'octopi.py') +PySource('gem5.components.cachehierarchies.ruby.caches.mesi_three_level', + 'gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/' + 'core_complex.py') +PySource('gem5.components.cachehierarchies.ruby.caches.mesi_three_level', + 'gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/' + 'octopi_network.py') +PySource('gem5.components.cachehierarchies.ruby.caches.mesi_three_level', + 'gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/' + 'ruby_network_components.py') PySource('gem5.components.cachehierarchies.ruby.caches.mi_example', 'gem5/components/cachehierarchies/ruby/caches/mi_example/__init__.py') PySource('gem5.components.cachehierarchies.ruby.caches.mi_example', diff --git a/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/__init__.py b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/__init__.py new file mode 100644 index 0000000000..b08f46b513 --- /dev/null +++ b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/__init__.py @@ -0,0 +1,25 @@ +# Copyright (c) 2022-2023 The Regents of the University of California +# 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. diff --git a/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/core_complex.py b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/core_complex.py new file mode 100644 index 0000000000..f056d76f98 --- /dev/null +++ b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/core_complex.py @@ -0,0 +1,245 @@ +# Copyright (c) 2022-2023 The Regents of the University of California +# 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 typing import List, Tuple + +from gem5.isas import ISA +from gem5.components.boards.abstract_board import AbstractBoard +from gem5.components.processors.abstract_core import AbstractCore +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l1_cache import ( + L1Cache, +) +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l2_cache import ( + L2Cache, +) +from gem5.components.cachehierarchies.ruby.caches.mesi_three_level.l3_cache import ( + L3Cache, +) + +from m5.objects import SubSystem, RubySequencer + +from .ruby_network_components import ( + RubyRouter, + RubyExtLink, + RubyIntLink, + RubyNetworkComponent, +) + + +class CoreComplex(SubSystem, RubyNetworkComponent): + _core_id = 0 + _core_complex_id = 0 + + @classmethod + def _get_core_id(cls): + cls._core_id += 1 + return cls._core_id - 1 + + @classmethod + def _get_core_complex_id(cls): + cls._core_complex_id += 1 + return cls._core_complex_id - 1 + + def __init__( + self, + board: AbstractBoard, + cores: List[AbstractCore], + ruby_system, + l1i_size: str, + l1i_assoc: int, + l1d_size: str, + l1d_assoc: int, + l2_size: str, + l2_assoc: int, + l3_size: str, + l3_assoc: int, + ): + SubSystem.__init__(self=self) + RubyNetworkComponent.__init__(self=self) + + self._l1i_size = l1i_size + self._l1i_assoc = l1i_assoc + self._l1d_size = l1d_size + self._l1d_assoc = l1d_assoc + self._l2_size = l2_size + self._l2_assoc = l2_assoc + self._l3_size = l3_size + self._l3_assoc = l3_assoc + + self._board = board + self._cores = cores + self._ruby_system = ruby_system + self._cache_line_size = 64 + + self._directory_controllers = [] + + self._core_complex_id = self._get_core_complex_id() + self.main_router = RubyRouter( + self._ruby_system + ) # this will be connect to component outside the core complex + self._add_router(self.main_router) + self._create_core_complex() + + def get_main_router(self): + return self.main_router + + def _create_core_complex(self): + # Create L1 caches, L2 cache, and corresponding controllers per core + self.core_clusters = [ + self._create_core_cluster(core) for core in self._cores + ] + # Create L3 cache and its corresponding controller + self._create_shared_cache() + # Setting up one router and one external link per controller + self._create_external_links() + # Setting up L1/L2 links, L2/main links, L3/main link + self._create_internal_links() + + def _create_core_cluster(self, core: AbstractCore): + cluster = SubSystem() + core_id = self._get_core_id() + + cluster.l1_cache = L1Cache( + l1i_size=self._l1i_size, + l1i_assoc=self._l1i_assoc, + l1d_size=self._l1d_size, + l1d_assoc=self._l1d_assoc, + network=self._ruby_system.network, + core=core, + cache_line_size=self._cache_line_size, + target_isa=self._board.processor.get_isa(), + clk_domain=self._board.get_clock_domain(), + ) + cluster.l1_cache.sequencer = RubySequencer( + version=core_id, + dcache=cluster.l1_cache.Dcache, + clk_domain=cluster.l1_cache.clk_domain, + ) + + if self._board.has_io_bus(): + cluster.l1_cache.sequencer.connectIOPorts(self._board.get_io_bus()) + cluster.l1_cache.ruby_system = self._ruby_system + core.connect_icache(cluster.l1_cache.sequencer.in_ports) + core.connect_dcache(cluster.l1_cache.sequencer.in_ports) + core.connect_walker_ports( + cluster.l1_cache.sequencer.in_ports, + cluster.l1_cache.sequencer.in_ports, + ) + if self._board.get_processor().get_isa() == ISA.X86: + core.connect_interrupt( + cluster.l1_cache.sequencer.interrupt_out_port, + cluster.l1_cache.sequencer.in_ports, + ) + else: + core.connect_interrupt() + + cluster.l2_cache = L2Cache( + l2_size=self._l2_size, + l2_assoc=self._l2_assoc, + network=self._ruby_system.network, + core=core, + num_l3Caches=1, # each core complex has 1 slice of L3 Cache + cache_line_size=self._cache_line_size, + cluster_id=self._core_complex_id, + target_isa=self._board.processor.get_isa(), + clk_domain=self._board.get_clock_domain(), + ) + cluster.l2_cache.ruby_system = self._ruby_system + # L0Cache in the ruby backend is l1 cache in stdlib + # L1Cache in the ruby backend is l2 cache in stdlib + cluster.l2_cache.bufferFromL0 = cluster.l1_cache.bufferToL1 + cluster.l2_cache.bufferToL0 = cluster.l1_cache.bufferFromL1 + + return cluster + + def _create_shared_cache(self): + self.l3_cache = L3Cache( + l3_size=self._l3_size, + l3_assoc=self._l3_assoc, + network=self._ruby_system.network, + num_l3Caches=1, + cache_line_size=self._cache_line_size, + cluster_id=self._core_complex_id, + ) + self.l3_cache.ruby_system = self._ruby_system + + # This is where all routers and links are created + def _create_external_links(self): + # create a router per cache controller + # - there is one L3 per ccd + self.l3_router = RubyRouter(self._ruby_system) + self._add_router(self.l3_router) + # - there is one L1 and one L2 per cluster + for cluster in self.core_clusters: + cluster.l1_router = RubyRouter(self._ruby_system) + self._add_router(cluster.l1_router) + cluster.l2_router = RubyRouter(self._ruby_system) + self._add_router(cluster.l2_router) + + # create an ext link from a controller to a router + self.l3_router_link = RubyExtLink( + ext_node=self.l3_cache, + int_node=self.l3_router, + bandwidth_factor=64, + ) + self._add_ext_link(self.l3_router_link) + for cluster in self.core_clusters: + cluster.l1_router_link = RubyExtLink( + ext_node=cluster.l1_cache, int_node=cluster.l1_router + ) + self._add_ext_link(cluster.l1_router_link) + cluster.l2_router_link = RubyExtLink( + ext_node=cluster.l2_cache, int_node=cluster.l2_router + ) + self._add_ext_link(cluster.l2_router_link) + + def _create_internal_links(self): + # create L1/L2 links + for cluster in self.core_clusters: + l1_to_l2, l2_to_l1 = RubyIntLink.create_bidirectional_links( + cluster.l1_router, cluster.l2_router + ) + cluster.l1_to_l2_link = l1_to_l2 + cluster.l2_to_l1_link = l2_to_l1 + self._add_int_link(l1_to_l2) + self._add_int_link(l2_to_l1) + # create L2/main_router links + for cluster in self.core_clusters: + l2_to_main, main_to_l2 = RubyIntLink.create_bidirectional_links( + cluster.l2_router, self.main_router + ) + cluster.l2_to_main_link = l2_to_main + cluster.main_to_l2_link = main_to_l2 + self._add_int_link(l2_to_main) + self._add_int_link(main_to_l2) + # create L3/main_router link + l3_to_main, main_to_l3 = RubyIntLink.create_bidirectional_links( + self.l3_router, self.main_router, bandwidth_factor=64 + ) + self.l3_to_main_link = l3_to_main + self.main_to_l3_link = main_to_l3 + self._add_int_link(l3_to_main) + self._add_int_link(main_to_l3) diff --git a/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/octopi.py b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/octopi.py new file mode 100644 index 0000000000..9c8b93d812 --- /dev/null +++ b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/octopi.py @@ -0,0 +1,257 @@ +# Copyright (c) 2022-2023 The Regents of the University of California +# 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 ...abstract_ruby_cache_hierarchy import AbstractRubyCacheHierarchy +from ....abstract_three_level_cache_hierarchy import ( + AbstractThreeLevelCacheHierarchy, +) +from ......coherence_protocol import CoherenceProtocol +from ......components.boards.abstract_board import AbstractBoard +from ......utils.requires import requires + +from ......components.cachehierarchies.ruby.caches.mesi_three_level.directory import ( + Directory, +) +from ......components.cachehierarchies.ruby.caches.mesi_three_level.dma_controller import ( + DMAController, +) + +from m5.objects import RubySystem, DMASequencer, RubyPortProxy + +from .core_complex import CoreComplex +from .octopi_network import OctopiNetwork +from .ruby_network_components import RubyRouter, RubyExtLink, RubyIntLink + +# CoreComplex sub-systems own the L1, L2, L3 controllers +# OctopiCache owns the directory controllers +# RubySystem owns the DMA Controllers +class OctopiCache( + AbstractRubyCacheHierarchy, AbstractThreeLevelCacheHierarchy +): + def __init__( + self, + l1i_size: str, + l1i_assoc: int, + l1d_size: str, + l1d_assoc: int, + l2_size: str, + l2_assoc: int, + l3_size: str, + l3_assoc: int, + num_core_complexes: int, + is_fullsystem: bool, + ): + AbstractRubyCacheHierarchy.__init__(self=self) + AbstractThreeLevelCacheHierarchy.__init__( + self=self, + l1i_size=l1i_size, + l1i_assoc=l1i_assoc, + l1d_size=l1d_size, + l1d_assoc=l1d_assoc, + l2_size=l2_size, + l2_assoc=l2_assoc, + l3_size=l3_size, + l3_assoc=l3_assoc, + ) + + self._directory_controllers = [] + self._dma_controllers = [] + self._io_controllers = [] + self._core_complexes = [] + self._num_core_complexes = num_core_complexes + self._is_fullsystem = is_fullsystem + + def incorporate_cache(self, board: AbstractBoard) -> None: + + requires( + coherence_protocol_required=CoherenceProtocol.MESI_THREE_LEVEL + ) + + cache_line_size = board.get_cache_line_size() + + self.ruby_system = RubySystem() + # MESI_Three_Level needs 3 virtual networks + self.ruby_system.number_of_virtual_networks = 3 + self.ruby_system.network = OctopiNetwork(self.ruby_system) + + # Setting up the core complex + all_cores = board.get_processor().get_cores() + num_cores_per_core_complex = len(all_cores) // self._num_core_complexes + + self.core_complexes = [ + CoreComplex( + board=board, + cores=all_cores[ + core_complex_idx + * num_cores_per_core_complex : (core_complex_idx + 1) + * num_cores_per_core_complex + ], + ruby_system=self.ruby_system, + l1i_size=self._l1i_size, + l1i_assoc=self._l1i_assoc, + l1d_size=self._l1d_size, + l1d_assoc=self._l1d_assoc, + l2_size=self._l2_size, + l2_assoc=self._l2_assoc, + l3_size=self._l3_size, + l3_assoc=self._l3_assoc, + ) + for core_complex_idx in range(self._num_core_complexes) + ] + + self.ruby_system.network.incorporate_ccds(self.core_complexes) + + self._create_directory_controllers(board) + self._create_dma_controllers(board, self.ruby_system) + + self.ruby_system.num_of_sequencers = ( + len(all_cores) + + len(self._dma_controllers) + + len(self._io_controllers) + ) + # SimpleNetwork requires .int_links and .routers to exist + # if we want to call SimpleNetwork.setup_buffers() + self.ruby_system.network.int_links = ( + self.ruby_system.network._int_links + ) + self.ruby_system.network.ext_links = ( + self.ruby_system.network._ext_links + ) + self.ruby_system.network.routers = self.ruby_system.network._routers + self.ruby_system.network.setup_buffers() + + # Set up a proxy port for the system_port. Used for load binaries and + # other functional-only things. + self.ruby_system.sys_port_proxy = RubyPortProxy() + board.connect_system_port(self.ruby_system.sys_port_proxy.in_ports) + + def _create_directory_controllers(self, board): + # Adding controllers + self.directory_controllers = [ + Directory( + self.ruby_system.network, + board.get_cache_line_size(), + addr_range, + mem_port, + ) + for addr_range, mem_port in board.get_mem_ports() + ] + for ctrl in self.directory_controllers: + ctrl.ruby_system = self.ruby_system + # Adding controller routers + self.directory_controller_routers = [ + RubyRouter(self.ruby_system.network) + for _ in range(len(self.directory_controllers)) + ] + for router in self.directory_controller_routers: + self.ruby_system.network._add_router(router) + # Adding an external link for each controller and its router + self.directory_controller_ext_links = [ + RubyExtLink(ext_node=dir_ctrl, int_node=dir_router) + for dir_ctrl, dir_router in zip( + self.directory_controllers, self.directory_controller_routers + ) + ] + for ext_link in self.directory_controller_ext_links: + self.ruby_system.network._add_ext_link(ext_link) + _directory_controller_int_links = [] + for router in self.directory_controller_routers: + int_link_1, int_link_2 = RubyIntLink.create_bidirectional_links( + router, self.ruby_system.network.cross_ccd_router + ) + _directory_controller_int_links.extend([int_link_1, int_link_2]) + self.ruby_system.network._add_int_link(int_link_1) + self.ruby_system.network._add_int_link(int_link_2) + self.directory_controller_int_links = _directory_controller_int_links + + def _create_dma_controllers(self, board, ruby_system): + # IOController for full system simulation + if self._is_fullsystem: + self.io_sequencer = DMASequencer( + version=0, ruby_system=self.ruby_system + ) + self.io_sequencer.in_ports = board.get_mem_side_coherent_io_port() + self.ruby_system.io_controller = DMAController( + dma_sequencer=self.io_sequencer, ruby_system=self.ruby_system + ) + self._io_controllers.append(self.ruby_system.io_controller) + self.io_controller_router = RubyRouter(self.ruby_system.network) + self.ruby_system.network._add_router(self.io_controller_router) + self.io_controller_ext_link = RubyExtLink( + ext_node=self._io_controllers[0], + int_node=self.io_controller_router, + ) + self.ruby_system.network._add_ext_link(self.io_controller_ext_link) + self.io_controller_int_links = ( + RubyIntLink.create_bidirectional_links( + self.io_controller_router, + self.ruby_system.network.cross_ccd_router, + ) + ) + self.ruby_system.network._add_int_link( + self.io_controller_int_links[0] + ) + self.ruby_system.network._add_int_link( + self.io_controller_int_links[1] + ) + + self._dma_controllers = [] + if board.has_dma_ports(): + self.ruby_system.dma_controllers = [ + DMAController( + dma_sequencer=DMASequencer(version=i + 1, in_ports=port), + ruby_system=self.ruby_system, + ) + for i, port in enumerate(board.get_dma_ports()) + ] + self._dma_controllers = self.ruby_system.dma_controllers + self.dma_routers = [ + RubyRouter(self.ruby_system.network) + for dma_controller in self._dma_controllers + ] + for dma_router in self.dma_routers: + self.ruby_system.network._add_router(dma_router) + self.dma_ext_links = [ + RubyExtLink(ext_node=dma_controller, int_node=dma_router) + for dma_controller, dma_router in zip( + self._dma_controllers, self.dma_routers + ) + ] + for link in self.dma_ext_links: + self.ruby_system.network._add_ext_link(link) + self.dma_int_links = [ + RubyIntLink( + dma_router, self.ruby_system.network.cross_ccd_router + ) + for dma_router in self.dma_routers + ] + [ + RubyIntLink( + self.ruby_system.network.cross_ccd_router, dma_router + ) + for dma_router in self.dma_routers + ] + for link in self.dma_int_links: + self.ruby_system.network._add_int_link(link) diff --git a/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/octopi_network.py b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/octopi_network.py new file mode 100644 index 0000000000..745ef826c7 --- /dev/null +++ b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/octopi_network.py @@ -0,0 +1,67 @@ +# Copyright (c) 2022-2023 The Regents of the University of California +# 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 m5.objects import SimpleNetwork + +from .ruby_network_components import ( + RubyNetworkComponent, + RubyRouter, + RubyIntLink, +) + +# . The Network owns all routers, all int links and all ext links that are not in CCD's. +# . The CCD subsystems are not of type RubyNetwork, so we need to copy the references of +# routers and links to OctopiNetwork._routers, ._int_links, and ._ext_links; which will +# be, in turns, copied to RubyNetwork.routers, .int_links, and .ext_links respectively. +class OctopiNetwork(SimpleNetwork, RubyNetworkComponent): + def __init__(self, ruby_system): + SimpleNetwork.__init__(self=self) + RubyNetworkComponent.__init__(self=self) + self.netifs = [] + self.ruby_system = ruby_system + self.number_of_virtual_networks = ( + ruby_system.number_of_virtual_networks + ) + + self.cross_ccd_router = RubyRouter(self) + self._add_router(self.cross_ccd_router) + + def connect_ccd_routers_to_cross_ccd_router(self, ccds): + for ccd in ccds: + int_link_1, int_link_2 = RubyIntLink.create_bidirectional_links( + self.cross_ccd_router, + ccd.get_main_router(), + bandwidth_factor=64, + ) + ccd.to_cross_ccd_router_link = int_link_1 + ccd.from_cross_ccd_router_link = int_link_2 + self._add_int_link(int_link_1) + self._add_int_link(int_link_2) + + def incorporate_ccds(self, ccds): + for ccd in ccds: + self.incorporate_ruby_subsystem(ccd) + self.connect_ccd_routers_to_cross_ccd_router(ccds) diff --git a/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/ruby_network_components.py b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/ruby_network_components.py new file mode 100644 index 0000000000..8a413ea59d --- /dev/null +++ b/src/python/gem5/components/cachehierarchies/ruby/caches/prebuilt/octopi_cache/ruby_network_components.py @@ -0,0 +1,111 @@ +# Copyright (c) 2022-2023 The Regents of the University of California +# 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 m5.objects import Switch, SimpleIntLink, SimpleExtLink + + +class RubyNetworkComponent: + def __init__(self): + super().__init__() + self._routers = [] + self._ext_links = [] + self._int_links = [] + + def _add_router(self, router): + self._routers.append(router) + + def _add_ext_link(self, link): + self._ext_links.append(link) + + def _add_int_link(self, link): + self._int_links.append(link) + + def get_routers(self): + return self._routers + + def get_ext_links(self): + return self._ext_links + + def get_int_links(self): + return self._int_links + + def incorporate_ruby_subsystem(self, other_ruby_subsystem): + self._routers.extend(other_ruby_subsystem.get_routers()) + self._ext_links.extend(other_ruby_subsystem.get_ext_links()) + self._int_links.extend(other_ruby_subsystem.get_int_links()) + + +class RubyRouter(Switch): + _router_id = 0 + + @classmethod + def _get_router_id(cls): + cls._router_id += 1 + return cls._router_id - 1 + + def __init__(self, network): + super().__init__() + self.router_id = self._get_router_id() + self.virt_nets = network.number_of_virtual_networks + + +class RubyExtLink(SimpleExtLink): + _link_id = 0 + + @classmethod + def _get_link_id(cls): + cls._link_id += 1 + return cls._link_id - 1 + + def __init__(self, ext_node, int_node, bandwidth_factor=16): + super().__init__() + self.link_id = self._get_link_id() + self.ext_node = ext_node + self.int_node = int_node + self.bandwidth_factor = bandwidth_factor + + +class RubyIntLink(SimpleIntLink): + _link_id = 0 + + @classmethod + def _get_link_id(cls): + cls._link_id += 1 + return cls._link_id - 1 + + @classmethod + def create_bidirectional_links(cls, node_1, node_2, bandwidth_factor=16): + return [ + RubyIntLink(node_1, node_2, bandwidth_factor), + RubyIntLink(node_2, node_1, bandwidth_factor), + ] + + def __init__(self, src_node, dst_node, bandwidth_factor=16): + super().__init__() + self.link_id = self._get_link_id() + self.src_node = src_node + self.dst_node = dst_node + self.bandwidth_factor = bandwidth_factor