| # Copyright (c) 2005-2006 The Regents of The University of Michigan | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions are | |
| # met: redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer; | |
| # redistributions in binary form must reproduce the above copyright | |
| # notice, this list of conditions and the following disclaimer in the | |
| # documentation and/or other materials provided with the distribution; | |
| # neither the name of the copyright holders nor the names of its | |
| # contributors may be used to endorse or promote products derived from | |
| # this software without specific prior written permission. | |
| # | |
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| # | |
| # Authors: Nathan Binkert | |
| from __future__ import print_function | |
| 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__.iteritems(): | |
| if key.startswith('_') or key in ('name', 'desc'): | |
| continue | |
| if key not in self.__dict__: | |
| self.__dict__[key] = val | |
| continue | |
| if not isinstance(val, dict): | |
| if self.__dict__[key] == val: | |
| continue | |
| raise AttributeError, \ | |
| "%s specified more than once old: %s new: %s" % \ | |
| (key, self.__dict__[key], val) | |
| d = self.__dict__[key] | |
| for k,v in val.iteritems(): | |
| if k in d: | |
| raise AttributeError, \ | |
| "%s specified more than once in %s" % (k, key) | |
| d[k] = v | |
| if hasattr(self, 'system') and hasattr(obj, 'system'): | |
| if self.system != obj.system: | |
| raise AttributeError, \ | |
| "conflicting values for system: '%s'/'%s'" % \ | |
| (self.system, obj.system) | |
| def printinfo(self): | |
| if self.name: | |
| print('name: %s' % self.name) | |
| if self.desc: | |
| print('desc: %s' % self.desc) | |
| try: | |
| if self.system: | |
| print('system: %s' % self.system) | |
| except AttributeError: | |
| pass | |
| def printverbose(self): | |
| for key in self: | |
| val = self[key] | |
| if isinstance(val, dict): | |
| import pprint | |
| val = pprint.pformat(val) | |
| print('%-20s = %s' % (key, val)) | |
| print() | |
| def __contains__(self, attr): | |
| if attr.startswith('_'): | |
| return False | |
| return attr in self.__dict__ | |
| def __getitem__(self, key): | |
| if key.startswith('_'): | |
| raise KeyError, "Key '%s' not found" % attr | |
| return self.__dict__[key] | |
| def __iter__(self): | |
| keys = self.__dict__.keys() | |
| keys.sort() | |
| for key in keys: | |
| if not key.startswith('_'): | |
| yield key | |
| def optiondict(self): | |
| 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__.iteritems(): | |
| if not key.startswith('_'): | |
| d[key] = value | |
| return "<%s: %s>" % (type(self).__name__, d) | |
| def __str__(self): | |
| return self.name | |
| class Job(Data): | |
| def __init__(self, options): | |
| super(Job, self).__init__('', '') | |
| config = options[0]._config | |
| for opt in options: | |
| if opt._config != config: | |
| raise AttributeError, \ | |
| "All options are not from the same Configuration" | |
| self._config = config | |
| self._groups = [ opt._group for opt in options ] | |
| self._options = options | |
| self.update(self._config) | |
| for group in self._groups: | |
| self.update(group) | |
| self._is_checkpoint = True | |
| for option in self._options: | |
| self.update(option) | |
| if not option._group._checkpoint: | |
| self._is_checkpoint = False | |
| if option._suboption: | |
| self.update(option._suboption) | |
| self._is_checkpoint = False | |
| names = [ ] | |
| for opt in self._options: | |
| if opt.name: | |
| names.append(opt.name) | |
| self.name = ':'.join(names) | |
| descs = [ ] | |
| for opt in self._options: | |
| if opt.desc: | |
| descs.append(opt.desc) | |
| self.desc = ', '.join(descs) | |
| self._checkpoint = None | |
| if not self._is_checkpoint: | |
| opts = [] | |
| for opt in options: | |
| cpt = opt._group._checkpoint | |
| if not cpt: | |
| continue | |
| if isinstance(cpt, Option): | |
| opt = cpt.clone(suboptions=False) | |
| else: | |
| opt = opt.clone(suboptions=False) | |
| opts.append(opt) | |
| if opts: | |
| self._checkpoint = Job(opts) | |
| def clone(self): | |
| return Job(self._options) | |
| def printinfo(self): | |
| super(Job, self).printinfo() | |
| if self._checkpoint: | |
| print('checkpoint: %s' % self._checkpoint.name) | |
| print('config: %s' % self._config.name) | |
| print('groups: %s' % [ g.name for g in self._groups ]) | |
| print('options: %s' % [ o.name for o in self._options ]) | |
| super(Job, self).printverbose() | |
| class SubOption(Data): | |
| def __init__(self, name, desc, **kwargs): | |
| super(SubOption, self).__init__(name, desc, **kwargs) | |
| self._number = None | |
| class Option(Data): | |
| def __init__(self, name, desc, **kwargs): | |
| super(Option, self).__init__(name, desc, **kwargs) | |
| self._suboptions = [] | |
| self._suboption = None | |
| self._number = None | |
| def __getattribute__(self, attr): | |
| if attr == 'name': | |
| name = self.__dict__[attr] | |
| if self._suboption is not None: | |
| name = '%s:%s' % (name, self._suboption.name) | |
| return name | |
| if attr == 'desc': | |
| desc = [ self.__dict__[attr] ] | |
| if self._suboption is not None and self._suboption.desc: | |
| desc.append(self._suboption.desc) | |
| return ', '.join(desc) | |
| return super(Option, self).__getattribute__(attr) | |
| def suboption(self, name, desc, **kwargs): | |
| subo = SubOption(name, desc, **kwargs) | |
| subo._config = self._config | |
| subo._group = self._group | |
| subo._option = self | |
| subo._number = len(self._suboptions) | |
| self._suboptions.append(subo) | |
| return subo | |
| def clone(self, suboptions=True): | |
| option = Option(self.__dict__['name'], self.__dict__['desc']) | |
| option.update(self) | |
| option._group = self._group | |
| option._config = self._config | |
| option._number = self._number | |
| if suboptions: | |
| option._suboptions.extend(self._suboptions) | |
| option._suboption = self._suboption | |
| return option | |
| def subopts(self): | |
| if not self._suboptions: | |
| return [ self ] | |
| subopts = [] | |
| for subo in self._suboptions: | |
| option = self.clone() | |
| option._suboption = subo | |
| subopts.append(option) | |
| return subopts | |
| def printinfo(self): | |
| super(Option, self).printinfo() | |
| print('config: %s' % self._config.name) | |
| super(Option, self).printverbose() | |
| class Group(Data): | |
| def __init__(self, name, desc, **kwargs): | |
| super(Group, self).__init__(name, desc, **kwargs) | |
| self._options = [] | |
| self._number = None | |
| self._checkpoint = False | |
| def option(self, name, desc, **kwargs): | |
| opt = Option(name, desc, **kwargs) | |
| opt._config = self._config | |
| opt._group = self | |
| opt._number = len(self._options) | |
| self._options.append(opt) | |
| return opt | |
| def options(self): | |
| return self._options | |
| def subopts(self): | |
| subopts = [] | |
| for opt in self._options: | |
| for subo in opt.subopts(): | |
| subopts.append(subo) | |
| return subopts | |
| def printinfo(self): | |
| super(Group, self).printinfo() | |
| print('config: %s' % self._config.name) | |
| print('options: %s' % [ o.name for o in self._options ]) | |
| super(Group, self).printverbose() | |
| class Configuration(Data): | |
| def __init__(self, name, desc, **kwargs): | |
| super(Configuration, self).__init__(name, desc, **kwargs) | |
| self._groups = [] | |
| self._posfilters = [] | |
| self._negfilters = [] | |
| def group(self, name, desc, **kwargs): | |
| grp = Group(name, desc, **kwargs) | |
| grp._config = self | |
| grp._number = len(self._groups) | |
| self._groups.append(grp) | |
| return grp | |
| def groups(self): | |
| return self._groups | |
| def checkchildren(self, kids): | |
| for kid in kids: | |
| if kid._config != self: | |
| raise AttributeError, "child from the wrong configuration" | |
| def sortgroups(self, groups): | |
| groups = [ (grp._number, grp) for grp in groups ] | |
| groups.sort() | |
| return [ grp[1] for grp in groups ] | |
| def options(self, groups=None, checkpoint=False): | |
| if groups is None: | |
| groups = self._groups | |
| self.checkchildren(groups) | |
| groups = self.sortgroups(groups) | |
| if checkpoint: | |
| groups = [ grp for grp in groups if grp._checkpoint ] | |
| optgroups = [ g.options() for g in groups ] | |
| else: | |
| optgroups = [ g.subopts() for g in groups ] | |
| if not optgroups: | |
| return | |
| 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 = {} | |
| execfile(filename, data) | |
| if 'conf' not in data: | |
| raise ImportError, 'cannot import name conf from %s' % jobfile | |
| return data['conf'] | |
| def main(conf=None): | |
| usage = 'Usage: %s [-b] [-c] [-v]' % sys.argv[0] | |
| if conf is None: | |
| usage += ' <jobfile>' | |
| try: | |
| import getopt | |
| opts, args = getopt.getopt(sys.argv[1:], '-bcv') | |
| except getopt.GetoptError: | |
| sys.exit(usage) | |
| both = False | |
| checkpoint = False | |
| verbose = False | |
| for opt,arg in opts: | |
| if opt == '-b': | |
| both = True | |
| checkpoint = True | |
| if opt == '-c': | |
| checkpoint = True | |
| if opt == '-v': | |
| verbose = True | |
| if conf is None: | |
| if len(args) != 1: | |
| raise AttributeError, usage | |
| conf = JobFile(args[0]) | |
| else: | |
| if len(args) != 0: | |
| raise AttributeError, usage | |
| if both: | |
| jobs = conf.alljobs() | |
| elif checkpoint: | |
| jobs = conf.checkpoints() | |
| else: | |
| jobs = conf.jobs() | |
| for job in jobs: | |
| if verbose: | |
| job.printinfo() | |
| else: | |
| cpt = '' | |
| if job._checkpoint: | |
| cpt = job._checkpoint.name | |
| print(job.name, cpt) | |
| if __name__ == '__main__': | |
| main() |