Better handling of latency/frequency parameter types
authorNathan Binkert <binkertn@umich.edu>
Sat, 26 Mar 2005 03:59:29 +0000 (22:59 -0500)
committerNathan Binkert <binkertn@umich.edu>
Sat, 26 Mar 2005 03:59:29 +0000 (22:59 -0500)
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

python/m5/config.py
python/m5/convert.py
python/m5/objects/Bus.mpy
python/m5/objects/Root.mpy
python/m5/smartdict.py

index 3b5d94b152861e286a88cf677742de5464aacc5b..a791bbebf88b505d5e01d397ff70ac5062b447bf 100644 (file)
@@ -1160,8 +1160,24 @@ class MemorySize(CheckedInt):
         return '%d' % value
     _string = classmethod(_string)
 
-class Addr(MemorySize):
-    pass
+class Addr(CheckedInt):
+    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):
     type = Addr
@@ -1169,15 +1185,18 @@ class AddrRange(Range):
 # Boolean parameter type.
 class Bool(ParamType):
     _cpp_param_decl = 'bool'
-    #def __new__(cls, value):
-    #    return super(MemorySize, cls).__new__(cls, toBool(value))
+    def __init__(self, value):
+        try:
+            self.value = toBool(value)
+        except TypeError:
+            self.value = bool(value)
 
     def _convert(cls, value):
-        return toBool(value)
+        return cls(value)
     _convert = classmethod(_convert)
 
     def _string(cls, value):
-        if value:
+        if value.value:
             return "true"
         else:
             return "false"
@@ -1344,42 +1363,109 @@ class Enum(ParamType):
     def _string(self, value):
         return str(value)
     _string = classmethod(_string)
+
+root_frequency = None
+
 #
 # "Constants"... handy aliases for various values.
 #
+class RootFrequency(float,ParamType):
+    _cpp_param_decl = 'Tick'
 
-class Frequency(int,ParamType):
+    def __new__(cls, value):
+        return super(cls, RootFrequency).__new__(cls, toFrequency(value))
+
+    def _convert(cls, value):
+        return cls(value)
+    _convert = classmethod(_convert)
+
+    def _string(cls, value):
+        return '%d' % int(value)
+    _string = classmethod(_string)
+
+class ClockPeriod(float,ParamType):
+    _cpp_param_decl = 'Tick'
+    def __new__(cls, value):
+        relative = False
+        try:
+            val = toClockPeriod(value)
+        except ValueError, e:
+            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):
+        return cls(value)
+    _convert = classmethod(_convert)
+
+    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):
-        if isinstance(value, basestring):
-            val = int(env['FREQUENCY'] / toFrequency(value))
-        else:
+        relative = False
+        try:
             val = toFrequency(value)
-        return super(cls, Frequency).__new__(cls, val)
+        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):
-        return '%d' % value
+        if not value.relative:
+            value = root_frequency / value
+
+        return '%d' % int(value)
     _string = classmethod(_string)
 
-class Latency(int,ParamType):
+class Latency(float,ParamType):
     _cpp_param_decl = 'Tick'
     def __new__(cls, value):
-        if isinstance(value, basestring):
-            val = int(env['FREQUENCY'] * toLatency(value))
-        else:
+        relative = False
+        try:
             val = toLatency(value)
-        return super(cls, Latency).__new__(cls, val)
+        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
     _string = classmethod(_string)
 
@@ -1394,7 +1480,9 @@ AllMemory = AddrRange(0, MaxAddr)
 # The final hook to generate .ini files.  Called from configuration
 # script once config is built.
 def instantiate(root):
+    global root_frequency
     instance = root.instantiate('root')
+    root_frequency = RootFrequency._convert(root.frequency._getattr())
     instance.fixup()
     instance.display()
     if not noDot:
@@ -1427,6 +1515,7 @@ __all__ = ['ConfigNode', 'SimObject', 'ParamContext', 'Param', 'VectorParam',
            'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16',
            'Int32', 'UInt32', 'Int64', 'UInt64',
            'Counter', 'Addr', 'Tick', 'Percent',
-           'MemorySize', 'Frequency', 'Latency',
+           'MemorySize', 'RootFrequency', 'Frequency', 'Latency',
+           'ClockPeriod',
            'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory', 'NULL',
            'NextEthernetAddr', 'instantiate']
index 4a4492af7f3557a1af5f961a9580d656e1f11b79..6ccefd2fc20d424c5236ee6d1d9c2344fa61ce0d 100644 (file)
@@ -22,162 +22,185 @@ pebi = tebi * 1024
 exbi = pebi * 1024
 
 # memory size configuration stuff
-def toInteger(value):
+def toFloat(value):
     if not isinstance(value, str):
-        result = int(value)
-    elif value.endswith('Ei'):
-        result = int(value[:-2]) * exbi
+        raise TypeError, "wrong type '%s' should be str" % type(value)
+
+    if value.endswith('Ei'):
+        return float(value[:-2]) * exbi
     elif value.endswith('Pi'):
-        result = int(value[:-2]) * pebi
+        return float(value[:-2]) * pebi
     elif value.endswith('Ti'):
-        result = int(value[:-2]) * tebi
+        return float(value[:-2]) * tebi
     elif value.endswith('Gi'):
-        result = int(value[:-2]) * gibi
+        return float(value[:-2]) * gibi
     elif value.endswith('Mi'):
-        result = int(value[:-2]) * mebi
+        return float(value[:-2]) * mebi
     elif value.endswith('ki'):
-        result = int(value[:-2]) * kibi
+        return float(value[:-2]) * kibi
     elif value.endswith('E'):
-        result = int(value[:-1]) * exa
+        return float(value[:-1]) * exa
     elif value.endswith('P'):
-        result = int(value[:-1]) * peta
+        return float(value[:-1]) * peta
     elif value.endswith('T'):
-        result = int(value[:-1]) * tera
+        return float(value[:-1]) * tera
     elif value.endswith('G'):
-        result = int(value[:-1]) * giga
+        return float(value[:-1]) * giga
     elif value.endswith('M'):
-        result = int(value[:-1]) * mega
+        return float(value[:-1]) * mega
     elif value.endswith('k'):
-        result = int(value[:-1]) * kilo
+        return float(value[:-1]) * kilo
     elif value.endswith('m'):
-        result = int(value[:-1]) * milli
+        return float(value[:-1]) * milli
     elif value.endswith('u'):
-        result = int(value[:-1]) * micro
+        return float(value[:-1]) * micro
     elif value.endswith('n'):
-        result = int(value[:-1]) * nano
+        return float(value[:-1]) * nano
     elif value.endswith('p'):
-        result = int(value[:-1]) * pico
+        return float(value[:-1]) * pico
     elif value.endswith('f'):
-        result = int(value[:-1]) * femto
+        return float(value[:-1]) * femto
     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
 
-def toBool(val):
-    t = type(val)
-    if t == bool:
-        return val
+def toInteger(value):
+    value = toFloat(value)
+    result = int(value)
+    if value != result:
+        raise ValueError, "cannot convert '%s' to integer" % value
 
-    if t == None:
-        return False
+    return result
 
-    if t == int or t == long:
-        return bool(val)
+def toBool(value):
+    if not isinstance(value, str):
+        raise TypeError, "wrong type '%s' should be str" % type(value)
 
-    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
+    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 toInteger(val) != 0
+    raise ValueError, "cannot convert '%s' to bool" % value
 
 def toFrequency(value):
     if not isinstance(value, str):
-        result = float(value)
-    elif value.endswith('THz'):
-        result = float(value[:-3]) * tera
+        raise TypeError, "wrong type '%s' should be str" % type(value)
+
+    if value.endswith('THz'):
+        return float(value[:-3]) * tera
     elif value.endswith('GHz'):
-        result = float(value[:-3]) * giga
+        return float(value[:-3]) * giga
     elif value.endswith('MHz'):
-        result = float(value[:-3]) * mega
+        return float(value[:-3]) * mega
     elif value.endswith('kHz'):
-        result = float(value[:-3]) * kilo
+        return float(value[:-3]) * kilo
     elif value.endswith('Hz'):
-        result = float(value[:-2])
-    else:
-        result = float(value)
+        return float(value[:-2])
 
-    return result
+    raise ValueError, "cannot convert '%s' to frequency" % value
 
 def toLatency(value):
     if not isinstance(value, str):
-        result = float(value)
-    elif value.endswith('c'):
-        result = float(value[:-1])
-    elif value.endswith('ps'):
-        result = float(value[:-2]) * pico
+        raise TypeError, "wrong type '%s' should be str" % type(value)
+
+    if value.endswith('ps'):
+        return float(value[:-2]) * pico
     elif value.endswith('ns'):
-        result = float(value[:-2]) * nano
+        return float(value[:-2]) * nano
     elif value.endswith('us'):
-        result = float(value[:-2]) * micro
+        return float(value[:-2]) * micro
     elif value.endswith('ms'):
-        result = float(value[:-2]) * milli
+        return float(value[:-2]) * milli
     elif value.endswith('s'):
-        result = float(value[:-1])
-    else:
-        result = float(value)
+        return float(value[:-1])
+
+    raise ValueError, "cannot convert '%s' to latency" % 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):
     if not isinstance(value, str):
-        result = float(value)
-    elif value.endswith('Tbps'):
-        result = float(value[:-3]) * tera
+        raise TypeError, "wrong type '%s' should be str" % type(value)
+
+    if value.endswith('Tbps'):
+        return float(value[:-3]) * tera
     elif value.endswith('Gbps'):
-        result = float(value[:-3]) * giga
+        return float(value[:-3]) * giga
     elif value.endswith('Mbps'):
-        result = float(value[:-3]) * mega
+        return float(value[:-3]) * mega
     elif value.endswith('kbps'):
-        result = float(value[:-3]) * kilo
+        return float(value[:-3]) * kilo
     elif value.endswith('bps'):
-        result = float(value[:-2])
+        return float(value[:-2])
     else:
-        result = float(value)
+        return float(value)
 
-    return result
+    raise ValueError, "cannot convert '%s' to network bandwidth" % value
 
 def toMemoryBandwidth(value):
     if not isinstance(value, str):
-        result = int(value)
-    elif value.endswith('PB/s'):
-        result = int(value[:-4]) * pebi
+        raise TypeError, "wrong type '%s' should be str" % type(value)
+
+    if value.endswith('PB/s'):
+        return float(value[:-4]) * pebi
     elif value.endswith('TB/s'):
-        result = int(value[:-4]) * tebi
+        return float(value[:-4]) * tebi
     elif value.endswith('GB/s'):
-        result = int(value[:-4]) * gibi
+        return float(value[:-4]) * gibi
     elif value.endswith('MB/s'):
-        result = int(value[:-4]) * mebi
+        return float(value[:-4]) * mebi
     elif value.endswith('kB/s'):
-        result = int(value[:-4]) * kibi
+        return float(value[:-4]) * kibi
     elif value.endswith('B/s'):
-        result = int(value[:-3])
-    else:
-        result = int(value)
+        return float(value[:-3])
 
-    return result
+    raise ValueError, "cannot convert '%s' to memory bandwidth" % value
 
 def toMemorySize(value):
     if not isinstance(value, str):
-        result = int(value)
-    elif value.endswith('PB'):
-        result = int(value[:-2]) * pebi
+        raise TypeError, "wrong type '%s' should be str" % type(value)
+
+    if value.endswith('PB'):
+        return float(value[:-2]) * pebi
     elif value.endswith('TB'):
-        result = int(value[:-2]) * tebi
+        return float(value[:-2]) * tebi
     elif value.endswith('GB'):
-        result = int(value[:-2]) * gibi
+        return float(value[:-2]) * gibi
     elif value.endswith('MB'):
-        result = int(value[:-2]) * mebi
+        return float(value[:-2]) * mebi
     elif value.endswith('kB'):
-        result = int(value[:-2]) * kibi
+        return float(value[:-2]) * kibi
     elif value.endswith('B'):
-        result = int(value[:-1])
-    else:
-        result = int(value)
+        return float(value[:-1])
 
-    return result
+    raise ValueError, "cannot convert '%s' to memory size" % value
index 330a2c82b62d3f6458daf76b3e6043098a8fa444..aa12f757aca690bf26babeb616a12926be7f7383 100644 (file)
@@ -2,5 +2,5 @@ from BaseHier import BaseHier
 
 simobj Bus(BaseHier):
     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")
index 0e531054b08041312011fd424db86ce2e7b5fb14..c535bd2dcde34c15e06249fd1bc6404755afaf6b 100644 (file)
@@ -5,7 +5,7 @@ from Trace import Trace
 
 simobj Root(SimObject):
     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")
     full_system = Param.Bool("Full system simulation?")
     hier = HierParams(do_data = False, do_events = True)
index 0dbcc50b07d129a0583af3a88e222d648395ea41..a2661c279faa710b4df6ca407222e6d175902ce9 100644 (file)
 
 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):
+    """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):
-        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):
+        """intercept the setting of any variable so that we always
+        store strings in the dict"""
         dict.__setitem__(self, key, str(item))
 
     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):
         for value in dict.itervalues(self):
-            yield self.Proxy(value)
+            yield Variable(value)
 
     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):
         for key,value in dict.iteritems(self):
-            yield key, self.Proxy(value)
+            yield key, Variable(value)
 
     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'):
-        return self.Proxy(dict.setdefault(self, key, str(default)))
+        return Variable(dict.setdefault(self, key, str(default)))
 
+__all__ = [ 'SmartDict' ]