mem: Move crossbar default latencies to subclasses
authorAndreas Hansson <andreas.hansson@arm.com>
Mon, 2 Mar 2015 09:00:47 +0000 (04:00 -0500)
committerAndreas Hansson <andreas.hansson@arm.com>
Mon, 2 Mar 2015 09:00:47 +0000 (04:00 -0500)
This patch introduces a few subclasses to the CoherentXBar and
NoncoherentXBar to distinguish the different uses in the system. We
use the crossbar in a wide range of places: interfacing cores to the
L2, as a system interconnect, connecting I/O and peripherals,
etc. Needless to say, these crossbars have very different performance,
and the clock frequency alone is not enough to distinguish these
scenarios.

Instead of trying to capture every possible case, this patch
introduces dedicated subclasses for the three primary use-cases:
L2XBar, SystemXBar and IOXbar. More can be added if needed, and the
defaults can be overridden.

20 files changed:
configs/common/CacheConfig.py
configs/common/FSConfig.py
configs/dram/sweep.py
configs/example/memcheck.py
configs/example/memtest.py
configs/example/ruby_mem_test.py
configs/example/se.py
configs/ruby/Ruby.py
configs/splash2/cluster.py
configs/splash2/run.py
src/cpu/BaseCPU.py
src/mem/XBar.py
tests/configs/base_config.py
tests/configs/memtest-filter.py
tests/configs/memtest.py
tests/configs/o3-timing-mp-ruby.py
tests/configs/o3-timing-ruby.py
tests/configs/simple-atomic-mp-ruby.py
tests/configs/tgen-dram-ctrl.py
tests/configs/tgen-simple-mem.py

index f31b3d566ab4a31daa99b2ec0585fe519c0ff723..66fe491e1ffecc9950ceac6fc851d23e4daf2f04 100644 (file)
@@ -65,14 +65,12 @@ def config_cache(options, system):
     if options.l2cache:
         # Provide a clock for the L2 and the L1-to-L2 bus here as they
         # are not connected using addTwoLevelCacheHierarchy. Use the
-        # same clock as the CPUs, and set the L1-to-L2 bus width to 32
-        # bytes (256 bits).
+        # same clock as the CPUs.
         system.l2 = l2_cache_class(clk_domain=system.cpu_clk_domain,
                                    size=options.l2_size,
                                    assoc=options.l2_assoc)
 
-        system.tol2bus = CoherentXBar(clk_domain = system.cpu_clk_domain,
-                                      width = 32)
+        system.tol2bus = L2XBar(clk_domain = system.cpu_clk_domain)
         system.l2.cpu_side = system.tol2bus.master
         system.l2.mem_side = system.membus.slave
 
index cfa6dee4d650920c990028647321f1a32b8a4221..e95fff42419bed599033151780677ab524d988f8 100644 (file)
@@ -50,7 +50,7 @@ class CowIdeDisk(IdeDisk):
     def childImage(self, ci):
         self.image.child.image_file = ci
 
-class MemBus(CoherentXBar):
+class MemBus(SystemXBar):
     badaddr_responder = BadAddr()
     default = Self.badaddr_responder.pio
 
@@ -78,7 +78,7 @@ def makeLinuxAlphaSystem(mem_mode, mdesc=None, ruby=False, cmdline=None):
     self.tsunami = BaseTsunami()
 
     # Create the io bus to connect all device ports
-    self.iobus = NoncoherentXBar()
+    self.iobus = IOXBar()
     self.tsunami.attachIO(self.iobus)
 
     self.tsunami.ide.pio = self.iobus.master
@@ -143,7 +143,7 @@ def makeSparcSystem(mem_mode, mdesc=None):
         # generic system
         mdesc = SysConfig()
     self.readfile = mdesc.script()
-    self.iobus = NoncoherentXBar()
+    self.iobus = IOXBar()
     self.membus = MemBus()
     self.bridge = Bridge(delay='50ns')
     self.t1000 = T1000()
@@ -205,7 +205,7 @@ def makeArmSystem(mem_mode, machine_type, num_cpus=1, mdesc=None,
         mdesc = SysConfig()
 
     self.readfile = mdesc.script()
-    self.iobus = NoncoherentXBar()
+    self.iobus = IOXBar()
     self.membus = MemBus()
     self.membus.badaddr_responder.warn_access = "warn"
     self.bridge = Bridge(delay='50ns')
@@ -311,7 +311,7 @@ def makeLinuxMipsSystem(mem_mode, mdesc=None, cmdline=None):
         # generic system
         mdesc = SysConfig()
     self.readfile = mdesc.script()
-    self.iobus = NoncoherentXBar()
+    self.iobus = IOXBar()
     self.membus = MemBus()
     self.bridge = Bridge(delay='50ns')
     self.mem_ranges = [AddrRange('1GB')]
@@ -358,7 +358,7 @@ def connectX86ClassicSystem(x86_sys, numCPUs):
     x86_sys.membus = MemBus()
 
     # North Bridge
-    x86_sys.iobus = NoncoherentXBar()
+    x86_sys.iobus = IOXBar()
     x86_sys.bridge = Bridge(delay='50ns')
     x86_sys.bridge.master = x86_sys.iobus.slave
     x86_sys.bridge.slave = x86_sys.membus.master
@@ -394,7 +394,7 @@ def connectX86ClassicSystem(x86_sys, numCPUs):
 
 def connectX86RubySystem(x86_sys):
     # North Bridge
-    x86_sys.iobus = NoncoherentXBar()
+    x86_sys.iobus = IOXBar()
 
     # add the ide to the list of dma devices that later need to attach to
     # dma controllers
index 18a58b2da4eb358e66018cf726b59c29f86d7968..f0b20dcc5dc85d7c236be47694e0a171a486157a 100644 (file)
@@ -84,7 +84,7 @@ if args:
 # start with the system itself, using a multi-layer 1.5 GHz
 # crossbar, delivering 64 bytes / 5 cycles (one header cycle)
 # which amounts to 19.2 GByte/s per layer and thus per port
-system = System(membus = NoncoherentXBar(width = 16))
+system = System(membus = IOXBar(width = 16))
 system.clk_domain = SrcClockDomain(clock = '1.5GHz',
                                    voltage_domain =
                                    VoltageDomain(voltage = '1V'))
index 4f85223d9b1c18b1d1ccd7322ca31012ef13e686..f0bc26e32044243ca4255cb450e988a983506726 100644 (file)
@@ -243,7 +243,7 @@ def make_cache_level(ncaches, prototypes, level, next_cache):
      if level != 0:
           # Create a crossbar and add it to the subsystem, note that
           # we do this even with a single element on this level
-          xbar = CoherentXBar(width = 32)
+          xbar = L2XBar(width = 32)
           subsys.xbar = xbar
           if next_cache:
                xbar.master = next_cache.cpu_side
@@ -269,7 +269,7 @@ def make_cache_level(ncaches, prototypes, level, next_cache):
 
           if ntesters > 1:
                # Create a crossbar and add it to the subsystem
-               xbar = CoherentXBar(width = 32)
+               xbar = L2XBar(width = 32)
                subsys.xbar = xbar
                xbar.master = next_cache.cpu_side
                for tester, checker in zip(testers, checkers):
index 6c1e657e461af529f66ffb36e6909d6beadbded4..9a66320d80e1db32f2a853ecb91e328e4024a73f 100644 (file)
@@ -233,7 +233,7 @@ def make_cache_level(ncaches, prototypes, level, next_cache):
      if level != 0:
           # Create a crossbar and add it to the subsystem, note that
           # we do this even with a single element on this level
-          xbar = CoherentXBar(width = 32)
+          xbar = L2XBar()
           subsys.xbar = xbar
           if next_cache:
                xbar.master = next_cache.cpu_side
@@ -258,7 +258,7 @@ def make_cache_level(ncaches, prototypes, level, next_cache):
 
           if ntesters > 1:
                # Create a crossbar and add it to the subsystem
-               xbar = CoherentXBar(width = 32)
+               xbar = L2XBar()
                subsys.xbar = xbar
                xbar.master = next_cache.cpu_side
                for tester in testers:
index f5e6d2a8240cee6360564191ccc8f2e4e5ad556e..e2887410f767041e750a015b2564759c94f6a45c 100644 (file)
@@ -106,7 +106,7 @@ cpus = [ MemTest(atomic = False,
 
 system = System(cpu = cpus,
                 funcmem = SimpleMemory(in_addr_map = False),
-                funcbus = NoncoherentXBar(),
+                funcbus = IOXBar(),
                 clk_domain = SrcClockDomain(clock = options.sys_clock),
                 mem_ranges = [AddrRange(options.mem_size)])
 
index 3f51acdeb3fd049e161be59a7b46407b82b83419..a582d29762de571c5ed2a3a464e57c05dda12595 100644 (file)
@@ -265,7 +265,7 @@ if options.ruby:
             system.cpu[i].dtb.walker.port = ruby_port.slave
 else:
     MemClass = Simulation.setMemClass(options)
-    system.membus = CoherentXBar()
+    system.membus = SystemXBar()
     system.system_port = system.membus.slave
     CacheConfig.config_cache(options, system)
     MemConfig.config_mem(options, system)
index e0d53fd6ce47175229ceb4882c6d5d1fd4e5d206..1fa969782c0c30af83823d3343325b6992212989 100644 (file)
@@ -116,7 +116,7 @@ def setup_memory_controllers(system, ruby, dir_cntrls, options):
 
         crossbar = None
         if len(system.mem_ranges) > 1:
-            crossbar = NoncoherentXBar()
+            crossbar = IOXBar()
             crossbars.append(crossbar)
             dir_cntrl.memory = crossbar.slave
 
index b17c8877eeb76ef9060849e4295d03c0479bd0f6..9fafcb70cc1239c288befc83c2736bea6c71c5bb 100644 (file)
@@ -171,7 +171,7 @@ if options.timing:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = CoherentXBar(clock=busFrequency)
+        cluster.clusterbus = L2XBar(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [TimingSimpleCPU(cpu_id = i + cluster.id,
                                         clock=options.frequency)
@@ -184,7 +184,7 @@ elif options.detailed:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = CoherentXBar(clock=busFrequency)
+        cluster.clusterbus = L2XBar(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [DerivO3CPU(cpu_id = i + cluster.id,
                                    clock=options.frequency)
@@ -197,7 +197,7 @@ else:
     for j in xrange(options.numclusters):
         clusters[j].id = j
     for cluster in clusters:
-        cluster.clusterbus = CoherentXBar(clock=busFrequency)
+        cluster.clusterbus = L2XBar(clock=busFrequency)
         all_l1buses += [cluster.clusterbus]
         cluster.cpus = [AtomicSimpleCPU(cpu_id = i + cluster.id,
                                         clock=options.frequency)
@@ -211,10 +211,10 @@ else:
 # ----------------------
 system = System(cpu = all_cpus, l1_ = all_l1s, l1bus_ = all_l1buses,
                 physmem = SimpleMemory(),
-                membus = CoherentXBar(clock = busFrequency))
+                membus = SystemXBar(clock = busFrequency))
 system.clock = '1GHz'
 
-system.toL2bus = CoherentXBar(clock = busFrequency)
+system.toL2bus = L2XBar(clock = busFrequency)
 system.l2 = L2(size = options.l2size, assoc = 8)
 
 # ----------------------
index d542a94370a68c8e3edfbd9d08d0436fd8e309dd..14e5f47d4dcdceeb3876c1a9f4d6600137d803a7 100644 (file)
@@ -196,10 +196,10 @@ else:
 # Create a system, and add system wide objects
 # ----------------------
 system = System(cpu = cpus, physmem = SimpleMemory(),
-                membus = CoherentXBar(clock = busFrequency))
+                membus = SystemXBar(clock = busFrequency))
 system.clock = '1GHz'
 
-system.toL2bus = CoherentXBar(clock = busFrequency)
+system.toL2bus = L2XBar(clock = busFrequency)
 system.l2 = L2(size = options.l2size, assoc = 8)
 
 # ----------------------
index ee6c05f467b13b8d771e96ff361dae05bf3f39bd..9aa24c97b3380d3f82df4e823e5d73ade9a5223c 100644 (file)
@@ -47,7 +47,7 @@ from m5.defines import buildEnv
 from m5.params import *
 from m5.proxy import *
 
-from XBar import CoherentXBar
+from XBar import L2XBar
 from InstTracer import InstTracer
 from CPUTracers import ExeTracer
 from MemObject import MemObject
@@ -285,10 +285,7 @@ class BaseCPU(MemObject):
 
     def addTwoLevelCacheHierarchy(self, ic, dc, l2c, iwc = None, dwc = None):
         self.addPrivateSplitL1Caches(ic, dc, iwc, dwc)
-        # Set a width of 32 bytes (256-bits), which is four times that
-        # of the default bus. The clock of the CPU is inherited by
-        # default.
-        self.toL2Bus = CoherentXBar(width = 32)
+        self.toL2Bus = L2XBar()
         self.connectCachedPorts(self.toL2Bus)
         self.l2cache = l2c
         self.toL2Bus.master = self.l2cache.cpu_side
index 64910ed72636d9992864c8eb70315f7cf6a00e30..a445b5e37ec45c7e8c2223d4b2baaae1d233af97 100644 (file)
@@ -66,12 +66,12 @@ class BaseXBar(MemObject):
     # is the latency involved once a decision is made to forward the
     # request. The response latency, is similar to the forward
     # latency, but for responses rather than requests.
-    frontend_latency = Param.Cycles(3, "Frontend latency")
-    forward_latency = Param.Cycles(4, "Forward latency")
-    response_latency = Param.Cycles(2, "Response latency")
+    frontend_latency = Param.Cycles("Frontend latency")
+    forward_latency = Param.Cycles("Forward latency")
+    response_latency = Param.Cycles("Response latency")
 
     # Width governing the throughput of the crossbar
-    width = Param.Unsigned(8, "Datapath width per port (bytes)")
+    width = Param.Unsigned("Datapath width per port (bytes)")
 
     # The default port can be left unconnected, or be used to connect
     # a default slave port
@@ -95,7 +95,7 @@ class CoherentXBar(BaseXBar):
 
     # The coherent crossbar additionally has snoop responses that are
     # forwarded after a specific latency.
-    snoop_response_latency = Param.Cycles(4, "Snoop response latency")
+    snoop_response_latency = Param.Cycles("Snoop response latency")
 
     # An optional snoop filter
     snoop_filter = Param.SnoopFilter(NULL, "Selected snoop filter")
@@ -111,3 +111,44 @@ class SnoopFilter(SimObject):
     lookup_latency = Param.Cycles(1, "Lookup latency")
 
     system = Param.System(Parent.any, "System that the crossbar belongs to.")
+
+# We use a coherent crossbar to connect multiple masters to the L2
+# caches. Normally this crossbar would be part of the cache itself.
+class L2XBar(CoherentXBar):
+    # 256-bit crossbar by default
+    width = 32
+
+    # Assume that most of this is covered by the cache latencies, with
+    # no more than a single pipeline stage for any packet.
+    frontend_latency = 1
+    forward_latency = 0
+    response_latency = 1
+    snoop_response_latency = 1
+
+# One of the key coherent crossbar instances is the system
+# interconnect, tying together the CPU clusters, GPUs, and any I/O
+# coherent masters, and DRAM controllers.
+class SystemXBar(CoherentXBar):
+    # 128-bit crossbar by default
+    width = 16
+
+    # A handful pipeline stages for each portion of the latency
+    # contributions.
+    frontend_latency = 3
+    forward_latency = 4
+    response_latency = 2
+    snoop_response_latency = 4
+
+# In addition to the system interconnect, we typically also have one
+# or more on-chip I/O crossbars. Note that at some point we might want
+# to also define an off-chip I/O crossbar such as PCIe.
+class IOXBar(NoncoherentXBar):
+    # 128-bit crossbar by default
+    width = 16
+
+    # Assume a simpler datapath than a coherent crossbar, incuring
+    # less pipeline stages for decision making and forwarding of
+    # requests.
+    frontend_latency = 2
+    forward_latency = 1
+    response_latency = 2
index 5637ca3f548a42a4b9e73fec7a3bd7f64f163f82..c440d48d96456003643c7377951c006b3437f24c 100644 (file)
@@ -104,7 +104,7 @@ class BaseSystem(object):
         Returns:
           A bus that CPUs should use to connect to the shared cache.
         """
-        system.toL2Bus = CoherentXBar(clk_domain=system.cpu_clk_domain)
+        system.toL2Bus = L2XBar(clk_domain=system.cpu_clk_domain)
         system.l2c = L2Cache(clk_domain=system.cpu_clk_domain,
                              size='4MB', assoc=8)
         system.l2c.cpu_side = system.toL2Bus.master
@@ -186,7 +186,7 @@ class BaseSESystem(BaseSystem):
 
     def create_system(self):
         system = System(physmem = self.mem_class(),
-                        membus = CoherentXBar(),
+                        membus = SystemXBar(),
                         mem_mode = self.mem_mode)
         system.system_port = system.membus.slave
         system.physmem.port = system.membus.master
index 42dd05639431e9bea269b48fe7ff0ff6c6ac894b..34ac75f00e5aad1c54bc198ef604c64a6c715ff8 100644 (file)
@@ -38,7 +38,7 @@ cpus = [ MemTest() for i in xrange(nb_cores) ]
 # system simulated
 system = System(cpu = cpus,
                 physmem = SimpleMemory(),
-                membus = CoherentXBar(width=16, snoop_filter = SnoopFilter()))
+                membus = SystemXBar(width=16, snoop_filter = SnoopFilter()))
 # Dummy voltage domain for all our clock domains
 system.voltage_domain = VoltageDomain()
 system.clk_domain = SrcClockDomain(clock = '1GHz',
@@ -49,8 +49,8 @@ system.clk_domain = SrcClockDomain(clock = '1GHz',
 system.cpu_clk_domain = SrcClockDomain(clock = '2GHz',
                                        voltage_domain = system.voltage_domain)
 
-system.toL2Bus = CoherentXBar(clk_domain = system.cpu_clk_domain, width=16,
-                              snoop_filter = SnoopFilter())
+system.toL2Bus = L2XBar(clk_domain = system.cpu_clk_domain,
+                        snoop_filter = SnoopFilter())
 system.l2c = L2Cache(clk_domain = system.cpu_clk_domain, size='64kB', assoc=8)
 system.l2c.cpu_side = system.toL2Bus.master
 
index 42f50ce3b96bf5d367be5d486f187892964afeef..5bbfeb774bb27121804f0b8361a8129bf74ca0d3 100644 (file)
@@ -38,7 +38,7 @@ cpus = [ MemTest() for i in xrange(nb_cores) ]
 # system simulated
 system = System(cpu = cpus,
                 physmem = SimpleMemory(),
-                membus = CoherentXBar(width=16))
+                membus = SystemXBar())
 # Dummy voltage domain for all our clock domains
 system.voltage_domain = VoltageDomain()
 system.clk_domain = SrcClockDomain(clock = '1GHz',
@@ -49,7 +49,7 @@ system.clk_domain = SrcClockDomain(clock = '1GHz',
 system.cpu_clk_domain = SrcClockDomain(clock = '2GHz',
                                        voltage_domain = system.voltage_domain)
 
-system.toL2Bus = CoherentXBar(clk_domain = system.cpu_clk_domain, width=16)
+system.toL2Bus = L2XBar(clk_domain = system.cpu_clk_domain)
 system.l2c = L2Cache(clk_domain = system.cpu_clk_domain, size='64kB', assoc=8)
 system.l2c.cpu_side = system.toL2Bus.master
 
index 3fea4ed7117861379fd8b502044c13547c54e060..fb2d56fd1f5e789fc82327269cd8805c00eb89a2 100644 (file)
@@ -38,7 +38,7 @@ import ruby_config
 ruby_memory = ruby_config.generate("TwoLevel_SplitL1UnifiedL2.rb", nb_cores)
 
 # system simulated
-system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentXBar(),
+system = System(cpu = cpus, physmem = ruby_memory, membus = SystemXBar(),
                 mem_mode = "timing",
                 clk_domain = SrcClockDomain(clock = '1GHz'))
 
index 68a07e702535b7c83d30d43d1882d1c78d5dcd39..c47d9f355caa3de7575397aaf692cca1369485db 100644 (file)
@@ -39,7 +39,7 @@ cpu = DerivO3CPU(cpu_id=0)
 
 system = System(cpu = cpu,
                 physmem = ruby_memory,
-                membus = CoherentXBar(),
+                membus = SystemXBar(),
                 mem_mode = "timing",
                 clk_domain = SrcClockDomain(clock = '1GHz'))
 
index 321cb977fbcf1bce468c09412153fee53d1f5170..bdda6d0051c02e645734310911ebce82ec2d47b4 100644 (file)
@@ -38,7 +38,7 @@ import ruby_config
 ruby_memory = ruby_config.generate("TwoLevel_SplitL1UnifiedL2.rb", nb_cores)
 
 # system simulated
-system = System(cpu = cpus, physmem = ruby_memory, membus = CoherentXBar(),
+system = System(cpu = cpus, physmem = ruby_memory, membus = SystemXBar(),
                 clk_domain = SrcClockDomain(clock = '1GHz'))
 
 # Create a seperate clock domain for components that should run at
index d170ac0774d406e831b34f0859a45059c6a3875e..cd6721e6dd613bd1592bc2cf2d999aeb41ef1f3b 100644 (file)
@@ -49,7 +49,7 @@ cpu = TrafficGen(config_file = "tests/quick/se/70.tgen/tgen-dram-ctrl.cfg")
 
 # system simulated
 system = System(cpu = cpu, physmem = DDR3_1600_x64(),
-                membus = NoncoherentXBar(width = 16),
+                membus = IOXBar(width = 16),
                 clk_domain = SrcClockDomain(clock = '1GHz',
                                             voltage_domain =
                                             VoltageDomain()))
index be700ac7af8daa29e028fa2f218d5ce0e8fe0264..edb2f9fcdc9ce9bf57e8feafce6a928b0399bebb 100644 (file)
@@ -49,7 +49,7 @@ cpu = TrafficGen(config_file = "tests/quick/se/70.tgen/tgen-simple-mem.cfg")
 
 # system simulated
 system = System(cpu = cpu, physmem = SimpleMemory(),
-                membus = NoncoherentXBar(width = 16),
+                membus = IOXBar(width = 16),
                 clk_domain = SrcClockDomain(clock = '1GHz',
                                             voltage_domain =
                                             VoltageDomain()))