diff options
author | Nathan Binkert <nate@binkert.org> | 2007-07-23 21:51:38 -0700 |
---|---|---|
committer | Nathan Binkert <nate@binkert.org> | 2007-07-23 21:51:38 -0700 |
commit | abc76f20cb98c90e8dab416dd16dfd4a954013ba (patch) | |
tree | f3131e68a09c1b4537e17df5b14df21df53746e4 /src/python | |
parent | 552097b92e37fb4c0fd27960afe0a03c02894f11 (diff) | |
download | gem5-abc76f20cb98c90e8dab416dd16dfd4a954013ba.tar.xz |
Major changes to how SimObjects are created and initialized. Almost all
creation and initialization now happens in python. Parameter objects
are generated and initialized by python. The .ini file is now solely for
debugging purposes and is not used in construction of the objects in any
way.
--HG--
extra : convert_revision : 7e722873e417cb3d696f2e34c35ff488b7bff4ed
Diffstat (limited to 'src/python')
-rw-r--r-- | src/python/SConscript | 5 | ||||
-rw-r--r-- | src/python/generate.py | 324 | ||||
-rw-r--r-- | src/python/m5/SimObject.py | 205 | ||||
-rw-r--r-- | src/python/m5/__init__.py | 200 | ||||
-rw-r--r-- | src/python/m5/environment.py | 43 | ||||
-rw-r--r-- | src/python/m5/params.py | 229 | ||||
-rw-r--r-- | src/python/m5/simulate.py | 199 | ||||
-rw-r--r-- | src/python/m5/ticks.py | 6 | ||||
-rw-r--r-- | src/python/swig/inet.i | 43 | ||||
-rw-r--r-- | src/python/swig/pyobject.cc | 8 | ||||
-rw-r--r-- | src/python/swig/pyobject.hh | 1 | ||||
-rw-r--r-- | src/python/swig/range.i | 35 | ||||
-rw-r--r-- | src/python/swig/sim_object.i | 13 | ||||
-rw-r--r-- | src/python/swig/time.i | 44 |
14 files changed, 1058 insertions, 297 deletions
diff --git a/src/python/SConscript b/src/python/SConscript index 66b852d25..f1b6a393f 100644 --- a/src/python/SConscript +++ b/src/python/SConscript @@ -29,10 +29,8 @@ # Authors: Steve Reinhardt # Nathan Binkert -import os Import('*') -Source('swig/init.cc') Source('swig/pyevent.cc') Source('swig/pyobject.cc') @@ -45,13 +43,12 @@ PySource('m5', 'm5/main.py') PySource('m5', 'm5/multidict.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/util.py') -PySource('m5', os.path.join(env['ROOT'], 'util/pbs/jobfile.py')) - SwigSource('m5.internal', 'swig/core.i') SwigSource('m5.internal', 'swig/debug.i') SwigSource('m5.internal', 'swig/event.i') diff --git a/src/python/generate.py b/src/python/generate.py new file mode 100644 index 000000000..6a09b8106 --- /dev/null +++ b/src/python/generate.py @@ -0,0 +1,324 @@ +# 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: Nathan Binkert + +import imp +import py_compile +import sys +import zipfile + +from os.path import basename +from os.path import exists + +class DictImporter(object): + '''This importer takes a dictionary of arbitrary module names that + map to arbitrary filenames.''' + def __init__(self, modules, build_env): + self.modules = modules + self.installed = set() + self.build_env = build_env + + def __del__(self): + self.unload() + + def unload(self): + for module in self.installed: + del sys.modules[module] + + def find_module(self, fullname, path): + if fullname == '__scons': + return self + + if fullname == 'm5.objects': + return self + + if fullname.startswith('m5.internal'): + return None + + if fullname in self.modules and exists(self.modules[fullname]): + return self + + return None + + def load_module(self, fullname): + mod = imp.new_module(fullname) + sys.modules[fullname] = mod + self.installed.add(fullname) + + mod.__loader__ = self + if fullname == 'm5.objects': + mod.__path__ = fullname.split('.') + return mod + + if fullname == '__scons': + mod.__dict__['m5_build_env'] = self.build_env + return mod + + srcfile = self.modules[fullname] + if basename(srcfile) == '__init__.py': + mod.__path__ = fullname.split('.') + mod.__file__ = srcfile + + exec file(srcfile, 'r') in mod.__dict__ + + return mod + +class ordered_dict(dict): + def keys(self): + keys = super(ordered_dict, self).keys() + keys.sort() + return keys + + def values(self): + return [ self[key] for key in self.keys() ] + + def items(self): + return [ (key,self[key]) for key in self.keys() ] + + def iterkeys(self): + for key in self.keys(): + yield key + + def itervalues(self): + for value in self.values(): + yield value + + def iteritems(self): + for key,value in self.items(): + yield key, value + +class Generate(object): + def __init__(self, py_sources, sim_objects, build_env): + self.py_sources = py_sources + self.py_modules = {} + for source in py_sources: + self.py_modules[source.modpath] = source.srcpath + + importer = DictImporter(self.py_modules, build_env) + + # install the python importer so we can grab stuff from the source + # tree itself. + sys.meta_path[0:0] = [ importer ] + + import m5 + self.m5 = m5 + + # import all sim objects so we can populate the all_objects list + # make sure that we're working with a list, then let's sort it + sim_objects = list(sim_objects) + sim_objects.sort() + for simobj in sim_objects: + exec('from m5.objects import %s' % simobj) + + # we need to unload all of the currently imported modules so that they + # will be re-imported the next time the sconscript is run + importer.unload() + sys.meta_path.remove(importer) + + self.sim_objects = m5.SimObject.allClasses + self.enums = m5.params.allEnums + + self.params = {} + for name,obj in self.sim_objects.iteritems(): + for param in obj._params.local.values(): + if not hasattr(param, 'swig_decl'): + continue + pname = param.ptype_str + if pname not in self.params: + self.params[pname] = param + + def createSimObjectParam(self, target, source, env): + assert len(target) == 1 and len(source) == 1 + + hh_file = file(target[0].abspath, 'w') + name = str(source[0].get_contents()) + obj = self.sim_objects[name] + + print >>hh_file, obj.cxx_decl() + + # Generate Python file containing a dict specifying the current + # build_env flags. + def makeDefinesPyFile(self, target, source, env): + f = file(str(target[0]), 'w') + print >>f, "m5_build_env = ", source[0] + f.close() + + # Generate python file containing info about the M5 source code + def makeInfoPyFile(self, target, source, env): + f = file(str(target[0]), 'w') + for src in source: + data = ''.join(file(src.srcnode().abspath, 'r').xreadlines()) + print >>f, "%s = %s" % (src, repr(data)) + f.close() + + # Generate the __init__.py file for m5.objects + def makeObjectsInitFile(self, target, source, env): + f = file(str(target[0]), 'w') + print >>f, 'from params import *' + print >>f, 'from m5.SimObject import *' + for module in source: + print >>f, 'from %s import *' % module.get_contents() + f.close() + + def createSwigParam(self, target, source, env): + assert len(target) == 1 and len(source) == 1 + + i_file = file(target[0].abspath, 'w') + name = str(source[0].get_contents()) + param = self.params[name] + + for line in param.swig_decl(): + print >>i_file, line + + def createEnumStrings(self, target, source, env): + assert len(target) == 1 and len(source) == 1 + + cc_file = file(target[0].abspath, 'w') + name = str(source[0].get_contents()) + obj = self.enums[name] + + print >>cc_file, obj.cxx_def() + cc_file.close() + + def createEnumParam(self, target, source, env): + assert len(target) == 1 and len(source) == 1 + + hh_file = file(target[0].abspath, 'w') + name = str(source[0].get_contents()) + obj = self.enums[name] + + print >>hh_file, obj.cxx_decl() + + def buildParams(self, target, source, env): + names = [ s.get_contents() for s in source ] + objs = [ self.sim_objects[name] for name in names ] + out = file(target[0].abspath, 'w') + + ordered_objs = [] + obj_seen = set() + def order_obj(obj): + name = str(obj) + if name in obj_seen: + return + + obj_seen.add(name) + if str(obj) != 'SimObject': + order_obj(obj.__bases__[0]) + + ordered_objs.append(obj) + + for obj in objs: + order_obj(obj) + + enums = set() + predecls = [] + pd_seen = set() + + def add_pds(*pds): + for pd in pds: + if pd not in pd_seen: + predecls.append(pd) + pd_seen.add(pd) + + for obj in ordered_objs: + params = obj._params.local.values() + for param in params: + ptype = param.ptype + if issubclass(ptype, self.m5.params.Enum): + if ptype not in enums: + enums.add(ptype) + pds = param.swig_predecls() + if isinstance(pds, (list, tuple)): + add_pds(*pds) + else: + add_pds(pds) + + print >>out, '%module params' + + print >>out, '%{' + for obj in ordered_objs: + print >>out, '#include "params/%s.hh"' % obj + print >>out, '%}' + + for pd in predecls: + print >>out, pd + + enums = list(enums) + enums.sort() + for enum in enums: + print >>out, '%%import "enums/%s.hh"' % enum.__name__ + print >>out + + for obj in ordered_objs: + code = 'class %s ' % obj.cxx_class + if str(obj) != 'SimObject': + code += ': public %s ' % obj.__bases__[0] + code += '{};' + + klass = obj.cxx_class; + if hasattr(obj, 'cxx_namespace'): + code = 'namespace %s { %s }' % (obj.cxx_namespace, code) + klass = '%s::%s' % (obj.cxx_namespace, klass) + + print >>out, '%%ignore %s;' % klass + print >>out, code + + for obj in ordered_objs: + print >>out, '%%include "params/%s.hh"' % obj + + def makeSwigInit(self, target, source, env): + f = file(str(target[0]), 'w') + print >>f, 'extern "C" {' + for module in source: + print >>f, ' void init_%s();' % module.get_contents() + print >>f, '}' + print >>f, 'void init_swig() {' + for module in source: + print >>f, ' init_%s();' % module.get_contents() + print >>f, '}' + f.close() + + def compilePyFile(self, target, source, env): + '''Action function to compile a .py into a .pyc''' + py_compile.compile(str(source[0]), str(target[0])) + + def buildPyZip(self, target, source, env): + '''Action function to build the zip archive. Uses the + PyZipFile module included in the standard Python library.''' + + py_compiled = {} + for s in self.py_sources: + compname = str(s.compiled) + assert compname not in py_compiled + py_compiled[compname] = s + + zf = zipfile.ZipFile(str(target[0]), 'w') + for s in source: + zipname = str(s) + arcname = py_compiled[zipname].arcname + zf.write(zipname, arcname) + zf.close() diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py index f87e13732..1e7d289e2 100644 --- a/src/python/m5/SimObject.py +++ b/src/python/m5/SimObject.py @@ -29,6 +29,8 @@ import sys, types +import proxy +import m5 from util import * from multidict import multidict @@ -61,7 +63,7 @@ def isSimObjectOrSequence(value): 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, isNullPointer, SimObjVector +from params import ParamDesc, VectorParamDesc, isNullPointer, SimObjVector noDot = False try: @@ -109,6 +111,9 @@ except: # ##################################################################### +# list of all SimObject classes +allClasses = {} + # dict to look up SimObjects based on path instanceDict = {} @@ -119,12 +124,14 @@ 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, + 'swig_predecls' : types.ListType, 'type' : types.StringType } # Attributes that can be set any time - keywords = { 'check' : types.FunctionType, - 'cxx_type' : types.StringType, - 'cxx_predecls' : types.ListType, - 'swig_predecls' : types.ListType } + keywords = { 'check' : types.FunctionType } # __new__ is called before __init__, and is where the statements # in the body of the class definition get loaded into the class's @@ -132,6 +139,8 @@ 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 + # Copy "private" attributes, functions, and classes to the # official dict. Everything else goes in _init_dict to be # filtered in __init__. @@ -144,8 +153,13 @@ class MetaSimObject(type): else: # must be a param/port setting value_dict[key] = val + if 'abstract' not in value_dict: + value_dict['abstract'] = False cls_dict['_value_dict'] = value_dict - return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) + cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict) + if 'type' in value_dict: + allClasses[name] = cls + return cls # subclass initialization def __init__(cls, name, bases, dict): @@ -183,6 +197,34 @@ class MetaSimObject(type): # mark base as having been subclassed base._instantiated = True + # 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 + + 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 + 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) + cls._value_dict['cxx_predecls'] = [decl] + + if 'swig_predecls' not in cls._value_dict: + # A forward class declaration is sufficient since we are + # just declaring a pointer. + cls._value_dict['swig_predecls'] = \ + cls._value_dict['cxx_predecls'] + # Now process the _value_dict items. They could be defining # new (or overriding existing) parameters or ports, setting # class keywords (e.g., 'abstract'), or setting parameter @@ -207,12 +249,6 @@ class MetaSimObject(type): else: setattr(cls, key, val) - cls.cxx_type = cls.type + '*' - # A forward class declaration is sufficient since we are just - # declaring a pointer. - cls.cxx_predecls = ['class %s;' % cls.type] - cls.swig_predecls = cls.cxx_predecls - def _set_keyword(cls, keyword, val, kwtype): if not isinstance(val, kwtype): raise TypeError, 'keyword %s has bad type %s (expecting %s)' % \ @@ -310,18 +346,19 @@ class MetaSimObject(type): return cls.__name__ def cxx_decl(cls): - code = "#ifndef __PARAMS__%s\n#define __PARAMS__%s\n\n" % (cls, cls) - if str(cls) != 'SimObject': base = cls.__bases__[0].type else: base = None + code = "#ifndef __PARAMS__%s\n" % cls + code += "#define __PARAMS__%s\n\n" % cls + # The 'dict' attribute restricts us to the params declared in # the object itself, not including inherited params (which # will also be inherited from the base class's param struct # here). - params = cls._params.dict.values() + params = cls._params.local.values() try: ptypes = [p.ptype for p in params] except: @@ -330,9 +367,10 @@ class MetaSimObject(type): raise # get a list of lists of predeclaration lines - predecls = [p.cxx_predecls() for p in params] - # flatten - predecls = reduce(lambda x,y:x+y, predecls, []) + predecls = [] + predecls.extend(cls.cxx_predecls) + for p in params: + predecls.extend(p.cxx_predecls()) # remove redundant lines predecls2 = [] for pd in predecls: @@ -345,17 +383,21 @@ class MetaSimObject(type): if base: code += '#include "params/%s.hh"\n\n' % base - # Generate declarations for locally defined enumerations. - enum_ptypes = [t for t in ptypes if issubclass(t, Enum)] - if enum_ptypes: - code += "\n".join([t.cxx_decl() for t in enum_ptypes]) - code += "\n\n" + for ptype in ptypes: + if issubclass(ptype, Enum): + code += '#include "enums/%s.hh"\n' % ptype.__name__ + code += "\n\n" # now generate the actual param struct code += "struct %sParams" % cls if base: code += " : public %sParams" % base - code += " {\n" + 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 decls = [p.cxx_decl() for p in params] decls.sort() code += "".join([" %s\n" % d for d in decls]) @@ -365,12 +407,34 @@ class MetaSimObject(type): code += "\n#endif\n" return code + def cxx_type_decl(cls): + if str(cls) != 'SimObject': + base = cls.__bases__[0] + else: + base = None + + 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): + code = '%%module %s\n' % cls - code = '%%module %sParams\n' % cls + code += '%{\n' + code += '#include "params/%s.hh"\n' % cls + code += '%}\n\n' if str(cls) != 'SimObject': - base = cls.__bases__[0].type + base = cls.__bases__[0] else: base = None @@ -378,11 +442,12 @@ class MetaSimObject(type): # the object itself, not including inherited params (which # will also be inherited from the base class's param struct # here). - params = cls._params.dict.values() + params = cls._params.local.values() ptypes = [p.ptype for p in params] # get a list of lists of predeclaration lines - predecls = [p.swig_predecls() for p in params] + predecls = [] + predecls.extend([ p.swig_predecls() for p in params ]) # flatten predecls = reduce(lambda x,y:x+y, predecls, []) # remove redundant lines @@ -395,11 +460,14 @@ class MetaSimObject(type): code += "\n\n"; if base: - code += '%%import "python/m5/swig/%sParams.i"\n\n' % base + code += '%%import "params/%s.i"\n\n' % base - code += '%{\n' - code += '#include "params/%s.hh"\n' % cls - code += '%}\n\n' + for ptype in ptypes: + if issubclass(ptype, Enum): + code += '%%import "enums/%s.hh"\n' % ptype.__name__ + code += "\n\n" + + code += '%%import "params/%s_type.hh"\n\n' % cls code += '%%include "params/%s.hh"\n\n' % cls return code @@ -412,6 +480,7 @@ class SimObject(object): # get this metaclass. __metaclass__ = MetaSimObject type = 'SimObject' + abstract = True name = Param.String("Object name") @@ -440,6 +509,7 @@ class SimObject(object): self._parent = None self._children = {} self._ccObject = None # pointer to C++ object + self._ccParams = None self._instantiated = False # really "cloned" # Inherit parameter values from class using multidict so @@ -577,8 +647,11 @@ class SimObject(object): value._maybe_set_parent(self, attr) elif isSimObjectSequence(value): value = SimObjVector(value) - [v._maybe_set_parent(self, "%s%d" % (attr, i)) - for i,v in enumerate(value)] + if len(value) == 1: + value[0]._maybe_set_parent(self, attr) + else: + for i,v in enumerate(value): + v._maybe_set_parent(self, "%s%d" % (attr, i)) self._values[attr] = value @@ -680,25 +753,66 @@ class SimObject(object): for child in child_names: self._children[child].print_ini() - # Call C++ to create C++ object corresponding to this object and - # (recursively) all its children - def createCCObject(self): - self.getCCObject() # force creation - for child in self._children.itervalues(): - child.createCCObject() + def getCCParams(self): + if self._ccParams: + return self._ccParams + + cc_params_struct = eval('m5.objects.params.%sParams' % self.type) + cc_params = cc_params_struct() + cc_params.object = self + cc_params.name = str(self) + + param_names = self._params.keys() + param_names.sort() + for param in param_names: + value = self._values.get(param) + if value is None: + continue + + value = value.getValue() + if isinstance(self._params[param], VectorParamDesc): + assert isinstance(value, list) + vec = getattr(cc_params, param) + assert not len(vec) + for v in value: + vec.append(v) + else: + setattr(cc_params, param, value) + + port_names = self._ports.keys() + port_names.sort() + for port_name in port_names: + port = self._port_refs.get(port_name, None) + if port != None: + setattr(cc_params, port_name, port) + self._ccParams = cc_params + return self._ccParams # Get C++ object corresponding to this object, calling C++ if # necessary to construct it. Does *not* recursively create # children. def getCCObject(self): + import internal + params = self.getCCParams() if not self._ccObject: self._ccObject = -1 # flag to catch cycles in recursion - self._ccObject = internal.sim_object.createSimObject(self.path()) + self._ccObject = params.create() elif self._ccObject == -1: raise RuntimeError, "%s: recursive call to getCCObject()" \ % self.path() return self._ccObject + # Call C++ to create C++ object corresponding to this object and + # (recursively) all its children + def createCCObject(self): + self.getCCParams() + self.getCCObject() # force creation + for child in self._children.itervalues(): + child.createCCObject() + + def getValue(self): + return self.getCCObject() + # Create C++ port connections corresponding to the connections in # _port_refs (& recursively for all children) def connectPorts(self): @@ -730,6 +844,7 @@ class SimObject(object): return system_ptr.getMemoryMode() def changeTiming(self, mode): + import internal if isinstance(self, m5.objects.System): # i don't know if there's a better way to do this - calling # setMemoryMode directly from self._ccObject results in calling @@ -740,6 +855,7 @@ class SimObject(object): child.changeTiming(mode) def takeOverFrom(self, old_cpu): + import internal cpu_ptr = internal.sim_object.convertToBaseCPUPtr(old_cpu._ccObject) self._ccObject.takeOverFrom(cpu_ptr) @@ -794,9 +910,4 @@ def resolveSimObject(name): # __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. -__all__ = ['SimObject'] - -# see comment on imports at end of __init__.py. -import proxy -import internal -import m5 +__all__ = [ 'SimObject' ] diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py index a9206a474..36f2eba61 100644 --- a/src/python/m5/__init__.py +++ b/src/python/m5/__init__.py @@ -27,19 +27,10 @@ # Authors: Nathan Binkert # Steve Reinhardt -import atexit import os import sys -# import the SWIG-wrapped main C++ functions -import internal -# import a few SWIG-wrapped items (those that are likely to be used -# directly by user scripts) completely into this module for -# convenience -import event - -# import the m5 compile options -import defines +import smartdict # define a MaxTick parameter MaxTick = 2**63 - 1 @@ -69,178 +60,12 @@ def AddToPath(path): sys.path.insert(1, path) # 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) -# The final hook to generate .ini files. Called from the user script -# once the config is built. -def instantiate(root): - # we need to fix the global frequency - ticks.fixGlobalFrequency() - - root.unproxy_all() - # ugly temporary hack to get output to config.ini - sys.stdout = file(os.path.join(options.outdir, 'config.ini'), 'w') - root.print_ini() - sys.stdout.close() # close config.ini - sys.stdout = sys.__stdout__ # restore to original - - # load config.ini into C++ - internal.core.loadIniFile(resolveSimObject) - - # Initialize the global statistics - internal.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.sim_object.initAll() - - # Do a third pass to initialize statistics - internal.sim_object.regAllStats() - - # Check to make sure that the stats package is properly initialized - internal.stats.check() - - # Reset to put the stats in a consistent state. - internal.stats.reset() - -def doDot(root): - dot = pydot.Dot() - instance.outputDot(dot) - dot.orientation = "portrait" - dot.size = "8.5,11" - dot.ranksep="equally" - dot.rank="samerank" - dot.write("config.dot") - dot.write_ps("config.ps") - -need_resume = [] -need_startup = True -def simulate(*args, **kwargs): - global need_resume, need_startup - - if need_startup: - internal.core.SimStartup() - need_startup = False - - for root in need_resume: - resume(root) - need_resume = [] - - return internal.event.simulate(*args, **kwargs) - -# Export curTick to user script. -def curTick(): - return internal.core.cvar.curTick - -# Python exit handlers happen in reverse order. We want to dump stats last. -atexit.register(internal.stats.dump) - -# register our C++ exit callback function with Python -atexit.register(internal.core.doExitCleanup) - -# This loops until all objects have been fully drained. -def doDrain(root): - all_drained = drain(root) - while (not all_drained): - all_drained = drain(root) - -# Tries to drain all objects. Draining might not be completed unless -# all objects return that they are drained on the first call. This is -# because as objects drain they may cause other objects to no longer -# be drained. -def drain(root): - all_drained = False - drain_event = internal.event.createCountedDrain() - unready_objects = root.startDrain(drain_event, True) - # If we've got some objects that can't drain immediately, then simulate - if unready_objects > 0: - drain_event.setCount(unready_objects) - simulate() - else: - all_drained = True - internal.event.cleanupCountedDrain(drain_event) - return all_drained - -def resume(root): - root.resume() - -def checkpoint(root, dir): - if not isinstance(root, objects.Root): - raise TypeError, "Checkpoint must be called on a root object." - doDrain(root) - print "Writing checkpoint" - internal.sim_object.serializeAll(dir) - resume(root) - -def restoreCheckpoint(root, dir): - print "Restoring from checkpoint" - internal.sim_object.unserializeAll(dir) - need_resume.append(root) - -def changeToAtomic(system): - if not isinstance(system, (objects.Root, objects.System)): - raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \ - (type(system), objects.Root, objects.System) - if system.getMemoryMode() != internal.sim_object.SimObject.Atomic: - doDrain(system) - print "Changing memory mode to atomic" - system.changeTiming(internal.sim_object.SimObject.Atomic) - -def changeToTiming(system): - if not isinstance(system, (objects.Root, objects.System)): - raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \ - (type(system), objects.Root, objects.System) - - if system.getMemoryMode() != internal.sim_object.SimObject.Timing: - doDrain(system) - print "Changing memory mode to timing" - system.changeTiming(internal.sim_object.SimObject.Timing) - -def switchCpus(cpuList): - print "switching cpus" - if not isinstance(cpuList, list): - raise RuntimeError, "Must pass a list to this function" - for i in cpuList: - if not isinstance(i, tuple): - raise RuntimeError, "List must have tuples of (oldCPU,newCPU)" - - [old_cpus, new_cpus] = zip(*cpuList) - - for cpu in old_cpus: - if not isinstance(cpu, objects.BaseCPU): - raise TypeError, "%s is not of type BaseCPU" % cpu - for cpu in new_cpus: - if not isinstance(cpu, objects.BaseCPU): - raise TypeError, "%s is not of type BaseCPU" % cpu - - # Drain all of the individual CPUs - drain_event = internal.event.createCountedDrain() - unready_cpus = 0 - for old_cpu in old_cpus: - unready_cpus += old_cpu.startDrain(drain_event, False) - # If we've got some objects that can't drain immediately, then simulate - if unready_cpus > 0: - drain_event.setCount(unready_cpus) - simulate() - internal.event.cleanupCountedDrain(drain_event) - # Now all of the CPUs are ready to be switched out - for old_cpu in old_cpus: - old_cpu._ccObject.switchOut() - index = 0 - for new_cpu in new_cpus: - new_cpu.takeOverFrom(old_cpus[index]) - new_cpu._ccObject.resume() - index += 1 - # 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 @@ -250,7 +75,24 @@ def switchCpus(cpuList): # 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*). -from main import options -import objects +try: + import internal + running_m5 = True +except ImportError: + running_m5 = False + +if running_m5: + from event import * + from simulate import * + from main import options + +if running_m5: + import defines + build_env.update(defines.m5_build_env) +else: + import __scons + build_env.update(__scons.m5_build_env) + +import SimObject import params -from SimObject import resolveSimObject +import objects diff --git a/src/python/m5/environment.py b/src/python/m5/environment.py new file mode 100644 index 000000000..bea0bc1d0 --- /dev/null +++ b/src/python/m5/environment.py @@ -0,0 +1,43 @@ +# 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/params.py b/src/python/m5/params.py index 88b162874..3fca4e97a 100644 --- a/src/python/m5/params.py +++ b/src/python/m5/params.py @@ -47,6 +47,7 @@ import copy import datetime import inspect +import re import sys import time @@ -55,6 +56,17 @@ import proxy import ticks from util import * +import SimObject + +def isSimObject(*args, **kwargs): + return SimObject.isSimObject(*args, **kwargs) + +def isSimObjectSequence(*args, **kwargs): + return SimObject.isSimObjectSequence(*args, **kwargs) + +def isSimObjectClass(*args, **kwargs): + return SimObject.isSimObjectClass(*args, **kwargs) + # Dummy base class to identify types that are legitimate for SimObject # parameters. class ParamValue(object): @@ -108,14 +120,15 @@ class ParamDesc(object): def __getattr__(self, attr): if attr == 'ptype': try: - ptype = eval(self.ptype_str, objects.__dict__) + ptype = SimObject.allClasses[self.ptype_str] if not isinstance(ptype, type): raise NameError self.ptype = ptype return ptype except NameError: - raise TypeError, \ - "Param qualifier '%s' is not a type" % self.ptype_str + raise + #raise TypeError, \ + # "Param qualifier '%s' is not a type" % self.ptype_str raise AttributeError, "'%s' object has no attribute '%s'" % \ (type(self).__name__, attr) @@ -150,6 +163,9 @@ class VectorParamValue(list): def ini_str(self): return ' '.join([v.ini_str() for v in self]) + def getValue(self): + return [ v.getValue() for v in self ] + def unproxy(self, base): return [v.unproxy(base) for v in self] @@ -165,20 +181,26 @@ class VectorParamDesc(ParamDesc): if isinstance(value, (list, tuple)): # list: coerce each element into new list tmp_list = [ ParamDesc.convert(self, v) for v in value ] - if isSimObjectSequence(tmp_list): - return SimObjVector(tmp_list) - else: - return VectorParamValue(tmp_list) else: - # singleton: leave it be (could coerce to a single-element - # list here, but for some historical reason we don't... - return ParamDesc.convert(self, value) + # singleton: coerce to a single-element list + tmp_list = [ ParamDesc.convert(self, value) ] - def cxx_predecls(self): - return ['#include <vector>'] + self.ptype.cxx_predecls + if isSimObjectSequence(tmp_list): + return SimObjVector(tmp_list) + else: + return VectorParamValue(tmp_list) def swig_predecls(self): - return ['%include "std_vector.i"'] + self.ptype.swig_predecls + return ['%%include "%s_vptype.i"' % self.ptype_str] + + def swig_decl(self): + cxx_type = re.sub('std::', '', self.ptype.cxx_type) + vdecl = 'namespace std { %%template(vector_%s) vector< %s >; }' % \ + (self.ptype_str, cxx_type) + return ['%include "std_vector.i"'] + self.ptype.swig_predecls + [vdecl] + + def cxx_predecls(self): + return ['#include <vector>'] + self.ptype.cxx_predecls def cxx_decl(self): return 'std::vector< %s > %s;' % (self.ptype.cxx_type, self.name) @@ -232,7 +254,10 @@ class String(ParamValue,str): cxx_predecls = ['#include <string>'] swig_predecls = ['%include "std_string.i"\n' + '%apply const std::string& {std::string *};'] - pass + swig_predecls = ['%include "std_string.i"' ] + + def getValue(self): + return self # superclass for "numeric" parameter values, to emulate math # operations in a type-safe way. e.g., a Latency times an int returns @@ -291,7 +316,7 @@ class CheckedIntType(type): if not cls.swig_predecls: # most derived types require this, so we just do it here once - cls.swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + + cls.swig_predecls = ['%import "stdint.i"\n' + '%import "sim/host.hh"'] if not (hasattr(cls, 'min') and hasattr(cls, 'max')): @@ -328,6 +353,9 @@ class CheckedInt(NumericParamValue): % type(value).__name__ self._check() + def getValue(self): + return long(self.value) + class Int(CheckedInt): cxx_type = 'int'; size = 32; unsigned = False class Unsigned(CheckedInt): cxx_type = 'unsigned'; size = 32; unsigned = True @@ -350,6 +378,9 @@ class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100 class Float(ParamValue, float): cxx_type = 'double' + def getValue(self): + return float(self.value) + class MemorySize(CheckedInt): cxx_type = 'uint64_t' size = 64 @@ -374,7 +405,7 @@ class MemorySize32(CheckedInt): class Addr(CheckedInt): cxx_type = 'Addr' - cxx_predecls = ['#include "targetarch/isa_traits.hh"'] + cxx_predecls = ['#include "arch/isa_traits.hh"'] size = 64 unsigned = True def __init__(self, value): @@ -443,9 +474,27 @@ class Range(ParamValue): class AddrRange(Range): type = Addr + swig_predecls = ['%include "python/swig/range.i"'] + + def getValue(self): + from m5.objects.params import AddrRange + + value = AddrRange() + value.start = long(self.first) + value.end = long(self.second) + return value class TickRange(Range): type = Tick + swig_predecls = ['%include "python/swig/range.i"'] + + def getValue(self): + from m5.objects.params import TickRange + + value = TickRange() + value.start = long(self.first) + value.end = long(self.second) + return value # Boolean parameter type. Python doesn't let you subclass bool, since # it doesn't want to let you create multiple instances of True and @@ -458,6 +507,9 @@ class Bool(ParamValue): except TypeError: self.value = bool(value) + def getValue(self): + return bool(self.value) + def __str__(self): return str(self.value) @@ -489,7 +541,7 @@ def NextEthernetAddr(): class EthernetAddr(ParamValue): cxx_type = 'Net::EthAddr' cxx_predecls = ['#include "base/inet.hh"'] - swig_predecls = ['class Net::EthAddr;'] + swig_predecls = ['%include "python/swig/inet.i"'] def __init__(self, value): if value == NextEthernetAddr: self.value = value @@ -513,6 +565,10 @@ class EthernetAddr(ParamValue): return EthernetAddr(self.value()) return self + def getValue(self): + from m5.objects.params import EthAddr + return EthAddr(self.value) + def ini_str(self): return self.value @@ -555,13 +611,40 @@ def parse_time(value): raise ValueError, "Could not parse '%s' as a time" % value class Time(ParamValue): - cxx_type = 'time_t' + cxx_type = 'tm' + cxx_predecls = [ '#include <time.h>' ] + swig_predecls = [ '%include "python/swig/time.i"' ] def __init__(self, value): self.value = parse_time(value) + def getValue(self): + from m5.objects.params import tm + + c_time = tm() + py_time = self.value + + # UNIX is years since 1900 + c_time.tm_year = py_time.tm_year - 1900; + + # Python starts at 1, UNIX starts at 0 + c_time.tm_mon = py_time.tm_mon - 1; + c_time.tm_mday = py_time.tm_mday; + c_time.tm_hour = py_time.tm_hour; + c_time.tm_min = py_time.tm_min; + c_time.tm_sec = py_time.tm_sec; + + # Python has 0 as Monday, UNIX is 0 as sunday + c_time.tm_wday = py_time.tm_wday + 1 + if c_time.tm_wday > 6: + c_time.tm_wday -= 7; + + # Python starts at 1, Unix starts at 0 + c_time.tm_yday = py_time.tm_yday - 1; + + return c_time + def __str__(self): - tm = self.value - return ' '.join([ str(tm[i]) for i in xrange(8)]) + return time.asctime(self.value) def ini_str(self): return str(self) @@ -580,9 +663,16 @@ class Time(ParamValue): # classes (_ListEnum and _DictEnum) to serve as base classes, then # derive the new type from the appropriate base class on the fly. - +allEnums = {} # Metaclass for Enum types class MetaEnum(type): + def __new__(mcls, name, bases, dict): + assert name not in allEnums + + cls = super(MetaEnum, mcls).__new__(mcls, name, bases, dict) + allEnums[name] = cls + return cls + def __init__(cls, name, bases, init_dict): if init_dict.has_key('map'): if not isinstance(cls.map, dict): @@ -603,18 +693,42 @@ class MetaEnum(type): raise TypeError, "Enum-derived class must define "\ "attribute 'map' or 'vals'" - cls.cxx_type = name + '::Enum' + cls.cxx_type = 'Enums::%s' % name 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): - s = 'struct %s {\n enum Enum {\n ' % cls.__name__ - s += ',\n '.join(['%s = %d' % (v,cls.map[v]) for v in cls.vals]) - s += '\n };\n};\n' - return s + code = "#ifndef __ENUM__%s\n" % cls + code += '#define __ENUM__%s\n' % cls + code += '\n' + code += 'namespace Enums {\n' + code += ' enum %s {\n' % cls + for val in cls.vals: + code += ' %s = %d,\n' % (val, cls.map[val]) + code += ' Num_%s = %d,\n' % (cls, len(cls.vals)) + code += ' };\n' + code += ' extern const char *%sStrings[Num_%s];\n' % (cls, cls) + code += '}\n' + code += '\n' + code += '#endif\n' + return code + + def cxx_def(cls): + code = '#include "enums/%s.hh"\n' % cls + code += 'namespace Enums {\n' + code += ' const char *%sStrings[Num_%s] =\n' % (cls, cls) + code += ' {\n' + for val in cls.vals: + code += ' "%s",\n' % val + code += ' };\n' + code += '}\n' + return code # Base class for enum types. class Enum(ParamValue): @@ -627,6 +741,9 @@ class Enum(ParamValue): % (value, self.vals) self.value = value + def getValue(self): + return int(self.map[self.value]) + def __str__(self): return self.value @@ -636,9 +753,12 @@ frequency_tolerance = 0.001 # 0.1% class TickParamValue(NumericParamValue): cxx_type = 'Tick' cxx_predecls = ['#include "sim/host.hh"'] - swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + + swig_predecls = ['%import "stdint.i"\n' + '%import "sim/host.hh"'] + def getValue(self): + return long(self.value) + class Latency(TickParamValue): def __init__(self, value): if isinstance(value, (Latency, Clock)): @@ -661,12 +781,16 @@ class Latency(TickParamValue): return Frequency(self) raise AttributeError, "Latency object has no attribute '%s'" % attr - # convert latency to ticks - def ini_str(self): + def getValue(self): if self.ticks or self.value == 0: - return '%d' % self.value + value = self.value else: - return '%d' % (ticks.fromSeconds(self.value)) + value = ticks.fromSeconds(self.value) + return long(value) + + # convert latency to ticks + def ini_str(self): + return '%d' % self.getValue() class Frequency(TickParamValue): def __init__(self, value): @@ -691,11 +815,15 @@ class Frequency(TickParamValue): raise AttributeError, "Frequency object has no attribute '%s'" % attr # convert latency to ticks - def ini_str(self): + def getValue(self): if self.ticks or self.value == 0: - return '%d' % self.value + value = self.value else: - return '%d' % (ticks.fromSeconds(1.0 / self.value)) + value = ticks.fromSeconds(1.0 / self.value) + return long(value) + + def ini_str(self): + return '%d' % self.getValue() # A generic frequency and/or Latency value. Value is stored as a latency, # but to avoid ambiguity this object does not support numeric ops (* or /). @@ -703,7 +831,7 @@ class Frequency(TickParamValue): class Clock(ParamValue): cxx_type = 'Tick' cxx_predecls = ['#include "sim/host.hh"'] - swig_predecls = ['%import "python/m5/swig/stdint.i"\n' + + swig_predecls = ['%import "stdint.i"\n' + '%import "sim/host.hh"'] def __init__(self, value): if isinstance(value, (Latency, Clock)): @@ -726,6 +854,9 @@ class Clock(ParamValue): return Latency(self) raise AttributeError, "Frequency object has no attribute '%s'" % attr + def getValue(self): + return self.period.getValue() + def ini_str(self): return self.period.ini_str() @@ -739,11 +870,15 @@ class NetworkBandwidth(float,ParamValue): def __str__(self): return str(self.val) - def ini_str(self): + def getValue(self): # convert to seconds per byte value = 8.0 / float(self) # convert to ticks per byte - return '%f' % (ticks.fromSeconds(value)) + value = ticks.fromSeconds(value) + return float(value) + + def ini_str(self): + return '%f' % self.getValue() class MemoryBandwidth(float,ParamValue): cxx_type = 'float' @@ -755,11 +890,15 @@ class MemoryBandwidth(float,ParamValue): def __str__(self): return str(self.val) - def ini_str(self): + def getValue(self): # convert to seconds per byte value = 1.0 / float(self) # convert to ticks per byte - return '%f' % (ticks.fromSeconds(value)) + value = ticks.fromSeconds(value) + return float(value) + + def ini_str(self): + return '%f' % self.getValue() # # "Constants"... handy aliases for various values. @@ -786,9 +925,13 @@ class NullSimObject(object): def set_path(self, parent, name): pass + def __str__(self): return 'Null' + def getValue(self): + return None + # The only instance you'll ever need... NULL = NullSimObject() @@ -882,6 +1025,8 @@ class PortRef(object): # Call C++ to create corresponding port connection between C++ objects def ccConnect(self): + import internal + if self.ccConnected: # already done this return peer = self.peer @@ -1006,7 +1151,6 @@ class PortParamDesc(object): ptype_str = 'Port' ptype = Port - __all__ = ['Param', 'VectorParam', 'Enum', 'Bool', 'String', 'Float', 'Int', 'Unsigned', 'Int8', 'UInt8', 'Int16', 'UInt16', @@ -1021,8 +1165,3 @@ __all__ = ['Param', 'VectorParam', 'Time', 'NextEthernetAddr', 'NULL', 'Port', 'VectorPort'] - -# see comment on imports at end of __init__.py. -from SimObject import isSimObject, isSimObjectSequence, isSimObjectClass -import objects -import internal diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py new file mode 100644 index 000000000..1ef78d6cb --- /dev/null +++ b/src/python/m5/simulate.py @@ -0,0 +1,199 @@ +# 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 atexit +import os +import sys + +# import the SWIG-wrapped main C++ functions +import internal +from main import options +import SimObject +import ticks + +# The final hook to generate .ini files. Called from the user script +# once the config is built. +def instantiate(root): + # we need to fix the global frequency + ticks.fixGlobalFrequency() + + root.unproxy_all() + # ugly temporary hack to get output to config.ini + sys.stdout = file(os.path.join(options.outdir, 'config.ini'), 'w') + root.print_ini() + sys.stdout.close() # close config.ini + sys.stdout = sys.__stdout__ # restore to original + + # Initialize the global statistics + internal.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.sim_object.initAll() + + # Do a third pass to initialize statistics + internal.sim_object.regAllStats() + + # Check to make sure that the stats package is properly initialized + internal.stats.check() + + # Reset to put the stats in a consistent state. + internal.stats.reset() + +def doDot(root): + dot = pydot.Dot() + instance.outputDot(dot) + dot.orientation = "portrait" + dot.size = "8.5,11" + dot.ranksep="equally" + dot.rank="samerank" + dot.write("config.dot") + dot.write_ps("config.ps") + +need_resume = [] +need_startup = True +def simulate(*args, **kwargs): + global need_resume, need_startup + + if need_startup: + internal.core.SimStartup() + need_startup = False + + for root in need_resume: + resume(root) + need_resume = [] + + return internal.event.simulate(*args, **kwargs) + +# Export curTick to user script. +def curTick(): + return internal.core.cvar.curTick + +# Python exit handlers happen in reverse order. We want to dump stats last. +atexit.register(internal.stats.dump) + +# register our C++ exit callback function with Python +atexit.register(internal.core.doExitCleanup) + +# This loops until all objects have been fully drained. +def doDrain(root): + all_drained = drain(root) + while (not all_drained): + all_drained = drain(root) + +# Tries to drain all objects. Draining might not be completed unless +# all objects return that they are drained on the first call. This is +# because as objects drain they may cause other objects to no longer +# be drained. +def drain(root): + all_drained = False + drain_event = internal.event.createCountedDrain() + unready_objects = root.startDrain(drain_event, True) + # If we've got some objects that can't drain immediately, then simulate + if unready_objects > 0: + drain_event.setCount(unready_objects) + simulate() + else: + all_drained = True + internal.event.cleanupCountedDrain(drain_event) + return all_drained + +def resume(root): + root.resume() + +def checkpoint(root, dir): + if not isinstance(root, objects.Root): + raise TypeError, "Checkpoint must be called on a root object." + doDrain(root) + print "Writing checkpoint" + internal.sim_object.serializeAll(dir) + resume(root) + +def restoreCheckpoint(root, dir): + print "Restoring from checkpoint" + internal.sim_object.unserializeAll(dir) + need_resume.append(root) + +def changeToAtomic(system): + if not isinstance(system, (objects.Root, objects.System)): + raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \ + (type(system), objects.Root, objects.System) + if system.getMemoryMode() != internal.sim_object.SimObject.Atomic: + doDrain(system) + print "Changing memory mode to atomic" + system.changeTiming(internal.sim_object.SimObject.Atomic) + +def changeToTiming(system): + if not isinstance(system, (objects.Root, objects.System)): + raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \ + (type(system), objects.Root, objects.System) + + if system.getMemoryMode() != internal.sim_object.SimObject.Timing: + doDrain(system) + print "Changing memory mode to timing" + system.changeTiming(internal.sim_object.SimObject.Timing) + +def switchCpus(cpuList): + print "switching cpus" + if not isinstance(cpuList, list): + raise RuntimeError, "Must pass a list to this function" + for i in cpuList: + if not isinstance(i, tuple): + raise RuntimeError, "List must have tuples of (oldCPU,newCPU)" + + [old_cpus, new_cpus] = zip(*cpuList) + + for cpu in old_cpus: + if not isinstance(cpu, objects.BaseCPU): + raise TypeError, "%s is not of type BaseCPU" % cpu + for cpu in new_cpus: + if not isinstance(cpu, objects.BaseCPU): + raise TypeError, "%s is not of type BaseCPU" % cpu + + # Drain all of the individual CPUs + drain_event = internal.event.createCountedDrain() + unready_cpus = 0 + for old_cpu in old_cpus: + unready_cpus += old_cpu.startDrain(drain_event, False) + # If we've got some objects that can't drain immediately, then simulate + if unready_cpus > 0: + drain_event.setCount(unready_cpus) + simulate() + internal.event.cleanupCountedDrain(drain_event) + # Now all of the CPUs are ready to be switched out + for old_cpu in old_cpus: + old_cpu._ccObject.switchOut() + index = 0 + for new_cpu in new_cpus: + new_cpu.takeOverFrom(old_cpus[index]) + new_cpu._ccObject.resume() + index += 1 diff --git a/src/python/m5/ticks.py b/src/python/m5/ticks.py index e91b470ff..91834c9c8 100644 --- a/src/python/m5/ticks.py +++ b/src/python/m5/ticks.py @@ -28,14 +28,12 @@ import sys -import convert -import internal - tps = 1.0e12 # default to 1 THz (1 Tick == 1 ps) tps_fixed = False # once set to true, can't be changed # fix the global frequency and tell C++ about it def fixGlobalFrequency(): + import internal global tps, tps_fixed if not tps_fixed: tps_fixed = True @@ -43,6 +41,8 @@ def fixGlobalFrequency(): print "Global frequency set at %d ticks per second" % int(tps) def setGlobalFrequency(ticksPerSecond): + import convert + global tps, tps_fixed if tps_fixed: diff --git a/src/python/swig/inet.i b/src/python/swig/inet.i new file mode 100644 index 000000000..96b4b85d0 --- /dev/null +++ b/src/python/swig/inet.i @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 + */ + +%{ +#include "base/inet.hh" +%} + +namespace Net { +struct EthAddr +{ + EthAddr(); + EthAddr(const uint8_t ea[6]); + EthAddr(const std::string &addr); +}; +} + diff --git a/src/python/swig/pyobject.cc b/src/python/swig/pyobject.cc index 2a5f2b9fb..455888c04 100644 --- a/src/python/swig/pyobject.cc +++ b/src/python/swig/pyobject.cc @@ -36,7 +36,6 @@ #include "base/output.hh" #include "mem/mem_object.hh" #include "mem/port.hh" -#include "sim/builder.hh" #include "sim/sim_object.hh" using namespace std; @@ -89,12 +88,6 @@ inifile() return inifile; } -SimObject * -createSimObject(const string &name) -{ - return SimObjectClass::createObject(inifile(), name); -} - /** * Pointer to the Python function that maps names to SimObjects. */ @@ -130,7 +123,6 @@ void loadIniFile(PyObject *_resolveFunc) { resolveFunc = _resolveFunc; - configStream = simout.find("config.out"); // The configuration database is now complete; start processing it. inifile().load(simout.resolve("config.ini")); diff --git a/src/python/swig/pyobject.hh b/src/python/swig/pyobject.hh index d8efc9149..da609e07e 100644 --- a/src/python/swig/pyobject.hh +++ b/src/python/swig/pyobject.hh @@ -36,7 +36,6 @@ #include "sim/sim_object.hh" #include "sim/system.hh" -SimObject *createSimObject(const std::string &name); extern "C" SimObject *convertSwigSimObjectPtr(PyObject *); SimObject *resolveSimObject(const std::string &name); void loadIniFile(PyObject *_resolveFunc); diff --git a/src/python/swig/range.i b/src/python/swig/range.i new file mode 100644 index 000000000..40809dae4 --- /dev/null +++ b/src/python/swig/range.i @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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 + */ + +%include "base/range.hh" +%include "sim/host.hh" + +%template(AddrRange) Range<Addr>; +%template(TickRange) Range<Tick>; diff --git a/src/python/swig/sim_object.i b/src/python/swig/sim_object.i index a1737c438..ebd019ca3 100644 --- a/src/python/swig/sim_object.i +++ b/src/python/swig/sim_object.i @@ -31,6 +31,7 @@ %module sim_object %{ +#include "enums/MemoryMode.hh" #include "python/swig/pyobject.hh" %} @@ -49,12 +50,6 @@ class SimObject { Drained }; - enum MemoryMode { - Invalid, - Atomic, - Timing - }; - unsigned int drain(Event *drain_event); void resume(); void switchOut(); @@ -66,12 +61,10 @@ class System { private: System(); public: - SimObject::MemoryMode getMemoryMode(); - void setMemoryMode(SimObject::MemoryMode mode); + Enums::MemoryMode getMemoryMode(); + void setMemoryMode(Enums::MemoryMode mode); }; -SimObject *createSimObject(const std::string &name); - int connectPorts(SimObject *o1, const std::string &name1, int i1, SimObject *o2, const std::string &name2, int i2); diff --git a/src/python/swig/time.i b/src/python/swig/time.i new file mode 100644 index 000000000..9bbad081a --- /dev/null +++ b/src/python/swig/time.i @@ -0,0 +1,44 @@ +/* + * Copyright (c) 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 + */ + +%{ +#include <sys/time.h> +%} + +struct tm { + int tm_sec; /* seconds after the minute [0-60] */ + int tm_min; /* minutes after the hour [0-59] */ + int tm_hour; /* hours since midnight [0-23] */ + int tm_mday; /* day of the month [1-31] */ + int tm_mon; /* months since January [0-11] */ + int tm_year; /* years since 1900 */ + int tm_wday; /* days since Sunday [0-6] */ + int tm_yday; /* days since January 1 [0-365] */ +}; |