summaryrefslogtreecommitdiff
path: root/src/python/m5
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/m5')
-rw-r--r--src/python/m5/SimObject.py96
-rw-r--r--src/python/m5/__init__.py48
-rw-r--r--src/python/m5/config.py50
-rw-r--r--src/python/m5/core.py40
-rw-r--r--src/python/m5/debug.py31
-rw-r--r--src/python/m5/event.py37
-rw-r--r--src/python/m5/main.py333
-rw-r--r--src/python/m5/options.py142
-rw-r--r--src/python/m5/params.py25
-rw-r--r--src/python/m5/simulate.py23
-rw-r--r--src/python/m5/stats.py19
-rw-r--r--src/python/m5/trace.py52
-rw-r--r--src/python/m5/util/__init__.py45
-rw-r--r--src/python/m5/util/attrdict.py (renamed from src/python/m5/attrdict.py)30
-rw-r--r--src/python/m5/util/jobfile.py472
-rw-r--r--src/python/m5/util/misc.py (renamed from src/python/m5/util.py)28
-rw-r--r--src/python/m5/util/multidict.py (renamed from src/python/m5/multidict.py)0
-rw-r--r--src/python/m5/util/orderdict.py80
18 files changed, 1296 insertions, 255 deletions
diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py
index 78df6bef1..8ef22be4e 100644
--- a/src/python/m5/SimObject.py
+++ b/src/python/m5/SimObject.py
@@ -27,12 +27,13 @@
# Authors: Steve Reinhardt
# Nathan Binkert
-import sys, types
+import math
+import sys
+import types
import proxy
import m5
from util import *
-from multidict import multidict
# These utility functions have to come first because they're
# referenced in params.py... otherwise they won't be defined when we
@@ -64,6 +65,7 @@ from 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 *
noDot = False
try:
@@ -124,7 +126,6 @@ instanceDict = {}
class MetaSimObject(type):
# Attributes that can be set only at initialization time
init_keywords = { 'abstract' : types.BooleanType,
- 'cxx_namespace' : types.StringType,
'cxx_class' : types.StringType,
'cxx_type' : types.StringType,
'cxx_predecls' : types.ListType,
@@ -191,33 +192,31 @@ class MetaSimObject(type):
# the following is not true is when we define the SimObject
# class itself (in which case the multidicts have no parent).
if isinstance(base, MetaSimObject):
+ cls._base = base
cls._params.parent = base._params
cls._ports.parent = base._ports
cls._values.parent = base._values
cls._port_refs.parent = base._port_refs
# mark base as having been subclassed
base._instantiated = True
+ else:
+ cls._base = None
# default keyword values
if 'type' in cls._value_dict:
- _type = cls._value_dict['type']
if 'cxx_class' not in cls._value_dict:
- cls._value_dict['cxx_class'] = _type
+ cls._value_dict['cxx_class'] = cls._value_dict['type']
- namespace = cls._value_dict.get('cxx_namespace', None)
-
- _cxx_class = cls._value_dict['cxx_class']
- if 'cxx_type' not in cls._value_dict:
- t = _cxx_class + '*'
- if namespace:
- t = '%s::%s' % (namespace, t)
- cls._value_dict['cxx_type'] = t
+ cls._value_dict['cxx_type'] = '%s *' % cls._value_dict['cxx_class']
+
if 'cxx_predecls' not in cls._value_dict:
# A forward class declaration is sufficient since we are
# just declaring a pointer.
- decl = 'class %s;' % _cxx_class
- if namespace:
- decl = 'namespace %s { %s }' % (namespace, decl)
+ class_path = cls._value_dict['cxx_class'].split('::')
+ class_path.reverse()
+ decl = 'class %s;' % class_path[0]
+ for ns in class_path[1:]:
+ decl = 'namespace %s { %s }' % (ns, decl)
cls._value_dict['cxx_predecls'] = [decl]
if 'swig_predecls' not in cls._value_dict:
@@ -349,12 +348,6 @@ class MetaSimObject(type):
def __str__(cls):
return cls.__name__
- def get_base(cls):
- if str(cls) == 'SimObject':
- return None
-
- return cls.__bases__[0].type
-
def cxx_decl(cls):
code = "#ifndef __PARAMS__%s\n" % cls
code += "#define __PARAMS__%s\n\n" % cls
@@ -385,22 +378,29 @@ class MetaSimObject(type):
code += "\n".join(predecls2)
code += "\n\n";
- base = cls.get_base()
- if base:
- code += '#include "params/%s.hh"\n\n' % base
+ if cls._base:
+ code += '#include "params/%s.hh"\n\n' % cls._base.type
for ptype in ptypes:
if issubclass(ptype, Enum):
code += '#include "enums/%s.hh"\n' % ptype.__name__
code += "\n\n"
+ code += cls.cxx_struct(cls._base, params)
+
+ # close #ifndef __PARAMS__* guard
+ code += "\n#endif\n"
+ return code
+
+ def cxx_struct(cls, base, params):
+ if cls == SimObject:
+ return '#include "sim/sim_object_params.hh"\n'
+
# now generate the actual param struct
- code += "struct %sParams" % cls
+ code = "struct %sParams" % cls
if base:
- code += " : public %sParams" % base
+ code += " : public %sParams" % base.type
code += "\n{\n"
- if cls == SimObject:
- code += " virtual ~%sParams() {}\n" % cls
if not hasattr(cls, 'abstract') or not cls.abstract:
if 'type' in cls.__dict__:
code += " %s create();\n" % cls.cxx_type
@@ -409,28 +409,9 @@ class MetaSimObject(type):
code += "".join([" %s\n" % d for d in decls])
code += "};\n"
- # close #ifndef __PARAMS__* guard
- code += "\n#endif\n"
- return code
-
- def cxx_type_decl(cls):
- base = cls.get_base()
- code = ''
-
- if base:
- code += '#include "%s_type.h"\n' % base
-
- # now generate dummy code for inheritance
- code += "struct %s" % cls.cxx_class
- if base:
- code += " : public %s" % base.cxx_class
- code += "\n{};\n"
-
return code
def swig_decl(cls):
- base = cls.get_base()
-
code = '%%module %s\n' % cls
code += '%{\n'
@@ -458,8 +439,8 @@ class MetaSimObject(type):
code += "\n".join(predecls2)
code += "\n\n";
- if base:
- code += '%%import "params/%s.i"\n\n' % base
+ if cls._base:
+ code += '%%import "params/%s.i"\n\n' % cls._base.type
for ptype in ptypes:
if issubclass(ptype, Enum):
@@ -481,7 +462,6 @@ class SimObject(object):
type = 'SimObject'
abstract = True
- name = Param.String("Object name")
swig_objdecls = [ '%include "python/swig/sim_object.i"' ]
# Initialize new instance. For objects with SimObject-valued
@@ -650,8 +630,9 @@ class SimObject(object):
if len(value) == 1:
value[0]._maybe_set_parent(self, attr)
else:
+ width = int(math.ceil(math.log(len(value))/math.log(10)))
for i,v in enumerate(value):
- v._maybe_set_parent(self, "%s%d" % (attr, i))
+ v._maybe_set_parent(self, "%s%0*d" % (attr, width, i))
self._values[attr] = value
@@ -687,7 +668,7 @@ class SimObject(object):
match_obj = self._values[pname]
if found_obj != None and found_obj != match_obj:
raise AttributeError, \
- 'parent.any matched more than one: %s' % obj.path
+ 'parent.any matched more than one: %s and %s' % (found_obj.path, match_obj.path)
found_obj = match_obj
return found_obj, found_obj != None
@@ -722,7 +703,7 @@ class SimObject(object):
self._children[child].unproxy_all()
def print_ini(self, ini_file):
- print >>ini_file, '[' + self.path() + ']' # .ini section header
+ print >>ini_file, '[' + self.path() + ']' # .ini section header
instanceDict[self.path()] = self
@@ -749,7 +730,7 @@ class SimObject(object):
if port != None:
print >>ini_file, '%s=%s' % (port_name, port.ini_str())
- print >>ini_file # blank line between objects
+ print >>ini_file # blank line between objects
for child in child_names:
self._children[child].print_ini(ini_file)
@@ -760,7 +741,7 @@ class SimObject(object):
cc_params_struct = getattr(m5.objects.params, '%sParams' % self.type)
cc_params = cc_params_struct()
- cc_params.object = self
+ cc_params.pyobj = self
cc_params.name = str(self)
param_names = self._params.keys()
@@ -768,7 +749,8 @@ class SimObject(object):
for param in param_names:
value = self._values.get(param)
if value is None:
- continue
+ m5.fatal("%s.%s without default or user set value",
+ self.path(), param)
value = value.getValue()
if isinstance(self._params[param], VectorParamDesc):
diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py
index f21bb362e..733258acf 100644
--- a/src/python/m5/__init__.py
+++ b/src/python/m5/__init__.py
@@ -36,8 +36,31 @@ import smartdict
MaxTick = 2**63 - 1
# define this here so we can use it right away if necessary
-def panic(string):
- print >>sys.stderr, 'panic:', string
+
+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
@@ -77,22 +100,23 @@ env.update(os.environ)
# importing *you*).
try:
import internal
- running_m5 = True
except ImportError:
- running_m5 = False
+ internal = None
+
+import defines
+build_env.update(defines.buildEnv)
-if running_m5:
- import defines
- build_env.update(defines.m5_build_env)
-else:
- import __scons
- build_env.update(__scons.m5_build_env)
+if internal:
+ defines.compileDate = internal.core.compileDate
+ for k,v in internal.core.__dict__.iteritems():
+ if k.startswith('flag_'):
+ setattr(defines, k[5:], v)
-if running_m5:
from event import *
from simulate import *
- from main import options
+ from main import options, main
import stats
+ import core
import SimObject
import params
diff --git a/src/python/m5/config.py b/src/python/m5/config.py
new file mode 100644
index 000000000..c28f6675a
--- /dev/null
+++ b/src/python/m5/config.py
@@ -0,0 +1,50 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# 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
+
+import os
+from os.path import isdir, isfile, join as joinpath
+
+
+confdir = os.environ.get('M5_CONFIG')
+
+if not confdir:
+ # HOME is not set when running regressions, due to use of scons
+ # Execute() function.
+ homedir = os.environ.get('HOME')
+ if homedir and isdir(joinpath(homedir, '.m5')):
+ confdir = joinpath(homedir, '.m5')
+
+def get(name):
+ if not confdir:
+ return None
+ conffile = joinpath(confdir, name)
+ if not isfile(conffile):
+ return None
+
+ return conffile
+
diff --git a/src/python/m5/core.py b/src/python/m5/core.py
new file mode 100644
index 000000000..1d7985be6
--- /dev/null
+++ b/src/python/m5/core.py
@@ -0,0 +1,40 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# 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
+
+import internal
+from internal.core import initAll, regAllStats
+
+def setOutputDir(dir):
+ internal.core.setOutputDir(dir)
+
+def initAll():
+ internal.core.initAll()
+
+def regAllStats():
+ internal.core.regAllStats()
+
diff --git a/src/python/m5/debug.py b/src/python/m5/debug.py
new file mode 100644
index 000000000..cd40b8fa3
--- /dev/null
+++ b/src/python/m5/debug.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# 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
+
+import internal
+
+from internal.debug import schedBreakCycle, setRemoteGDBPort
diff --git a/src/python/m5/event.py b/src/python/m5/event.py
index 2d6497464..35095599d 100644
--- a/src/python/m5/event.py
+++ b/src/python/m5/event.py
@@ -26,17 +26,36 @@
#
# Authors: Nathan Binkert
-from internal.event import create
-from internal.event import SimLoopExitEvent as SimExit
+import m5
+import internal.event
+
+from internal.event import PythonEvent, SimLoopExitEvent as SimExit
+
+mainq = internal.event.cvar.mainEventQueue
+
+def create(obj, priority=None):
+ if priority is None:
+ priority = Event.Default_Pri
+ return PythonEvent(obj, priority)
-class ProgressEvent(object):
- def __init__(self, period):
- self.period = int(period)
- self.schedule()
- def schedule(self):
- create(self, m5.curTick() + self.period)
+# As a reminder, priorities found in sim/eventq.hh are stuck into the
+# Event class by swig
+class Event(PythonEvent):
+ def __init__(self, priority=None):
+ if priority is None:
+ priority = Event.Default_Pri
+ super(Event, self).__init__(self, priority)
+
+class ProgressEvent(Event):
+ def __init__(self, eventq, period):
+ super(ProgressEvent, self).__init__()
+ self.period = int(period)
+ self.eventq = eventq
+ self.eventq.schedule(self, m5.curTick() + self.period)
def __call__(self):
print "Progress! Time now %fs" % (m5.curTick()/1e12)
- self.schedule()
+ self.eventq.schedule(self, m5.curTick() + self.period)
+
+__all__ = [ 'create', 'Event', 'ProgressEvent', 'SimExit', 'mainq' ]
diff --git a/src/python/m5/main.py b/src/python/m5/main.py
index 4bcca46d2..98019b197 100644
--- a/src/python/m5/main.py
+++ b/src/python/m5/main.py
@@ -28,14 +28,13 @@
import code
import datetime
-import optparse
import os
import socket
import sys
-from attrdict import attrdict
-import defines
-import traceflags
+from util import attrdict
+import config
+from options import OptionParser
__all__ = [ 'options', 'arguments', 'main' ]
@@ -47,77 +46,11 @@ The Regents of The University of Michigan
All Rights Reserved
'''
-def print_list(items, indent=4):
- line = ' ' * indent
- for i,item in enumerate(items):
- if len(line) + len(item) > 76:
- print line
- line = ' ' * indent
-
- if i < len(items) - 1:
- line += '%s, ' % item
- else:
- line += item
- print line
-
-# there's only one option parsing done, so make it global and add some
-# helper functions to make it work well.
-parser = optparse.OptionParser(usage=usage, version=version,
- description=brief_copyright,
- formatter=optparse.TitledHelpFormatter())
-parser.disable_interspersed_args()
-
-# current option group
-group = None
-
-def set_group(*args, **kwargs):
- '''set the current option group'''
- global group
- if not args and not kwargs:
- group = None
- else:
- group = parser.add_option_group(*args, **kwargs)
-
-class splitter(object):
- def __init__(self, split):
- self.split = split
- def __call__(self, option, opt_str, value, parser):
- getattr(parser.values, option.dest).extend(value.split(self.split))
-
-def add_option(*args, **kwargs):
- '''add an option to the current option group, or global none set'''
-
- # if action=split, but allows the option arguments
- # themselves to be lists separated by the split variable'''
-
- if kwargs.get('action', None) == 'append' and 'split' in kwargs:
- split = kwargs.pop('split')
- kwargs['default'] = []
- kwargs['type'] = 'string'
- kwargs['action'] = 'callback'
- kwargs['callback'] = splitter(split)
-
- if group:
- return group.add_option(*args, **kwargs)
-
- return parser.add_option(*args, **kwargs)
-
-def bool_option(name, default, help):
- '''add a boolean option called --name and --no-name.
- Display help depending on which is the default'''
-
- tname = '--%s' % name
- fname = '--no-%s' % name
- dest = name.replace('-', '_')
- if default:
- thelp = optparse.SUPPRESS_HELP
- fhelp = help
- else:
- thelp = help
- fhelp = optparse.SUPPRESS_HELP
-
- add_option(tname, action="store_true", default=default, help=thelp)
- add_option(fname, action="store_false", dest=dest, help=fhelp)
+options = OptionParser(usage=usage, version=version,
+ description=brief_copyright)
+add_option = options.add_option
+set_group = options.set_group
+usage = options.usage
# Help options
add_option('-A', "--authors", action="store_true", default=False,
@@ -132,8 +65,16 @@ add_option('-N', "--release-notes", action="store_true", default=False,
help="Show the release notes")
# Options for configuring the base simulator
-add_option('-d', "--outdir", metavar="DIR", default=".",
+add_option('-d', "--outdir", metavar="DIR", default="m5out",
help="Set the output directory to DIR [Default: %default]")
+add_option('-r', "--redirect-stdout", action="store_true", default=False,
+ help="Redirect stdout (& stderr, without -e) to file")
+add_option('-e', "--redirect-stderr", action="store_true", default=False,
+ help="Redirect stderr to file")
+add_option("--stdout-file", metavar="FILE", default="simout",
+ help="Filename for -r redirection [Default: %default]")
+add_option("--stderr-file", metavar="FILE", default="simerr",
+ help="Filename for -e redirection [Default: %default]")
add_option('-i', "--interactive", action="store_true", default=False,
help="Invoke the interactive interpreter after running the script")
add_option("--pdb", action="store_true", default=False,
@@ -147,13 +88,20 @@ add_option('-v', "--verbose", action="count", default=0,
# Statistics options
set_group("Statistics Options")
-add_option("--stats-file", metavar="FILE", default="m5stats.txt",
+add_option("--stats-file", metavar="FILE", default="stats.txt",
help="Sets the output file for statistics [Default: %default]")
+# Configuration Options
+set_group("Configuration Options")
+add_option("--dump-config", metavar="FILE", default="config.ini",
+ help="Dump configuration output file [Default: %default]")
+
# Debugging options
set_group("Debugging Options")
add_option("--debug-break", metavar="TIME[,TIME]", action='append', split=',',
help="Cycle to create a breakpoint")
+add_option("--remote-gdb-port", type='int', default=7000,
+ help="Remote gdb base port")
# Tracing options
set_group("Trace Options")
@@ -168,39 +116,61 @@ add_option("--trace-file", metavar="FILE", default="cout",
add_option("--trace-ignore", metavar="EXPR", action='append', split=':',
help="Ignore EXPR sim objects")
-options = attrdict()
-arguments = []
+# Help options
+set_group("Help Options")
+add_option("--list-sim-objects", action='store_true', default=False,
+ help="List all built-in SimObjects, their parameters and default values")
-def usage(exitcode=None):
- parser.print_help()
- if exitcode is not None:
- sys.exit(exitcode)
+def main():
+ import core
+ import debug
+ import defines
+ import event
+ import info
+ import stats
+ import trace
-def parse_args():
- _opts,args = parser.parse_args()
- opts = attrdict(_opts.__dict__)
+ def check_tracing():
+ if defines.TRACING_ON:
+ return
- # setting verbose and quiet at the same time doesn't make sense
- if opts.verbose > 0 and opts.quiet > 0:
- usage(2)
+ fatal("Tracing is not enabled. Compile with TRACING_ON")
- # store the verbosity in a single variable. 0 is default,
- # negative numbers represent quiet and positive values indicate verbose
- opts.verbose -= opts.quiet
+ # load the options.py config file to allow people to set their own
+ # default options
+ options_file = config.get('options.py')
+ if options_file:
+ scope = { 'options' : options }
+ execfile(options_file, scope)
- del opts.quiet
+ arguments = options.parse_args()
- options.update(opts)
- arguments.extend(args)
- return opts,args
+ if not os.path.isdir(options.outdir):
+ os.makedirs(options.outdir)
-def main():
- import defines
- import event
- import info
- import internal
+ # These filenames are used only if the redirect_std* options are set
+ stdout_file = os.path.join(options.outdir, options.stdout_file)
+ stderr_file = os.path.join(options.outdir, options.stderr_file)
- parse_args()
+ # Print redirection notices here before doing any redirection
+ if options.redirect_stdout and not options.redirect_stderr:
+ print "Redirecting stdout and stderr to", stdout_file
+ else:
+ if options.redirect_stdout:
+ print "Redirecting stdout to", stdout_file
+ if options.redirect_stderr:
+ print "Redirecting stderr to", stderr_file
+
+ # Now redirect stdout/stderr as desired
+ if options.redirect_stdout:
+ redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
+ os.dup2(redir_fd, sys.stdout.fileno())
+ if not options.redirect_stderr:
+ os.dup2(redir_fd, sys.stderr.fileno())
+
+ if options.redirect_stderr:
+ redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
+ os.dup2(redir_fd, sys.stderr.fileno())
done = False
@@ -208,14 +178,13 @@ def main():
done = True
print 'Build information:'
print
- print 'compiled %s' % internal.core.cvar.compileDate;
- print 'started %s' % datetime.datetime.now().ctime()
- print 'executing on %s' % socket.gethostname()
+ print 'compiled %s' % defines.compileDate;
+ print "revision %s" % defines.hgRev
print 'build options:'
- keys = defines.m5_build_env.keys()
+ keys = defines.buildEnv.keys()
keys.sort()
for key in keys:
- val = defines.m5_build_env[key]
+ val = defines.buildEnv[key]
print ' %s = %s' % (key, val)
print
@@ -247,27 +216,49 @@ def main():
if options.trace_help:
done = True
- print "Base Flags:"
- print_list(traceflags.baseFlags, indent=4)
- print
- print "Compound Flags:"
- for flag in traceflags.compoundFlags:
- if flag == 'All':
- continue
- print " %s:" % flag
- print_list(traceflags.compoundFlagMap[flag], indent=8)
+ check_tracing()
+ trace.help()
+
+ if options.list_sim_objects:
+ import SimObject
+ done = True
+ print "SimObjects:"
+ objects = SimObject.allClasses.keys()
+ objects.sort()
+ for name in objects:
+ obj = SimObject.allClasses[name]
+ print " %s" % obj
+ params = obj._params.keys()
+ params.sort()
+ for pname in params:
+ param = obj._params[pname]
+ default = getattr(param, 'default', '')
+ print " %s" % pname
+ if default:
+ print " default: %s" % default
+ print " desc: %s" % param.desc
+ print
print
if done:
sys.exit(0)
+ # setting verbose and quiet at the same time doesn't make sense
+ if options.verbose > 0 and options.quiet > 0:
+ options.usage(2)
+
+ verbose = options.verbose - options.quiet
if options.verbose >= 0:
print "M5 Simulator System"
print brief_copyright
print
- print "M5 compiled %s" % internal.core.cvar.compileDate;
- print "M5 started %s" % datetime.datetime.now().ctime()
+
+ print "M5 compiled %s" % defines.compileDate;
+ print "M5 revision %s" % defines.hgRev
+
+ print "M5 started %s" % datetime.datetime.now().strftime("%b %e %Y %X")
print "M5 executing on %s" % socket.gethostname()
+
print "command line:",
for argv in sys.argv:
print argv,
@@ -278,61 +269,67 @@ def main():
if arguments and not os.path.isfile(arguments[0]):
print "Script %s not found" % arguments[0]
- usage(2)
+ options.usage(2)
# tell C++ about output directory
- internal.core.setOutputDir(options.outdir)
+ core.setOutputDir(options.outdir)
# update the system path with elements from the -p option
sys.path[0:0] = options.path
- import objects
-
# set stats options
- internal.stats.initText(options.stats_file)
+ stats.initText(options.stats_file)
# set debugging options
+ debug.setRemoteGDBPort(options.remote_gdb_port)
for when in options.debug_break:
- internal.debug.schedBreakCycle(int(when))
-
- on_flags = []
- off_flags = []
- for flag in options.trace_flags:
- off = False
- if flag.startswith('-'):
- flag = flag[1:]
- off = True
- if flag not in traceflags.allFlags:
- print >>sys.stderr, "invalid trace flag '%s'" % flag
- sys.exit(1)
-
- if off:
- off_flags.append(flag)
- else:
- on_flags.append(flag)
-
- for flag in on_flags:
- internal.trace.set(flag)
-
- for flag in off_flags:
- internal.trace.clear(flag)
+ debug.schedBreakCycle(int(when))
+
+ if options.trace_flags:
+ check_tracing()
+
+ on_flags = []
+ off_flags = []
+ for flag in options.trace_flags:
+ off = False
+ if flag.startswith('-'):
+ flag = flag[1:]
+ off = True
+ if flag not in trace.flags.all and flag != "All":
+ print >>sys.stderr, "invalid trace flag '%s'" % flag
+ sys.exit(1)
+
+ if off:
+ off_flags.append(flag)
+ else:
+ on_flags.append(flag)
+
+ for flag in on_flags:
+ trace.set(flag)
+
+ for flag in off_flags:
+ trace.clear(flag)
if options.trace_start:
- def enable_trace():
- internal.trace.cvar.enabled = True
- event.create(enable_trace, int(options.trace_start))
+ check_tracing()
+ e = event.create(trace.enable, event.Event.Trace_Enable_Pri)
+ event.mainq.schedule(e, options.trace_start)
else:
- internal.trace.cvar.enabled = True
+ trace.enable()
- internal.trace.output(options.trace_file)
+ trace.output(options.trace_file)
for ignore in options.trace_ignore:
- internal.trace.ignore(ignore)
+ check_tracing()
+ trace.ignore(ignore)
sys.argv = arguments
sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
- scope = { '__file__' : sys.argv[0],
+ filename = sys.argv[0]
+ filedata = file(filename, 'r').read()
+ filecode = compile(filedata, filename, 'exec')
+ scope = { '__file__' : filename,
'__name__' : '__m5_main__' }
# we want readline if we're doing anything interactive
@@ -342,11 +339,24 @@ def main():
# if pdb was requested, execfile the thing under pdb, otherwise,
# just do the execfile normally
if options.pdb:
- from pdb import Pdb
- debugger = Pdb()
- debugger.run('execfile("%s")' % sys.argv[0], scope)
+ import pdb
+ import traceback
+
+ pdb = pdb.Pdb()
+ try:
+ pdb.run(filecode, scope)
+ except SystemExit:
+ print "The program exited via sys.exit(). Exit status: ",
+ print sys.exc_info()[1]
+ except:
+ traceback.print_exc()
+ print "Uncaught exception. Entering post mortem debugging"
+ t = sys.exc_info()[2]
+ while t.tb_next is not None:
+ t = t.tb_next
+ pdb.interaction(t.tb_frame,t)
else:
- execfile(sys.argv[0], scope)
+ exec filecode in scope
# once the script is done
if options.interactive:
@@ -356,7 +366,14 @@ def main():
if __name__ == '__main__':
from pprint import pprint
- parse_args()
+ # load the options.py config file to allow people to set their own
+ # default options
+ options_file = config.get('options.py')
+ if options_file:
+ scope = { 'options' : options }
+ execfile(options_file, scope)
+
+ arguments = options.parse_args()
print 'opts:'
pprint(options, indent=4)
diff --git a/src/python/m5/options.py b/src/python/m5/options.py
new file mode 100644
index 000000000..1f534a314
--- /dev/null
+++ b/src/python/m5/options.py
@@ -0,0 +1,142 @@
+# 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
+
+import optparse
+import sys
+
+from optparse import *
+
+class nodefault(object): pass
+
+class splitter(object):
+ def __init__(self, split):
+ self.split = split
+ def __call__(self, option, opt_str, value, parser):
+ values = value.split(self.split)
+ dest = getattr(parser.values, option.dest)
+ if dest is None:
+ setattr(parser.values, option.dest, values)
+ else:
+ dest.extend(values)
+
+class OptionParser(dict):
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault('formatter', optparse.TitledHelpFormatter())
+ self._optparse = optparse.OptionParser(*args, **kwargs)
+ self._optparse.disable_interspersed_args()
+
+ self._allopts = {}
+
+ # current option group
+ self._group = self._optparse
+
+ def set_defaults(self, *args, **kwargs):
+ return self._optparse.set_defaults(*args, **kwargs)
+
+ def set_group(self, *args, **kwargs):
+ '''set the current option group'''
+ if not args and not kwargs:
+ self._group = self._optparse
+ else:
+ self._group = self._optparse.add_option_group(*args, **kwargs)
+
+ def add_option(self, *args, **kwargs):
+ '''add an option to the current option group, or global none set'''
+
+ # if action=split, but allows the option arguments
+ # themselves to be lists separated by the split variable'''
+
+ if kwargs.get('action', None) == 'append' and 'split' in kwargs:
+ split = kwargs.pop('split')
+ kwargs['default'] = []
+ kwargs['type'] = 'string'
+ kwargs['action'] = 'callback'
+ kwargs['callback'] = splitter(split)
+
+ option = self._group.add_option(*args, **kwargs)
+ dest = option.dest
+ if dest not in self._allopts:
+ self._allopts[dest] = option
+
+ return option
+
+ def bool_option(self, name, default, help):
+ '''add a boolean option called --name and --no-name.
+ Display help depending on which is the default'''
+
+ tname = '--%s' % name
+ fname = '--no-%s' % name
+ dest = name.replace('-', '_')
+ if default:
+ thelp = optparse.SUPPRESS_HELP
+ fhelp = help
+ else:
+ thelp = help
+ fhelp = optparse.SUPPRESS_HELP
+
+ topt = self.add_option(tname, action="store_true", default=default,
+ help=thelp)
+ fopt = self.add_option(fname, action="store_false", dest=dest,
+ help=fhelp)
+
+ return topt,fopt
+
+ def __getattr__(self, attr):
+ if attr.startswith('_'):
+ return super(OptionParser, self).__getattribute__(attr)
+
+ if attr in self:
+ return self[attr]
+
+ return super(OptionParser, self).__getattribute__(attr)
+
+ def __setattr__(self, attr, value):
+ if attr.startswith('_'):
+ super(OptionParser, self).__setattr__(attr, value)
+ elif attr in self._allopts:
+ defaults = { attr : value }
+ self.set_defaults(**defaults)
+ if attr in self:
+ self[attr] = value
+ else:
+ super(OptionParser, self).__setattr__(attr, value)
+
+ def parse_args(self):
+ opts,args = self._optparse.parse_args()
+
+ for key,val in opts.__dict__.iteritems():
+ if val is not None or key not in self:
+ self[key] = val
+
+ return args
+
+ def usage(self, exitcode=None):
+ self._optparse.print_help()
+ if exitcode is not None:
+ sys.exit(exitcode)
+
diff --git a/src/python/m5/params.py b/src/python/m5/params.py
index 241d4ceaf..18eeac0d1 100644
--- a/src/python/m5/params.py
+++ b/src/python/m5/params.py
@@ -166,6 +166,10 @@ class ParamDesc(object):
class VectorParamValue(list):
__metaclass__ = MetaParamValue
+ def __setattr__(self, attr, value):
+ raise AttributeError, \
+ "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
+
def ini_str(self):
return ' '.join([v.ini_str() for v in self])
@@ -323,8 +327,8 @@ class CheckedIntType(MetaParamValue):
if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
panic("CheckedInt subclass %s must define either\n" \
- " 'min' and 'max' or 'size' and 'unsigned'\n" \
- % name);
+ " 'min' and 'max' or 'size' and 'unsigned'\n",
+ name);
if cls.unsigned:
cls.min = 0
cls.max = 2 ** cls.size - 1
@@ -379,6 +383,13 @@ class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
class Float(ParamValue, float):
cxx_type = 'double'
+ def __init__(self, value):
+ if isinstance(value, (int, long, float, NumericParamValue, Float)):
+ self.value = float(value)
+ else:
+ raise TypeError, "Can't convert object of type %s to Float" \
+ % type(value).__name__
+
def getValue(self):
return float(self.value)
@@ -406,7 +417,6 @@ class MemorySize32(CheckedInt):
class Addr(CheckedInt):
cxx_type = 'Addr'
- cxx_predecls = ['#include "arch/isa_traits.hh"']
size = 64
unsigned = True
def __init__(self, value):
@@ -886,7 +896,7 @@ class NetworkBandwidth(float,ParamValue):
class MemoryBandwidth(float,ParamValue):
cxx_type = 'float'
- def __new__(self, value):
+ def __new__(cls, value):
# we want the number of ticks per byte of data
val = convert.toMemoryBandwidth(value)
return super(cls, MemoryBandwidth).__new__(cls, val)
@@ -896,7 +906,9 @@ class MemoryBandwidth(float,ParamValue):
def getValue(self):
# convert to seconds per byte
- value = 1.0 / float(self)
+ value = float(self)
+ if value:
+ value = 1.0 / float(self)
# convert to ticks per byte
value = ticks.fromSeconds(value)
return float(value)
@@ -992,6 +1004,7 @@ class PortRef(object):
if self.peer and not proxy.isproxy(self.peer):
print "warning: overwriting port", self, \
"value", self.peer, "with", other
+ self.peer.peer = None
self.peer = other
if proxy.isproxy(other):
other.set_param_desc(PortParamDesc())
@@ -1034,6 +1047,8 @@ class PortRef(object):
if self.ccConnected: # already done this
return
peer = self.peer
+ if not self.peer: # nothing to connect to
+ return
connectPorts(self.simobj.getCCObject(), self.name, self.index,
peer.simobj.getCCObject(), peer.name, peer.index)
self.ccConnected = True
diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py
index 3d91da368..45992fe85 100644
--- a/src/python/m5/simulate.py
+++ b/src/python/m5/simulate.py
@@ -33,6 +33,8 @@ import sys
# import the SWIG-wrapped main C++ functions
import internal
+import core
+import stats
from main import options
import SimObject
import ticks
@@ -46,28 +48,29 @@ def instantiate(root):
root.unproxy_all()
- ini_file = file(os.path.join(options.outdir, 'config.ini'), 'w')
- root.print_ini(ini_file)
- ini_file.close() # close config.ini
+ if options.dump_config:
+ ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
+ root.print_ini(ini_file)
+ ini_file.close()
# Initialize the global statistics
- internal.stats.initSimStats()
+ stats.initSimStats()
# Create the C++ sim objects and connect ports
root.createCCObject()
root.connectPorts()
# Do a second pass to finish initializing the sim objects
- internal.core.initAll()
+ core.initAll()
# Do a third pass to initialize statistics
- internal.core.regAllStats()
+ core.regAllStats()
- # Check to make sure that the stats package is properly initialized
- internal.stats.check()
+ # We're done registering statistics. Enable the stats package now.
+ stats.enable()
# Reset to put the stats in a consistent state.
- internal.stats.reset()
+ stats.reset()
def doDot(root):
dot = pydot.Dot()
@@ -182,3 +185,5 @@ def switchCpus(cpuList):
for old_cpu, new_cpu in cpuList:
new_cpu.takeOverFrom(old_cpu)
+
+from internal.core import disableAllListeners
diff --git a/src/python/m5/stats.py b/src/python/m5/stats.py
index 041a3f58d..5bd9d5f6a 100644
--- a/src/python/m5/stats.py
+++ b/src/python/m5/stats.py
@@ -28,9 +28,6 @@
import internal
-from internal.stats import dump
-from internal.stats import initSimStats
-from internal.stats import reset
from internal.stats import StatEvent as event
def initText(filename, desc=True, compat=True):
@@ -44,3 +41,19 @@ def initMySQL(host, database, user='', passwd='', project='test', name='test',
internal.stats.initMySQL(host, database, user, passwd, project, name,
sample)
+
+def initSimStats():
+ internal.stats.initSimStats()
+
+def enable():
+ internal.stats.enable()
+
+def dump():
+ # Currently prepare happens in the dump, but we should maybe move
+ # that out.
+
+ #internal.stats.prepare()
+ internal.stats.dump()
+
+def reset():
+ internal.stats.reset()
diff --git a/src/python/m5/trace.py b/src/python/m5/trace.py
new file mode 100644
index 000000000..17aa6196c
--- /dev/null
+++ b/src/python/m5/trace.py
@@ -0,0 +1,52 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# 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
+
+import internal
+import traceflags as flags
+import util
+
+from internal.trace import clear, output, set, ignore
+
+def disable():
+ internal.trace.cvar.enabled = False
+
+def enable():
+ internal.trace.cvar.enabled = True
+
+def help():
+ print "Base Flags:"
+ for flag in flags.basic:
+ print " %s: %s" % (flag, flags.descriptions[flag])
+ print
+ print "Compound Flags:"
+ for flag in flags.compound:
+ if flag == 'All':
+ continue
+ print " %s: %s" % (flag, flags.descriptions[flag])
+ util.print_list(flags.compoundMap[flag], indent=8)
+ print
diff --git a/src/python/m5/util/__init__.py b/src/python/m5/util/__init__.py
new file mode 100644
index 000000000..5c4a066c6
--- /dev/null
+++ b/src/python/m5/util/__init__.py
@@ -0,0 +1,45 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# 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
+
+from attrdict import attrdict, optiondict
+from misc import *
+from multidict import multidict
+import jobfile
+
+def print_list(items, indent=4):
+ line = ' ' * indent
+ for i,item in enumerate(items):
+ if len(line) + len(item) > 76:
+ print line
+ line = ' ' * indent
+
+ if i < len(items) - 1:
+ line += '%s, ' % item
+ else:
+ line += item
+ print line
diff --git a/src/python/m5/attrdict.py b/src/python/m5/util/attrdict.py
index 4ee7f1b8c..56f67217b 100644
--- a/src/python/m5/attrdict.py
+++ b/src/python/m5/util/attrdict.py
@@ -26,16 +26,17 @@
#
# Authors: Nathan Binkert
-__all__ = [ 'attrdict' ]
+__all__ = [ 'attrdict', 'multiattrdict', 'optiondict' ]
class attrdict(dict):
+ """Wrap dict, so you can use attribute access to get/set elements"""
def __getattr__(self, attr):
if attr in self:
return self.__getitem__(attr)
return super(attrdict, self).__getattribute__(attr)
def __setattr__(self, attr, value):
- if attr in dir(self):
+ if attr in dir(self) or attr.startswith('_'):
return super(attrdict, self).__setattr__(attr, value)
return self.__setitem__(attr, value)
@@ -44,6 +45,25 @@ class attrdict(dict):
return self.__delitem__(attr)
return super(attrdict, self).__delattr__(attr, value)
+class multiattrdict(attrdict):
+ """Wrap attrdict so that nested attribute accesses automatically create
+ nested dictionaries."""
+ def __getattr__(self, attr):
+ try:
+ return super(multiattrdict, self).__getattr__(attr)
+ except AttributeError:
+ d = optiondict()
+ setattr(self, attr, d)
+ return d
+
+class optiondict(attrdict):
+ """Modify attrdict so that a missing attribute just returns None"""
+ def __getattr__(self, attr):
+ try:
+ return super(optiondict, self).__getattr__(attr)
+ except AttributeError:
+ return None
+
if __name__ == '__main__':
x = attrdict()
x.y = 1
@@ -59,3 +79,9 @@ if __name__ == '__main__':
del x.z
print dir(x)
print(x)
+
+ x = multiattrdict()
+ x.y.z = 9
+ print x
+ print x.y
+ print x.y.z
diff --git a/src/python/m5/util/jobfile.py b/src/python/m5/util/jobfile.py
new file mode 100644
index 000000000..c830895f6
--- /dev/null
+++ b/src/python/m5/util/jobfile.py
@@ -0,0 +1,472 @@
+# Copyright (c) 2005-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: Nathan Binkert
+
+import sys
+
+from attrdict import optiondict
+from misc import crossproduct
+
+class Data(object):
+ def __init__(self, name, desc, **kwargs):
+ self.name = name
+ self.desc = desc
+ self.__dict__.update(kwargs)
+
+ def update(self, obj):
+ if not isinstance(obj, Data):
+ raise AttributeError, "can only update from Data object"
+
+ for key,val in obj.__dict__.iteritems():
+ if key.startswith('_') or key in ('name', 'desc'):
+ continue
+
+ if key not in self.__dict__:
+ self.__dict__[key] = val
+ continue
+
+ if not isinstance(val, dict):
+ if self.__dict__[key] == val:
+ continue
+
+ raise AttributeError, \
+ "%s specified more than once old: %s new: %s" % \
+ (key, self.__dict__[key], val)
+
+ d = self.__dict__[key]
+ for k,v in val.iteritems():
+ if k in d:
+ raise AttributeError, \
+ "%s specified more than once in %s" % (k, key)
+ d[k] = v
+
+ if hasattr(self, 'system') and hasattr(obj, 'system'):
+ if self.system != obj.system:
+ raise AttributeError, \
+ "conflicting values for system: '%s'/'%s'" % \
+ (self.system, obj.system)
+
+ def printinfo(self):
+ if self.name:
+ print 'name: %s' % self.name
+ if self.desc:
+ print 'desc: %s' % self.desc
+ try:
+ if self.system:
+ print 'system: %s' % self.system
+ except AttributeError:
+ pass
+
+ def printverbose(self):
+ for key in self:
+ val = self[key]
+ if isinstance(val, dict):
+ import pprint
+ val = pprint.pformat(val)
+ print '%-20s = %s' % (key, val)
+ print
+
+ def __contains__(self, attr):
+ if attr.startswith('_'):
+ return False
+ return attr in self.__dict__
+
+ def __getitem__(self, key):
+ if key.startswith('_'):
+ raise KeyError, "Key '%s' not found" % attr
+ return self.__dict__[key]
+
+ def __iter__(self):
+ keys = self.__dict__.keys()
+ keys.sort()
+ for key in keys:
+ if not key.startswith('_'):
+ yield key
+
+ def optiondict(self):
+ result = optiondict()
+ for key in self:
+ result[key] = self[key]
+ return result
+
+ def __repr__(self):
+ d = {}
+ for key,value in self.__dict__.iteritems():
+ if not key.startswith('_'):
+ d[key] = value
+
+ return "<%s: %s>" % (type(self).__name__, d)
+
+ def __str__(self):
+ return self.name
+
+class Job(Data):
+ def __init__(self, options):
+ super(Job, self).__init__('', '')
+
+ config = options[0]._config
+ for opt in options:
+ if opt._config != config:
+ raise AttributeError, \
+ "All options are not from the same Configuration"
+
+ self._config = config
+ self._groups = [ opt._group for opt in options ]
+ self._options = options
+
+ self.update(self._config)
+ for group in self._groups:
+ self.update(group)
+
+ self._is_checkpoint = True
+
+ for option in self._options:
+ self.update(option)
+ if not option._group._checkpoint:
+ self._is_checkpoint = False
+
+ if option._suboption:
+ self.update(option._suboption)
+ self._is_checkpoint = False
+
+ names = [ ]
+ for opt in self._options:
+ if opt.name:
+ names.append(opt.name)
+ self.name = ':'.join(names)
+
+ descs = [ ]
+ for opt in self._options:
+ if opt.desc:
+ descs.append(opt.desc)
+ self.desc = ', '.join(descs)
+
+ self._checkpoint = None
+ if not self._is_checkpoint:
+ opts = []
+ for opt in options:
+ cpt = opt._group._checkpoint
+ if not cpt:
+ continue
+ if isinstance(cpt, Option):
+ opt = cpt.clone(suboptions=False)
+ else:
+ opt = opt.clone(suboptions=False)
+
+ opts.append(opt)
+
+ if opts:
+ self._checkpoint = Job(opts)
+
+ def clone(self):
+ return Job(self._options)
+
+ def printinfo(self):
+ super(Job, self).printinfo()
+ if self._checkpoint:
+ print 'checkpoint: %s' % self._checkpoint.name
+ print 'config: %s' % self._config.name
+ print 'groups: %s' % [ g.name for g in self._groups ]
+ print 'options: %s' % [ o.name for o in self._options ]
+ super(Job, self).printverbose()
+
+class SubOption(Data):
+ def __init__(self, name, desc, **kwargs):
+ super(SubOption, self).__init__(name, desc, **kwargs)
+ self._number = None
+
+class Option(Data):
+ def __init__(self, name, desc, **kwargs):
+ super(Option, self).__init__(name, desc, **kwargs)
+ self._suboptions = []
+ self._suboption = None
+ self._number = None
+
+ def __getattribute__(self, attr):
+ if attr == 'name':
+ name = self.__dict__[attr]
+ if self._suboption is not None:
+ name = '%s:%s' % (name, self._suboption.name)
+ return name
+
+ if attr == 'desc':
+ desc = [ self.__dict__[attr] ]
+ if self._suboption is not None and self._suboption.desc:
+ desc.append(self._suboption.desc)
+ return ', '.join(desc)
+
+ return super(Option, self).__getattribute__(attr)
+
+ def suboption(self, name, desc, **kwargs):
+ subo = SubOption(name, desc, **kwargs)
+ subo._config = self._config
+ subo._group = self._group
+ subo._option = self
+ subo._number = len(self._suboptions)
+ self._suboptions.append(subo)
+ return subo
+
+ def clone(self, suboptions=True):
+ option = Option(self.__dict__['name'], self.__dict__['desc'])
+ option.update(self)
+ option._group = self._group
+ option._config = self._config
+ option._number = self._number
+ if suboptions:
+ option._suboptions.extend(self._suboptions)
+ option._suboption = self._suboption
+ return option
+
+ def subopts(self):
+ if not self._suboptions:
+ return [ self ]
+
+ subopts = []
+ for subo in self._suboptions:
+ option = self.clone()
+ option._suboption = subo
+ subopts.append(option)
+
+ return subopts
+
+ def printinfo(self):
+ super(Option, self).printinfo()
+ print 'config: %s' % self._config.name
+ super(Option, self).printverbose()
+
+class Group(Data):
+ def __init__(self, name, desc, **kwargs):
+ super(Group, self).__init__(name, desc, **kwargs)
+ self._options = []
+ self._number = None
+ self._checkpoint = False
+
+ def option(self, name, desc, **kwargs):
+ opt = Option(name, desc, **kwargs)
+ opt._config = self._config
+ opt._group = self
+ opt._number = len(self._options)
+ self._options.append(opt)
+ return opt
+
+ def options(self):
+ return self._options
+
+ def subopts(self):
+ subopts = []
+ for opt in self._options:
+ for subo in opt.subopts():
+ subopts.append(subo)
+ return subopts
+
+ def printinfo(self):
+ super(Group, self).printinfo()
+ print 'config: %s' % self._config.name
+ print 'options: %s' % [ o.name for o in self._options ]
+ super(Group, self).printverbose()
+
+class Configuration(Data):
+ def __init__(self, name, desc, **kwargs):
+ super(Configuration, self).__init__(name, desc, **kwargs)
+ self._groups = []
+ self._posfilters = []
+ self._negfilters = []
+
+ def group(self, name, desc, **kwargs):
+ grp = Group(name, desc, **kwargs)
+ grp._config = self
+ grp._number = len(self._groups)
+ self._groups.append(grp)
+ return grp
+
+ def groups(self):
+ return self._groups
+
+ def checkchildren(self, kids):
+ for kid in kids:
+ if kid._config != self:
+ raise AttributeError, "child from the wrong configuration"
+
+ def sortgroups(self, groups):
+ groups = [ (grp._number, grp) for grp in groups ]
+ groups.sort()
+ return [ grp[1] for grp in groups ]
+
+ def options(self, groups=None, checkpoint=False):
+ if groups is None:
+ groups = self._groups
+ self.checkchildren(groups)
+ groups = self.sortgroups(groups)
+ if checkpoint:
+ groups = [ grp for grp in groups if grp._checkpoint ]
+ optgroups = [ g.options() for g in groups ]
+ else:
+ optgroups = [ g.subopts() for g in groups ]
+ if not optgroups:
+ return
+ for options in crossproduct(optgroups):
+ for opt in options:
+ cpt = opt._group._checkpoint
+ if not isinstance(cpt, bool) and cpt != opt:
+ if checkpoint:
+ break
+ else:
+ yield options
+ else:
+ if checkpoint:
+ yield options
+
+ def addfilter(self, filt, pos=True):
+ import re
+ filt = re.compile(filt)
+ if pos:
+ self._posfilters.append(filt)
+ else:
+ self._negfilters.append(filt)
+
+ def jobfilter(self, job):
+ for filt in self._negfilters:
+ if filt.match(job.name):
+ return False
+
+ if not self._posfilters:
+ return True
+
+ for filt in self._posfilters:
+ if filt.match(job.name):
+ return True
+
+ return False
+
+ def checkpoints(self, groups=None):
+ for options in self.options(groups, True):
+ job = Job(options)
+ if self.jobfilter(job):
+ yield job
+
+ def jobs(self, groups=None):
+ for options in self.options(groups, False):
+ job = Job(options)
+ if self.jobfilter(job):
+ yield job
+
+ def alljobs(self, groups=None):
+ for options in self.options(groups, True):
+ yield Job(options)
+ for options in self.options(groups, False):
+ yield Job(options)
+
+ def find(self, jobname):
+ for job in self.alljobs():
+ if job.name == jobname:
+ return job
+ else:
+ raise AttributeError, "job '%s' not found" % jobname
+
+ def job(self, options):
+ self.checkchildren(options)
+ options = [ (opt._group._number, opt) for opt in options ]
+ options.sort()
+ options = [ opt[1] for opt in options ]
+ job = Job(options)
+ return job
+
+ def printinfo(self):
+ super(Configuration, self).printinfo()
+ print 'groups: %s' % [ g.name for g in self._groups ]
+ super(Configuration, self).printverbose()
+
+def JobFile(jobfile):
+ from os.path import expanduser, isfile, join as joinpath
+ filename = expanduser(jobfile)
+
+ # Can't find filename in the current path, search sys.path
+ if not isfile(filename):
+ for path in sys.path:
+ testname = joinpath(path, filename)
+ if isfile(testname):
+ filename = testname
+ break
+ else:
+ raise AttributeError, \
+ "Could not find file '%s'" % jobfile
+
+ data = {}
+ execfile(filename, data)
+ if 'conf' not in data:
+ raise ImportError, 'cannot import name conf from %s' % jobfile
+ return data['conf']
+
+def main(conf=None):
+ usage = 'Usage: %s [-b] [-c] [-v]' % sys.argv[0]
+ if conf is None:
+ usage += ' <jobfile>'
+
+ try:
+ import getopt
+ opts, args = getopt.getopt(sys.argv[1:], '-bcv')
+ except getopt.GetoptError:
+ sys.exit(usage)
+
+ both = False
+ checkpoint = False
+ verbose = False
+ for opt,arg in opts:
+ if opt == '-b':
+ both = True
+ checkpoint = True
+ if opt == '-c':
+ checkpoint = True
+ if opt == '-v':
+ verbose = True
+
+ if conf is None:
+ if len(args) != 1:
+ raise AttributeError, usage
+ conf = JobFile(args[0])
+ else:
+ if len(args) != 0:
+ raise AttributeError, usage
+
+ if both:
+ jobs = conf.alljobs()
+ elif checkpoint:
+ jobs = conf.checkpoints()
+ else:
+ jobs = conf.jobs()
+
+ for job in jobs:
+ if verbose:
+ job.printinfo()
+ else:
+ cpt = ''
+ if job._checkpoint:
+ cpt = job._checkpoint.name
+ print job.name, cpt
+
+if __name__ == '__main__':
+ main()
diff --git a/src/python/m5/util.py b/src/python/m5/util/misc.py
index 28b8b1b94..094e3ed9a 100644
--- a/src/python/m5/util.py
+++ b/src/python/m5/util/misc.py
@@ -56,4 +56,32 @@ def applyOrMap(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/multidict.py b/src/python/m5/util/multidict.py
index b5cd700ef..b5cd700ef 100644
--- a/src/python/m5/multidict.py
+++ b/src/python/m5/util/multidict.py
diff --git a/src/python/m5/util/orderdict.py b/src/python/m5/util/orderdict.py
new file mode 100644
index 000000000..3f755d299
--- /dev/null
+++ b/src/python/m5/util/orderdict.py
@@ -0,0 +1,80 @@
+# 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
+
+__all__ = [ 'orderdict' ]
+
+class orderdict(dict):
+ def __init__(self, d = {}):
+ self._keys = d.keys()
+ super(orderdict, self).__init__(d)
+
+ def __setitem__(self, key, item):
+ super(orderdict, self).__setitem__(key, item)
+ if not hasattr(self, '_keys'):
+ self._keys = [key,]
+ if key not in self._keys:
+ self._keys.append(key)
+
+ def __delitem__(self, key):
+ super(orderdict, self).__delitem__(key)
+ self._keys.remove(key)
+
+ def clear(self):
+ super(orderdict, self).clear()
+ self._keys = []
+
+ def items(self):
+ for i in self._keys:
+ yield i, self[i]
+
+ def keys(self):
+ return self._keys
+
+ def popitem(self):
+ if len(self._keys) == 0:
+ raise KeyError('dictionary is empty')
+ else:
+ key = self._keys[-1]
+ val = self[key]
+ del self[key]
+ return key, val
+
+ def setdefault(self, key, failobj = None):
+ super(orderdict, self).setdefault(key, failobj)
+ if key not in self._keys:
+ self._keys.append(key)
+
+ def update(self, d):
+ for key in d.keys():
+ if not self.has_key(key):
+ self._keys.append(key)
+ super(orderdict, self).update(d)
+
+ def values(self):
+ for i in self._keys:
+ yield self[i]