First step in fixing up parameter handling. Clean up the

way ranges work, more fully support metric prefixes for all
integer types, and convert memory sized parameters to the
MemorySize type.

python/m5/config.py:
    - no more _Param and _ParamProxy stuff.  Use the names
    ParamBase and ParamFactory to hopefully make it clearer
    what we intend.
    - Get rid of RangeSize and the old Range class and more fully flesh
    out the Range class to deal with types of parameters and different
    kinds of ranges.
    - Call toInteger on the CheckedInt types so we can use metric prefixes
    in strings for all integers.
    - Get rid of the K, M, and G constants.  Use the proper type or call
    one of the functions in the convert package.
python/m5/convert.py:
    Simple way to deal with both floating point and integer strings.
python/m5/objects/BaseCache.mpy:
python/m5/objects/Ethernet.mpy:
    This is a MemorySize typed parameter

--HG--
extra : convert_revision : 92b4ea662d723abdd6c0a49065b79c25400fac9b
This commit is contained in:
Nathan Binkert 2005-03-23 13:25:48 -05:00
parent 48e0b9ed4d
commit 153130e558
4 changed files with 123 additions and 72 deletions

View file

@ -65,7 +65,7 @@ class Singleton(type):
# object, either using keyword assignment in the constructor or in
# separate assignment statements. For example:
#
# cache = BaseCache('my_cache', root, size=64*K)
# cache = BaseCache('my_cache', root, size='64KB')
# cache.hit_latency = 3
# cache.assoc = 8
#
@ -373,7 +373,7 @@ classes. You're trying to derive from:
# now process remaining _init_dict items
for key,val in cls._init_dict.items():
# param descriptions
if isinstance(val, _Param):
if isinstance(val, ParamBase):
cls._new_param(key, val)
# init-time-only keywords
@ -433,8 +433,8 @@ classes. You're trying to derive from:
try:
param.valid(value)
except Exception, e:
panic("Exception: %s\nError setting param %s.%s to %s\n" % \
(e, cls.__name__, attr, value))
raise e.__class__, "%s\nError setting param %s.%s to %s\n" % \
(e, cls.__name__, attr, value)
cls._values[attr] = value
elif isConfigNode(value) or isSimObjSequence(value):
cls._values[attr] = value
@ -837,7 +837,7 @@ class Value(object):
return len(self._getattr())
# Regular parameter.
class _Param(object):
class ParamBase(object):
def __init__(self, ptype, *args, **kwargs):
if isinstance(ptype, types.StringType):
self.ptype_string = ptype
@ -909,13 +909,13 @@ class _Param(object):
def cpp_decl(self, name):
return '%s %s;' % (self.ptype._cpp_param_decl, name)
class _ParamProxy(object):
class ParamFactory(object):
def __init__(self, type):
self.ptype = type
# E.g., Param.Int(5, "number of widgets")
def __call__(self, *args, **kwargs):
return _Param(self.ptype, *args, **kwargs)
return ParamBase(self.ptype, *args, **kwargs)
# Strange magic to theoretically allow dotted names as Param classes,
# e.g., Param.Foo.Bar(...) to have a param of type Foo.Bar
@ -929,17 +929,17 @@ class _ParamProxy(object):
if attr != 'ptype':
raise AttributeError, \
'Attribute %s not available in %s' % (attr, self.__class__)
super(_ParamProxy, self).__setattr__(attr, value)
super(ParamFactory, self).__setattr__(attr, value)
Param = _ParamProxy(None)
Param = ParamFactory(None)
# Vector-valued parameter description. Just like Param, except that
# the value is a vector (list) of the specified type instead of a
# single value.
class _VectorParam(_Param):
class VectorParamBase(ParamBase):
def __init__(self, type, *args, **kwargs):
_Param.__init__(self, type, *args, **kwargs)
ParamBase.__init__(self, type, *args, **kwargs)
def valid(self, value):
if value == None:
@ -974,12 +974,12 @@ class _VectorParam(_Param):
def cpp_decl(self, name):
return 'std::vector<%s> %s;' % (self.ptype._cpp_param_decl, name)
class _VectorParamProxy(_ParamProxy):
class VectorParamFactory(ParamFactory):
# E.g., VectorParam.Int(5, "number of widgets")
def __call__(self, *args, **kwargs):
return _VectorParam(self.ptype, *args, **kwargs)
return VectorParamBase(self.ptype, *args, **kwargs)
VectorParam = _VectorParamProxy(None)
VectorParam = VectorParamFactory(None)
#####################################################################
#
@ -995,6 +995,80 @@ VectorParam = _VectorParamProxy(None)
#
#####################################################################
class MetaRange(type):
def __init__(cls, name, bases, dict):
super(MetaRange, cls).__init__(name, bases, dict)
if name == 'Range':
return
cls._cpp_param_decl = 'Range<%s>' % cls.type._cpp_param_decl
def _convert(cls, value):
if not isinstance(value, Range):
raise TypeError, 'value %s is not a Pair' % value
value = cls(value)
value.first = cls.type._convert(value.first)
value.second = cls.type._convert(value.second)
return value
def _string(cls, value):
first = int(value.first)
second = int(value.second)
if value.extend:
second += first
if not value.inclusive:
second -= 1
return '%s:%s' % (cls.type._string(first), cls.type._string(second))
class Range(ParamType):
__metaclass__ = MetaRange
def __init__(self, *args, **kwargs):
if len(args) == 0:
self.first = kwargs.pop('start')
if 'end' in kwargs:
self.second = kwargs.pop('end')
self.inclusive = True
self.extend = False
elif 'size' in kwargs:
self.second = kwargs.pop('size')
self.inclusive = False
self.extend = True
else:
raise TypeError, "Either end or size must be specified"
elif len(args) == 1:
if kwargs:
self.first = args[0]
if 'end' in kwargs:
self.second = kwargs.pop('end')
self.inclusive = True
self.extend = False
elif 'size' in kwargs:
self.second = kwargs.pop('size')
self.inclusive = False
self.extend = True
else:
raise TypeError, "Either end or size must be specified"
elif isinstance(args[0], Range):
self.first = args[0].first
self.second = args[0].second
self.inclusive = args[0].inclusive
self.extend = args[0].extend
else:
self.first = 0
self.second = args[0]
self.inclusive = False
self.extend = True
elif len(args) == 2:
self.first, self.second = args
self.inclusive = True
self.extend = False
else:
raise TypeError, "Too many arguments specified"
if kwargs:
raise TypeError, "too many keywords: %s" % kwargs.keys()
# Metaclass for bounds-checked integer parameters. See CheckedInt.
class CheckedIntType(type):
@ -1028,8 +1102,10 @@ class CheckedIntType(type):
if not isinstance(value, (int, long, float, str)):
raise TypeError, 'Integer param of invalid type %s' % type(value)
if isinstance(value, (str, float)):
value = long(float(value))
if isinstance(value, float):
value = long(value)
elif isinstance(value, str):
value = toInteger(value)
if not cls.min <= value <= cls.max:
raise TypeError, 'Integer param out of bounds %d < %d < %d' % \
@ -1044,7 +1120,7 @@ class CheckedIntType(type):
# class is subclassed to generate parameter classes with specific
# bounds. Initialization of the min and max bounds is done in the
# metaclass CheckedIntType.__init__.
class CheckedInt(ParamType):
class CheckedInt(long,ParamType):
__metaclass__ = CheckedIntType
class Int(CheckedInt): cppname = 'int'; size = 32; unsigned = False
@ -1060,68 +1136,47 @@ class Int64(CheckedInt): cppname = 'int64_t'; size = 64; unsigned = False
class UInt64(CheckedInt): cppname = 'uint64_t'; size = 64; unsigned = True
class Counter(CheckedInt): cppname = 'Counter'; size = 64; unsigned = True
class Addr(CheckedInt): cppname = 'Addr'; size = 64; unsigned = True
class Tick(CheckedInt): cppname = 'Tick'; size = 64; unsigned = True
class Percent(CheckedInt): cppname = 'int'; min = 0; max = 100
class Pair(object):
def __init__(self, first, second):
self.first = first
self.second = second
class MetaRange(type):
def __init__(cls, name, bases, dict):
super(MetaRange, cls).__init__(name, bases, dict)
if name == 'Range':
return
cls._cpp_param_decl = 'Range<%s>' % cls.type._cpp_param_decl
class MemorySize(CheckedInt):
cppname = 'uint64_t'
size = 64
unsigned = True
def __new__(cls, value):
return super(MemorySize, cls).__new__(cls, toMemorySize(value))
def _convert(cls, value):
if not isinstance(value, Pair):
raise TypeError, 'value %s is not a Pair' % value
return Pair(cls.type._convert(value.first),
cls.type._convert(value.second))
return cls(value)
_convert = classmethod(_convert)
def _string(cls, value):
return '%s:%s' % (cls.type._string(value.first),
cls.type._string(value.second))
return '%d' % value
_string = classmethod(_string)
class Range(ParamType):
__metaclass__ = MetaRange
class Addr(MemorySize):
pass
def RangeSize(start, size):
return Pair(start, start + size - 1)
class AddrRange(Range): type = Addr
class AddrRange(Range):
type = Addr
# Boolean parameter type.
class Bool(ParamType):
_cpp_param_decl = 'bool'
def _convert(value):
t = type(value)
if t == bool:
return value
#def __new__(cls, value):
# return super(MemorySize, cls).__new__(cls, toBool(value))
if t == int or t == long:
return bool(value)
def _convert(cls, value):
return toBool(value)
_convert = classmethod(_convert)
if t == str:
v = value.lower()
if v == "true" or v == "t" or v == "yes" or v == "y":
return True
elif v == "false" or v == "f" or v == "no" or v == "n":
return False
raise TypeError, 'Bool parameter (%s) of invalid type %s' % (v, t)
_convert = staticmethod(_convert)
def _string(value):
def _string(cls, value):
if value:
return "true"
else:
return "false"
_string = staticmethod(_string)
_string = classmethod(_string)
# String-valued parameter.
class String(ParamType):
@ -1291,13 +1346,9 @@ class Enum(ParamType):
#
# Some memory range specifications use this as a default upper bound.
MAX_ADDR = Addr.max
MaxAddr = Addr.max
MaxTick = Tick.max
# For power-of-two sizing, e.g. 64*K gives an integer value 65536.
K = 1024
M = K*K
G = K*M
AllMemory = AddrRange(0, MaxAddr)
#####################################################################
@ -1337,6 +1388,6 @@ __all__ = ['ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam',
'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
'Int32', 'UInt32', 'Int64', 'UInt64',
'Counter', 'Addr', 'Tick', 'Percent',
'Pair', 'RangeSize', 'AddrRange', 'MAX_ADDR', 'NULL', 'K', 'M',
'NextEthernetAddr',
'instantiate']
'MemorySize',
'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'NULL',
'NextEthernetAddr', 'instantiate']

View file

@ -60,7 +60,7 @@ def toInteger(value):
elif value.endswith('f'):
result = int(value[:-1]) * femto
else:
result = int(value)
result = int(float(value))
return result

View file

@ -23,7 +23,7 @@ simobj BaseCache(BaseMem):
"always service demand misses first")
protocol = Param.CoherenceProtocol(NULL, "coherence protocol to use")
repl = Param.Repl(NULL, "replacement policy")
size = Param.Int("capacity in bytes")
size = Param.MemorySize("capacity in bytes")
split = Param.Bool(False, "whether or not this cache is split")
split_size = Param.Int(0,
"How many ways of the cache belong to CPU/LRU partition")

View file

@ -68,8 +68,8 @@ simobj NSGigE(PciDevice):
rx_delay = Param.Tick(1000, "Receive Delay")
tx_delay = Param.Tick(1000, "Transmit Delay")
rx_fifo_size = Param.Int(131072, "max size in bytes of rxFifo")
tx_fifo_size = Param.Int(131072, "max size in bytes of txFifo")
rx_fifo_size = Param.MemorySize('128kB', "max size in bytes of rxFifo")
tx_fifo_size = Param.MemorySize('128kB', "max size in bytes of txFifo")
intr_delay = Param.Tick(0, "Interrupt Delay in microseconds")
payload_bus = Param.Bus(NULL, "The IO Bus to attach to for payload")