diff options
-rw-r--r-- | cpu/exec_context.hh | 2 | ||||
-rw-r--r-- | kern/kernel_stats.cc | 391 | ||||
-rw-r--r-- | kern/kernel_stats.hh | 63 | ||||
-rw-r--r-- | util/config/m5configbase.py (renamed from util/config/m5config.py) | 253 |
4 files changed, 528 insertions, 181 deletions
diff --git a/cpu/exec_context.hh b/cpu/exec_context.hh index a62225f1b..7409095e2 100644 --- a/cpu/exec_context.hh +++ b/cpu/exec_context.hh @@ -44,7 +44,7 @@ class BaseCPU; #include "targetarch/alpha_memory.hh" class MemoryController; -#include "kern/tru64/kernel_stats.hh" +#include "kern/kernel_stats.hh" #include "sim/system.hh" #include "sim/sw_context.hh" diff --git a/kern/kernel_stats.cc b/kern/kernel_stats.cc new file mode 100644 index 000000000..de944329a --- /dev/null +++ b/kern/kernel_stats.cc @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2003 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. + */ + +#include <map> +#include <stack> +#include <string> + +#include "base/statistics.hh" +#include "base/trace.hh" +#include "cpu/exec_context.hh" +#include "kern/kernel_stats.hh" +#include "sim/stats.hh" +#include "sim/sw_context.hh" +#include "targetarch/isa_traits.hh" +#include "targetarch/osfpal.hh" +#include "targetarch/syscalls.hh" + +using namespace std; +using namespace Stats; + +class KSData +{ + private: + string _name; + ExecContext *xc; + BaseCPU *cpu; + + public: + KSData(ExecContext *_xc, BaseCPU *_cpu) + : xc(_xc), cpu(_cpu), iplLast(0), iplLastTick(0), lastUser(false), + lastModeTick(0) + {} + + const string &name() { return _name; } + void regStats(const string &name); + + public: + Scalar<> _arm; + Scalar<> _quiesce; + Scalar<> _ivlb; + Scalar<> _ivle; + Scalar<> _hwrei; + + Vector<> _iplCount; + Vector<> _iplGood; + Vector<> _iplTicks; + Formula _iplUsed; + + Vector<> _callpal; + Vector<> _syscall; + Vector<> _faults; + + Vector<> _mode; + Vector<> _modeGood; + Formula _modeFraction; + Vector<> _modeTicks; + + Scalar<> _swap_context; + + private: + int iplLast; + Tick iplLastTick; + + bool lastUser; + Tick lastModeTick; + + public: + void swpipl(int ipl); + void mode(bool user); + void callpal(int code); +}; + +KernelStats::KernelStats(ExecContext *xc, BaseCPU *cpu) +{ data = new KSData(xc, cpu); } + +KernelStats::~KernelStats() +{ delete data; } + +void +KernelStats::regStats(const string &name) +{ data->regStats(name); } + +void +KSData::regStats(const string &name) +{ + _name = name; + + _arm + .name(name + ".inst.arm") + .desc("number of arm instructions executed") + ; + + _quiesce + .name(name + ".inst.quiesce") + .desc("number of quiesce instructions executed") + ; + + _ivlb + .name(name + ".inst.ivlb") + .desc("number of ivlb instructions executed") + ; + + _ivle + .name(name + ".inst.ivle") + .desc("number of ivle instructions executed") + ; + + _hwrei + .name(name + ".inst.hwrei") + .desc("number of hwrei instructions executed") + ; + + _iplCount + .init(32) + .name(name + ".ipl_count") + .desc("number of times we switched to this ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplGood + .init(32) + .name(name + ".ipl_good") + .desc("number of times we switched to this ipl from a different ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplTicks + .init(32) + .name(name + ".ipl_ticks") + .desc("number of cycles we spent at this ipl") + .flags(total | pdf | nozero | nonan) + ; + + _iplUsed + .name(name + ".ipl_used") + .desc("fraction of swpipl calls that actually changed the ipl") + .flags(total | nozero | nonan) + ; + + _iplUsed = _iplGood / _iplCount; + + _callpal + .init(256) + .name(name + ".callpal") + .desc("number of callpals executed") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 0; i < PAL::NumCodes; ++i) { + const char *str = PAL::name(i); + if (str) + _callpal.subname(i, str); + } + + _syscall + .init(SystemCalls<Tru64>::Number) + .name(name + ".syscall") + .desc("number of syscalls executed") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 0; i < SystemCalls<Tru64>::Number; ++i) { + const char *str = SystemCalls<Tru64>::name(i); + if (str) { + _syscall.subname(i, str); + } + } + + _faults + .init(Num_Faults) + .name(name + ".faults") + .desc("number of faults") + .flags(total | pdf | nozero | nonan) + ; + + for (int i = 1; i < Num_Faults; ++i) { + const char *str = FaultName(i); + if (str) + _faults.subname(i, str); + } + + _mode + .init(2) + .name(name + ".mode_switch") + .subname(0, "kernel") + .subname(1, "user") + .desc("number of protection mode switches") + ; + + _modeGood + .init(2) + ; + + _modeFraction + .name(name + ".mode_switch_good") + .subname(0, "kernel") + .subname(1, "user") + .desc("fraction of useful protection mode switches") + .flags(total) + ; + _modeFraction = _modeGood / _mode; + + _modeTicks + .init(2) + .name(name + ".mode_ticks") + .subname(0, "kernel") + .subname(1, "user") + .desc("number of ticks spent at the given mode") + .flags(pdf) + ; + + _swap_context + .name(name + ".swap_context") + .desc("number of times the context was actually changed") + ; +} + +void +KernelStats::arm() +{ data->_arm++; } + +void +KernelStats::quiesce() +{ data->_quiesce++; } + +void +KernelStats::ivlb() +{ data->_ivlb++; } + +void +KernelStats::ivle() +{ data->_ivle++; } + +void +KernelStats::hwrei() +{ data->_hwrei++; } + +void +KernelStats::fault(Fault fault) +{ data->_faults[fault]++; } + +void +KernelStats::swpipl(int ipl) +{ data->swpipl(ipl); } + +void +KernelStats::mode(bool user) +{ data->mode(user); } + +void +KernelStats::context(Addr old_pcbb, Addr new_pcbb) +{ data->_swap_context++; } + +void +KernelStats::callpal(int code) +{ data->callpal(code); } + + +void +KSData::swpipl(int ipl) +{ + assert(ipl >= 0 && ipl <= 0x1f && "invalid IPL\n"); + + _iplCount[ipl]++; + + if (ipl == iplLast) + return; + + _iplGood[ipl]++; + _iplTicks[iplLast] += curTick - iplLastTick; + iplLastTick = curTick; + iplLast = ipl; +} + +void +KSData::mode(bool user) +{ + _mode[user]++; + if (user == lastUser) + return; + + _modeGood[user]++; + _modeTicks[lastUser] += curTick - lastModeTick; + + lastModeTick = curTick; + lastUser = user; + + if (xc->system->bin) { + if (!xc->swCtx || xc->swCtx->callStack.empty()) { + if (user) + xc->system->User->activate(); + else + xc->system->Kernel->activate(); + } + } +} + +void +KSData::callpal(int code) +{ + if (!PAL::name(code)) + return; + + _callpal[code]++; + + switch (code) { + case PAL::callsys: + { + int number = xc->regs.intRegFile[0]; + if (SystemCalls<Tru64>::validSyscallNumber(number)) { + int cvtnum = SystemCalls<Tru64>::convert(number); + _syscall[cvtnum]++; + } + } + break; + } + + if (code == PAL::swpctx) { + SWContext *out = xc->swCtx; + System *sys = xc->system; + if (!sys->bin) + return; + DPRINTF(TCPIP, "swpctx event\n"); + if (out) { + DPRINTF(TCPIP, "swapping context out with this stack!\n"); + xc->system->dumpState(xc); + Addr oldPCB = xc->regs.ipr[TheISA::IPR_PALtemp23]; + + if (out->callStack.empty()) { + DPRINTF(TCPIP, "but removing it, cuz empty!\n"); + SWContext *find = sys->findContext(oldPCB); + if (find) { + assert(sys->findContext(oldPCB) == out); + sys->remContext(oldPCB); + } + delete out; + } else { + DPRINTF(TCPIP, "switching out context with pcb %#x, top fn %s\n", + oldPCB, out->callStack.top()->name); + if (!sys->findContext(oldPCB)) { + if (!sys->addContext(oldPCB, out)) + panic("could not add context"); + } + } + } + + Addr newPCB = xc->regs.intRegFile[16]; + SWContext *in = sys->findContext(newPCB); + xc->swCtx = in; + + if (in) { + assert(!in->callStack.empty() && + "should not be switching in empty context"); + DPRINTF(TCPIP, "swapping context in with this callstack!\n"); + xc->system->dumpState(xc); + sys->remContext(newPCB); + fnCall *top = in->callStack.top(); + DPRINTF(TCPIP, "switching in to pcb %#x, %s\n", newPCB, top->name); + assert(top->myBin && "should not switch to context with no Bin"); + top->myBin->activate(); + } else { + sys->Kernel->activate(); + } + DPRINTF(TCPIP, "end swpctx\n"); + } +} diff --git a/kern/kernel_stats.hh b/kern/kernel_stats.hh new file mode 100644 index 000000000..497403762 --- /dev/null +++ b/kern/kernel_stats.hh @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003 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. + */ + +#ifndef __KERNEL_STATS_HH__ +#define __KERNEL_STATS_HH__ + +#include <string> + +class KSData; +class ExecContext; +class BaseCPU; +enum Fault; + +class KernelStats +{ + private: + KSData *data; + + public: + KernelStats(ExecContext *_xc, BaseCPU *_cpu); + ~KernelStats(); + + void regStats(const std::string &name); + + void arm(); + void quiesce(); + void ivlb(); + void ivle(); + void hwrei(); + + void fault(Fault fault); + void swpipl(int ipl); + void mode(bool user); + void context(Addr old_pcbb, Addr new_pcbb); + void callpal(int code); +}; + +#endif // __KERNEL_STATS_HH__ diff --git a/util/config/m5config.py b/util/config/m5configbase.py index 9aa3e0387..2daf5d94d 100644 --- a/util/config/m5config.py +++ b/util/config/m5configbase.py @@ -157,6 +157,21 @@ class MetaConfigNode(type): print "Error setting '%s' default on class '%s'\n" \ % (pname, cls.__name__), exc + # Set the class's parameter dictionary given a code string of + # parameter initializers (as from an object description file). + # Note that the caller must pass in the namespace in which to + # execute the code (usually the caller's globals()), since if we + # call globals() from inside this function all we get is this + # module's internal scope. + def init_params(cls, init_code, ctx): + dict = {} + try: + exec fixPythonIndentation(init_code) in ctx, dict + except Exception, exc: + print "Error in %s.init_params:" % cls.__name__, exc + raise + cls.set_param_dict(dict) + # Lookup a parameter description by name in the given class. Use # the _param_bases list defined in __init__ to go up the # inheritance hierarchy if necessary. @@ -220,14 +235,13 @@ class ConfigNode(object): % (self.__class__.__name__, _name, type(_name)) self._name = _name self._parent = _parent - self._children = {} if (_parent): - _parent.__addChild(self) - # Set up absolute path from root. - if (_parent and _parent._path != 'Universe'): - self._path = _parent._path + '.' + self._name - else: - self._path = self._name + _parent._add_child(self) + self._children = {} + # keep a list of children in addition to the dictionary keys + # so we can remember the order they were added and print them + # out in that order. + self._child_list = [] # When printing (e.g. to .ini file), just give the name. def __str__(self): @@ -248,7 +262,7 @@ class ConfigNode(object): # Set attribute. All attribute assignments go through here. Must # be private attribute (starts with '_') or valid parameter entry. # Basically identical to MetaConfigClass.__setattr__(), except - # this handles instances rather than class attributes. + # this sets attributes on specific instances rather than on classes. def __setattr__(self, attr_name, value): if attr_name.startswith('_'): object.__setattr__(self, attr_name, value) @@ -261,11 +275,30 @@ class ConfigNode(object): % (self.__class__.__name__, attr_name) # It's ok: set attribute by delegating to 'object' class. # Note the use of param.make_value() to verify/canonicalize - # the assigned value - object.__setattr__(self, attr_name, param.make_value(value)) + # the assigned value. + v = param.make_value(value) + object.__setattr__(self, attr_name, v) + + # A little convenient magic: if the parameter is a ConfigNode + # (or vector of ConfigNodes, or anything else with a + # '_set_parent_if_none' function attribute) that does not have + # a parent (and so is not part of the configuration + # hierarchy), then make this node its parent. + if hasattr(v, '_set_parent_if_none'): + v._set_parent_if_none(self) + + def _path(self): + # Return absolute path from root. + if not self._parent and self._name != 'Universe': + print >> sys.stderr, "Warning:", self._name, "has no parent" + parent_path = self._parent and self._parent._path() + if parent_path and parent_path != 'Universe': + return parent_path + '.' + self._name + else: + return self._name # Add a child to this node. - def __addChild(self, new_child): + def _add_child(self, new_child): # set child's parent before calling this function assert new_child._parent == self if not isinstance(new_child, ConfigNode): @@ -276,6 +309,7 @@ class ConfigNode(object): "Node '%s' already has a child '%s'" \ % (self._name, new_child._name) self._children[new_child._name] = new_child + self._child_list += [new_child] # operator overload for '+='. You can say "node += child" to add # a child that was created with parent=None. An early attempt @@ -285,27 +319,28 @@ class ConfigNode(object): raise AttributeError, \ "Node '%s' already has a parent" % new_child._name new_child._parent = self - self.__addChild(new_child) + self._add_child(new_child) return self + # Set this instance's parent to 'parent' if it doesn't already + # have one. See ConfigNode.__setattr__(). + def _set_parent_if_none(self, parent): + if self._parent == None: + parent += self + # Print instance info to .ini file. def _instantiate(self): - print '[' + self._path + ']' # .ini section header - if self._children: - # instantiate children in sorted order for backward - # compatibility (else we can end up with cpu1 before cpu0). - child_names = self._children.keys() - child_names.sort() - print 'children =', - for child_name in child_names: - print child_name, - print + print '[' + self._path() + ']' # .ini section header + if self._child_list: + # instantiate children in same order they were added for + # backward compatibility (else we can end up with cpu1 + # before cpu0). + print 'children =', ' '.join([c._name for c in self._child_list]) self._instantiateParams() print # recursively dump out children - if self._children: - for child_name in child_names: - self._children[child_name]._instantiate() + for c in self._child_list: + c._instantiate() # ConfigNodes have no parameters. Overridden by SimObject. def _instantiateParams(self): @@ -373,9 +408,6 @@ class SimObject(ConfigNode): def isNullPointer(value): return isinstance(value, NullSimObject) -def isSimObjectType(ptype): - return issubclass(ptype, SimObject) - # Regular parameter. class Param(object): # Constructor. E.g., Param(Int, "number of widgets", 5) @@ -391,7 +423,7 @@ class Param(object): # nothing to do if None or already correct type. Also allow NULL # pointer to be assigned where a SimObject is expected. if value == None or isinstance(value, self.ptype) or \ - isNullPointer(value) and isSimObjectType(self.ptype): + isNullPointer(value) and issubclass(self.ptype, ConfigNode): return value # this type conversion will raise an exception if it's illegal return self.ptype(value) @@ -414,12 +446,21 @@ class Param(object): # storing these instead of a raw Python list is that we can override # the __str__() method to not print out '[' and ']' in the .ini file. class _VectorParamValue(object): - def __init__(self, list): - self.value = list + def __init__(self, value): + assert isinstance(value, list) or value == None + self.value = value def __str__(self): return ' '.join(map(str, self.value)) + # Set member instance's parents to 'parent' if they don't already + # have one. Extends "magic" parenting of ConfigNodes to vectors + # of ConfigNodes as well. See ConfigNode.__setattr__(). + def _set_parent_if_none(self, parent): + if self.value and hasattr(self.value[0], '_set_parent_if_none'): + for v in self.value: + v._set_parent_if_none(parent) + # Vector-valued parameter description. Just like Param, except that # the value is a vector (list) of the specified type instead of a # single value. @@ -623,7 +664,7 @@ false = False true = True # Some memory range specifications use this as a default upper bound. -MAX_ADDR = 2 ** 63 +MAX_ADDR = 2**64 - 1 # For power-of-two sizing, e.g. 64*K gives an integer value 65536. K = 1024 @@ -631,109 +672,6 @@ M = K*K G = K*M ##################################################################### -# -# Object description loading. -# -# The final step is to define the classes corresponding to M5 objects -# and their parameters. These classes are described in .odesc files -# in the source tree. This code walks the tree to find those files -# and loads up the descriptions (by evaluating them in pieces as -# Python code). -# -# -# Because SimObject classes inherit from other SimObject classes, and -# can use arbitrary other SimObject classes as parameter types, we -# have to do this in three steps: -# -# 1. Walk the tree to find all the .odesc files. Note that the base -# of the filename *must* match the class name. This step builds a -# mapping from class names to file paths. -# -# 2. Start generating empty class definitions (via def_class()) using -# the OBJECT field of the .odesc files to determine inheritance. -# def_class() recurses on demand to define needed base classes before -# derived classes. -# -# 3. Now that all of the classes are defined, go through the .odesc -# files one more time loading the parameter descriptions. -# -##################################################################### - -# dictionary: maps object names to file paths -odesc_file = {} - -# dictionary: maps object names to boolean flag indicating whether -# class definition was loaded yet. Since SimObject is defined in -# m5.config.py, count it as loaded. -odesc_loaded = { 'SimObject': True } - -# Find odesc files in namelist and initialize odesc_file and -# odesc_loaded dictionaries. Called via os.path.walk() (see below). -def find_odescs(process, dirpath, namelist): - # Prune out SCCS directories so we don't process s.*.odesc files. - i = 0 - while i < len(namelist): - if namelist[i] == "SCCS": - del namelist[i] - else: - i = i + 1 - # Find .odesc files and record them. - for name in namelist: - if name.endswith('.odesc'): - objname = name[:name.rindex('.odesc')] - path = os.path.join(dirpath, name) - if odesc_file.has_key(objname): - print "Warning: duplicate object names:", \ - odesc_file[objname], path - odesc_file[objname] = path - odesc_loaded[objname] = False - - -# Regular expression string for parsing .odesc files. -file_re_string = r''' -^OBJECT: \s* (\w+) \s* \( \s* (\w+) \s* \) -\s* -^PARAMS: \s*\n ( (\s+.*\n)* ) -''' - -# Compiled regular expression object. -file_re = re.compile(file_re_string, re.MULTILINE | re.VERBOSE) - -# .odesc file parsing function. Takes a filename and returns tuple of -# object name, object base, and parameter description section. -def parse_file(path): - f = open(path, 'r').read() - m = file_re.search(f) - if not m: - print "Can't parse", path - sys.exit(1) - return (m.group(1), m.group(2), m.group(3)) - -# Define SimObject class based on description in specified filename. -# Class itself is empty except for _name attribute; parameter -# descriptions will be loaded later. Will recurse to define base -# classes as needed before defining specified class. -def def_class(path): - # load & parse file - (obj, parent, params) = parse_file(path) - # check to see if base class is defined yet; define it if not - if not odesc_loaded.has_key(parent): - print "No .odesc file found for", parent - sys.exit(1) - if not odesc_loaded[parent]: - def_class(odesc_file[parent]) - # define the class. The _name attribute of the class lets us - # track the actual SimObject class name even when we derive new - # subclasses in scripts (to provide new parameter value settings). - s = "class %s(%s): _name = '%s'" % (obj, parent, obj) - try: - # execute in global namespace, so new class will be globally - # visible - exec s in globals() - except Exception, exc: - print "Object error in %s:" % path, exc - # mark this file as loaded - odesc_loaded[obj] = True # Munge an arbitrary Python code string to get it to execute (mostly # dealing with indentation). Stolen from isa_parser.py... see @@ -745,51 +683,6 @@ def fixPythonIndentation(s): s = 'if 1:\n' + s return s -# Load parameter descriptions from .odesc file. Object class must -# already be defined. -def def_params(path): - # load & parse file - (obj_name, parent_name, param_code) = parse_file(path) - # initialize param dict - param_dict = {} - # execute parameter descriptions. - try: - # "in globals(), param_dict" makes exec use the current - # globals as the global namespace (so all of the Param - # etc. objects are visible) and param_dict as the local - # namespace (so the newly defined parameter variables will be - # entered into param_dict). - exec fixPythonIndentation(param_code) in globals(), param_dict - except Exception, exc: - print "Param error in %s:" % path, exc - return - # Convert object name string to Python class object - obj = eval(obj_name) - # Set the object's parameter description dictionary (see MetaConfigNode). - obj.set_param_dict(param_dict) - - -# Walk directory tree to find .odesc files. -# Someday we'll have to make the root path an argument instead of -# hard-coding it. For now the assumption is you're running this in -# util/config. -root = '../..' -os.path.walk(root, find_odescs, None) - -# Iterate through file dictionary and define classes. -for objname, path in odesc_file.iteritems(): - if not odesc_loaded[objname]: - def_class(path) - -sim_object_list = odesc_loaded.keys() -sim_object_list.sort() - -# Iterate through files again and load parameters. -for path in odesc_file.itervalues(): - def_params(path) - -##################################################################### - # Hook to generate C++ parameter code. def gen_sim_code(file): for objname in sim_object_list: |