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
3013714Sandreas.sandberg@arm.comfrom __future__ import absolute_import
3112563Sgabeblack@google.com
321428SN/Aimport sys
331428SN/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):
4213663Sandreas.sandberg@arm.com            raise AttributeError("can only update from Data object")
431881SN/A
4413709Sandreas.sandberg@arm.com        for key,val in obj.__dict__.items():
455618Snate@binkert.org            if key.startswith('_') or key in ('name', 'desc'):
465618Snate@binkert.org                continue
475618Snate@binkert.org
485618Snate@binkert.org            if key not in self.__dict__:
495618Snate@binkert.org                self.__dict__[key] = val
505618Snate@binkert.org                continue
515618Snate@binkert.org
525618Snate@binkert.org            if not isinstance(val, dict):
535618Snate@binkert.org                if self.__dict__[key] == val:
545618Snate@binkert.org                    continue
555618Snate@binkert.org
5613663Sandreas.sandberg@arm.com                raise AttributeError(
5713663Sandreas.sandberg@arm.com                    "%s specified more than once old: %s new: %s" % \
5813663Sandreas.sandberg@arm.com                    (key, self.__dict__[key], val))
595618Snate@binkert.org
605618Snate@binkert.org            d = self.__dict__[key]
6113709Sandreas.sandberg@arm.com            for k,v in val.items():
625618Snate@binkert.org                if k in d:
6313663Sandreas.sandberg@arm.com                    raise AttributeError(
6413663Sandreas.sandberg@arm.com                        "%s specified more than once in %s" % (k, key))
655618Snate@binkert.org                d[k] = v
665618Snate@binkert.org
675467Snate@binkert.org        if hasattr(self, 'system') and hasattr(obj, 'system'):
685467Snate@binkert.org            if self.system != obj.system:
6913663Sandreas.sandberg@arm.com                raise AttributeError(
7013663Sandreas.sandberg@arm.com                    "conflicting values for system: '%s'/'%s'" % \
7113663Sandreas.sandberg@arm.com                    (self.system, obj.system))
721881SN/A
731881SN/A    def printinfo(self):
741881SN/A        if self.name:
7512563Sgabeblack@google.com            print('name: %s' % self.name)
761881SN/A        if self.desc:
7712563Sgabeblack@google.com            print('desc: %s' % self.desc)
785467Snate@binkert.org        try:
795467Snate@binkert.org            if self.system:
8012563Sgabeblack@google.com                print('system: %s' % self.system)
815467Snate@binkert.org        except AttributeError:
825467Snate@binkert.org            pass
831881SN/A
841881SN/A    def printverbose(self):
855467Snate@binkert.org        for key in self:
865467Snate@binkert.org            val = self[key]
875467Snate@binkert.org            if isinstance(val, dict):
885467Snate@binkert.org                import pprint
895467Snate@binkert.org                val = pprint.pformat(val)
9012563Sgabeblack@google.com            print('%-20s = %s' % (key, val))
9112563Sgabeblack@google.com        print()
925467Snate@binkert.org
935467Snate@binkert.org    def __contains__(self, attr):
945467Snate@binkert.org        if attr.startswith('_'):
955467Snate@binkert.org            return False
965467Snate@binkert.org        return attr in self.__dict__
975467Snate@binkert.org
985467Snate@binkert.org    def __getitem__(self, key):
995467Snate@binkert.org        if key.startswith('_'):
10013663Sandreas.sandberg@arm.com            raise KeyError("Key '%s' not found" % attr)
1015467Snate@binkert.org        return self.__dict__[key]
1025467Snate@binkert.org
1035467Snate@binkert.org    def __iter__(self):
10413709Sandreas.sandberg@arm.com        keys = list(self.__dict__.keys())
1051881SN/A        keys.sort()
1061881SN/A        for key in keys:
1075467Snate@binkert.org            if not key.startswith('_'):
1085467Snate@binkert.org                yield key
1095467Snate@binkert.org
1105467Snate@binkert.org    def optiondict(self):
1116654Snate@binkert.org        import m5.util
1126654Snate@binkert.org        result = m5.util.optiondict()
1135467Snate@binkert.org        for key in self:
1145467Snate@binkert.org            result[key] = self[key]
1155467Snate@binkert.org        return result
1161881SN/A
1175618Snate@binkert.org    def __repr__(self):
1185618Snate@binkert.org        d = {}
11913709Sandreas.sandberg@arm.com        for key,value in self.__dict__.items():
1205618Snate@binkert.org            if not key.startswith('_'):
1215618Snate@binkert.org                d[key] = value
1225618Snate@binkert.org
1235618Snate@binkert.org        return "<%s: %s>" % (type(self).__name__, d)
1245618Snate@binkert.org
1251881SN/A    def __str__(self):
1261881SN/A        return self.name
1271881SN/A
1281881SN/Aclass Job(Data):
1291881SN/A    def __init__(self, options):
1301881SN/A        super(Job, self).__init__('', '')
1311881SN/A
1325467Snate@binkert.org        config = options[0]._config
1331881SN/A        for opt in options:
1345467Snate@binkert.org            if opt._config != config:
13513663Sandreas.sandberg@arm.com                raise AttributeError(
13613663Sandreas.sandberg@arm.com                    "All options are not from the same Configuration")
1371881SN/A
1385467Snate@binkert.org        self._config = config
1395467Snate@binkert.org        self._groups = [ opt._group for opt in options ]
1405467Snate@binkert.org        self._options = options
1411881SN/A
1425467Snate@binkert.org        self.update(self._config)
1435467Snate@binkert.org        for group in self._groups:
1441881SN/A            self.update(group)
1451881SN/A
1465467Snate@binkert.org        self._is_checkpoint = True
1475467Snate@binkert.org
1485467Snate@binkert.org        for option in self._options:
1491881SN/A            self.update(option)
1505467Snate@binkert.org            if not option._group._checkpoint:
1515467Snate@binkert.org                self._is_checkpoint = False
1525467Snate@binkert.org
1531881SN/A            if option._suboption:
1541881SN/A                self.update(option._suboption)
1555467Snate@binkert.org                self._is_checkpoint = False
1565467Snate@binkert.org
1575467Snate@binkert.org        names = [ ]
1585467Snate@binkert.org        for opt in self._options:
1595467Snate@binkert.org            if opt.name:
1605467Snate@binkert.org                names.append(opt.name)
1615467Snate@binkert.org        self.name = ':'.join(names)
1625467Snate@binkert.org
1635467Snate@binkert.org        descs = [ ]
1645467Snate@binkert.org        for opt in self._options:
1655467Snate@binkert.org            if opt.desc:
1665467Snate@binkert.org                descs.append(opt.desc)
1675467Snate@binkert.org        self.desc = ', '.join(descs)
1685467Snate@binkert.org
1695467Snate@binkert.org        self._checkpoint = None
1705467Snate@binkert.org        if not self._is_checkpoint:
1715467Snate@binkert.org            opts = []
1725467Snate@binkert.org            for opt in options:
1735467Snate@binkert.org                cpt = opt._group._checkpoint
1745467Snate@binkert.org                if not cpt:
1755467Snate@binkert.org                    continue
1765467Snate@binkert.org                if isinstance(cpt, Option):
1775467Snate@binkert.org                    opt = cpt.clone(suboptions=False)
1785467Snate@binkert.org                else:
1795467Snate@binkert.org                    opt = opt.clone(suboptions=False)
1805467Snate@binkert.org
1815467Snate@binkert.org                opts.append(opt)
1825467Snate@binkert.org
1835467Snate@binkert.org            if opts:
1845467Snate@binkert.org                self._checkpoint = Job(opts)
1855467Snate@binkert.org
1865467Snate@binkert.org    def clone(self):
1875467Snate@binkert.org        return Job(self._options)
1881881SN/A
1891881SN/A    def printinfo(self):
1901881SN/A        super(Job, self).printinfo()
1915467Snate@binkert.org        if self._checkpoint:
19212563Sgabeblack@google.com            print('checkpoint: %s' % self._checkpoint.name)
19312563Sgabeblack@google.com        print('config: %s' % self._config.name)
19412563Sgabeblack@google.com        print('groups: %s' % [ g.name for g in self._groups ])
19512563Sgabeblack@google.com        print('options: %s' % [ o.name for o in self._options ])
1961881SN/A        super(Job, self).printverbose()
1971881SN/A
1981881SN/Aclass SubOption(Data):
1991881SN/A    def __init__(self, name, desc, **kwargs):
2001881SN/A        super(SubOption, self).__init__(name, desc, **kwargs)
2015467Snate@binkert.org        self._number = None
2021881SN/A
2031881SN/Aclass Option(Data):
2041881SN/A    def __init__(self, name, desc, **kwargs):
2051881SN/A        super(Option, self).__init__(name, desc, **kwargs)
2061881SN/A        self._suboptions = []
2071881SN/A        self._suboption = None
2085467Snate@binkert.org        self._number = None
2091881SN/A
2101881SN/A    def __getattribute__(self, attr):
2111881SN/A        if attr == 'name':
2121881SN/A            name = self.__dict__[attr]
2131881SN/A            if self._suboption is not None:
2141881SN/A                name = '%s:%s' % (name, self._suboption.name)
2151881SN/A            return name
2161881SN/A
2171881SN/A        if attr == 'desc':
2182142SN/A            desc = [ self.__dict__[attr] ]
2192142SN/A            if self._suboption is not None and self._suboption.desc:
2202142SN/A                desc.append(self._suboption.desc)
2212142SN/A            return ', '.join(desc)
2222142SN/A
2231881SN/A        return super(Option, self).__getattribute__(attr)
2241881SN/A
2251881SN/A    def suboption(self, name, desc, **kwargs):
2261881SN/A        subo = SubOption(name, desc, **kwargs)
2275467Snate@binkert.org        subo._config = self._config
2285467Snate@binkert.org        subo._group = self._group
2295467Snate@binkert.org        subo._option = self
2305467Snate@binkert.org        subo._number = len(self._suboptions)
2311881SN/A        self._suboptions.append(subo)
2321881SN/A        return subo
2331881SN/A
2341881SN/A    def clone(self, suboptions=True):
2351881SN/A        option = Option(self.__dict__['name'], self.__dict__['desc'])
2361881SN/A        option.update(self)
2375467Snate@binkert.org        option._group = self._group
2385467Snate@binkert.org        option._config = self._config
2395467Snate@binkert.org        option._number = self._number
2401881SN/A        if suboptions:
2411881SN/A            option._suboptions.extend(self._suboptions)
2421881SN/A            option._suboption = self._suboption
2431881SN/A        return option
2441881SN/A
2451881SN/A    def subopts(self):
2461881SN/A        if not self._suboptions:
2471881SN/A            return [ self ]
2481881SN/A
2491881SN/A        subopts = []
2501881SN/A        for subo in self._suboptions:
2511881SN/A            option = self.clone()
2521881SN/A            option._suboption = subo
2531881SN/A            subopts.append(option)
2541881SN/A
2551881SN/A        return subopts
2561881SN/A
2571881SN/A    def printinfo(self):
2581881SN/A        super(Option, self).printinfo()
25912563Sgabeblack@google.com        print('config: %s' % self._config.name)
2601881SN/A        super(Option, self).printverbose()
2611881SN/A
2621881SN/Aclass Group(Data):
2631881SN/A    def __init__(self, name, desc, **kwargs):
2641881SN/A        super(Group, self).__init__(name, desc, **kwargs)
2651881SN/A        self._options = []
2665467Snate@binkert.org        self._number = None
2675467Snate@binkert.org        self._checkpoint = False
2681881SN/A
2691881SN/A    def option(self, name, desc, **kwargs):
2701881SN/A        opt = Option(name, desc, **kwargs)
2715467Snate@binkert.org        opt._config = self._config
2725467Snate@binkert.org        opt._group = self
2735467Snate@binkert.org        opt._number = len(self._options)
2741881SN/A        self._options.append(opt)
2751881SN/A        return opt
2761881SN/A
2771881SN/A    def options(self):
2781881SN/A        return self._options
2791881SN/A
2801881SN/A    def subopts(self):
2811881SN/A        subopts = []
2821881SN/A        for opt in self._options:
2831881SN/A            for subo in opt.subopts():
2841881SN/A                subopts.append(subo)
2851881SN/A        return subopts
2861881SN/A
2871881SN/A    def printinfo(self):
2881881SN/A        super(Group, self).printinfo()
28912563Sgabeblack@google.com        print('config: %s' % self._config.name)
29012563Sgabeblack@google.com        print('options: %s' % [ o.name for o in self._options ])
2911881SN/A        super(Group, self).printverbose()
2921881SN/A
2931881SN/Aclass Configuration(Data):
2941881SN/A    def __init__(self, name, desc, **kwargs):
2951881SN/A        super(Configuration, self).__init__(name, desc, **kwargs)
2961881SN/A        self._groups = []
2972141SN/A        self._posfilters = []
2982141SN/A        self._negfilters = []
2991881SN/A
3001881SN/A    def group(self, name, desc, **kwargs):
3011881SN/A        grp = Group(name, desc, **kwargs)
3025467Snate@binkert.org        grp._config = self
3035467Snate@binkert.org        grp._number = len(self._groups)
3041881SN/A        self._groups.append(grp)
3051881SN/A        return grp
3061881SN/A
3075467Snate@binkert.org    def groups(self):
3085467Snate@binkert.org        return self._groups
3091881SN/A
3101881SN/A    def checkchildren(self, kids):
3111881SN/A        for kid in kids:
3125467Snate@binkert.org            if kid._config != self:
31313663Sandreas.sandberg@arm.com                raise AttributeError("child from the wrong configuration")
3141881SN/A
3151881SN/A    def sortgroups(self, groups):
3165467Snate@binkert.org        groups = [ (grp._number, grp) for grp in groups ]
3171881SN/A        groups.sort()
3181881SN/A        return [ grp[1] for grp in groups ]
3191881SN/A
3205467Snate@binkert.org    def options(self, groups=None, checkpoint=False):
3211881SN/A        if groups is None:
3221881SN/A            groups = self._groups
3231881SN/A        self.checkchildren(groups)
3241881SN/A        groups = self.sortgroups(groups)
3251881SN/A        if checkpoint:
3265467Snate@binkert.org            groups = [ grp for grp in groups if grp._checkpoint ]
3271881SN/A            optgroups = [ g.options() for g in groups ]
3281881SN/A        else:
3291881SN/A            optgroups = [ g.subopts() for g in groups ]
3305467Snate@binkert.org        if not optgroups:
3315467Snate@binkert.org            return
3326654Snate@binkert.org
3336654Snate@binkert.org        import m5.util
3346654Snate@binkert.org        for options in m5.util.crossproduct(optgroups):
3351881SN/A            for opt in options:
3365467Snate@binkert.org                cpt = opt._group._checkpoint
3371881SN/A                if not isinstance(cpt, bool) and cpt != opt:
3381881SN/A                    if checkpoint:
3391881SN/A                        break
3401881SN/A                    else:
3411881SN/A                        yield options
3421881SN/A            else:
3431881SN/A                if checkpoint:
3441881SN/A                    yield options
3451881SN/A
3462141SN/A    def addfilter(self, filt, pos=True):
3472141SN/A        import re
3482141SN/A        filt = re.compile(filt)
3492141SN/A        if pos:
3502141SN/A            self._posfilters.append(filt)
3512141SN/A        else:
3522141SN/A            self._negfilters.append(filt)
3532141SN/A
3542141SN/A    def jobfilter(self, job):
3552141SN/A        for filt in self._negfilters:
3562141SN/A            if filt.match(job.name):
3572141SN/A                return False
3582141SN/A
3592141SN/A        if not self._posfilters:
3602141SN/A            return True
3612141SN/A
3622141SN/A        for filt in self._posfilters:
3632141SN/A            if filt.match(job.name):
3642141SN/A                return True
3652141SN/A
3662141SN/A        return False
3672141SN/A
3685467Snate@binkert.org    def checkpoints(self, groups=None):
3691881SN/A        for options in self.options(groups, True):
3702141SN/A            job = Job(options)
3712141SN/A            if self.jobfilter(job):
3722141SN/A                yield job
3731881SN/A
3745467Snate@binkert.org    def jobs(self, groups=None):
3751881SN/A        for options in self.options(groups, False):
3762141SN/A            job = Job(options)
3772141SN/A            if self.jobfilter(job):
3782141SN/A                yield job
3791881SN/A
3805467Snate@binkert.org    def alljobs(self, groups=None):
3811881SN/A        for options in self.options(groups, True):
3821881SN/A            yield Job(options)
3831881SN/A        for options in self.options(groups, False):
3841881SN/A            yield Job(options)
3851881SN/A
3861881SN/A    def find(self, jobname):
3871881SN/A        for job in self.alljobs():
3881881SN/A            if job.name == jobname:
3891881SN/A                return job
3901881SN/A        else:
39113663Sandreas.sandberg@arm.com            raise AttributeError("job '%s' not found" % jobname)
3921881SN/A
3931881SN/A    def job(self, options):
3941881SN/A        self.checkchildren(options)
3955467Snate@binkert.org        options = [ (opt._group._number, opt) for opt in options ]
3961881SN/A        options.sort()
3971881SN/A        options = [ opt[1] for opt in options ]
3981881SN/A        job = Job(options)
3991881SN/A        return job
4001881SN/A
4011881SN/A    def printinfo(self):
4021881SN/A        super(Configuration, self).printinfo()
40312563Sgabeblack@google.com        print('groups: %s' % [ g.name for g in self._groups ])
4041881SN/A        super(Configuration, self).printverbose()
4051881SN/A
4061881SN/Adef JobFile(jobfile):
4071881SN/A    from os.path import expanduser, isfile, join as joinpath
4081881SN/A    filename = expanduser(jobfile)
4091881SN/A
4101881SN/A    # Can't find filename in the current path, search sys.path
4111881SN/A    if not isfile(filename):
4121881SN/A        for path in sys.path:
4131881SN/A            testname = joinpath(path, filename)
4141881SN/A            if isfile(testname):
4151881SN/A                filename = testname
4161881SN/A                break
4171881SN/A        else:
41813663Sandreas.sandberg@arm.com            raise AttributeError("Could not find file '%s'" % jobfile)
4191881SN/A
4201881SN/A    data = {}
42113671Sandreas.sandberg@arm.com    exec(compile(open(filename).read(), filename, 'exec'), data)
4221881SN/A    if 'conf' not in data:
42313663Sandreas.sandberg@arm.com        raise ImportError('cannot import name conf from %s' % jobfile)
4245618Snate@binkert.org    return data['conf']
4251881SN/A
4265467Snate@binkert.orgdef main(conf=None):
4275618Snate@binkert.org    usage = 'Usage: %s [-b] [-c] [-v]' % sys.argv[0]
4285618Snate@binkert.org    if conf is None:
4295618Snate@binkert.org        usage += ' <jobfile>'
4301881SN/A
4311881SN/A    try:
4321881SN/A        import getopt
4331881SN/A        opts, args = getopt.getopt(sys.argv[1:], '-bcv')
4341881SN/A    except getopt.GetoptError:
4351881SN/A        sys.exit(usage)
4361881SN/A
4371881SN/A    both = False
4381881SN/A    checkpoint = False
4391881SN/A    verbose = False
4401881SN/A    for opt,arg in opts:
4411881SN/A        if opt == '-b':
4421881SN/A            both = True
4431881SN/A            checkpoint = True
4441881SN/A        if opt == '-c':
4451881SN/A            checkpoint = True
4461881SN/A        if opt == '-v':
4471881SN/A            verbose = True
4481881SN/A
4495467Snate@binkert.org    if conf is None:
4505467Snate@binkert.org        if len(args) != 1:
45113663Sandreas.sandberg@arm.com            raise AttributeError(usage)
4525467Snate@binkert.org        conf = JobFile(args[0])
4535467Snate@binkert.org    else:
4545467Snate@binkert.org        if len(args) != 0:
45513663Sandreas.sandberg@arm.com            raise AttributeError(usage)
4561881SN/A
4571881SN/A    if both:
4585467Snate@binkert.org        jobs = conf.alljobs()
4591881SN/A    elif checkpoint:
4605467Snate@binkert.org        jobs = conf.checkpoints()
4611881SN/A    else:
4625467Snate@binkert.org        jobs = conf.jobs()
4631881SN/A
4645467Snate@binkert.org    for job in jobs:
4655467Snate@binkert.org        if verbose:
4665467Snate@binkert.org            job.printinfo()
4675467Snate@binkert.org        else:
4681881SN/A            cpt = ''
4695467Snate@binkert.org            if job._checkpoint:
4705467Snate@binkert.org                cpt = job._checkpoint.name
47112563Sgabeblack@google.com            print(job.name, cpt)
4725467Snate@binkert.org
4735467Snate@binkert.orgif __name__ == '__main__':
4745467Snate@binkert.org    main()
475