Better handling of latency/frequency parameter types

python/m5/config.py:
    Addr is slightly different from memory size in that Addr
    will take non strings.
    Deal with the fact that the convert.toFoo functions only accept
    strings.
    Add RootFrequency as a special type for the Root.frequency
    parameter which is not scaled.
    Add ClockPeriod parameter type.
python/m5/convert.py:
    Be more strict about what's allowed.
    Only accept strings as inputs for these conversion functions.
    If the user wants to accept something else, they need to deal
    with the failure and convert other types on their own.
python/m5/objects/Bus.mpy:
    Use the new ClockPeriod parameter type
python/m5/objects/Root.mpy:
    Can't use integers for frequency anymore
python/m5/smartdict.py:
    rename SmartDict.Proxy to just Variable.  Create a new class
    UndefinedVariable that is returned when the user tries to get
    a variable that is not in the dict.  Undefined variable evaluates
    to false, and will cause an error elsewhere.

--HG--
extra : convert_revision : 1d55246fd1af65106f102396234827d6401ef9ce
This commit is contained in:
Nathan Binkert 2005-03-25 22:59:29 -05:00
parent 7e1995a29c
commit 40bab977bc
5 changed files with 337 additions and 207 deletions

View file

@ -1160,8 +1160,24 @@ class MemorySize(CheckedInt):
return '%d' % value return '%d' % value
_string = classmethod(_string) _string = classmethod(_string)
class Addr(MemorySize): class Addr(CheckedInt):
pass cppname = 'Addr'
size = 64
unsigned = True
def __new__(cls, value):
try:
value = long(toMemorySize(value))
except TypeError:
value = long(value)
return super(Addr, cls).__new__(cls, value)
def _convert(cls, value):
return cls(value)
_convert = classmethod(_convert)
def _string(cls, value):
return '%d' % value
_string = classmethod(_string)
class AddrRange(Range): class AddrRange(Range):
type = Addr type = Addr
@ -1169,15 +1185,18 @@ class AddrRange(Range):
# Boolean parameter type. # Boolean parameter type.
class Bool(ParamType): class Bool(ParamType):
_cpp_param_decl = 'bool' _cpp_param_decl = 'bool'
#def __new__(cls, value): def __init__(self, value):
# return super(MemorySize, cls).__new__(cls, toBool(value)) try:
self.value = toBool(value)
except TypeError:
self.value = bool(value)
def _convert(cls, value): def _convert(cls, value):
return toBool(value) return cls(value)
_convert = classmethod(_convert) _convert = classmethod(_convert)
def _string(cls, value): def _string(cls, value):
if value: if value.value:
return "true" return "true"
else: else:
return "false" return "false"
@ -1344,42 +1363,109 @@ class Enum(ParamType):
def _string(self, value): def _string(self, value):
return str(value) return str(value)
_string = classmethod(_string) _string = classmethod(_string)
root_frequency = None
# #
# "Constants"... handy aliases for various values. # "Constants"... handy aliases for various values.
# #
class RootFrequency(float,ParamType):
class Frequency(int,ParamType):
_cpp_param_decl = 'Tick' _cpp_param_decl = 'Tick'
def __new__(cls, value): def __new__(cls, value):
if isinstance(value, basestring): return super(cls, RootFrequency).__new__(cls, toFrequency(value))
val = int(env['FREQUENCY'] / toFrequency(value))
else:
val = toFrequency(value)
return super(cls, Frequency).__new__(cls, val)
def _convert(cls, value): def _convert(cls, value):
return cls(value) return cls(value)
_convert = classmethod(_convert) _convert = classmethod(_convert)
def _string(cls, value): def _string(cls, value):
return '%d' % value return '%d' % int(value)
_string = classmethod(_string) _string = classmethod(_string)
class Latency(int,ParamType): class ClockPeriod(float,ParamType):
_cpp_param_decl = 'Tick' _cpp_param_decl = 'Tick'
def __new__(cls, value): def __new__(cls, value):
if isinstance(value, basestring): relative = False
val = int(env['FREQUENCY'] * toLatency(value)) try:
else: val = toClockPeriod(value)
val = toLatency(value) except ValueError, e:
return super(cls, Latency).__new__(cls, val) relative = True
if value.endswith('f'):
val = float(value[:-1])
if val:
val = 1 / val
elif value.endswith('c'):
val = float(value[:-1])
else:
raise e
self = super(cls, ClockPeriod).__new__(cls, val)
self.relative = relative
return self
def _convert(cls, value): def _convert(cls, value):
return cls(value) return cls(value)
_convert = classmethod(_convert) _convert = classmethod(_convert)
def _string(cls, value): def _string(cls, value):
if not value.relative:
value *= root_frequency
return '%d' % int(value)
_string = classmethod(_string)
class Frequency(float,ParamType):
_cpp_param_decl = 'Tick'
def __new__(cls, value):
relative = False
try:
val = toFrequency(value)
except ValueError, e:
if value.endswith('f'):
val = float(value[:-1])
relative = True
else:
raise e
self = super(cls, Frequency).__new__(cls, val)
self.relative = relative
return self
def _convert(cls, value):
return cls(value)
_convert = classmethod(_convert)
def _string(cls, value):
if not value.relative:
value = root_frequency / value
return '%d' % int(value)
_string = classmethod(_string)
class Latency(float,ParamType):
_cpp_param_decl = 'Tick'
def __new__(cls, value):
relative = False
try:
val = toLatency(value)
except ValueError, e:
if value.endswith('c'):
val = float(value[:-1])
relative = True
else:
raise e
self = super(cls, Latency).__new__(cls, val)
self.relative = relative
return self
def _convert(cls, value):
return cls(value)
_convert = classmethod(_convert)
def _string(cls, value):
if not value.relative:
value *= root_frequency
return '%d' % value return '%d' % value
_string = classmethod(_string) _string = classmethod(_string)
@ -1394,7 +1480,9 @@ AllMemory = AddrRange(0, MaxAddr)
# The final hook to generate .ini files. Called from configuration # The final hook to generate .ini files. Called from configuration
# script once config is built. # script once config is built.
def instantiate(root): def instantiate(root):
global root_frequency
instance = root.instantiate('root') instance = root.instantiate('root')
root_frequency = RootFrequency._convert(root.frequency._getattr())
instance.fixup() instance.fixup()
instance.display() instance.display()
if not noDot: if not noDot:
@ -1427,6 +1515,7 @@ __all__ = ['ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam',
'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
'Int32', 'UInt32', 'Int64', 'UInt64', 'Int32', 'UInt32', 'Int64', 'UInt64',
'Counter', 'Addr', 'Tick', 'Percent', 'Counter', 'Addr', 'Tick', 'Percent',
'MemorySize', 'Frequency', 'Latency', 'MemorySize', 'RootFrequency', 'Frequency', 'Latency',
'ClockPeriod',
'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'NULL', 'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'NULL',
'NextEthernetAddr', 'instantiate'] 'NextEthernetAddr', 'instantiate']

View file

@ -22,162 +22,185 @@ pebi = tebi * 1024
exbi = pebi * 1024 exbi = pebi * 1024
# memory size configuration stuff # memory size configuration stuff
def toInteger(value): def toFloat(value):
if not isinstance(value, str): if not isinstance(value, str):
result = int(value) raise TypeError, "wrong type '%s' should be str" % type(value)
elif value.endswith('Ei'):
result = int(value[:-2]) * exbi if value.endswith('Ei'):
return float(value[:-2]) * exbi
elif value.endswith('Pi'): elif value.endswith('Pi'):
result = int(value[:-2]) * pebi return float(value[:-2]) * pebi
elif value.endswith('Ti'): elif value.endswith('Ti'):
result = int(value[:-2]) * tebi return float(value[:-2]) * tebi
elif value.endswith('Gi'): elif value.endswith('Gi'):
result = int(value[:-2]) * gibi return float(value[:-2]) * gibi
elif value.endswith('Mi'): elif value.endswith('Mi'):
result = int(value[:-2]) * mebi return float(value[:-2]) * mebi
elif value.endswith('ki'): elif value.endswith('ki'):
result = int(value[:-2]) * kibi return float(value[:-2]) * kibi
elif value.endswith('E'): elif value.endswith('E'):
result = int(value[:-1]) * exa return float(value[:-1]) * exa
elif value.endswith('P'): elif value.endswith('P'):
result = int(value[:-1]) * peta return float(value[:-1]) * peta
elif value.endswith('T'): elif value.endswith('T'):
result = int(value[:-1]) * tera return float(value[:-1]) * tera
elif value.endswith('G'): elif value.endswith('G'):
result = int(value[:-1]) * giga return float(value[:-1]) * giga
elif value.endswith('M'): elif value.endswith('M'):
result = int(value[:-1]) * mega return float(value[:-1]) * mega
elif value.endswith('k'): elif value.endswith('k'):
result = int(value[:-1]) * kilo return float(value[:-1]) * kilo
elif value.endswith('m'): elif value.endswith('m'):
result = int(value[:-1]) * milli return float(value[:-1]) * milli
elif value.endswith('u'): elif value.endswith('u'):
result = int(value[:-1]) * micro return float(value[:-1]) * micro
elif value.endswith('n'): elif value.endswith('n'):
result = int(value[:-1]) * nano return float(value[:-1]) * nano
elif value.endswith('p'): elif value.endswith('p'):
result = int(value[:-1]) * pico return float(value[:-1]) * pico
elif value.endswith('f'): elif value.endswith('f'):
result = int(value[:-1]) * femto return float(value[:-1]) * femto
else: else:
result = int(float(value)) return float(value)
def toLong(value):
value = toFloat(value)
result = int(value)
if value != result:
raise ValueError, "cannot convert '%s' to long" % value
return result return result
def toBool(val): def toInteger(value):
t = type(val) value = toFloat(value)
if t == bool: result = int(value)
return val if value != result:
raise ValueError, "cannot convert '%s' to integer" % value
if t == None: return result
def toBool(value):
if not isinstance(value, str):
raise TypeError, "wrong type '%s' should be str" % type(value)
value = value.lower()
if value == "true" or value == "t" or value == "yes" or value == "y":
return True
elif value == "false" or value == "f" or value == "no" or value == "n":
return False return False
if t == int or t == long: raise ValueError, "cannot convert '%s' to bool" % value
return bool(val)
if t == str:
val = val.lower()
if val == "true" or val == "t" or val == "yes" or val == "y":
return True
elif val == "false" or val == "f" or val == "no" or val == "n":
return False
elif val == "":
return False
return toInteger(val) != 0
def toFrequency(value): def toFrequency(value):
if not isinstance(value, str): if not isinstance(value, str):
result = float(value) raise TypeError, "wrong type '%s' should be str" % type(value)
elif value.endswith('THz'):
result = float(value[:-3]) * tera
elif value.endswith('GHz'):
result = float(value[:-3]) * giga
elif value.endswith('MHz'):
result = float(value[:-3]) * mega
elif value.endswith('kHz'):
result = float(value[:-3]) * kilo
elif value.endswith('Hz'):
result = float(value[:-2])
else:
result = float(value)
return result if value.endswith('THz'):
return float(value[:-3]) * tera
elif value.endswith('GHz'):
return float(value[:-3]) * giga
elif value.endswith('MHz'):
return float(value[:-3]) * mega
elif value.endswith('kHz'):
return float(value[:-3]) * kilo
elif value.endswith('Hz'):
return float(value[:-2])
raise ValueError, "cannot convert '%s' to frequency" % value
def toLatency(value): def toLatency(value):
if not isinstance(value, str): if not isinstance(value, str):
result = float(value) raise TypeError, "wrong type '%s' should be str" % type(value)
elif value.endswith('c'):
result = float(value[:-1]) if value.endswith('ps'):
elif value.endswith('ps'): return float(value[:-2]) * pico
result = float(value[:-2]) * pico elif value.endswith('ns'):
elif value.endswith('ns'): return float(value[:-2]) * nano
result = float(value[:-2]) * nano elif value.endswith('us'):
elif value.endswith('us'): return float(value[:-2]) * micro
result = float(value[:-2]) * micro elif value.endswith('ms'):
elif value.endswith('ms'): return float(value[:-2]) * milli
result = float(value[:-2]) * milli elif value.endswith('s'):
elif value.endswith('s'): return float(value[:-1])
result = float(value[:-1])
else: raise ValueError, "cannot convert '%s' to latency" % value
result = float(value)
def toClockPeriod(value):
"""result is a clock period"""
if not isinstance(value, str):
raise TypeError, "wrong type '%s' should be str" % type(value)
try:
val = toFrequency(value)
if val != 0:
val = 1 / val
return val
except ValueError:
pass
try:
val = toLatency(value)
return val
except ValueError:
pass
raise ValueError, "cannot convert '%s' to clock period" % value
return result;
def toNetworkBandwidth(value): def toNetworkBandwidth(value):
if not isinstance(value, str): if not isinstance(value, str):
result = float(value) raise TypeError, "wrong type '%s' should be str" % type(value)
elif value.endswith('Tbps'):
result = float(value[:-3]) * tera
elif value.endswith('Gbps'):
result = float(value[:-3]) * giga
elif value.endswith('Mbps'):
result = float(value[:-3]) * mega
elif value.endswith('kbps'):
result = float(value[:-3]) * kilo
elif value.endswith('bps'):
result = float(value[:-2])
else:
result = float(value)
return result if value.endswith('Tbps'):
return float(value[:-3]) * tera
elif value.endswith('Gbps'):
return float(value[:-3]) * giga
elif value.endswith('Mbps'):
return float(value[:-3]) * mega
elif value.endswith('kbps'):
return float(value[:-3]) * kilo
elif value.endswith('bps'):
return float(value[:-2])
else:
return float(value)
raise ValueError, "cannot convert '%s' to network bandwidth" % value
def toMemoryBandwidth(value): def toMemoryBandwidth(value):
if not isinstance(value, str): if not isinstance(value, str):
result = int(value) raise TypeError, "wrong type '%s' should be str" % type(value)
elif value.endswith('PB/s'):
result = int(value[:-4]) * pebi
elif value.endswith('TB/s'):
result = int(value[:-4]) * tebi
elif value.endswith('GB/s'):
result = int(value[:-4]) * gibi
elif value.endswith('MB/s'):
result = int(value[:-4]) * mebi
elif value.endswith('kB/s'):
result = int(value[:-4]) * kibi
elif value.endswith('B/s'):
result = int(value[:-3])
else:
result = int(value)
return result if value.endswith('PB/s'):
return float(value[:-4]) * pebi
elif value.endswith('TB/s'):
return float(value[:-4]) * tebi
elif value.endswith('GB/s'):
return float(value[:-4]) * gibi
elif value.endswith('MB/s'):
return float(value[:-4]) * mebi
elif value.endswith('kB/s'):
return float(value[:-4]) * kibi
elif value.endswith('B/s'):
return float(value[:-3])
raise ValueError, "cannot convert '%s' to memory bandwidth" % value
def toMemorySize(value): def toMemorySize(value):
if not isinstance(value, str): if not isinstance(value, str):
result = int(value) raise TypeError, "wrong type '%s' should be str" % type(value)
elif value.endswith('PB'):
result = int(value[:-2]) * pebi
elif value.endswith('TB'):
result = int(value[:-2]) * tebi
elif value.endswith('GB'):
result = int(value[:-2]) * gibi
elif value.endswith('MB'):
result = int(value[:-2]) * mebi
elif value.endswith('kB'):
result = int(value[:-2]) * kibi
elif value.endswith('B'):
result = int(value[:-1])
else:
result = int(value)
return result if value.endswith('PB'):
return float(value[:-2]) * pebi
elif value.endswith('TB'):
return float(value[:-2]) * tebi
elif value.endswith('GB'):
return float(value[:-2]) * gibi
elif value.endswith('MB'):
return float(value[:-2]) * mebi
elif value.endswith('kB'):
return float(value[:-2]) * kibi
elif value.endswith('B'):
return float(value[:-1])
raise ValueError, "cannot convert '%s' to memory size" % value

View file

@ -2,5 +2,5 @@ from BaseHier import BaseHier
simobj Bus(BaseHier): simobj Bus(BaseHier):
type = 'Bus' type = 'Bus'
clock_ratio = Param.Frequency("ratio of CPU to bus frequency") clock_ratio = Param.ClockPeriod("ratio of CPU to bus frequency")
width = Param.Int("bus width in bytes") width = Param.Int("bus width in bytes")

View file

@ -5,7 +5,7 @@ from Trace import Trace
simobj Root(SimObject): simobj Root(SimObject):
type = 'Root' type = 'Root'
frequency = Param.Tick(200000000, "tick frequency") frequency = Param.RootFrequency('200MHz', "tick frequency")
output_file = Param.String('cout', "file to dump simulator output to") output_file = Param.String('cout', "file to dump simulator output to")
full_system = Param.Bool("Full system simulation?") full_system = Param.Bool("Full system simulation?")
hier = HierParams(do_data = False, do_events = True) hier = HierParams(do_data = False, do_events = True)

View file

@ -16,93 +16,111 @@
from convert import * from convert import *
class Variable(str):
"""Intelligent proxy class for SmartDict. Variable will use the
various convert functions to attempt to convert values to useable
types"""
def __int__(self):
return toInteger(str(self))
def __long__(self):
return toLong(str(self))
def __float__(self):
return toFloat(str(self))
def __nonzero__(self):
return toBool(str(self))
def convert(self, other):
t = type(other)
if t == bool:
return bool(self)
if t == int:
return int(self)
if t == long:
return long(self)
if t == float:
return float(self)
return str(self)
def __lt__(self, other):
return self.convert(other) < other
def __le__(self, other):
return self.convert(other) <= other
def __eq__(self, other):
return self.convert(other) == other
def __ne__(self, other):
return self.convert(other) != other
def __gt__(self, other):
return self.convert(other) > other
def __ge__(self, other):
return self.convert(other) >= other
def __add__(self, other):
return self.convert(other) + other
def __sub__(self, other):
return self.convert(other) - other
def __mul__(self, other):
return self.convert(other) * other
def __div__(self, other):
return self.convert(other) / other
def __truediv__(self, other):
return self.convert(other) / other
def __radd__(self, other):
return other + self.convert(other)
def __rsub__(self, other):
return other - self.convert(other)
def __rmul__(self, other):
return other * self.convert(other)
def __rdiv__(self, other):
return other / self.convert(other)
def __rtruediv__(self, other):
return other / self.convert(other)
class UndefinedVariable(object):
"""Placeholder class to represent undefined variables. Will
generally cause an exception whenever it is used, but evaluates to
zero for boolean truth testing such as in an if statement"""
def __nonzero__(self):
return False
class SmartDict(dict): class SmartDict(dict):
"""Dictionary class that holds strings, but intelligently converts
those strings to other types depending on their usage"""
class Proxy(str):
def __int__(self):
return int(toInteger(str(self)))
def __long__(self):
return long(toInteger(str(self)))
def __float__(self):
return float(toInteger(str(self)))
def __nonzero__(self):
return toBool(str(self))
def convert(self, other):
t = type(other)
if t == bool:
return bool(self)
if t == int:
return int(self)
if t == long:
return long(self)
if t == float:
return float(self)
return str(self)
def __lt__(self, other):
return self.convert(other) < other
def __le__(self, other):
return self.convert(other) <= other
def __eq__(self, other):
return self.convert(other) == other
def __ne__(self, other):
return self.convert(other) != other
def __gt__(self, other):
return self.convert(other) > other
def __ge__(self, other):
return self.convert(other) >= other
def __add__(self, other):
return self.convert(other) + other
def __sub__(self, other):
return self.convert(other) - other
def __mul__(self, other):
return self.convert(other) * other
def __div__(self, other):
return self.convert(other) / other
def __truediv__(self, other):
return self.convert(other) / other
def __radd__(self, other):
return other + self.convert(other)
def __rsub__(self, other):
return other - self.convert(other)
def __rmul__(self, other):
return other * self.convert(other)
def __rdiv__(self, other):
return other / self.convert(other)
def __rtruediv__(self, other):
return other / self.convert(other)
# __getitem__ uses dict.get() to return 'False' if the key is not
# found (rather than raising KeyError). Note that this does *not*
# set the key's value to 'False' in the dict, so that even after
# we call env['foo'] we still get a meaningful answer from "'foo'
# in env" (which calls dict.__contains__, which we do not
# override).
def __getitem__(self, key): def __getitem__(self, key):
return self.Proxy(dict.get(self, key, 'False')) """returns a Variable proxy if the values exists in the database and
returns an UndefinedVariable otherwise"""
if key in self:
return Variable(dict.get(self, key))
else:
# Note that this does *not* change the contents of the dict,
# so that even after we call env['foo'] we still get a
# meaningful answer from "'foo' in env" (which
# calls dict.__contains__, which we do not override).
return UndefinedVariable()
def __setitem__(self, key, item): def __setitem__(self, key, item):
"""intercept the setting of any variable so that we always
store strings in the dict"""
dict.__setitem__(self, key, str(item)) dict.__setitem__(self, key, str(item))
def values(self): def values(self):
return [ self.Proxy(v) for v in dict.values(self) ] return [ Variable(v) for v in dict.values(self) ]
def itervalues(self): def itervalues(self):
for value in dict.itervalues(self): for value in dict.itervalues(self):
yield self.Proxy(value) yield Variable(value)
def items(self): def items(self):
return [ (k, self.Proxy(v)) for k,v in dict.items(self) ] return [ (k, Variable(v)) for k,v in dict.items(self) ]
def iteritems(self): def iteritems(self):
for key,value in dict.iteritems(self): for key,value in dict.iteritems(self):
yield key, self.Proxy(value) yield key, Variable(value)
def get(self, key, default='False'): def get(self, key, default='False'):
return self.Proxy(dict.get(self, key, str(default))) return Variable(dict.get(self, key, str(default)))
def setdefault(self, key, default='False'): def setdefault(self, key, default='False'):
return self.Proxy(dict.setdefault(self, key, str(default))) return Variable(dict.setdefault(self, key, str(default)))
__all__ = [ 'SmartDict' ]