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.
This commit is contained in:
Andreas Hansson 2013-08-19 03:52:34 -04:00
parent 49d88f08b0
commit c26911013c
5 changed files with 76 additions and 41 deletions

View file

@ -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

View file

@ -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)")

View file

@ -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':

View file

@ -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)

View file

@ -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")