jobfile.py revision 13663
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
2912563Sgabeblack@google.comfrom __future__ import print_function
3012563Sgabeblack@google.com
311428SN/Aimport sys
321428SN/A
331881SN/Aclass Data(object):
341881SN/A    def __init__(self, name, desc, **kwargs):
351881SN/A        self.name = name
361881SN/A        self.desc = desc
375467Snate@binkert.org        self.__dict__.update(kwargs)
381881SN/A
391881SN/A    def update(self, obj):
401881SN/A        if not isinstance(obj, Data):
4113663Sandreas.sandberg@arm.com            raise AttributeError("can only update from Data object")
421881SN/A
435618Snate@binkert.org        for key,val in obj.__dict__.iteritems():
445618Snate@binkert.org            if key.startswith('_') or key in ('name', 'desc'):
455618Snate@binkert.org                continue
465618Snate@binkert.org
475618Snate@binkert.org            if key not in self.__dict__:
485618Snate@binkert.org                self.__dict__[key] = val
495618Snate@binkert.org                continue
505618Snate@binkert.org
515618Snate@binkert.org            if not isinstance(val, dict):
525618Snate@binkert.org                if self.__dict__[key] == val:
535618Snate@binkert.org                    continue
545618Snate@binkert.org
5513663Sandreas.sandberg@arm.com                raise AttributeError(
5613663Sandreas.sandberg@arm.com                    "%s specified more than once old: %s new: %s" % \
5713663Sandreas.sandberg@arm.com                    (key, self.__dict__[key], val))
585618Snate@binkert.org
595618Snate@binkert.org            d = self.__dict__[key]
605618Snate@binkert.org            for k,v in val.iteritems():
615618Snate@binkert.org                if k in d:
6213663Sandreas.sandberg@arm.com                    raise AttributeError(
6313663Sandreas.sandberg@arm.com                        "%s specified more than once in %s" % (k, key))
645618Snate@binkert.org                d[k] = v
655618Snate@binkert.org
665467Snate@binkert.org        if hasattr(self, 'system') and hasattr(obj, 'system'):
675467Snate@binkert.org            if self.system != obj.system:
6813663Sandreas.sandberg@arm.com                raise AttributeError(
6913663Sandreas.sandberg@arm.com                    "conflicting values for system: '%s'/'%s'" % \
7013663Sandreas.sandberg@arm.com                    (self.system, obj.system))
711881SN/A
721881SN/A    def printinfo(self):
731881SN/A        if self.name:
7412563Sgabeblack@google.com            print('name: %s' % self.name)
751881SN/A        if self.desc:
7612563Sgabeblack@google.com            print('desc: %s' % self.desc)
775467Snate@binkert.org        try:
785467Snate@binkert.org            if self.system:
7912563Sgabeblack@google.com                print('system: %s' % self.system)
805467Snate@binkert.org        except AttributeError:
815467Snate@binkert.org            pass
821881SN/A
831881SN/A    def printverbose(self):
845467Snate@binkert.org        for key in self:
855467Snate@binkert.org            val = self[key]
865467Snate@binkert.org            if isinstance(val, dict):
875467Snate@binkert.org                import pprint
885467Snate@binkert.org                val = pprint.pformat(val)
8912563Sgabeblack@google.com            print('%-20s = %s' % (key, val))
9012563Sgabeblack@google.com        print()
915467Snate@binkert.org
925467Snate@binkert.org    def __contains__(self, attr):
935467Snate@binkert.org        if attr.startswith('_'):
945467Snate@binkert.org            return False
955467Snate@binkert.org        return attr in self.__dict__
965467Snate@binkert.org
975467Snate@binkert.org    def __getitem__(self, key):
985467Snate@binkert.org        if key.startswith('_'):
9913663Sandreas.sandberg@arm.com            raise KeyError("Key '%s' not found" % attr)
1005467Snate@binkert.org        return self.__dict__[key]
1015467Snate@binkert.org
1025467Snate@binkert.org    def __iter__(self):
1035467Snate@binkert.org        keys = self.__dict__.keys()
1041881SN/A        keys.sort()
1051881SN/A        for key in keys:
1065467Snate@binkert.org            if not key.startswith('_'):
1075467Snate@binkert.org                yield key
1085467Snate@binkert.org
1095467Snate@binkert.org    def optiondict(self):
1106654Snate@binkert.org        import m5.util
1116654Snate@binkert.org        result = m5.util.optiondict()
1125467Snate@binkert.org        for key in self:
1135467Snate@binkert.org            result[key] = self[key]
1145467Snate@binkert.org        return result
1151881SN/A
1165618Snate@binkert.org    def __repr__(self):
1175618Snate@binkert.org        d = {}
1185618Snate@binkert.org        for key,value in self.__dict__.iteritems():
1195618Snate@binkert.org            if not key.startswith('_'):
1205618Snate@binkert.org                d[key] = value
1215618Snate@binkert.org
1225618Snate@binkert.org        return "<%s: %s>" % (type(self).__name__, d)
1235618Snate@binkert.org
1241881SN/A    def __str__(self):
1251881SN/A        return self.name
1261881SN/A
1271881SN/Aclass Job(Data):
1281881SN/A    def __init__(self, options):
1291881SN/A        super(Job, self).__init__('', '')
1301881SN/A
1315467Snate@binkert.org        config = options[0]._config
1321881SN/A        for opt in options:
1335467Snate@binkert.org            if opt._config != config:
13413663Sandreas.sandberg@arm.com                raise AttributeError(
13513663Sandreas.sandberg@arm.com                    "All options are not from the same Configuration")
1361881SN/A
1375467Snate@binkert.org        self._config = config
1385467Snate@binkert.org        self._groups = [ opt._group for opt in options ]
1395467Snate@binkert.org        self._options = options
1401881SN/A
1415467Snate@binkert.org        self.update(self._config)
1425467Snate@binkert.org        for group in self._groups:
1431881SN/A            self.update(group)
1441881SN/A
1455467Snate@binkert.org        self._is_checkpoint = True
1465467Snate@binkert.org
1475467Snate@binkert.org        for option in self._options:
1481881SN/A            self.update(option)
1495467Snate@binkert.org            if not option._group._checkpoint:
1505467Snate@binkert.org                self._is_checkpoint = False
1515467Snate@binkert.org
1521881SN/A            if option._suboption:
1531881SN/A                self.update(option._suboption)
1545467Snate@binkert.org                self._is_checkpoint = False
1555467Snate@binkert.org
1565467Snate@binkert.org        names = [ ]
1575467Snate@binkert.org        for opt in self._options:
1585467Snate@binkert.org            if opt.name:
1595467Snate@binkert.org                names.append(opt.name)
1605467Snate@binkert.org        self.name = ':'.join(names)
1615467Snate@binkert.org
1625467Snate@binkert.org        descs = [ ]
1635467Snate@binkert.org        for opt in self._options:
1645467Snate@binkert.org            if opt.desc:
1655467Snate@binkert.org                descs.append(opt.desc)
1665467Snate@binkert.org        self.desc = ', '.join(descs)
1675467Snate@binkert.org
1685467Snate@binkert.org        self._checkpoint = None
1695467Snate@binkert.org        if not self._is_checkpoint:
1705467Snate@binkert.org            opts = []
1715467Snate@binkert.org            for opt in options:
1725467Snate@binkert.org                cpt = opt._group._checkpoint
1735467Snate@binkert.org                if not cpt:
1745467Snate@binkert.org                    continue
1755467Snate@binkert.org                if isinstance(cpt, Option):
1765467Snate@binkert.org                    opt = cpt.clone(suboptions=False)
1775467Snate@binkert.org                else:
1785467Snate@binkert.org                    opt = opt.clone(suboptions=False)
1795467Snate@binkert.org
1805467Snate@binkert.org                opts.append(opt)
1815467Snate@binkert.org
1825467Snate@binkert.org            if opts:
1835467Snate@binkert.org                self._checkpoint = Job(opts)
1845467Snate@binkert.org
1855467Snate@binkert.org    def clone(self):
1865467Snate@binkert.org        return Job(self._options)
1871881SN/A
1881881SN/A    def printinfo(self):
1891881SN/A        super(Job, self).printinfo()
1905467Snate@binkert.org        if self._checkpoint:
19112563Sgabeblack@google.com            print('checkpoint: %s' % self._checkpoint.name)
19212563Sgabeblack@google.com        print('config: %s' % self._config.name)
19312563Sgabeblack@google.com        print('groups: %s' % [ g.name for g in self._groups ])
19412563Sgabeblack@google.com        print('options: %s' % [ o.name for o in self._options ])
1951881SN/A        super(Job, self).printverbose()
1961881SN/A
1971881SN/Aclass SubOption(Data):
1981881SN/A    def __init__(self, name, desc, **kwargs):
1991881SN/A        super(SubOption, self).__init__(name, desc, **kwargs)
2005467Snate@binkert.org        self._number = None
2011881SN/A
2021881SN/Aclass Option(Data):
2031881SN/A    def __init__(self, name, desc, **kwargs):
2041881SN/A        super(Option, self).__init__(name, desc, **kwargs)
2051881SN/A        self._suboptions = []
2061881SN/A        self._suboption = None
2075467Snate@binkert.org        self._number = None
2081881SN/A
2091881SN/A    def __getattribute__(self, attr):
2101881SN/A        if attr == 'name':
2111881SN/A            name = self.__dict__[attr]
2121881SN/A            if self._suboption is not None:
2131881SN/A                name = '%s:%s' % (name, self._suboption.name)
2141881SN/A            return name
2151881SN/A
2161881SN/A        if attr == 'desc':
2172142SN/A            desc = [ self.__dict__[attr] ]
2182142SN/A            if self._suboption is not None and self._suboption.desc:
2192142SN/A                desc.append(self._suboption.desc)
2202142SN/A            return ', '.join(desc)
2212142SN/A
2221881SN/A        return super(Option, self).__getattribute__(attr)
2231881SN/A
2241881SN/A    def suboption(self, name, desc, **kwargs):
2251881SN/A        subo = SubOption(name, desc, **kwargs)
2265467Snate@binkert.org        subo._config = self._config
2275467Snate@binkert.org        subo._group = self._group
2285467Snate@binkert.org        subo._option = self
2295467Snate@binkert.org        subo._number = len(self._suboptions)
2301881SN/A        self._suboptions.append(subo)
2311881SN/A        return subo
2321881SN/A
2331881SN/A    def clone(self, suboptions=True):
2341881SN/A        option = Option(self.__dict__['name'], self.__dict__['desc'])
2351881SN/A        option.update(self)
2365467Snate@binkert.org        option._group = self._group
2375467Snate@binkert.org        option._config = self._config
2385467Snate@binkert.org        option._number = self._number
2391881SN/A        if suboptions:
2401881SN/A            option._suboptions.extend(self._suboptions)
2411881SN/A            option._suboption = self._suboption
2421881SN/A        return option
2431881SN/A
2441881SN/A    def subopts(self):
2451881SN/A        if not self._suboptions:
2461881SN/A            return [ self ]
2471881SN/A
2481881SN/A        subopts = []
2491881SN/A        for subo in self._suboptions:
2501881SN/A            option = self.clone()
2511881SN/A            option._suboption = subo
2521881SN/A            subopts.append(option)
2531881SN/A
2541881SN/A        return subopts
2551881SN/A
2561881SN/A    def printinfo(self):
2571881SN/A        super(Option, self).printinfo()
25812563Sgabeblack@google.com        print('config: %s' % self._config.name)
2591881SN/A        super(Option, self).printverbose()
2601881SN/A
2611881SN/Aclass Group(Data):
2621881SN/A    def __init__(self, name, desc, **kwargs):
2631881SN/A        super(Group, self).__init__(name, desc, **kwargs)
2641881SN/A        self._options = []
2655467Snate@binkert.org        self._number = None
2665467Snate@binkert.org        self._checkpoint = False
2671881SN/A
2681881SN/A    def option(self, name, desc, **kwargs):
2691881SN/A        opt = Option(name, desc, **kwargs)
2705467Snate@binkert.org        opt._config = self._config
2715467Snate@binkert.org        opt._group = self
2725467Snate@binkert.org        opt._number = len(self._options)
2731881SN/A        self._options.append(opt)
2741881SN/A        return opt
2751881SN/A
2761881SN/A    def options(self):
2771881SN/A        return self._options
2781881SN/A
2791881SN/A    def subopts(self):
2801881SN/A        subopts = []
2811881SN/A        for opt in self._options:
2821881SN/A            for subo in opt.subopts():
2831881SN/A                subopts.append(subo)
2841881SN/A        return subopts
2851881SN/A
2861881SN/A    def printinfo(self):
2871881SN/A        super(Group, self).printinfo()
28812563Sgabeblack@google.com        print('config: %s' % self._config.name)
28912563Sgabeblack@google.com        print('options: %s' % [ o.name for o in self._options ])
2901881SN/A        super(Group, self).printverbose()
2911881SN/A
2921881SN/Aclass Configuration(Data):
2931881SN/A    def __init__(self, name, desc, **kwargs):
2941881SN/A        super(Configuration, self).__init__(name, desc, **kwargs)
2951881SN/A        self._groups = []
2962141SN/A        self._posfilters = []
2972141SN/A        self._negfilters = []
2981881SN/A
2991881SN/A    def group(self, name, desc, **kwargs):
3001881SN/A        grp = Group(name, desc, **kwargs)
3015467Snate@binkert.org        grp._config = self
3025467Snate@binkert.org        grp._number = len(self._groups)
3031881SN/A        self._groups.append(grp)
3041881SN/A        return grp
3051881SN/A
3065467Snate@binkert.org    def groups(self):
3075467Snate@binkert.org        return self._groups
3081881SN/A
3091881SN/A    def checkchildren(self, kids):
3101881SN/A        for kid in kids:
3115467Snate@binkert.org            if kid._config != self:
31213663Sandreas.sandberg@arm.com                raise AttributeError("child from the wrong configuration")
3131881SN/A
3141881SN/A    def sortgroups(self, groups):
3155467Snate@binkert.org        groups = [ (grp._number, grp) for grp in groups ]
3161881SN/A        groups.sort()
3171881SN/A        return [ grp[1] for grp in groups ]
3181881SN/A
3195467Snate@binkert.org    def options(self, groups=None, checkpoint=False):
3201881SN/A        if groups is None:
3211881SN/A            groups = self._groups
3221881SN/A        self.checkchildren(groups)
3231881SN/A        groups = self.sortgroups(groups)
3241881SN/A        if checkpoint:
3255467Snate@binkert.org            groups = [ grp for grp in groups if grp._checkpoint ]
3261881SN/A            optgroups = [ g.options() for g in groups ]
3271881SN/A        else:
3281881SN/A            optgroups = [ g.subopts() for g in groups ]
3295467Snate@binkert.org        if not optgroups:
3305467Snate@binkert.org            return
3316654Snate@binkert.org
3326654Snate@binkert.org        import m5.util
3336654Snate@binkert.org        for options in m5.util.crossproduct(optgroups):
3341881SN/A            for opt in options:
3355467Snate@binkert.org                cpt = opt._group._checkpoint
3361881SN/A                if not isinstance(cpt, bool) and cpt != opt:
3371881SN/A                    if checkpoint:
3381881SN/A                        break
3391881SN/A                    else:
3401881SN/A                        yield options
3411881SN/A            else:
3421881SN/A                if checkpoint:
3431881SN/A                    yield options
3441881SN/A
3452141SN/A    def addfilter(self, filt, pos=True):
3462141SN/A        import re
3472141SN/A        filt = re.compile(filt)
3482141SN/A        if pos:
3492141SN/A            self._posfilters.append(filt)
3502141SN/A        else:
3512141SN/A            self._negfilters.append(filt)
3522141SN/A
3532141SN/A    def jobfilter(self, job):
3542141SN/A        for filt in self._negfilters:
3552141SN/A            if filt.match(job.name):
3562141SN/A                return False
3572141SN/A
3582141SN/A        if not self._posfilters:
3592141SN/A            return True
3602141SN/A
3612141SN/A        for filt in self._posfilters:
3622141SN/A            if filt.match(job.name):
3632141SN/A                return True
3642141SN/A
3652141SN/A        return False
3662141SN/A
3675467Snate@binkert.org    def checkpoints(self, groups=None):
3681881SN/A        for options in self.options(groups, True):
3692141SN/A            job = Job(options)
3702141SN/A            if self.jobfilter(job):
3712141SN/A                yield job
3721881SN/A
3735467Snate@binkert.org    def jobs(self, groups=None):
3741881SN/A        for options in self.options(groups, False):
3752141SN/A            job = Job(options)
3762141SN/A            if self.jobfilter(job):
3772141SN/A                yield job
3781881SN/A
3795467Snate@binkert.org    def alljobs(self, groups=None):
3801881SN/A        for options in self.options(groups, True):
3811881SN/A            yield Job(options)
3821881SN/A        for options in self.options(groups, False):
3831881SN/A            yield Job(options)
3841881SN/A
3851881SN/A    def find(self, jobname):
3861881SN/A        for job in self.alljobs():
3871881SN/A            if job.name == jobname:
3881881SN/A                return job
3891881SN/A        else:
39013663Sandreas.sandberg@arm.com            raise AttributeError("job '%s' not found" % jobname)
3911881SN/A
3921881SN/A    def job(self, options):
3931881SN/A        self.checkchildren(options)
3945467Snate@binkert.org        options = [ (opt._group._number, opt) for opt in options ]
3951881SN/A        options.sort()
3961881SN/A        options = [ opt[1] for opt in options ]
3971881SN/A        job = Job(options)
3981881SN/A        return job
3991881SN/A
4001881SN/A    def printinfo(self):
4011881SN/A        super(Configuration, self).printinfo()
40212563Sgabeblack@google.com        print('groups: %s' % [ g.name for g in self._groups ])
4031881SN/A        super(Configuration, self).printverbose()
4041881SN/A
4051881SN/Adef JobFile(jobfile):
4061881SN/A    from os.path import expanduser, isfile, join as joinpath
4071881SN/A    filename = expanduser(jobfile)
4081881SN/A
4091881SN/A    # Can't find filename in the current path, search sys.path
4101881SN/A    if not isfile(filename):
4111881SN/A        for path in sys.path:
4121881SN/A            testname = joinpath(path, filename)
4131881SN/A            if isfile(testname):
4141881SN/A                filename = testname
4151881SN/A                break
4161881SN/A        else:
41713663Sandreas.sandberg@arm.com            raise AttributeError("Could not find file '%s'" % jobfile)
4181881SN/A
4191881SN/A    data = {}
4201881SN/A    execfile(filename, data)
4211881SN/A    if 'conf' not in data:
42213663Sandreas.sandberg@arm.com        raise ImportError('cannot import name conf from %s' % jobfile)
4235618Snate@binkert.org    return data['conf']
4241881SN/A
4255467Snate@binkert.orgdef main(conf=None):
4265618Snate@binkert.org    usage = 'Usage: %s [-b] [-c] [-v]' % sys.argv[0]
4275618Snate@binkert.org    if conf is None:
4285618Snate@binkert.org        usage += ' <jobfile>'
4291881SN/A
4301881SN/A    try:
4311881SN/A        import getopt
4321881SN/A        opts, args = getopt.getopt(sys.argv[1:], '-bcv')
4331881SN/A    except getopt.GetoptError:
4341881SN/A        sys.exit(usage)
4351881SN/A
4361881SN/A    both = False
4371881SN/A    checkpoint = False
4381881SN/A    verbose = False
4391881SN/A    for opt,arg in opts:
4401881SN/A        if opt == '-b':
4411881SN/A            both = True
4421881SN/A            checkpoint = True
4431881SN/A        if opt == '-c':
4441881SN/A            checkpoint = True
4451881SN/A        if opt == '-v':
4461881SN/A            verbose = True
4471881SN/A
4485467Snate@binkert.org    if conf is None:
4495467Snate@binkert.org        if len(args) != 1:
45013663Sandreas.sandberg@arm.com            raise AttributeError(usage)
4515467Snate@binkert.org        conf = JobFile(args[0])
4525467Snate@binkert.org    else:
4535467Snate@binkert.org        if len(args) != 0:
45413663Sandreas.sandberg@arm.com            raise AttributeError(usage)
4551881SN/A
4561881SN/A    if both:
4575467Snate@binkert.org        jobs = conf.alljobs()
4581881SN/A    elif checkpoint:
4595467Snate@binkert.org        jobs = conf.checkpoints()
4601881SN/A    else:
4615467Snate@binkert.org        jobs = conf.jobs()
4621881SN/A
4635467Snate@binkert.org    for job in jobs:
4645467Snate@binkert.org        if verbose:
4655467Snate@binkert.org            job.printinfo()
4665467Snate@binkert.org        else:
4671881SN/A            cpt = ''
4685467Snate@binkert.org            if job._checkpoint:
4695467Snate@binkert.org                cpt = job._checkpoint.name
47012563Sgabeblack@google.com            print(job.name, cpt)
4715467Snate@binkert.org
4725467Snate@binkert.orgif __name__ == '__main__':
4735467Snate@binkert.org    main()
474