24.22.3.1. gem5 m5.objects
module
All SimObjects
seem to be automatically added to the m5.objects
namespace, and this is done in a very convoluted way, let’s try to understand a bit:
src/python/m5/objects/__init__.py
contains:
modules = __loader__.modules for module in modules.keys(): if module.startswith('m5.objects.'): exec("from %s import *" % module)
And from IPDB we see that this appears to loop over every object string of type m5.objects.modulename
.
This __init__
gets called from src/python/importer.py
at the exec
:
class CodeImporter(object): def load_module(self, fullname): override = os.environ.get('M5_OVERRIDE_PY_SOURCE', 'false').lower() if override in ('true', 'yes') and os.path.exists(abspath): src = open(abspath, 'r').read() code = compile(src, abspath, 'exec') if os.path.basename(srcfile) == '__init__.py': mod.__path__ = fullname.split('.') mod.__package__ = fullname else: mod.__package__ = fullname.rpartition('.')[0] mod.__file__ = srcfile exec(code, mod.__dict__) import sys importer = CodeImporter() add_module = importer.add_module sys.meta_path.append(importer)
Here as a bonus here we also see how M5_OVERRIDE_PY_SOURCE
works.
In src/SConscript
we see that SimObject
is just a PySource
with module equals to m5.objects
:
class SimObject(PySource): def __init__(self, source, tags=None, add_tags=None): '''Specify the source file and any tags (automatically in the m5.objects package)''' super(SimObject, self).__init__('m5.objects', source, tags, add_tags)
The add_module
method seems to be doing the magic and is called from src/sim/init.cc
:
bool EmbeddedPython::addModule() const { PyObject *code = getCode(); PyObject *result = PyObject_CallMethod(importerModule, PyCC("add_module"),
which is called from:
int EmbeddedPython::initAll() { // Load the importer module PyObject *code = importer->getCode(); importerModule = PyImport_ExecCodeModule(PyCC("importer"), code); if (!importerModule) { PyErr_Print(); return 1; } // Load the rest of the embedded python files into the embedded // python importer list<EmbeddedPython *>::iterator i = getList().begin(); list<EmbeddedPython *>::iterator end = getList().end(); for (; i != end; ++i) if (!(*i)->addModule())
and getList
comes from:
EmbeddedPython::EmbeddedPython(const char *filename, const char *abspath, const char *modpath, const unsigned char *code, int zlen, int len) : filename(filename), abspath(abspath), modpath(modpath), code(code), zlen(zlen), len(len) { // if we've added the importer keep track of it because we need it // to bootstrap. if (string(modpath) == string("importer")) importer = this; else getList().push_back(this); } list<EmbeddedPython *> & EmbeddedPython::getList() { static list<EmbeddedPython *> the_list; return the_list; }
and the constructor in turn gets called from per SimObject
autogenerated files such as e.g. dev/storage/Ide.py.cc
for src/dev/storage/Ide.py
:
EmbeddedPython embedded_m5_objects_Ide( "m5/objects/Ide.py", "/home/ciro/bak/git/linux-kernel-module-cheat/data/gem5/master4/src/dev/storage/Ide.py", "m5.objects.Ide", data_m5_objects_Ide, 947, 2099); } // anonymous namespace
which get autogenerated at src/SConscript
:
def embedPyFile(target, source, env): for source in PySource.all: base_py_env.Command(source.cpp, [ py_marshal, source.tnode ], MakeAction(embedPyFile, Transform("EMBED PY")))
where the PySource.all
thing as you might expect is a static list of all PySource
source files as they get updated in the constructor.
Tested in gem5 d9cb548d83fa81858599807f54b52e5be35a6b03.