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:
parent
49d88f08b0
commit
c26911013c
5 changed files with 76 additions and 41 deletions
|
@ -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
|
||||
|
|
|
@ -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)")
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in a new issue