summaryrefslogtreecommitdiff
path: root/src/python
diff options
context:
space:
mode:
Diffstat (limited to 'src/python')
-rw-r--r--src/python/m5/SimObject.py110
-rw-r--r--src/python/m5/params.py195
2 files changed, 297 insertions, 8 deletions
diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py
index 3784c716e..81923ac7c 100644
--- a/src/python/m5/SimObject.py
+++ b/src/python/m5/SimObject.py
@@ -172,6 +172,7 @@ class MetaSimObject(type):
# class or instance attributes
cls._values = multidict() # param values
+ cls._hr_values = multidict() # human readable param values
cls._children = multidict() # SimObject children
cls._port_refs = multidict() # port ref objects
cls._instantiated = False # really instantiated, cloned, or subclassed
@@ -197,6 +198,7 @@ class MetaSimObject(type):
cls._params.parent = base._params
cls._ports.parent = base._ports
cls._values.parent = base._values
+ cls._hr_values.parent = base._hr_values
cls._children.parent = base._children
cls._port_refs.parent = base._port_refs
# mark base as having been subclassed
@@ -273,6 +275,7 @@ class MetaSimObject(type):
def _set_param(cls, name, value, param):
assert(param.name == name)
try:
+ hr_value = value
value = param.convert(value)
except Exception, e:
msg = "%s\nError setting param %s.%s to %s\n" % \
@@ -284,6 +287,11 @@ class MetaSimObject(type):
# it gets cloned properly when the class is instantiated
if isSimObjectOrVector(value) and not value.has_parent():
cls._add_cls_child(name, value)
+ # update human-readable values of the param if it has a literal
+ # value and is not an object or proxy.
+ if not (isSimObjectOrVector(value) or\
+ isinstance(value, m5.proxy.BaseProxy)):
+ cls._hr_values[name] = hr_value
def _add_cls_child(cls, name, child):
# It's a little funky to have a class as a parent, but these
@@ -585,6 +593,28 @@ struct PyObject;
def isSimObjectOrVector(value):
return False
+# This class holds information about each simobject parameter
+# that should be displayed on the command line for use in the
+# configuration system.
+class ParamInfo(object):
+ def __init__(self, type, desc, type_str, example, default_val, access_str):
+ self.type = type
+ self.desc = desc
+ self.type_str = type_str
+ self.example_str = example
+ self.default_val = default_val
+ # The string representation used to access this param through python.
+ # The method to access this parameter presented on the command line may
+ # be different, so this needs to be stored for later use.
+ self.access_str = access_str
+ self.created = True
+
+ # Make it so we can only set attributes at initialization time
+ # and effectively make this a const object.
+ def __setattr__(self, name, value):
+ if not "created" in self.__dict__:
+ self.__dict__[name] = value
+
# The SimObject class is the root of the special hierarchy. Most of
# the code in this class deals with the configuration hierarchy itself
# (parent/child node relationships).
@@ -621,6 +651,64 @@ class SimObject(object):
void startup();
''')
+ # Returns a dict of all the option strings that can be
+ # generated as command line options for this simobject instance
+ # by tracing all reachable params in the top level instance and
+ # any children it contains.
+ def enumerateParams(self, flags_dict = {},
+ cmd_line_str = "", access_str = ""):
+ if hasattr(self, "_paramEnumed"):
+ print "Cycle detected enumerating params"
+ else:
+ self._paramEnumed = True
+ # Scan the children first to pick up all the objects in this SimObj
+ for keys in self._children:
+ child = self._children[keys]
+ next_cmdline_str = cmd_line_str + keys
+ next_access_str = access_str + keys
+ if not isSimObjectVector(child):
+ next_cmdline_str = next_cmdline_str + "."
+ next_access_str = next_access_str + "."
+ flags_dict = child.enumerateParams(flags_dict,
+ next_cmdline_str,
+ next_access_str)
+
+ # Go through the simple params in the simobject in this level
+ # of the simobject hierarchy and save information about the
+ # parameter to be used for generating and processing command line
+ # options to the simulator to set these parameters.
+ for keys,values in self._params.items():
+ if values.isCmdLineSettable():
+ type_str = ''
+ ex_str = values.example_str()
+ ptype = None
+ if isinstance(values, VectorParamDesc):
+ type_str = 'Vector_%s' % values.ptype_str
+ ptype = values
+ else:
+ type_str = '%s' % values.ptype_str
+ ptype = values.ptype
+
+ if keys in self._hr_values\
+ and keys in self._values\
+ and not isinstance(self._values[keys], m5.proxy.BaseProxy):
+ cmd_str = cmd_line_str + keys
+ acc_str = access_str + keys
+ flags_dict[cmd_str] = ParamInfo(ptype,
+ self._params[keys].desc, type_str, ex_str,
+ values.pretty_print(self._hr_values[keys]),
+ acc_str)
+ elif not keys in self._hr_values\
+ and not keys in self._values:
+ # Empty param
+ cmd_str = cmd_line_str + keys
+ acc_str = access_str + keys
+ flags_dict[cmd_str] = ParamInfo(ptype,
+ self._params[keys].desc,
+ type_str, ex_str, '', acc_str)
+
+ return flags_dict
+
# Initialize new instance. For objects with SimObject-valued
# children, we need to recursively clone the classes represented
# by those param values as well in a consistent "deep copy"-style
@@ -661,6 +749,7 @@ class SimObject(object):
# individual value settings can be overridden but we still
# inherit late changes to non-overridden class values.
self._values = multidict(ancestor._values)
+ self._hr_values = multidict(ancestor._hr_values)
# clone SimObject-valued parameters
for key,val in ancestor._values.iteritems():
val = tryAsSimObjectOrVector(val)
@@ -751,6 +840,7 @@ class SimObject(object):
param = self._params.get(attr)
if param:
try:
+ hr_value = value
value = param.convert(value)
except Exception, e:
msg = "%s\nError setting param %s.%s to %s\n" % \
@@ -761,6 +851,13 @@ class SimObject(object):
# implicitly parent unparented objects assigned as params
if isSimObjectOrVector(value) and not value.has_parent():
self.add_child(attr, value)
+ # set the human-readable value dict if this is a param
+ # with a literal value and is not being set as an object
+ # or proxy.
+ if not (isSimObjectOrVector(value) or\
+ isinstance(value, m5.proxy.BaseProxy)):
+ self._hr_values[attr] = hr_value
+
return
# if RHS is a SimObject, it's an implicit child assignment
@@ -778,7 +875,13 @@ class SimObject(object):
def __getitem__(self, key):
if key == 0:
return self
- raise TypeError, "Non-zero index '%s' to SimObject" % key
+ raise IndexError, "Non-zero index '%s' to SimObject" % key
+
+ # this hack allows us to iterate over a SimObject that may
+ # not be a vector, so we can call a loop over it and get just one
+ # element.
+ def __len__(self):
+ return 1
# Also implemented by SimObjectVector
def clear_parent(self, old_parent):
@@ -1054,8 +1157,9 @@ class SimObject(object):
# Cycles in the configuration hierarchy are not supported. This
# will catch the resulting recursion and stop.
self._ccObject = -1
- params = self.getCCParams()
- self._ccObject = params.create()
+ if not self.abstract:
+ params = self.getCCParams()
+ self._ccObject = params.create()
elif self._ccObject == -1:
raise RuntimeError, "%s: Cycle found in configuration hierarchy." \
% self.path()
diff --git a/src/python/m5/params.py b/src/python/m5/params.py
index ad06e5309..88d38f87a 100644
--- a/src/python/m5/params.py
+++ b/src/python/m5/params.py
@@ -93,7 +93,7 @@ class MetaParamValue(type):
# parameters.
class ParamValue(object):
__metaclass__ = MetaParamValue
-
+ cmd_line_settable = False
# Generate the code needed as a prerequisite for declaring a C++
# object of this type. Typically generates one or more #include
@@ -119,6 +119,10 @@ class ParamValue(object):
def unproxy(self, base):
return self
+ # Produce a human readable version of the stored value
+ def pretty_print(self, value):
+ return str(value)
+
# Regular parameter description.
class ParamDesc(object):
def __init__(self, ptype_str, ptype, *args, **kwargs):
@@ -162,6 +166,19 @@ class ParamDesc(object):
raise AttributeError, "'%s' object has no attribute '%s'" % \
(type(self).__name__, attr)
+ def example_str(self):
+ if hasattr(self.ptype, "ex_str"):
+ return self.ptype.ex_str
+ else:
+ return self.ptype_str
+
+ # Is the param available to be exposed on the command line
+ def isCmdLineSettable(self):
+ if hasattr(self.ptype, "cmd_line_settable"):
+ return self.ptype.cmd_line_settable
+ else:
+ return False
+
def convert(self, value):
if isinstance(value, proxy.BaseProxy):
value.set_param_desc(self)
@@ -176,6 +193,13 @@ class ParamDesc(object):
return value
return self.ptype(value)
+ def pretty_print(self, value):
+ if isinstance(value, proxy.BaseProxy):
+ return str(value)
+ if isNullPointer(value):
+ return NULL
+ return self.ptype(value).pretty_print(value)
+
def cxx_predecls(self, code):
code('#include <cstddef>')
self.ptype.cxx_predecls(code)
@@ -260,6 +284,26 @@ class SimObjectVector(VectorParamValue):
value.set_parent(val.get_parent(), val._name)
super(SimObjectVector, self).__setitem__(key, value)
+ # Enumerate the params of each member of the SimObject vector. Creates
+ # strings that will allow indexing into the vector by the python code and
+ # allow it to be specified on the command line.
+ def enumerateParams(self, flags_dict = {},
+ cmd_line_str = "",
+ access_str = ""):
+ if hasattr(self, "_paramEnumed"):
+ print "Cycle detected enumerating params at %s?!" % (cmd_line_str)
+ else:
+ x = 0
+ for vals in self:
+ # Each entry in the SimObjectVector should be an
+ # instance of a SimObject
+ flags_dict = vals.enumerateParams(flags_dict,
+ cmd_line_str + "%d." % x,
+ access_str + "[%d]." % x)
+ x = x + 1
+
+ return flags_dict
+
class VectorParamDesc(ParamDesc):
# Convert assigned value to appropriate type. If the RHS is not a
# list or tuple, it generates a single-element list.
@@ -276,6 +320,39 @@ class VectorParamDesc(ParamDesc):
else:
return VectorParamValue(tmp_list)
+ # Produce a human readable example string that describes
+ # how to set this vector parameter in the absence of a default
+ # value.
+ def example_str(self):
+ s = super(VectorParamDesc, self).example_str()
+ help_str = "[" + s + "," + s + ", ...]"
+ return help_str
+
+ # Produce a human readable representation of the value of this vector param.
+ def pretty_print(self, value):
+ if isinstance(value, (list, tuple)):
+ tmp_list = [ ParamDesc.pretty_print(self, v) for v in value ]
+ elif isinstance(value, str):
+ tmp_list = [ ParamDesc.pretty_print(self, v) for v in value.split(',') ]
+ else:
+ tmp_list = [ ParamDesc.pretty_print(self, value) ]
+
+ return tmp_list
+
+ # This is a helper function for the new config system
+ def __call__(self, value):
+ if isinstance(value, (list, tuple)):
+ # list: coerce each element into new list
+ tmp_list = [ ParamDesc.convert(self, v) for v in value ]
+ elif isinstance(value, str):
+ # If input is a csv string
+ tmp_list = [ ParamDesc.convert(self, v) for v in value.split(',') ]
+ else:
+ # singleton: coerce to a single-element list
+ tmp_list = [ ParamDesc.convert(self, value) ]
+
+ return VectorParamValue(tmp_list)
+
def swig_module_name(self):
return "%s_vector" % self.ptype_str
@@ -349,6 +426,7 @@ VectorParam = ParamFactory(VectorParamDesc)
# built-in str class.
class String(ParamValue,str):
cxx_type = 'std::string'
+ cmd_line_settable = True
@classmethod
def cxx_predecls(self, code):
@@ -358,6 +436,10 @@ class String(ParamValue,str):
def swig_predecls(cls, code):
code('%include "std_string.i"')
+ def __call__(self, value):
+ self = value
+ return value
+
def getValue(self):
return self
@@ -430,6 +512,7 @@ class CheckedIntType(MetaParamValue):
# metaclass CheckedIntType.__init__.
class CheckedInt(NumericParamValue):
__metaclass__ = CheckedIntType
+ cmd_line_settable = True
def _check(self):
if not self.min <= self.value <= self.max:
@@ -446,6 +529,10 @@ class CheckedInt(NumericParamValue):
% type(value).__name__
self._check()
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
@classmethod
def cxx_predecls(cls, code):
# most derived types require this, so we just do it here once
@@ -490,19 +577,25 @@ class Cycles(CheckedInt):
class Float(ParamValue, float):
cxx_type = 'double'
+ cmdLineSettable = True
def __init__(self, value):
- if isinstance(value, (int, long, float, NumericParamValue, Float)):
+ if isinstance(value, (int, long, float, NumericParamValue, Float, str)):
self.value = float(value)
else:
raise TypeError, "Can't convert object of type %s to Float" \
% type(value).__name__
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def getValue(self):
return float(self.value)
class MemorySize(CheckedInt):
cxx_type = 'uint64_t'
+ ex_str = '512MB'
size = 64
unsigned = True
def __init__(self, value):
@@ -514,6 +607,7 @@ class MemorySize(CheckedInt):
class MemorySize32(CheckedInt):
cxx_type = 'uint32_t'
+ ex_str = '512MB'
size = 32
unsigned = True
def __init__(self, value):
@@ -541,6 +635,12 @@ class Addr(CheckedInt):
return self.value + other.value
else:
return self.value + other
+ def pretty_print(self, value):
+ try:
+ val = convert.toMemorySize(value)
+ except TypeError:
+ val = long(value)
+ return "0x%x" % long(val)
class AddrRange(ParamValue):
cxx_type = 'AddrRange'
@@ -624,12 +724,18 @@ class AddrRange(ParamValue):
# False. Thus this is a little more complicated than String.
class Bool(ParamValue):
cxx_type = 'bool'
+ cmd_line_settable = True
+
def __init__(self, value):
try:
self.value = convert.toBool(value)
except TypeError:
self.value = bool(value)
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def getValue(self):
return bool(self.value)
@@ -668,6 +774,8 @@ def NextEthernetAddr():
class EthernetAddr(ParamValue):
cxx_type = 'Net::EthAddr'
+ ex_str = "00:90:00:00:00:01"
+ cmd_line_settable = True
@classmethod
def cxx_predecls(cls, code):
@@ -695,6 +803,10 @@ class EthernetAddr(ParamValue):
self.value = value
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def unproxy(self, base):
if self.value == NextEthernetAddr:
return EthernetAddr(self.value())
@@ -711,6 +823,8 @@ class EthernetAddr(ParamValue):
# the form "a.b.c.d", or an integer representing an IP.
class IpAddress(ParamValue):
cxx_type = 'Net::IpAddress'
+ ex_str = "127.0.0.1"
+ cmd_line_settable = True
@classmethod
def cxx_predecls(cls, code):
@@ -730,6 +844,10 @@ class IpAddress(ParamValue):
self.ip = long(value)
self.verifyIp()
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def __str__(self):
tup = [(self.ip >> i) & 0xff for i in (24, 16, 8, 0)]
return '%d.%d.%d.%d' % tuple(tup)
@@ -761,6 +879,8 @@ class IpAddress(ParamValue):
# positional or keyword arguments.
class IpNetmask(IpAddress):
cxx_type = 'Net::IpNetmask'
+ ex_str = "127.0.0.0/24"
+ cmd_line_settable = True
@classmethod
def cxx_predecls(cls, code):
@@ -806,6 +926,10 @@ class IpNetmask(IpAddress):
self.verify()
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def __str__(self):
return "%s/%d" % (super(IpNetmask, self).__str__(), self.netmask)
@@ -833,6 +957,8 @@ class IpNetmask(IpAddress):
# the form "a.b.c.d:p", or an ip and port as positional or keyword arguments.
class IpWithPort(IpAddress):
cxx_type = 'Net::IpWithPort'
+ ex_str = "127.0.0.1:80"
+ cmd_line_settable = True
@classmethod
def cxx_predecls(cls, code):
@@ -878,6 +1004,10 @@ class IpWithPort(IpAddress):
self.verify()
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def __str__(self):
return "%s:%d" % (super(IpWithPort, self).__str__(), self.port)
@@ -953,6 +1083,10 @@ class Time(ParamValue):
def __init__(self, value):
self.value = parse_time(value)
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def getValue(self):
from m5.internal.params import tm
@@ -1111,6 +1245,7 @@ $wrapper $wrapper_name {
class Enum(ParamValue):
__metaclass__ = MetaEnum
vals = []
+ cmd_line_settable = True
# The name of the wrapping namespace or struct
wrapper_name = 'Enums'
@@ -1127,6 +1262,10 @@ class Enum(ParamValue):
% (value, self.vals)
self.value = value
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
@classmethod
def cxx_predecls(cls, code):
code('#include "enums/$0.hh"', cls.__name__)
@@ -1146,6 +1285,8 @@ frequency_tolerance = 0.001 # 0.1%
class TickParamValue(NumericParamValue):
cxx_type = 'Tick'
+ ex_str = "1MHz"
+ cmd_line_settable = True
@classmethod
def cxx_predecls(cls, code):
@@ -1156,10 +1297,16 @@ class TickParamValue(NumericParamValue):
code('%import "stdint.i"')
code('%import "base/types.hh"')
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def getValue(self):
return long(self.value)
class Latency(TickParamValue):
+ ex_str = "100ns"
+
def __init__(self, value):
if isinstance(value, (Latency, Clock)):
self.ticks = value.ticks
@@ -1174,6 +1321,10 @@ class Latency(TickParamValue):
self.ticks = False
self.value = convert.toLatency(value)
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def __getattr__(self, attr):
if attr in ('latency', 'period'):
return self
@@ -1193,6 +1344,8 @@ class Latency(TickParamValue):
return '%d' % self.getValue()
class Frequency(TickParamValue):
+ ex_str = "1GHz"
+
def __init__(self, value):
if isinstance(value, (Latency, Clock)):
if value.value == 0:
@@ -1207,6 +1360,10 @@ class Frequency(TickParamValue):
self.ticks = False
self.value = convert.toFrequency(value)
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
def __getattr__(self, attr):
if attr == 'frequency':
return self
@@ -1242,6 +1399,13 @@ class Clock(TickParamValue):
self.ticks = False
self.value = convert.anyToLatency(value)
+ def __call__(self, value):
+ self.__init__(value)
+ return value
+
+ def __str__(self):
+ return "%s" % Latency(self)
+
def __getattr__(self, attr):
if attr == 'frequency':
return Frequency(self)
@@ -1257,13 +1421,21 @@ class Clock(TickParamValue):
class Voltage(float,ParamValue):
cxx_type = 'double'
+ ex_str = "1V"
+ cmd_line_settable = False
+
def __new__(cls, value):
# convert to voltage
val = convert.toVoltage(value)
return super(cls, Voltage).__new__(cls, val)
+ def __call__(self, value):
+ val = convert.toVoltage(value)
+ self.__init__(val)
+ return value
+
def __str__(self):
- return str(self.val)
+ return str(self.getValue())
def getValue(self):
value = float(self)
@@ -1274,6 +1446,9 @@ class Voltage(float,ParamValue):
class NetworkBandwidth(float,ParamValue):
cxx_type = 'float'
+ ex_str = "1Gbps"
+ cmd_line_settable = True
+
def __new__(cls, value):
# convert to bits per second
val = convert.toNetworkBandwidth(value)
@@ -1282,6 +1457,11 @@ class NetworkBandwidth(float,ParamValue):
def __str__(self):
return str(self.val)
+ def __call__(self, value):
+ val = convert.toNetworkBandwidth(value)
+ self.__init__(val)
+ return value
+
def getValue(self):
# convert to seconds per byte
value = 8.0 / float(self)
@@ -1294,13 +1474,18 @@ class NetworkBandwidth(float,ParamValue):
class MemoryBandwidth(float,ParamValue):
cxx_type = 'float'
+ ex_str = "1GB/s"
+ cmd_line_settable = True
+
def __new__(cls, value):
# convert to bytes per second
val = convert.toMemoryBandwidth(value)
return super(cls, MemoryBandwidth).__new__(cls, val)
- def __str__(self):
- return str(self.val)
+ def __call__(self, value):
+ val = convert.toMemoryBandwidth(value)
+ self.__init__(val)
+ return value
def getValue(self):
# convert to seconds per byte