diff options
Diffstat (limited to 'src/python')
-rw-r--r-- | src/python/m5/SimObject.py | 110 | ||||
-rw-r--r-- | src/python/m5/params.py | 195 |
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 |