From aa78db4adab413600547dc01a9f1db2fbbe8fa44 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 22 Sep 2009 15:24:16 -0700 Subject: code_formatter: use __builtin__ which is correct, not __builtins__ --- src/python/m5/util/code_formatter.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/python') diff --git a/src/python/m5/util/code_formatter.py b/src/python/m5/util/code_formatter.py index 919a6423b..396fe0e52 100644 --- a/src/python/m5/util/code_formatter.py +++ b/src/python/m5/util/code_formatter.py @@ -24,6 +24,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import __builtin__ import inspect import os import re @@ -64,8 +65,8 @@ class lookup(object): if self.formatter.globals and item in self.frame.f_globals: return self.frame.f_globals[item] - if item in __builtins__: - return __builtins__[item] + if item in __builtin__.__dict__: + return __builtin__.__dict__[item] try: item = int(item) -- cgit v1.2.3 From eec67312b5990dd73c6330e74bff978ad300f780 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 22 Sep 2009 15:24:16 -0700 Subject: attrdict: add pickle support to attrdict --- src/python/m5/util/attrdict.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src/python') diff --git a/src/python/m5/util/attrdict.py b/src/python/m5/util/attrdict.py index 0b30258b9..3336632f5 100644 --- a/src/python/m5/util/attrdict.py +++ b/src/python/m5/util/attrdict.py @@ -45,6 +45,12 @@ class attrdict(dict): return self.__delitem__(attr) return super(attrdict, self).__delattr__(attr) + def __getstate__(self): + return dict(self) + + def __setstate__(self, state): + self.update(state) + class multiattrdict(attrdict): """Wrap attrdict so that nested attribute accesses automatically create nested dictionaries.""" -- cgit v1.2.3 From 0d58d32ad51eed32e6c7f9135b901006777fbe87 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 22 Sep 2009 15:24:16 -0700 Subject: multiattrdict: make multilevel nesting work properly --- src/python/m5/util/attrdict.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/python') diff --git a/src/python/m5/util/attrdict.py b/src/python/m5/util/attrdict.py index 3336632f5..8f7d59698 100644 --- a/src/python/m5/util/attrdict.py +++ b/src/python/m5/util/attrdict.py @@ -58,7 +58,7 @@ class multiattrdict(attrdict): try: return super(multiattrdict, self).__getattr__(attr) except AttributeError: - d = optiondict() + d = multiattrdict() setattr(self, attr, d) return d @@ -86,8 +86,12 @@ if __name__ == '__main__': print dir(x) print(x) + print + print "multiattrdict" x = multiattrdict() + x.x.x.x = 9 x.y.z = 9 print x print x.y print x.y.z + print x.z.z -- cgit v1.2.3 From 9a8cb7db7e86c25a755f2e2817a0385b13e3ac32 Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 22 Sep 2009 15:24:16 -0700 Subject: python: Move more code into m5.util allow SCons to use that code. Get rid of misc.py and just stick misc things in __init__.py Move utility functions out of SCons files and into m5.util Move utility type stuff from m5/__init__.py to m5/util/__init__.py Remove buildEnv from m5 and allow access only from m5.defines Rename AddToPath to addToPath while we're moving it to m5.util Rename read_command to readCommand while we're moving it Rename compare_versions to compareVersions while we're moving it. --HG-- rename : src/python/m5/convert.py => src/python/m5/util/convert.py rename : src/python/m5/smartdict.py => src/python/m5/util/smartdict.py --- src/python/SConscript | 5 +- src/python/m5/SimObject.py | 79 +++++++------ src/python/m5/__init__.py | 102 ++-------------- src/python/m5/convert.py | 250 ---------------------------------------- src/python/m5/environment.py | 43 ------- src/python/m5/main.py | 2 +- src/python/m5/params.py | 33 +++--- src/python/m5/simulate.py | 3 + src/python/m5/smartdict.py | 154 ------------------------- src/python/m5/ticks.py | 2 +- src/python/m5/trace.py | 2 +- src/python/m5/util/__init__.py | 149 +++++++++++++++++++++++- src/python/m5/util/convert.py | 250 ++++++++++++++++++++++++++++++++++++++++ src/python/m5/util/jobfile.py | 10 +- src/python/m5/util/misc.py | 87 -------------- src/python/m5/util/smartdict.py | 154 +++++++++++++++++++++++++ 16 files changed, 634 insertions(+), 691 deletions(-) delete mode 100644 src/python/m5/convert.py delete mode 100644 src/python/m5/environment.py delete mode 100644 src/python/m5/smartdict.py create mode 100644 src/python/m5/util/convert.py delete mode 100644 src/python/m5/util/misc.py create mode 100644 src/python/m5/util/smartdict.py (limited to 'src/python') diff --git a/src/python/SConscript b/src/python/SConscript index bb892f376..935986a12 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -38,7 +38,6 @@ PySource('', 'importer.py') PySource('m5', 'm5/__init__.py') PySource('m5', 'm5/SimObject.py') PySource('m5', 'm5/config.py') -PySource('m5', 'm5/convert.py') PySource('m5', 'm5/core.py') PySource('m5', 'm5/debug.py') PySource('m5', 'm5/event.py') @@ -47,18 +46,18 @@ PySource('m5', 'm5/options.py') PySource('m5', 'm5/params.py') PySource('m5', 'm5/proxy.py') PySource('m5', 'm5/simulate.py') -PySource('m5', 'm5/smartdict.py') PySource('m5', 'm5/stats.py') PySource('m5', 'm5/ticks.py') PySource('m5', 'm5/trace.py') PySource('m5.util', 'm5/util/__init__.py') PySource('m5.util', 'm5/util/attrdict.py') PySource('m5.util', 'm5/util/code_formatter.py') +PySource('m5.util', 'm5/util/convert.py') PySource('m5.util', 'm5/util/grammar.py') PySource('m5.util', 'm5/util/jobfile.py') -PySource('m5.util', 'm5/util/misc.py') PySource('m5.util', 'm5/util/multidict.py') PySource('m5.util', 'm5/util/orderdict.py') +PySource('m5.util', 'm5/util/smartdict.py') SwigSource('m5.internal', 'swig/core.i') SwigSource('m5.internal', 'swig/debug.i') diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index 8ef22be4e..0e0ffaea9 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -31,47 +31,24 @@ import math import sys import types -import proxy -import m5 -from util import * - -# These utility functions have to come first because they're -# referenced in params.py... otherwise they won't be defined when we -# import params below, and the recursive import of this file from -# params.py will not find these names. -def isSimObject(value): - return isinstance(value, SimObject) - -def isSimObjectClass(value): - return issubclass(value, SimObject) - -def isSimObjectSequence(value): - if not isinstance(value, (list, tuple)) or len(value) == 0: - return False - - for val in value: - if not isNullPointer(val) and not isSimObject(val): - return False - - return True +try: + import pydot +except: + pydot = False -def isSimObjectOrSequence(value): - return isSimObject(value) or isSimObjectSequence(value) +import m5 +from m5.util import * # Have to import params up top since Param is referenced on initial # load (when SimObject class references Param to create a class # variable, the 'name' param)... -from params import * +from m5.params import * # There are a few things we need that aren't in params.__all__ since # normal users don't need them -from params import ParamDesc, VectorParamDesc, isNullPointer, SimObjVector -from proxy import * +from m5.params import ParamDesc, VectorParamDesc, isNullPointer, SimObjVector -noDot = False -try: - import pydot -except: - noDot = True +from m5.proxy import * +from m5.proxy import isproxy ##################################################################### # @@ -141,7 +118,7 @@ class MetaSimObject(type): # and only allow "private" attributes to be passed to the base # __new__ (starting with underscore). def __new__(mcls, name, bases, dict): - assert name not in allClasses + assert name not in allClasses, "SimObject %s already present" % name # Copy "private" attributes, functions, and classes to the # official dict. Everything else goes in _init_dict to be @@ -678,7 +655,7 @@ class SimObject(object): def unproxy_all(self): for param in self._params.iterkeys(): value = self._values.get(param) - if value != None and proxy.isproxy(value): + if value != None and isproxy(value): try: value = value.unproxy(self) except: @@ -749,8 +726,8 @@ class SimObject(object): for param in param_names: value = self._values.get(param) if value is None: - m5.fatal("%s.%s without default or user set value", - self.path(), param) + fatal("%s.%s without default or user set value", + self.path(), param) value = value.getValue() if isinstance(self._params[param], VectorParamDesc): @@ -886,6 +863,34 @@ def resolveSimObject(name): obj = instanceDict[name] return obj.getCCObject() +def isSimObject(value): + return isinstance(value, SimObject) + +def isSimObjectClass(value): + return issubclass(value, SimObject) + +def isSimObjectSequence(value): + if not isinstance(value, (list, tuple)) or len(value) == 0: + return False + + for val in value: + if not isNullPointer(val) and not isSimObject(val): + return False + + return True + +def isSimObjectOrSequence(value): + return isSimObject(value) or isSimObjectSequence(value) + +baseClasses = allClasses.copy() +baseInstances = instanceDict.copy() + +def clear(): + global allClasses, instanceDict + + allClasses = baseClasses.copy() + instanceDict = baseInstances.copy() + # __all__ defines the list of symbols that get exported when # 'from config import *' is invoked. Try to keep this reasonably # short to avoid polluting other namespaces. diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py index c3512cd0d..9f9459ae8 100644 --- a/src/python/m5/__init__.py +++ b/src/python/m5/__init__.py @@ -25,106 +25,24 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Authors: Nathan Binkert -# Steve Reinhardt -import os -import sys +# Import useful subpackages of M5, but *only* when run as an m5 +# script. This is mostly to keep backward compatibility with existing +# scripts while allowing new SCons code to operate properly. -import smartdict - -# define a MaxTick parameter -MaxTick = 2**63 - 1 - -# define this here so we can use it right away if necessary - -def errorURL(prefix, s): - try: - import zlib - hashstr = "%x" % zlib.crc32(s) - except: - hashstr = "UnableToHash" - return "For more information see: http://www.m5sim.org/%s/%s" % \ - (prefix, hashstr) - - -# panic() should be called when something happens that should never -# ever happen regardless of what the user does (i.e., an acutal m5 -# bug). -def panic(fmt, *args): - print >>sys.stderr, 'panic:', fmt % args - print >>sys.stderr, errorURL('panic',fmt) - sys.exit(1) - -# fatal() should be called when the simulation cannot continue due to -# some condition that is the user's fault (bad configuration, invalid -# arguments, etc.) and not a simulator bug. -def fatal(fmt, *args): - print >>sys.stderr, 'fatal:', fmt % args - print >>sys.stderr, errorURL('fatal',fmt) - sys.exit(1) - -# force scalars to one-element lists for uniformity -def makeList(objOrList): - if isinstance(objOrList, list): - return objOrList - return [objOrList] - -# Prepend given directory to system module search path. We may not -# need this anymore if we can structure our config library more like a -# Python package. -def AddToPath(path): - # if it's a relative path and we know what directory the current - # python script is in, make the path relative to that directory. - if not os.path.isabs(path) and sys.path[0]: - path = os.path.join(sys.path[0], path) - path = os.path.realpath(path) - # sys.path[0] should always refer to the current script's directory, - # so place the new dir right after that. - sys.path.insert(1, path) - -# make a SmartDict out of the build options for our local use -build_env = smartdict.SmartDict() - -# make a SmartDict out of the OS environment too -env = smartdict.SmartDict() -env.update(os.environ) - -# Since we have so many mutual imports in this package, we should: -# 1. Put all intra-package imports at the *bottom* of the file, unless -# they're absolutely needed before that (for top-level statements -# or class attributes). Imports of "trivial" packages that don't -# import other packages (e.g., 'smartdict') can be at the top. -# 2. Never use 'from foo import *' on an intra-package import since -# you can get the wrong result if foo is only partially imported -# at the point you do that (i.e., because foo is in the middle of -# importing *you*). try: import internal except ImportError: internal = None -try: - import defines - build_env.update(defines.buildEnv) -except ImportError: - defines = None - if internal: - defines.compileDate = internal.core.compileDate - for k,v in internal.core.__dict__.iteritems(): - if k.startswith('flag_'): - setattr(defines, k[5:], v) + import SimObject + import core + import objects + import params + import stats + import util from event import * - from simulate import * from main import options, main - import stats - import core - -import SimObject -import params - -try: - import objects -except ImportError: - objects = None + from simulate import * diff --git a/src/python/m5/convert.py b/src/python/m5/convert.py deleted file mode 100644 index bb9e3e1f1..000000000 --- a/src/python/m5/convert.py +++ /dev/null @@ -1,250 +0,0 @@ -# Copyright (c) 2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Nathan Binkert - -# metric prefixes -exa = 1.0e18 -peta = 1.0e15 -tera = 1.0e12 -giga = 1.0e9 -mega = 1.0e6 -kilo = 1.0e3 - -milli = 1.0e-3 -micro = 1.0e-6 -nano = 1.0e-9 -pico = 1.0e-12 -femto = 1.0e-15 -atto = 1.0e-18 - -# power of 2 prefixes -kibi = 1024 -mebi = kibi * 1024 -gibi = mebi * 1024 -tebi = gibi * 1024 -pebi = tebi * 1024 -exbi = pebi * 1024 - -# memory size configuration stuff -def toFloat(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('Ei'): - return float(value[:-2]) * exbi - elif value.endswith('Pi'): - return float(value[:-2]) * pebi - elif value.endswith('Ti'): - return float(value[:-2]) * tebi - elif value.endswith('Gi'): - return float(value[:-2]) * gibi - elif value.endswith('Mi'): - return float(value[:-2]) * mebi - elif value.endswith('ki'): - return float(value[:-2]) * kibi - elif value.endswith('E'): - return float(value[:-1]) * exa - elif value.endswith('P'): - return float(value[:-1]) * peta - elif value.endswith('T'): - return float(value[:-1]) * tera - elif value.endswith('G'): - return float(value[:-1]) * giga - elif value.endswith('M'): - return float(value[:-1]) * mega - elif value.endswith('k'): - return float(value[:-1]) * kilo - elif value.endswith('m'): - return float(value[:-1]) * milli - elif value.endswith('u'): - return float(value[:-1]) * micro - elif value.endswith('n'): - return float(value[:-1]) * nano - elif value.endswith('p'): - return float(value[:-1]) * pico - elif value.endswith('f'): - return float(value[:-1]) * femto - else: - return float(value) - -def toInteger(value): - value = toFloat(value) - result = long(value) - if value != result: - raise ValueError, "cannot convert '%s' to integer" % value - - return result - -_bool_dict = { - 'true' : True, 't' : True, 'yes' : True, 'y' : True, '1' : True, - 'false' : False, 'f' : False, 'no' : False, 'n' : False, '0' : False - } - -def toBool(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - value = value.lower() - result = _bool_dict.get(value, None) - if result == None: - raise ValueError, "cannot convert '%s' to bool" % value - return result - -def toFrequency(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - 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): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('ps'): - return float(value[:-2]) * pico - elif value.endswith('ns'): - return float(value[:-2]) * nano - elif value.endswith('us'): - return float(value[:-2]) * micro - elif value.endswith('ms'): - return float(value[:-2]) * milli - elif value.endswith('s'): - return float(value[:-1]) - - raise ValueError, "cannot convert '%s' to latency" % value - -def anyToLatency(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 - -def anyToFrequency(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) - return val - except ValueError: - pass - - try: - val = toLatency(value) - if val != 0: - val = 1 / val - return val - except ValueError: - pass - - raise ValueError, "cannot convert '%s' to clock period" % value - -def toNetworkBandwidth(value): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('Tbps'): - return float(value[:-4]) * tera - elif value.endswith('Gbps'): - return float(value[:-4]) * giga - elif value.endswith('Mbps'): - return float(value[:-4]) * mega - elif value.endswith('kbps'): - return float(value[:-4]) * kilo - elif value.endswith('bps'): - return float(value[:-3]) - else: - return float(value) - - raise ValueError, "cannot convert '%s' to network bandwidth" % value - -def toMemoryBandwidth(value): - if not isinstance(value, str): - 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'): - 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): - if not isinstance(value, str): - raise TypeError, "wrong type '%s' should be str" % type(value) - - if value.endswith('PB'): - return long(value[:-2]) * pebi - elif value.endswith('TB'): - return long(value[:-2]) * tebi - elif value.endswith('GB'): - return long(value[:-2]) * gibi - elif value.endswith('MB'): - return long(value[:-2]) * mebi - elif value.endswith('kB'): - return long(value[:-2]) * kibi - elif value.endswith('B'): - return long(value[:-1]) - - raise ValueError, "cannot convert '%s' to memory size" % value diff --git a/src/python/m5/environment.py b/src/python/m5/environment.py deleted file mode 100644 index bea0bc1d0..000000000 --- a/src/python/m5/environment.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Nathan Binkert -# Steve Reinhardt - -import os - -# import the m5 compile options -import defines - -# make a SmartDict out of the build options for our local use -import smartdict -build_env = smartdict.SmartDict() -build_env.update(defines.m5_build_env) - -# make a SmartDict out of the OS environment too -env = smartdict.SmartDict() -env.update(os.environ) - diff --git a/src/python/m5/main.py b/src/python/m5/main.py index 2a308ff09..29f8cc976 100644 --- a/src/python/m5/main.py +++ b/src/python/m5/main.py @@ -32,7 +32,7 @@ import os import socket import sys -from util import attrdict +from util import attrdict, fatal import config from options import OptionParser diff --git a/src/python/m5/params.py b/src/python/m5/params.py index edd78fa28..3a3a30014 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -50,13 +50,10 @@ import re import sys import time -import convert import proxy import ticks from util import * -import SimObject - def isSimObject(*args, **kwargs): return SimObject.isSimObject(*args, **kwargs) @@ -711,32 +708,31 @@ class MetaEnum(MetaParamValue): super(MetaEnum, cls).__init__(name, bases, init_dict) - def __str__(cls): - return cls.__name__ - # Generate C++ class declaration for this enum type. # Note that we wrap the enum in a class/struct to act as a namespace, # so that the enum strings can be brief w/o worrying about collisions. def cxx_decl(cls): - code = "#ifndef __ENUM__%s\n" % cls - code += '#define __ENUM__%s\n' % cls + name = cls.__name__ + code = "#ifndef __ENUM__%s\n" % name + code += '#define __ENUM__%s\n' % name code += '\n' code += 'namespace Enums {\n' - code += ' enum %s {\n' % cls + code += ' enum %s {\n' % name for val in cls.vals: code += ' %s = %d,\n' % (val, cls.map[val]) - code += ' Num_%s = %d,\n' % (cls, len(cls.vals)) + code += ' Num_%s = %d,\n' % (name, len(cls.vals)) code += ' };\n' - code += ' extern const char *%sStrings[Num_%s];\n' % (cls, cls) + code += ' extern const char *%sStrings[Num_%s];\n' % (name, name) code += '}\n' code += '\n' code += '#endif\n' return code def cxx_def(cls): - code = '#include "enums/%s.hh"\n' % cls + name = cls.__name__ + code = '#include "enums/%s.hh"\n' % name code += 'namespace Enums {\n' - code += ' const char *%sStrings[Num_%s] =\n' % (cls, cls) + code += ' const char *%sStrings[Num_%s] =\n' % (name, name) code += ' {\n' for val in cls.vals: code += ' "%s",\n' % val @@ -1170,6 +1166,15 @@ class PortParamDesc(object): ptype_str = 'Port' ptype = Port +baseEnums = allEnums.copy() +baseParams = allParams.copy() + +def clear(): + global allEnums, allParams + + allEnums = baseEnums.copy() + allParams = baseParams.copy() + __all__ = ['Param', 'VectorParam', 'Enum', 'Bool', 'String', 'Float', 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', @@ -1184,3 +1189,5 @@ __all__ = ['Param', 'VectorParam', 'Time', 'NextEthernetAddr', 'NULL', 'Port', 'VectorPort'] + +import SimObject diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py index 45992fe85..092bd0339 100644 --- a/src/python/m5/simulate.py +++ b/src/python/m5/simulate.py @@ -40,6 +40,9 @@ import SimObject import ticks import objects +# define a MaxTick parameter +MaxTick = 2**63 - 1 + # The final hook to generate .ini files. Called from the user script # once the config is built. def instantiate(root): diff --git a/src/python/m5/smartdict.py b/src/python/m5/smartdict.py deleted file mode 100644 index d85dbd517..000000000 --- a/src/python/m5/smartdict.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright (c) 2005 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Nathan Binkert - -# The SmartDict class fixes a couple of issues with using the content -# of os.environ or similar dicts of strings as Python variables: -# -# 1) Undefined variables should return False rather than raising KeyError. -# -# 2) String values of 'False', '0', etc., should evaluate to False -# (not just the empty string). -# -# #1 is solved by overriding __getitem__, and #2 is solved by using a -# proxy class for values and overriding __nonzero__ on the proxy. -# Everything else is just to (a) make proxies behave like normal -# values otherwise, (b) make sure any dict operation returns a proxy -# rather than a normal value, and (c) coerce values written to the -# dict to be strings. - - -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""" - - def __getitem__(self, key): - """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 [ Variable(v) for v in dict.values(self) ] - - def itervalues(self): - for value in dict.itervalues(self): - yield Variable(value) - - def 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, Variable(value) - - def get(self, key, default='False'): - return Variable(dict.get(self, key, str(default))) - - def setdefault(self, key, default='False'): - return Variable(dict.setdefault(self, key, str(default))) - -__all__ = [ 'SmartDict' ] diff --git a/src/python/m5/ticks.py b/src/python/m5/ticks.py index 91834c9c8..181a65eba 100644 --- a/src/python/m5/ticks.py +++ b/src/python/m5/ticks.py @@ -41,7 +41,7 @@ def fixGlobalFrequency(): print "Global frequency set at %d ticks per second" % int(tps) def setGlobalFrequency(ticksPerSecond): - import convert + from m5.util import convert global tps, tps_fixed diff --git a/src/python/m5/trace.py b/src/python/m5/trace.py index 17aa6196c..db239040a 100644 --- a/src/python/m5/trace.py +++ b/src/python/m5/trace.py @@ -48,5 +48,5 @@ def help(): if flag == 'All': continue print " %s: %s" % (flag, flags.descriptions[flag]) - util.print_list(flags.compoundMap[flag], indent=8) + util.printList(flags.compoundMap[flag], indent=8) print diff --git a/src/python/m5/util/__init__.py b/src/python/m5/util/__init__.py index 3930c8b6f..7a674dd2d 100644 --- a/src/python/m5/util/__init__.py +++ b/src/python/m5/util/__init__.py @@ -1,4 +1,5 @@ -# Copyright (c) 2008 The Hewlett-Packard Development Company +# Copyright (c) 2008-2009 The Hewlett-Packard Development Company +# Copyright (c) 2004-2006 The Regents of The University of Michigan # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -26,14 +27,130 @@ # # Authors: Nathan Binkert +import os +import re +import sys + +import convert +import jobfile + from attrdict import attrdict, optiondict from code_formatter import code_formatter -from misc import * from multidict import multidict from orderdict import orderdict -import jobfile +from smartdict import SmartDict + +# define this here so we can use it right away if necessary +def errorURL(prefix, s): + try: + import zlib + hashstr = "%x" % zlib.crc32(s) + except: + hashstr = "UnableToHash" + return "For more information see: http://www.m5sim.org/%s/%s" % \ + (prefix, hashstr) + +# panic() should be called when something happens that should never +# ever happen regardless of what the user does (i.e., an acutal m5 +# bug). +def panic(fmt, *args): + print >>sys.stderr, 'panic:', fmt % args + print >>sys.stderr, errorURL('panic',fmt) + sys.exit(1) + +# fatal() should be called when the simulation cannot continue due to +# some condition that is the user's fault (bad configuration, invalid +# arguments, etc.) and not a simulator bug. +def fatal(fmt, *args): + print >>sys.stderr, 'fatal:', fmt % args + print >>sys.stderr, errorURL('fatal',fmt) + sys.exit(1) + +class Singleton(type): + def __call__(cls, *args, **kwargs): + if hasattr(cls, '_instance'): + return cls._instance + + cls._instance = super(Singleton, cls).__call__(*args, **kwargs) + return cls._instance + +def addToPath(path): + """Prepend given directory to system module search path. We may not + need this anymore if we can structure our config library more like a + Python package.""" + + # if it's a relative path and we know what directory the current + # python script is in, make the path relative to that directory. + if not os.path.isabs(path) and sys.path[0]: + path = os.path.join(sys.path[0], path) + path = os.path.realpath(path) + # sys.path[0] should always refer to the current script's directory, + # so place the new dir right after that. + sys.path.insert(1, path) + +# Apply method to object. +# applyMethod(obj, 'meth', ) is equivalent to obj.meth() +def applyMethod(obj, meth, *args, **kwargs): + return getattr(obj, meth)(*args, **kwargs) -def print_list(items, indent=4): +# If the first argument is an (non-sequence) object, apply the named +# method with the given arguments. If the first argument is a +# sequence, apply the method to each element of the sequence (a la +# 'map'). +def applyOrMap(objOrSeq, meth, *args, **kwargs): + if not isinstance(objOrSeq, (list, tuple)): + return applyMethod(objOrSeq, meth, *args, **kwargs) + else: + return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq] + +def compareVersions(v1, v2): + """helper function: compare arrays or strings of version numbers. + E.g., compare_version((1,3,25), (1,4,1)') + returns -1, 0, 1 if v1 is <, ==, > v2 + """ + def make_version_list(v): + if isinstance(v, (list,tuple)): + return v + elif isinstance(v, str): + return map(lambda x: int(re.match('\d+', x).group()), v.split('.')) + else: + raise TypeError + + v1 = make_version_list(v1) + v2 = make_version_list(v2) + # Compare corresponding elements of lists + for n1,n2 in zip(v1, v2): + if n1 < n2: return -1 + if n1 > n2: return 1 + # all corresponding values are equal... see if one has extra values + if len(v1) < len(v2): return -1 + if len(v1) > len(v2): return 1 + return 0 + +def crossproduct(items): + if len(items) == 1: + for i in items[0]: + yield (i,) + else: + for i in items[0]: + for j in crossproduct(items[1:]): + yield (i,) + j + +def flatten(items): + while items: + item = items.pop(0) + if isinstance(item, (list, tuple)): + items[0:0] = item + else: + yield item + +# force scalars to one-element lists for uniformity +def makeList(objOrList): + if isinstance(objOrList, list): + return objOrList + return [objOrList] + +def printList(items, indent=4): line = ' ' * indent for i,item in enumerate(items): if len(line) + len(item) > 76: @@ -45,3 +162,27 @@ def print_list(items, indent=4): else: line += item print line + +def readCommand(cmd, **kwargs): + """run the command cmd, read the results and return them + this is sorta like `cmd` in shell""" + from subprocess import Popen, PIPE, STDOUT + + if isinstance(cmd, str): + cmd = cmd.split() + + no_exception = 'exception' in kwargs + exception = kwargs.pop('exception', None) + + kwargs.setdefault('shell', False) + kwargs.setdefault('stdout', PIPE) + kwargs.setdefault('stderr', STDOUT) + kwargs.setdefault('close_fds', True) + try: + subp = Popen(cmd, **kwargs) + except Exception, e: + if no_exception: + return exception + raise + + return subp.communicate()[0] diff --git a/src/python/m5/util/convert.py b/src/python/m5/util/convert.py new file mode 100644 index 000000000..bb9e3e1f1 --- /dev/null +++ b/src/python/m5/util/convert.py @@ -0,0 +1,250 @@ +# Copyright (c) 2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +# metric prefixes +exa = 1.0e18 +peta = 1.0e15 +tera = 1.0e12 +giga = 1.0e9 +mega = 1.0e6 +kilo = 1.0e3 + +milli = 1.0e-3 +micro = 1.0e-6 +nano = 1.0e-9 +pico = 1.0e-12 +femto = 1.0e-15 +atto = 1.0e-18 + +# power of 2 prefixes +kibi = 1024 +mebi = kibi * 1024 +gibi = mebi * 1024 +tebi = gibi * 1024 +pebi = tebi * 1024 +exbi = pebi * 1024 + +# memory size configuration stuff +def toFloat(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('Ei'): + return float(value[:-2]) * exbi + elif value.endswith('Pi'): + return float(value[:-2]) * pebi + elif value.endswith('Ti'): + return float(value[:-2]) * tebi + elif value.endswith('Gi'): + return float(value[:-2]) * gibi + elif value.endswith('Mi'): + return float(value[:-2]) * mebi + elif value.endswith('ki'): + return float(value[:-2]) * kibi + elif value.endswith('E'): + return float(value[:-1]) * exa + elif value.endswith('P'): + return float(value[:-1]) * peta + elif value.endswith('T'): + return float(value[:-1]) * tera + elif value.endswith('G'): + return float(value[:-1]) * giga + elif value.endswith('M'): + return float(value[:-1]) * mega + elif value.endswith('k'): + return float(value[:-1]) * kilo + elif value.endswith('m'): + return float(value[:-1]) * milli + elif value.endswith('u'): + return float(value[:-1]) * micro + elif value.endswith('n'): + return float(value[:-1]) * nano + elif value.endswith('p'): + return float(value[:-1]) * pico + elif value.endswith('f'): + return float(value[:-1]) * femto + else: + return float(value) + +def toInteger(value): + value = toFloat(value) + result = long(value) + if value != result: + raise ValueError, "cannot convert '%s' to integer" % value + + return result + +_bool_dict = { + 'true' : True, 't' : True, 'yes' : True, 'y' : True, '1' : True, + 'false' : False, 'f' : False, 'no' : False, 'n' : False, '0' : False + } + +def toBool(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + value = value.lower() + result = _bool_dict.get(value, None) + if result == None: + raise ValueError, "cannot convert '%s' to bool" % value + return result + +def toFrequency(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + 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): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('ps'): + return float(value[:-2]) * pico + elif value.endswith('ns'): + return float(value[:-2]) * nano + elif value.endswith('us'): + return float(value[:-2]) * micro + elif value.endswith('ms'): + return float(value[:-2]) * milli + elif value.endswith('s'): + return float(value[:-1]) + + raise ValueError, "cannot convert '%s' to latency" % value + +def anyToLatency(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 + +def anyToFrequency(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) + return val + except ValueError: + pass + + try: + val = toLatency(value) + if val != 0: + val = 1 / val + return val + except ValueError: + pass + + raise ValueError, "cannot convert '%s' to clock period" % value + +def toNetworkBandwidth(value): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('Tbps'): + return float(value[:-4]) * tera + elif value.endswith('Gbps'): + return float(value[:-4]) * giga + elif value.endswith('Mbps'): + return float(value[:-4]) * mega + elif value.endswith('kbps'): + return float(value[:-4]) * kilo + elif value.endswith('bps'): + return float(value[:-3]) + else: + return float(value) + + raise ValueError, "cannot convert '%s' to network bandwidth" % value + +def toMemoryBandwidth(value): + if not isinstance(value, str): + 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'): + 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): + if not isinstance(value, str): + raise TypeError, "wrong type '%s' should be str" % type(value) + + if value.endswith('PB'): + return long(value[:-2]) * pebi + elif value.endswith('TB'): + return long(value[:-2]) * tebi + elif value.endswith('GB'): + return long(value[:-2]) * gibi + elif value.endswith('MB'): + return long(value[:-2]) * mebi + elif value.endswith('kB'): + return long(value[:-2]) * kibi + elif value.endswith('B'): + return long(value[:-1]) + + raise ValueError, "cannot convert '%s' to memory size" % value diff --git a/src/python/m5/util/jobfile.py b/src/python/m5/util/jobfile.py index c830895f6..9c59778e5 100644 --- a/src/python/m5/util/jobfile.py +++ b/src/python/m5/util/jobfile.py @@ -28,9 +28,6 @@ import sys -from attrdict import optiondict -from misc import crossproduct - class Data(object): def __init__(self, name, desc, **kwargs): self.name = name @@ -108,7 +105,8 @@ class Data(object): yield key def optiondict(self): - result = optiondict() + import m5.util + result = m5.util.optiondict() for key in self: result[key] = self[key] return result @@ -328,7 +326,9 @@ class Configuration(Data): optgroups = [ g.subopts() for g in groups ] if not optgroups: return - for options in crossproduct(optgroups): + + import m5.util + for options in m5.util.crossproduct(optgroups): for opt in options: cpt = opt._group._checkpoint if not isinstance(cpt, bool) and cpt != opt: diff --git a/src/python/m5/util/misc.py b/src/python/m5/util/misc.py deleted file mode 100644 index 094e3ed9a..000000000 --- a/src/python/m5/util/misc.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2004-2006 The Regents of The University of Michigan -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Steve Reinhardt -# Nathan Binkert - -############################# -# -# Utility classes & methods -# -############################# - -class Singleton(type): - def __call__(cls, *args, **kwargs): - if hasattr(cls, '_instance'): - return cls._instance - - cls._instance = super(Singleton, cls).__call__(*args, **kwargs) - return cls._instance - -# Apply method to object. -# applyMethod(obj, 'meth', ) is equivalent to obj.meth() -def applyMethod(obj, meth, *args, **kwargs): - return getattr(obj, meth)(*args, **kwargs) - -# If the first argument is an (non-sequence) object, apply the named -# method with the given arguments. If the first argument is a -# sequence, apply the method to each element of the sequence (a la -# 'map'). -def applyOrMap(objOrSeq, meth, *args, **kwargs): - if not isinstance(objOrSeq, (list, tuple)): - return applyMethod(objOrSeq, meth, *args, **kwargs) - else: - return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq] - -def crossproduct(items): - if not isinstance(items, (list, tuple)): - raise AttributeError, 'crossproduct works only on sequences' - - if not items: - yield None - return - - current = items[0] - remainder = items[1:] - - if not hasattr(current, '__iter__'): - current = [ current ] - - for item in current: - for rem in crossproduct(remainder): - data = [ item ] - if rem: - data += rem - yield data - -def flatten(items): - if not isinstance(items, (list, tuple)): - yield items - return - - for item in items: - for flat in flatten(item): - yield flat diff --git a/src/python/m5/util/smartdict.py b/src/python/m5/util/smartdict.py new file mode 100644 index 000000000..d85dbd517 --- /dev/null +++ b/src/python/m5/util/smartdict.py @@ -0,0 +1,154 @@ +# Copyright (c) 2005 The Regents of The University of Michigan +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer; +# redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution; +# neither the name of the copyright holders nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# Authors: Nathan Binkert + +# The SmartDict class fixes a couple of issues with using the content +# of os.environ or similar dicts of strings as Python variables: +# +# 1) Undefined variables should return False rather than raising KeyError. +# +# 2) String values of 'False', '0', etc., should evaluate to False +# (not just the empty string). +# +# #1 is solved by overriding __getitem__, and #2 is solved by using a +# proxy class for values and overriding __nonzero__ on the proxy. +# Everything else is just to (a) make proxies behave like normal +# values otherwise, (b) make sure any dict operation returns a proxy +# rather than a normal value, and (c) coerce values written to the +# dict to be strings. + + +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""" + + def __getitem__(self, key): + """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 [ Variable(v) for v in dict.values(self) ] + + def itervalues(self): + for value in dict.itervalues(self): + yield Variable(value) + + def 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, Variable(value) + + def get(self, key, default='False'): + return Variable(dict.get(self, key, str(default))) + + def setdefault(self, key, default='False'): + return Variable(dict.setdefault(self, key, str(default))) + +__all__ = [ 'SmartDict' ] -- cgit v1.2.3 From 30d5d95b6a7c93ccf63ae0cfcc62d17306c31eee Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Tue, 22 Sep 2009 15:24:16 -0700 Subject: params: small cleanup to param description internals --- src/python/m5/params.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/python') diff --git a/src/python/m5/params.py b/src/python/m5/params.py index 3a3a30014..cf64070c5 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -93,6 +93,8 @@ class ParamValue(object): # Regular parameter description. class ParamDesc(object): + file_ext = 'ptype' + def __init__(self, ptype_str, ptype, *args, **kwargs): self.ptype_str = ptype_str # remember ptype only if it is provided @@ -127,7 +129,7 @@ class ParamDesc(object): def __getattr__(self, attr): if attr == 'ptype': ptype = SimObject.allClasses[self.ptype_str] - assert issubclass(ptype, SimObject.SimObject) + assert isSimObjectClass(ptype) self.ptype = ptype return ptype @@ -182,6 +184,8 @@ class SimObjVector(VectorParamValue): v.print_ini(ini_file) class VectorParamDesc(ParamDesc): + file_ext = 'vptype' + # Convert assigned value to appropriate type. If the RHS is not a # list or tuple, it generates a single-element list. def convert(self, value): -- cgit v1.2.3 From bae6a4a4d9ab3953051fb9d1b866172ecfcbccdb Mon Sep 17 00:00:00 2001 From: Nathan Binkert Date: Wed, 23 Sep 2009 18:28:29 -0700 Subject: ply grammar: Fixup Tokenizer class so you can get lexer arguments --- src/python/m5/util/grammar.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/python') diff --git a/src/python/m5/util/grammar.py b/src/python/m5/util/grammar.py index 93c2c84c4..ab5f35868 100644 --- a/src/python/m5/util/grammar.py +++ b/src/python/m5/util/grammar.py @@ -55,6 +55,7 @@ class Tokenizer(object): break yield tok self.input = _input() + self.lexer = lexer def next(self): return self.input.next() @@ -68,6 +69,9 @@ class Tokenizer(object): except StopIteration: return None + def __getattr__(self, attr): + return getattr(self.lexer, attr) + class Grammar(object): def __init__(self, output=None, debug=False): self.yacc_args = {} -- cgit v1.2.3