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