| # 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. |
| |
| import sys |
| |
| 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__.items(): |
| 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.items(): |
| 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 = list(self.__dict__.keys()) |
| keys.sort() |
| for key in keys: |
| if not key.startswith('_'): |
| yield key |
| |
| def optiondict(self): |
| import m5.util |
| result = m5.util.optiondict() |
| for key in self: |
| result[key] = self[key] |
| return result |
| |
| def __repr__(self): |
| d = {} |
| for key,value in self.__dict__.items(): |
| 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 |
| |
| import m5.util |
| for options in m5.util.crossproduct(optgroups): |
| for opt in options: |
| cpt = opt._group._checkpoint |
| if not isinstance(cpt, bool) and cpt != opt: |
| 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 = {} |
| exec(compile(open(filename).read(), filename, 'exec'), 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() |