From: Andreas Hansson Date: Mon, 19 Aug 2013 07:52:34 +0000 (-0400) Subject: config: Command line support for multi-channel memory X-Git-Tag: stable_2014_02_15~167 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c26911013c799d63dfe854de8cce11137324cde2;p=gem5.git config: Command line support for multi-channel memory This patch adds support for specifying multi-channel memory configurations on the command line, e.g. 'se/fs.py --mem-type=ddr3_1600_x64 --mem-channels=4'. To enable this, it enhances the functionality of MemConfig and moves the existing makeMultiChannel class method from SimpleDRAM to the support scripts. The se/fs.py example scripts are updated to make use of the new feature. --- diff --git a/configs/common/MemConfig.py b/configs/common/MemConfig.py index 6630be8ec..a74ff1d62 100644 --- a/configs/common/MemConfig.py +++ b/configs/common/MemConfig.py @@ -124,3 +124,70 @@ for alias, target in _mem_aliases_all: elif target in _mem_classes: # Normal alias _mem_aliases[alias] = target + +def config_mem(options, system): + """ + Create the memory controllers based on the options and attach them. + + If requested, we make a multi-channel configuration of the + selected memory controller class by creating multiple instances of + the specific class. The individual controllers have their + parameters set such that the address range is interleaved between + them. + """ + + nbr_mem_ctrls = options.mem_channels + import math + from m5.util import fatal + intlv_bits = int(math.log(nbr_mem_ctrls, 2)) + if 2 ** intlv_bits != nbr_mem_ctrls: + fatal("Number of memory channels must be a power of 2") + cls = get(options.mem_type) + mem_ctrls = [] + + # The default behaviour is to interleave on cache line granularity + cache_line_bit = int(math.log(system.cache_line_size.value, 2)) - 1 + intlv_low_bit = cache_line_bit + + # For every range (most systems will only have one), create an + # array of controllers and set their parameters to match their + # address mapping in the case of a DRAM + for r in system.mem_ranges: + for i in xrange(nbr_mem_ctrls): + # Create an instance so we can figure out the address + # mapping and row-buffer size + ctrl = cls() + + # Only do this for DRAMs + if issubclass(cls, m5.objects.SimpleDRAM): + # Inform each controller how many channels to account + # for + ctrl.channels = nbr_mem_ctrls + + # If the channel bits are appearing after the column + # bits, we need to add the appropriate number of bits + # for the row buffer size + if ctrl.addr_mapping.value == 'RaBaChCo': + # This computation only really needs to happen + # once, but as we rely on having an instance we + # end up having to repeat it for each and every + # one + rowbuffer_size = ctrl.device_rowbuffer_size.value * \ + ctrl.devices_per_rank.value + + intlv_low_bit = int(math.log(rowbuffer_size, 2)) - 1 + + # We got all we need to configure the appropriate address + # range + ctrl.range = m5.objects.AddrRange(r.start, size = r.size(), + intlvHighBit = \ + intlv_low_bit + intlv_bits, + intlvBits = intlv_bits, + intlvMatch = i) + mem_ctrls.append(ctrl) + + system.mem_ctrls = mem_ctrls + + # Connect the controllers to the membus + for i in xrange(nbr_mem_ctrls): + system.mem_ctrls[i].port = system.membus.master diff --git a/configs/common/Options.py b/configs/common/Options.py index 73def510c..6431d460f 100644 --- a/configs/common/Options.py +++ b/configs/common/Options.py @@ -88,6 +88,8 @@ def addCommonOptions(parser): parser.add_option("--mem-type", type="choice", default="simple_mem", choices=MemConfig.mem_names(), help = "type of memory to use") + parser.add_option("--mem-channels", type="int", default=1, + help = "number of memory channels") parser.add_option("--mem-size", action="store", type="string", default="512MB", help="Specify the physical memory size (single memory)") diff --git a/configs/example/fs.py b/configs/example/fs.py index bcd58ca5e..4d6d87eb8 100644 --- a/configs/example/fs.py +++ b/configs/example/fs.py @@ -53,6 +53,7 @@ from SysPaths import * from Benchmarks import * import Simulation import CacheConfig +import MemConfig from Caches import * import Options @@ -171,12 +172,7 @@ for i in xrange(np): test_sys.cpu[i].createThreads() CacheConfig.config_cache(options, test_sys) - -# Create the appropriate memory controllers and connect them to the -# memory bus -test_sys.mem_ctrls = [TestMemClass(range = r) for r in test_sys.mem_ranges] -for i in xrange(len(test_sys.mem_ctrls)): - test_sys.mem_ctrls[i].port = test_sys.membus.master +MemConfig.config_mem(options, test_sys) if len(bm) == 2: if buildEnv['TARGET_ISA'] == 'alpha': diff --git a/configs/example/se.py b/configs/example/se.py index 39572cd86..02a0d3b96 100644 --- a/configs/example/se.py +++ b/configs/example/se.py @@ -58,6 +58,7 @@ import Options import Ruby import Simulation import CacheConfig +import MemConfig from Caches import * from cpu2000 import * @@ -157,8 +158,8 @@ if options.smt and options.num_cpus > 1: np = options.num_cpus system = System(cpu = [CPUClass(cpu_id=i) for i in xrange(np)], - physmem = MemClass(range=AddrRange(options.mem_size)), mem_mode = test_mem_mode, + mem_ranges = [AddrRange(options.mem_size)], cache_line_size = options.cacheline_size) # Create a top-level voltage domain @@ -221,7 +222,8 @@ if options.ruby: sys.exit(1) # Set the option for physmem so that it is not allocated any space - system.physmem.null = True + system.physmem = MemClass(range=AddrRange(options.mem_size), + null = True) options.use_map = True Ruby.create_system(options, system) @@ -247,8 +249,8 @@ if options.ruby: else: system.membus = CoherentBus() system.system_port = system.membus.slave - system.physmem.port = system.membus.master CacheConfig.config_cache(options, system) + MemConfig.config_mem(options, system) root = Root(full_system = False, system = system) Simulation.run(options, root, system, FutureClass) diff --git a/src/mem/SimpleDRAM.py b/src/mem/SimpleDRAM.py index b066b27de..0ce94ba3e 100644 --- a/src/mem/SimpleDRAM.py +++ b/src/mem/SimpleDRAM.py @@ -64,38 +64,6 @@ class SimpleDRAM(AbstractMemory): type = 'SimpleDRAM' cxx_header = "mem/simple_dram.hh" - @classmethod - def makeMultiChannel(cls, nbr_mem_ctrls, mem_start_addr, mem_size, - intlv_high_bit = 11): - """ - Make a multi-channel configuration of this class. - - Create multiple instances of the specific class and set their - parameters such that the address range is interleaved between - them. - - Returns a list of controllers. - """ - import math - from m5.util import fatal - intlv_bits = int(math.log(nbr_mem_ctrls, 2)) - if 2 ** intlv_bits != nbr_mem_ctrls: - fatal("Number of memory channels must be a power of 2") - mem_ctrls = [] - for i in xrange(nbr_mem_ctrls): - # The default interleaving granularity is tuned to match a - # row buffer size of 32 cache lines of 64 bytes (starting - # at bit 11 for 2048 bytes). There is unfortunately no - # good way of checking this at instantiation time. - mem_ctrls.append(cls(range = AddrRange(mem_start_addr, - size = mem_size, - intlvHighBit = \ - intlv_high_bit, - intlvBits = intlv_bits, - intlvMatch = i), - channels = nbr_mem_ctrls)) - return mem_ctrls - # single-ported on the system interface side, instantiate with a # bus in front of the controller for multiple ports port = SlavePort("Slave port")