# 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 from __future__ import absolute_import 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 += ' ' 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()