|
# 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 |
|
|
|
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() |