jobfile.py revision 5467
12141SN/A# Copyright (c) 2005-2006 The Regents of The University of Michigan 21376SN/A# All rights reserved. 31376SN/A# 41376SN/A# Redistribution and use in source and binary forms, with or without 51376SN/A# modification, are permitted provided that the following conditions are 61376SN/A# met: redistributions of source code must retain the above copyright 71376SN/A# notice, this list of conditions and the following disclaimer; 81376SN/A# redistributions in binary form must reproduce the above copyright 91376SN/A# notice, this list of conditions and the following disclaimer in the 101376SN/A# documentation and/or other materials provided with the distribution; 111376SN/A# neither the name of the copyright holders nor the names of its 121376SN/A# contributors may be used to endorse or promote products derived from 131376SN/A# this software without specific prior written permission. 141376SN/A# 151376SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 161376SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 171376SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 181376SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 191376SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 201376SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 211376SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 221376SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 231376SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 241376SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 251376SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 261376SN/A# 271376SN/A# Authors: Nathan Binkert 281376SN/A 291428SN/Aimport sys 301428SN/A 315467Snate@binkert.orgfrom attrdict import attrdict, optiondict 325467Snate@binkert.orgfrom misc import crossproduct, flatten 331881SN/A 341881SN/Aclass Data(object): 351881SN/A def __init__(self, name, desc, **kwargs): 361881SN/A self.name = name 371881SN/A self.desc = desc 385467Snate@binkert.org self.__dict__.update(kwargs) 391881SN/A 401881SN/A def update(self, obj): 411881SN/A if not isinstance(obj, Data): 421881SN/A raise AttributeError, "can only update from Data object" 431881SN/A 445467Snate@binkert.org for k,v in obj.__dict__.iteritems(): 455467Snate@binkert.org if not k.startswith('_'): 465467Snate@binkert.org self.__dict__[k] = v 475467Snate@binkert.org if hasattr(self, 'system') and hasattr(obj, 'system'): 485467Snate@binkert.org if self.system != obj.system: 491881SN/A raise AttributeError, \ 501881SN/A "conflicting values for system: '%s'/'%s'" % \ 511881SN/A (self.system, obj.system) 521881SN/A 531881SN/A def printinfo(self): 541881SN/A if self.name: 551881SN/A print 'name: %s' % self.name 561881SN/A if self.desc: 571881SN/A print 'desc: %s' % self.desc 585467Snate@binkert.org try: 595467Snate@binkert.org if self.system: 605467Snate@binkert.org print 'system: %s' % self.system 615467Snate@binkert.org except AttributeError: 625467Snate@binkert.org pass 631881SN/A 641881SN/A def printverbose(self): 655467Snate@binkert.org for key in self: 665467Snate@binkert.org val = self[key] 675467Snate@binkert.org if isinstance(val, dict): 685467Snate@binkert.org import pprint 695467Snate@binkert.org val = pprint.pformat(val) 705467Snate@binkert.org print '%-20s = %s' % (key, val) 715467Snate@binkert.org print 725467Snate@binkert.org 735467Snate@binkert.org def __contains__(self, attr): 745467Snate@binkert.org if attr.startswith('_'): 755467Snate@binkert.org return False 765467Snate@binkert.org return attr in self.__dict__ 775467Snate@binkert.org 785467Snate@binkert.org def __getitem__(self, key): 795467Snate@binkert.org if key.startswith('_'): 805467Snate@binkert.org raise KeyError, "Key '%s' not found" % attr 815467Snate@binkert.org return self.__dict__[key] 825467Snate@binkert.org 835467Snate@binkert.org def __iter__(self): 845467Snate@binkert.org keys = self.__dict__.keys() 851881SN/A keys.sort() 861881SN/A for key in keys: 875467Snate@binkert.org if not key.startswith('_'): 885467Snate@binkert.org yield key 895467Snate@binkert.org 905467Snate@binkert.org def optiondict(self): 915467Snate@binkert.org result = optiondict() 925467Snate@binkert.org for key in self: 935467Snate@binkert.org result[key] = self[key] 945467Snate@binkert.org return result 951881SN/A 961881SN/A def __str__(self): 971881SN/A return self.name 981881SN/A 991881SN/Aclass Job(Data): 1001881SN/A def __init__(self, options): 1011881SN/A super(Job, self).__init__('', '') 1021881SN/A 1035467Snate@binkert.org config = options[0]._config 1041881SN/A for opt in options: 1055467Snate@binkert.org if opt._config != config: 1061881SN/A raise AttributeError, \ 1071881SN/A "All options are not from the same Configuration" 1081881SN/A 1095467Snate@binkert.org self._config = config 1105467Snate@binkert.org self._groups = [ opt._group for opt in options ] 1115467Snate@binkert.org self._options = options 1121881SN/A 1135467Snate@binkert.org self.update(self._config) 1145467Snate@binkert.org for group in self._groups: 1151881SN/A self.update(group) 1161881SN/A 1175467Snate@binkert.org self._is_checkpoint = True 1185467Snate@binkert.org 1195467Snate@binkert.org for option in self._options: 1201881SN/A self.update(option) 1215467Snate@binkert.org if not option._group._checkpoint: 1225467Snate@binkert.org self._is_checkpoint = False 1235467Snate@binkert.org 1241881SN/A if option._suboption: 1251881SN/A self.update(option._suboption) 1265467Snate@binkert.org self._is_checkpoint = False 1275467Snate@binkert.org 1285467Snate@binkert.org names = [ ] 1295467Snate@binkert.org for opt in self._options: 1305467Snate@binkert.org if opt.name: 1315467Snate@binkert.org names.append(opt.name) 1325467Snate@binkert.org self.name = ':'.join(names) 1335467Snate@binkert.org 1345467Snate@binkert.org descs = [ ] 1355467Snate@binkert.org for opt in self._options: 1365467Snate@binkert.org if opt.desc: 1375467Snate@binkert.org descs.append(opt.desc) 1385467Snate@binkert.org self.desc = ', '.join(descs) 1395467Snate@binkert.org 1405467Snate@binkert.org self._checkpoint = None 1415467Snate@binkert.org if not self._is_checkpoint: 1425467Snate@binkert.org opts = [] 1435467Snate@binkert.org for opt in options: 1445467Snate@binkert.org cpt = opt._group._checkpoint 1455467Snate@binkert.org if not cpt: 1465467Snate@binkert.org continue 1475467Snate@binkert.org if isinstance(cpt, Option): 1485467Snate@binkert.org opt = cpt.clone(suboptions=False) 1495467Snate@binkert.org else: 1505467Snate@binkert.org opt = opt.clone(suboptions=False) 1515467Snate@binkert.org 1525467Snate@binkert.org opts.append(opt) 1535467Snate@binkert.org 1545467Snate@binkert.org if opts: 1555467Snate@binkert.org self._checkpoint = Job(opts) 1565467Snate@binkert.org 1575467Snate@binkert.org def clone(self): 1585467Snate@binkert.org return Job(self._options) 1591881SN/A 1601881SN/A def printinfo(self): 1611881SN/A super(Job, self).printinfo() 1625467Snate@binkert.org if self._checkpoint: 1635467Snate@binkert.org print 'checkpoint: %s' % self._checkpoint.name 1645467Snate@binkert.org print 'config: %s' % self._config.name 1655467Snate@binkert.org print 'groups: %s' % [ g.name for g in self._groups ] 1665467Snate@binkert.org print 'options: %s' % [ o.name for o in self._options ] 1671881SN/A super(Job, self).printverbose() 1681881SN/A 1691881SN/Aclass SubOption(Data): 1701881SN/A def __init__(self, name, desc, **kwargs): 1711881SN/A super(SubOption, self).__init__(name, desc, **kwargs) 1725467Snate@binkert.org self._number = None 1731881SN/A 1741881SN/Aclass Option(Data): 1751881SN/A def __init__(self, name, desc, **kwargs): 1761881SN/A super(Option, self).__init__(name, desc, **kwargs) 1771881SN/A self._suboptions = [] 1781881SN/A self._suboption = None 1795467Snate@binkert.org self._number = None 1801881SN/A 1811881SN/A def __getattribute__(self, attr): 1821881SN/A if attr == 'name': 1831881SN/A name = self.__dict__[attr] 1841881SN/A if self._suboption is not None: 1851881SN/A name = '%s:%s' % (name, self._suboption.name) 1861881SN/A return name 1871881SN/A 1881881SN/A if attr == 'desc': 1892142SN/A desc = [ self.__dict__[attr] ] 1902142SN/A if self._suboption is not None and self._suboption.desc: 1912142SN/A desc.append(self._suboption.desc) 1922142SN/A return ', '.join(desc) 1932142SN/A 1941881SN/A return super(Option, self).__getattribute__(attr) 1951881SN/A 1961881SN/A def suboption(self, name, desc, **kwargs): 1971881SN/A subo = SubOption(name, desc, **kwargs) 1985467Snate@binkert.org subo._config = self._config 1995467Snate@binkert.org subo._group = self._group 2005467Snate@binkert.org subo._option = self 2015467Snate@binkert.org subo._number = len(self._suboptions) 2021881SN/A self._suboptions.append(subo) 2031881SN/A return subo 2041881SN/A 2051881SN/A def clone(self, suboptions=True): 2061881SN/A option = Option(self.__dict__['name'], self.__dict__['desc']) 2071881SN/A option.update(self) 2085467Snate@binkert.org option._group = self._group 2095467Snate@binkert.org option._config = self._config 2105467Snate@binkert.org option._number = self._number 2111881SN/A if suboptions: 2121881SN/A option._suboptions.extend(self._suboptions) 2131881SN/A option._suboption = self._suboption 2141881SN/A return option 2151881SN/A 2161881SN/A def subopts(self): 2171881SN/A if not self._suboptions: 2181881SN/A return [ self ] 2191881SN/A 2201881SN/A subopts = [] 2211881SN/A for subo in self._suboptions: 2221881SN/A option = self.clone() 2231881SN/A option._suboption = subo 2241881SN/A subopts.append(option) 2251881SN/A 2261881SN/A return subopts 2271881SN/A 2281881SN/A def printinfo(self): 2291881SN/A super(Option, self).printinfo() 2305467Snate@binkert.org print 'config: %s' % self._config.name 2311881SN/A super(Option, self).printverbose() 2321881SN/A 2331881SN/Aclass Group(Data): 2341881SN/A def __init__(self, name, desc, **kwargs): 2351881SN/A super(Group, self).__init__(name, desc, **kwargs) 2361881SN/A self._options = [] 2375467Snate@binkert.org self._number = None 2385467Snate@binkert.org self._checkpoint = False 2391881SN/A 2401881SN/A def option(self, name, desc, **kwargs): 2411881SN/A opt = Option(name, desc, **kwargs) 2425467Snate@binkert.org opt._config = self._config 2435467Snate@binkert.org opt._group = self 2445467Snate@binkert.org opt._number = len(self._options) 2451881SN/A self._options.append(opt) 2461881SN/A return opt 2471881SN/A 2481881SN/A def options(self): 2491881SN/A return self._options 2501881SN/A 2511881SN/A def subopts(self): 2521881SN/A subopts = [] 2531881SN/A for opt in self._options: 2541881SN/A for subo in opt.subopts(): 2551881SN/A subopts.append(subo) 2561881SN/A return subopts 2571881SN/A 2581881SN/A def printinfo(self): 2591881SN/A super(Group, self).printinfo() 2605467Snate@binkert.org print 'config: %s' % self._config.name 2611881SN/A print 'options: %s' % [ o.name for o in self._options ] 2621881SN/A super(Group, self).printverbose() 2631881SN/A 2641881SN/Aclass Configuration(Data): 2651881SN/A def __init__(self, name, desc, **kwargs): 2661881SN/A super(Configuration, self).__init__(name, desc, **kwargs) 2671881SN/A self._groups = [] 2682141SN/A self._posfilters = [] 2692141SN/A self._negfilters = [] 2701881SN/A 2711881SN/A def group(self, name, desc, **kwargs): 2721881SN/A grp = Group(name, desc, **kwargs) 2735467Snate@binkert.org grp._config = self 2745467Snate@binkert.org grp._number = len(self._groups) 2751881SN/A self._groups.append(grp) 2761881SN/A return grp 2771881SN/A 2785467Snate@binkert.org def groups(self): 2795467Snate@binkert.org return self._groups 2801881SN/A 2811881SN/A def checkchildren(self, kids): 2821881SN/A for kid in kids: 2835467Snate@binkert.org if kid._config != self: 2841881SN/A raise AttributeError, "child from the wrong configuration" 2851881SN/A 2861881SN/A def sortgroups(self, groups): 2875467Snate@binkert.org groups = [ (grp._number, grp) for grp in groups ] 2881881SN/A groups.sort() 2891881SN/A return [ grp[1] for grp in groups ] 2901881SN/A 2915467Snate@binkert.org def options(self, groups=None, checkpoint=False): 2921881SN/A if groups is None: 2931881SN/A groups = self._groups 2941881SN/A self.checkchildren(groups) 2951881SN/A groups = self.sortgroups(groups) 2961881SN/A if checkpoint: 2975467Snate@binkert.org groups = [ grp for grp in groups if grp._checkpoint ] 2981881SN/A optgroups = [ g.options() for g in groups ] 2991881SN/A else: 3001881SN/A optgroups = [ g.subopts() for g in groups ] 3015467Snate@binkert.org if not optgroups: 3025467Snate@binkert.org return 3031881SN/A for options in crossproduct(optgroups): 3041881SN/A for opt in options: 3055467Snate@binkert.org cpt = opt._group._checkpoint 3061881SN/A if not isinstance(cpt, bool) and cpt != opt: 3071881SN/A if checkpoint: 3081881SN/A break 3091881SN/A else: 3101881SN/A yield options 3111881SN/A else: 3121881SN/A if checkpoint: 3131881SN/A yield options 3141881SN/A 3152141SN/A def addfilter(self, filt, pos=True): 3162141SN/A import re 3172141SN/A filt = re.compile(filt) 3182141SN/A if pos: 3192141SN/A self._posfilters.append(filt) 3202141SN/A else: 3212141SN/A self._negfilters.append(filt) 3222141SN/A 3232141SN/A def jobfilter(self, job): 3242141SN/A for filt in self._negfilters: 3252141SN/A if filt.match(job.name): 3262141SN/A return False 3272141SN/A 3282141SN/A if not self._posfilters: 3292141SN/A return True 3302141SN/A 3312141SN/A for filt in self._posfilters: 3322141SN/A if filt.match(job.name): 3332141SN/A return True 3342141SN/A 3352141SN/A return False 3362141SN/A 3375467Snate@binkert.org def checkpoints(self, groups=None): 3381881SN/A for options in self.options(groups, True): 3392141SN/A job = Job(options) 3402141SN/A if self.jobfilter(job): 3412141SN/A yield job 3421881SN/A 3435467Snate@binkert.org def jobs(self, groups=None): 3441881SN/A for options in self.options(groups, False): 3452141SN/A job = Job(options) 3462141SN/A if self.jobfilter(job): 3472141SN/A yield job 3481881SN/A 3495467Snate@binkert.org def alljobs(self, groups=None): 3501881SN/A for options in self.options(groups, True): 3511881SN/A yield Job(options) 3521881SN/A for options in self.options(groups, False): 3531881SN/A yield Job(options) 3541881SN/A 3551881SN/A def find(self, jobname): 3561881SN/A for job in self.alljobs(): 3571881SN/A if job.name == jobname: 3581881SN/A return job 3591881SN/A else: 3601881SN/A raise AttributeError, "job '%s' not found" % jobname 3611881SN/A 3621881SN/A def job(self, options): 3631881SN/A self.checkchildren(options) 3645467Snate@binkert.org options = [ (opt._group._number, opt) for opt in options ] 3651881SN/A options.sort() 3661881SN/A options = [ opt[1] for opt in options ] 3671881SN/A job = Job(options) 3681881SN/A return job 3691881SN/A 3701881SN/A def printinfo(self): 3711881SN/A super(Configuration, self).printinfo() 3725467Snate@binkert.org print 'groups: %s' % [ g.name for g in self._groups ] 3731881SN/A super(Configuration, self).printverbose() 3741881SN/A 3751881SN/Adef JobFile(jobfile): 3761881SN/A from os.path import expanduser, isfile, join as joinpath 3771881SN/A filename = expanduser(jobfile) 3781881SN/A 3791881SN/A # Can't find filename in the current path, search sys.path 3801881SN/A if not isfile(filename): 3811881SN/A for path in sys.path: 3821881SN/A testname = joinpath(path, filename) 3831881SN/A if isfile(testname): 3841881SN/A filename = testname 3851881SN/A break 3861881SN/A else: 3871881SN/A raise AttributeError, \ 3881881SN/A "Could not find file '%s'" % jobfile 3891881SN/A 3901881SN/A data = {} 3911881SN/A execfile(filename, data) 3921881SN/A if 'conf' not in data: 3931881SN/A raise ImportError, 'cannot import name conf from %s' % jobfile 3941881SN/A conf = data['conf'] 3951881SN/A import jobfile 3961881SN/A if not isinstance(conf, Configuration): 3971881SN/A raise AttributeError, \ 3981881SN/A 'conf in jobfile: %s (%s) is not type %s' % \ 3991881SN/A (jobfile, type(conf), Configuration) 4001881SN/A return conf 4011881SN/A 4025467Snate@binkert.orgdef main(conf=None): 4031881SN/A import sys 4041881SN/A 4051881SN/A usage = 'Usage: %s [-b] [-c] [-v] <jobfile>' % sys.argv[0] 4061881SN/A 4071881SN/A try: 4081881SN/A import getopt 4091881SN/A opts, args = getopt.getopt(sys.argv[1:], '-bcv') 4101881SN/A except getopt.GetoptError: 4111881SN/A sys.exit(usage) 4121881SN/A 4131881SN/A both = False 4141881SN/A checkpoint = False 4151881SN/A verbose = False 4161881SN/A for opt,arg in opts: 4171881SN/A if opt == '-b': 4181881SN/A both = True 4191881SN/A checkpoint = True 4201881SN/A if opt == '-c': 4211881SN/A checkpoint = True 4221881SN/A if opt == '-v': 4231881SN/A verbose = True 4241881SN/A 4255467Snate@binkert.org if conf is None: 4265467Snate@binkert.org if len(args) != 1: 4275467Snate@binkert.org raise AttributeError, usage 4285467Snate@binkert.org conf = JobFile(args[0]) 4295467Snate@binkert.org else: 4305467Snate@binkert.org if len(args) != 0: 4315467Snate@binkert.org raise AttributeError, usage 4321881SN/A 4331881SN/A if both: 4345467Snate@binkert.org jobs = conf.alljobs() 4351881SN/A elif checkpoint: 4365467Snate@binkert.org jobs = conf.checkpoints() 4371881SN/A else: 4385467Snate@binkert.org jobs = conf.jobs() 4391881SN/A 4405467Snate@binkert.org for job in jobs: 4415467Snate@binkert.org if verbose: 4425467Snate@binkert.org job.printinfo() 4435467Snate@binkert.org else: 4441881SN/A cpt = '' 4455467Snate@binkert.org if job._checkpoint: 4465467Snate@binkert.org cpt = job._checkpoint.name 4471881SN/A print job.name, cpt 4485467Snate@binkert.org 4495467Snate@binkert.orgif __name__ == '__main__': 4505467Snate@binkert.org main() 451