xref: /linux-6.15/tools/perf/tests/shell/lib/attr.py (revision 21944462)
18296aa0fSIan Rogers# SPDX-License-Identifier: GPL-2.0
28296aa0fSIan Rogers
3*21944462SIan Rogersimport configparser
48296aa0fSIan Rogersimport os
58296aa0fSIan Rogersimport sys
68296aa0fSIan Rogersimport glob
78296aa0fSIan Rogersimport optparse
88296aa0fSIan Rogersimport platform
98296aa0fSIan Rogersimport tempfile
108296aa0fSIan Rogersimport logging
118296aa0fSIan Rogersimport re
128296aa0fSIan Rogersimport shutil
138296aa0fSIan Rogersimport subprocess
148296aa0fSIan Rogers
158296aa0fSIan Rogersdef data_equal(a, b):
168296aa0fSIan Rogers    # Allow multiple values in assignment separated by '|'
178296aa0fSIan Rogers    a_list = a.split('|')
188296aa0fSIan Rogers    b_list = b.split('|')
198296aa0fSIan Rogers
208296aa0fSIan Rogers    for a_item in a_list:
218296aa0fSIan Rogers        for b_item in b_list:
228296aa0fSIan Rogers            if (a_item == b_item):
238296aa0fSIan Rogers                return True
248296aa0fSIan Rogers            elif (a_item == '*') or (b_item == '*'):
258296aa0fSIan Rogers                return True
268296aa0fSIan Rogers
278296aa0fSIan Rogers    return False
288296aa0fSIan Rogers
298296aa0fSIan Rogersclass Fail(Exception):
308296aa0fSIan Rogers    def __init__(self, test, msg):
318296aa0fSIan Rogers        self.msg = msg
328296aa0fSIan Rogers        self.test = test
338296aa0fSIan Rogers    def getMsg(self):
348296aa0fSIan Rogers        return '\'%s\' - %s' % (self.test.path, self.msg)
358296aa0fSIan Rogers
368296aa0fSIan Rogersclass Notest(Exception):
378296aa0fSIan Rogers    def __init__(self, test, arch):
388296aa0fSIan Rogers        self.arch = arch
398296aa0fSIan Rogers        self.test = test
408296aa0fSIan Rogers    def getMsg(self):
418296aa0fSIan Rogers        return '[%s] \'%s\'' % (self.arch, self.test.path)
428296aa0fSIan Rogers
438296aa0fSIan Rogersclass Unsup(Exception):
448296aa0fSIan Rogers    def __init__(self, test):
458296aa0fSIan Rogers        self.test = test
468296aa0fSIan Rogers    def getMsg(self):
478296aa0fSIan Rogers        return '\'%s\'' % self.test.path
488296aa0fSIan Rogers
498296aa0fSIan Rogersclass Event(dict):
508296aa0fSIan Rogers    terms = [
518296aa0fSIan Rogers        'cpu',
528296aa0fSIan Rogers        'flags',
538296aa0fSIan Rogers        'type',
548296aa0fSIan Rogers        'size',
558296aa0fSIan Rogers        'config',
568296aa0fSIan Rogers        'sample_period',
578296aa0fSIan Rogers        'sample_type',
588296aa0fSIan Rogers        'read_format',
598296aa0fSIan Rogers        'disabled',
608296aa0fSIan Rogers        'inherit',
618296aa0fSIan Rogers        'pinned',
628296aa0fSIan Rogers        'exclusive',
638296aa0fSIan Rogers        'exclude_user',
648296aa0fSIan Rogers        'exclude_kernel',
658296aa0fSIan Rogers        'exclude_hv',
668296aa0fSIan Rogers        'exclude_idle',
678296aa0fSIan Rogers        'mmap',
688296aa0fSIan Rogers        'comm',
698296aa0fSIan Rogers        'freq',
708296aa0fSIan Rogers        'inherit_stat',
718296aa0fSIan Rogers        'enable_on_exec',
728296aa0fSIan Rogers        'task',
738296aa0fSIan Rogers        'watermark',
748296aa0fSIan Rogers        'precise_ip',
758296aa0fSIan Rogers        'mmap_data',
768296aa0fSIan Rogers        'sample_id_all',
778296aa0fSIan Rogers        'exclude_host',
788296aa0fSIan Rogers        'exclude_guest',
798296aa0fSIan Rogers        'exclude_callchain_kernel',
808296aa0fSIan Rogers        'exclude_callchain_user',
818296aa0fSIan Rogers        'wakeup_events',
828296aa0fSIan Rogers        'bp_type',
838296aa0fSIan Rogers        'config1',
848296aa0fSIan Rogers        'config2',
858296aa0fSIan Rogers        'branch_sample_type',
868296aa0fSIan Rogers        'sample_regs_user',
878296aa0fSIan Rogers        'sample_stack_user',
888296aa0fSIan Rogers    ]
898296aa0fSIan Rogers
908296aa0fSIan Rogers    def add(self, data):
918296aa0fSIan Rogers        for key, val in data:
928296aa0fSIan Rogers            log.debug("      %s = %s" % (key, val))
938296aa0fSIan Rogers            self[key] = val
948296aa0fSIan Rogers
958296aa0fSIan Rogers    def __init__(self, name, data, base):
968296aa0fSIan Rogers        log.debug("    Event %s" % name);
978296aa0fSIan Rogers        self.name  = name;
988296aa0fSIan Rogers        self.group = ''
998296aa0fSIan Rogers        self.add(base)
1008296aa0fSIan Rogers        self.add(data)
1018296aa0fSIan Rogers
1028296aa0fSIan Rogers    def equal(self, other):
1038296aa0fSIan Rogers        for t in Event.terms:
1048296aa0fSIan Rogers            log.debug("      [%s] %s %s" % (t, self[t], other[t]));
1058296aa0fSIan Rogers            if t not in self or t not in other:
1068296aa0fSIan Rogers                return False
1078296aa0fSIan Rogers            if not data_equal(self[t], other[t]):
1088296aa0fSIan Rogers                return False
1098296aa0fSIan Rogers        return True
1108296aa0fSIan Rogers
1118296aa0fSIan Rogers    def optional(self):
1128296aa0fSIan Rogers        if 'optional' in self and self['optional'] == '1':
1138296aa0fSIan Rogers            return True
1148296aa0fSIan Rogers        return False
1158296aa0fSIan Rogers
1168296aa0fSIan Rogers    def diff(self, other):
1178296aa0fSIan Rogers        for t in Event.terms:
1188296aa0fSIan Rogers            if t not in self or t not in other:
1198296aa0fSIan Rogers                continue
1208296aa0fSIan Rogers            if not data_equal(self[t], other[t]):
1218296aa0fSIan Rogers                log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
1228296aa0fSIan Rogers
1238296aa0fSIan Rogersdef parse_version(version):
1248296aa0fSIan Rogers    if not version:
1258296aa0fSIan Rogers        return None
1268296aa0fSIan Rogers    return [int(v) for v in version.split(".")[0:2]]
1278296aa0fSIan Rogers
1288296aa0fSIan Rogers# Test file description needs to have following sections:
1298296aa0fSIan Rogers# [config]
1308296aa0fSIan Rogers#   - just single instance in file
1318296aa0fSIan Rogers#   - needs to specify:
1328296aa0fSIan Rogers#     'command' - perf command name
1338296aa0fSIan Rogers#     'args'    - special command arguments
1348296aa0fSIan Rogers#     'ret'     - Skip test if Perf doesn't exit with this value (0 by default)
1358296aa0fSIan Rogers#     'test_ret'- If set to 'true', fail test instead of skipping for 'ret' argument
1368296aa0fSIan Rogers#     'arch'    - architecture specific test (optional)
1378296aa0fSIan Rogers#                 comma separated list, ! at the beginning
1388296aa0fSIan Rogers#                 negates it.
1398296aa0fSIan Rogers#     'auxv'    - Truthy statement that is evaled in the scope of the auxv map. When false,
1408296aa0fSIan Rogers#                 the test is skipped. For example 'auxv["AT_HWCAP"] == 10'. (optional)
1418296aa0fSIan Rogers#     'kernel_since' - Inclusive kernel version from which the test will start running. Only the
1428296aa0fSIan Rogers#                      first two values are supported, for example "6.1" (optional)
1438296aa0fSIan Rogers#     'kernel_until' - Exclusive kernel version from which the test will stop running. (optional)
1448296aa0fSIan Rogers# [eventX:base]
1458296aa0fSIan Rogers#   - one or multiple instances in file
1468296aa0fSIan Rogers#   - expected values assignments
1478296aa0fSIan Rogersclass Test(object):
1488296aa0fSIan Rogers    def __init__(self, path, options):
1498296aa0fSIan Rogers        parser = configparser.ConfigParser()
1508296aa0fSIan Rogers        parser.read(path)
1518296aa0fSIan Rogers
1528296aa0fSIan Rogers        log.warning("running '%s'" % path)
1538296aa0fSIan Rogers
1548296aa0fSIan Rogers        self.path     = path
1558296aa0fSIan Rogers        self.test_dir = options.test_dir
1568296aa0fSIan Rogers        self.perf     = options.perf
1578296aa0fSIan Rogers        self.command  = parser.get('config', 'command')
1588296aa0fSIan Rogers        self.args     = parser.get('config', 'args')
1598296aa0fSIan Rogers
1608296aa0fSIan Rogers        try:
1618296aa0fSIan Rogers            self.ret  = parser.get('config', 'ret')
1628296aa0fSIan Rogers        except:
1638296aa0fSIan Rogers            self.ret  = 0
1648296aa0fSIan Rogers
1658296aa0fSIan Rogers        self.test_ret = parser.getboolean('config', 'test_ret', fallback=False)
1668296aa0fSIan Rogers
1678296aa0fSIan Rogers        try:
1688296aa0fSIan Rogers            self.arch  = parser.get('config', 'arch')
1698296aa0fSIan Rogers            log.warning("test limitation '%s'" % self.arch)
1708296aa0fSIan Rogers        except:
1718296aa0fSIan Rogers            self.arch  = ''
1728296aa0fSIan Rogers
1738296aa0fSIan Rogers        self.auxv = parser.get('config', 'auxv', fallback=None)
1748296aa0fSIan Rogers        self.kernel_since = parse_version(parser.get('config', 'kernel_since', fallback=None))
1758296aa0fSIan Rogers        self.kernel_until = parse_version(parser.get('config', 'kernel_until', fallback=None))
1768296aa0fSIan Rogers        self.expect   = {}
1778296aa0fSIan Rogers        self.result   = {}
1788296aa0fSIan Rogers        log.debug("  loading expected events");
1798296aa0fSIan Rogers        self.load_events(path, self.expect)
1808296aa0fSIan Rogers
1818296aa0fSIan Rogers    def is_event(self, name):
1828296aa0fSIan Rogers        if name.find("event") == -1:
1838296aa0fSIan Rogers            return False
1848296aa0fSIan Rogers        else:
1858296aa0fSIan Rogers            return True
1868296aa0fSIan Rogers
1878296aa0fSIan Rogers    def skip_test_kernel_since(self):
1888296aa0fSIan Rogers        if not self.kernel_since:
1898296aa0fSIan Rogers            return False
1908296aa0fSIan Rogers        return not self.kernel_since <= parse_version(platform.release())
1918296aa0fSIan Rogers
1928296aa0fSIan Rogers    def skip_test_kernel_until(self):
1938296aa0fSIan Rogers        if not self.kernel_until:
1948296aa0fSIan Rogers            return False
1958296aa0fSIan Rogers        return not parse_version(platform.release()) < self.kernel_until
1968296aa0fSIan Rogers
1978296aa0fSIan Rogers    def skip_test_auxv(self):
1988296aa0fSIan Rogers        def new_auxv(a, pattern):
1998296aa0fSIan Rogers            items = list(filter(None, pattern.split(a)))
2008296aa0fSIan Rogers            # AT_HWCAP is hex but doesn't have a prefix, so special case it
2018296aa0fSIan Rogers            if items[0] == "AT_HWCAP":
2028296aa0fSIan Rogers                value = int(items[-1], 16)
2038296aa0fSIan Rogers            else:
2048296aa0fSIan Rogers                try:
2058296aa0fSIan Rogers                    value = int(items[-1], 0)
2068296aa0fSIan Rogers                except:
2078296aa0fSIan Rogers                    value = items[-1]
2088296aa0fSIan Rogers            return (items[0], value)
2098296aa0fSIan Rogers
2108296aa0fSIan Rogers        if not self.auxv:
2118296aa0fSIan Rogers            return False
2128296aa0fSIan Rogers        auxv = subprocess.check_output("LD_SHOW_AUXV=1 sleep 0", shell=True) \
2138296aa0fSIan Rogers               .decode(sys.stdout.encoding)
2148296aa0fSIan Rogers        pattern = re.compile(r"[: ]+")
2158296aa0fSIan Rogers        auxv = dict([new_auxv(a, pattern) for a in auxv.splitlines()])
2168296aa0fSIan Rogers        return not eval(self.auxv)
2178296aa0fSIan Rogers
2188296aa0fSIan Rogers    def skip_test_arch(self, myarch):
2198296aa0fSIan Rogers        # If architecture not set always run test
2208296aa0fSIan Rogers        if self.arch == '':
2218296aa0fSIan Rogers            # log.warning("test for arch %s is ok" % myarch)
2228296aa0fSIan Rogers            return False
2238296aa0fSIan Rogers
2248296aa0fSIan Rogers        # Allow multiple values in assignment separated by ','
2258296aa0fSIan Rogers        arch_list = self.arch.split(',')
2268296aa0fSIan Rogers
2278296aa0fSIan Rogers        # Handle negated list such as !s390x,ppc
2288296aa0fSIan Rogers        if arch_list[0][0] == '!':
2298296aa0fSIan Rogers            arch_list[0] = arch_list[0][1:]
2308296aa0fSIan Rogers            log.warning("excluded architecture list %s" % arch_list)
2318296aa0fSIan Rogers            for arch_item in arch_list:
2328296aa0fSIan Rogers                # log.warning("test for %s arch is %s" % (arch_item, myarch))
2338296aa0fSIan Rogers                if arch_item == myarch:
2348296aa0fSIan Rogers                    return True
2358296aa0fSIan Rogers            return False
2368296aa0fSIan Rogers
2378296aa0fSIan Rogers        for arch_item in arch_list:
2388296aa0fSIan Rogers            # log.warning("test for architecture '%s' current '%s'" % (arch_item, myarch))
2398296aa0fSIan Rogers            if arch_item == myarch:
2408296aa0fSIan Rogers                return False
2418296aa0fSIan Rogers        return True
2428296aa0fSIan Rogers
2438296aa0fSIan Rogers    def restore_sample_rate(self, value=10000):
2448296aa0fSIan Rogers        try:
2458296aa0fSIan Rogers            # Check value of sample_rate
2468296aa0fSIan Rogers            with open("/proc/sys/kernel/perf_event_max_sample_rate", "r") as fIn:
2478296aa0fSIan Rogers                curr_value = fIn.readline()
2488296aa0fSIan Rogers            # If too low restore to reasonable value
2498296aa0fSIan Rogers            if not curr_value or int(curr_value) < int(value):
2508296aa0fSIan Rogers                with open("/proc/sys/kernel/perf_event_max_sample_rate", "w") as fOut:
2518296aa0fSIan Rogers                    fOut.write(str(value))
2528296aa0fSIan Rogers
2538296aa0fSIan Rogers        except IOError as e:
2548296aa0fSIan Rogers            log.warning("couldn't restore sample_rate value: I/O error %s" % e)
2558296aa0fSIan Rogers        except ValueError as e:
2568296aa0fSIan Rogers            log.warning("couldn't restore sample_rate value: Value error %s" % e)
2578296aa0fSIan Rogers        except TypeError as e:
2588296aa0fSIan Rogers            log.warning("couldn't restore sample_rate value: Type error %s" % e)
2598296aa0fSIan Rogers
2608296aa0fSIan Rogers    def load_events(self, path, events):
2618296aa0fSIan Rogers        parser_event = configparser.ConfigParser()
2628296aa0fSIan Rogers        parser_event.read(path)
2638296aa0fSIan Rogers
2648296aa0fSIan Rogers        # The event record section header contains 'event' word,
2658296aa0fSIan Rogers        # optionaly followed by ':' allowing to load 'parent
2668296aa0fSIan Rogers        # event' first as a base
2678296aa0fSIan Rogers        for section in filter(self.is_event, parser_event.sections()):
2688296aa0fSIan Rogers
2698296aa0fSIan Rogers            parser_items = parser_event.items(section);
2708296aa0fSIan Rogers            base_items   = {}
2718296aa0fSIan Rogers
2728296aa0fSIan Rogers            # Read parent event if there's any
2738296aa0fSIan Rogers            if (':' in section):
2748296aa0fSIan Rogers                base = section[section.index(':') + 1:]
2758296aa0fSIan Rogers                parser_base = configparser.ConfigParser()
2768296aa0fSIan Rogers                parser_base.read(self.test_dir + '/' + base)
2778296aa0fSIan Rogers                base_items = parser_base.items('event')
2788296aa0fSIan Rogers
2798296aa0fSIan Rogers            e = Event(section, parser_items, base_items)
2808296aa0fSIan Rogers            events[section] = e
2818296aa0fSIan Rogers
2828296aa0fSIan Rogers    def run_cmd(self, tempdir):
2838296aa0fSIan Rogers        junk1, junk2, junk3, junk4, myarch = (os.uname())
2848296aa0fSIan Rogers
2858296aa0fSIan Rogers        if self.skip_test_arch(myarch):
2868296aa0fSIan Rogers            raise Notest(self, myarch)
2878296aa0fSIan Rogers
2888296aa0fSIan Rogers        if self.skip_test_auxv():
2898296aa0fSIan Rogers            raise Notest(self, "auxv skip")
2908296aa0fSIan Rogers
2918296aa0fSIan Rogers        if self.skip_test_kernel_since():
2928296aa0fSIan Rogers            raise Notest(self, "old kernel skip")
2938296aa0fSIan Rogers
2948296aa0fSIan Rogers        if self.skip_test_kernel_until():
2958296aa0fSIan Rogers            raise Notest(self, "new kernel skip")
2968296aa0fSIan Rogers
2978296aa0fSIan Rogers        self.restore_sample_rate()
2988296aa0fSIan Rogers        cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir,
2998296aa0fSIan Rogers              self.perf, self.command, tempdir, self.args)
3008296aa0fSIan Rogers        ret = os.WEXITSTATUS(os.system(cmd))
3018296aa0fSIan Rogers
3028296aa0fSIan Rogers        log.info("  '%s' ret '%s', expected '%s'" % (cmd, str(ret), str(self.ret)))
3038296aa0fSIan Rogers
3048296aa0fSIan Rogers        if not data_equal(str(ret), str(self.ret)):
3058296aa0fSIan Rogers            if self.test_ret:
3068296aa0fSIan Rogers                raise Fail(self, "Perf exit code failure")
3078296aa0fSIan Rogers            else:
3088296aa0fSIan Rogers                raise Unsup(self)
3098296aa0fSIan Rogers
3108296aa0fSIan Rogers    def compare(self, expect, result):
3118296aa0fSIan Rogers        match = {}
3128296aa0fSIan Rogers
3138296aa0fSIan Rogers        log.debug("  compare");
3148296aa0fSIan Rogers
3158296aa0fSIan Rogers        # For each expected event find all matching
3168296aa0fSIan Rogers        # events in result. Fail if there's not any.
3178296aa0fSIan Rogers        for exp_name, exp_event in expect.items():
3188296aa0fSIan Rogers            exp_list = []
3198296aa0fSIan Rogers            res_event = {}
3208296aa0fSIan Rogers            log.debug("    matching [%s]" % exp_name)
3218296aa0fSIan Rogers            for res_name, res_event in result.items():
3228296aa0fSIan Rogers                log.debug("      to [%s]" % res_name)
3238296aa0fSIan Rogers                if (exp_event.equal(res_event)):
3248296aa0fSIan Rogers                    exp_list.append(res_name)
3258296aa0fSIan Rogers                    log.debug("    ->OK")
3268296aa0fSIan Rogers                else:
3278296aa0fSIan Rogers                    log.debug("    ->FAIL");
3288296aa0fSIan Rogers
3298296aa0fSIan Rogers            log.debug("    match: [%s] matches %s" % (exp_name, str(exp_list)))
3308296aa0fSIan Rogers
3318296aa0fSIan Rogers            # we did not any matching event - fail
3328296aa0fSIan Rogers            if not exp_list:
3338296aa0fSIan Rogers                if exp_event.optional():
3348296aa0fSIan Rogers                    log.debug("    %s does not match, but is optional" % exp_name)
3358296aa0fSIan Rogers                else:
3368296aa0fSIan Rogers                    if not res_event:
3378296aa0fSIan Rogers                        log.debug("    res_event is empty");
3388296aa0fSIan Rogers                    else:
3398296aa0fSIan Rogers                        exp_event.diff(res_event)
3408296aa0fSIan Rogers                    raise Fail(self, 'match failure');
3418296aa0fSIan Rogers
3428296aa0fSIan Rogers            match[exp_name] = exp_list
3438296aa0fSIan Rogers
3448296aa0fSIan Rogers        # For each defined group in the expected events
3458296aa0fSIan Rogers        # check we match the same group in the result.
3468296aa0fSIan Rogers        for exp_name, exp_event in expect.items():
3478296aa0fSIan Rogers            group = exp_event.group
3488296aa0fSIan Rogers
3498296aa0fSIan Rogers            if (group == ''):
3508296aa0fSIan Rogers                continue
3518296aa0fSIan Rogers
3528296aa0fSIan Rogers            for res_name in match[exp_name]:
3538296aa0fSIan Rogers                res_group = result[res_name].group
3548296aa0fSIan Rogers                if res_group not in match[group]:
3558296aa0fSIan Rogers                    raise Fail(self, 'group failure')
3568296aa0fSIan Rogers
3578296aa0fSIan Rogers                log.debug("    group: [%s] matches group leader %s" %
3588296aa0fSIan Rogers                         (exp_name, str(match[group])))
3598296aa0fSIan Rogers
3608296aa0fSIan Rogers        log.debug("  matched")
3618296aa0fSIan Rogers
3628296aa0fSIan Rogers    def resolve_groups(self, events):
3638296aa0fSIan Rogers        for name, event in events.items():
3648296aa0fSIan Rogers            group_fd = event['group_fd'];
3658296aa0fSIan Rogers            if group_fd == '-1':
3668296aa0fSIan Rogers                continue;
3678296aa0fSIan Rogers
3688296aa0fSIan Rogers            for iname, ievent in events.items():
3698296aa0fSIan Rogers                if (ievent['fd'] == group_fd):
3708296aa0fSIan Rogers                    event.group = iname
3718296aa0fSIan Rogers                    log.debug('[%s] has group leader [%s]' % (name, iname))
3728296aa0fSIan Rogers                    break;
3738296aa0fSIan Rogers
3748296aa0fSIan Rogers    def run(self):
3758296aa0fSIan Rogers        tempdir = tempfile.mkdtemp();
3768296aa0fSIan Rogers
3778296aa0fSIan Rogers        try:
3788296aa0fSIan Rogers            # run the test script
3798296aa0fSIan Rogers            self.run_cmd(tempdir);
3808296aa0fSIan Rogers
3818296aa0fSIan Rogers            # load events expectation for the test
3828296aa0fSIan Rogers            log.debug("  loading result events");
3838296aa0fSIan Rogers            for f in glob.glob(tempdir + '/event*'):
3848296aa0fSIan Rogers                self.load_events(f, self.result);
3858296aa0fSIan Rogers
3868296aa0fSIan Rogers            # resolve group_fd to event names
3878296aa0fSIan Rogers            self.resolve_groups(self.expect);
3888296aa0fSIan Rogers            self.resolve_groups(self.result);
3898296aa0fSIan Rogers
3908296aa0fSIan Rogers            # do the expectation - results matching - both ways
3918296aa0fSIan Rogers            self.compare(self.expect, self.result)
3928296aa0fSIan Rogers            self.compare(self.result, self.expect)
3938296aa0fSIan Rogers
3948296aa0fSIan Rogers        finally:
3958296aa0fSIan Rogers            # cleanup
3968296aa0fSIan Rogers            shutil.rmtree(tempdir)
3978296aa0fSIan Rogers
3988296aa0fSIan Rogers
3998296aa0fSIan Rogersdef run_tests(options):
4008296aa0fSIan Rogers    for f in glob.glob(options.test_dir + '/' + options.test):
4018296aa0fSIan Rogers        try:
4028296aa0fSIan Rogers            Test(f, options).run()
4038296aa0fSIan Rogers        except Unsup as obj:
4048296aa0fSIan Rogers            log.warning("unsupp  %s" % obj.getMsg())
4058296aa0fSIan Rogers        except Notest as obj:
4068296aa0fSIan Rogers            log.warning("skipped %s" % obj.getMsg())
4078296aa0fSIan Rogers
4088296aa0fSIan Rogersdef setup_log(verbose):
4098296aa0fSIan Rogers    global log
4108296aa0fSIan Rogers    level = logging.CRITICAL
4118296aa0fSIan Rogers
4128296aa0fSIan Rogers    if verbose == 1:
4138296aa0fSIan Rogers        level = logging.WARNING
4148296aa0fSIan Rogers    if verbose == 2:
4158296aa0fSIan Rogers        level = logging.INFO
4168296aa0fSIan Rogers    if verbose >= 3:
4178296aa0fSIan Rogers        level = logging.DEBUG
4188296aa0fSIan Rogers
4198296aa0fSIan Rogers    log = logging.getLogger('test')
4208296aa0fSIan Rogers    log.setLevel(level)
4218296aa0fSIan Rogers    ch  = logging.StreamHandler()
4228296aa0fSIan Rogers    ch.setLevel(level)
4238296aa0fSIan Rogers    formatter = logging.Formatter('%(message)s')
4248296aa0fSIan Rogers    ch.setFormatter(formatter)
4258296aa0fSIan Rogers    log.addHandler(ch)
4268296aa0fSIan Rogers
4278296aa0fSIan RogersUSAGE = '''%s [OPTIONS]
4288296aa0fSIan Rogers  -d dir  # tests dir
4298296aa0fSIan Rogers  -p path # perf binary
4308296aa0fSIan Rogers  -t test # single test
4318296aa0fSIan Rogers  -v      # verbose level
4328296aa0fSIan Rogers''' % sys.argv[0]
4338296aa0fSIan Rogers
4348296aa0fSIan Rogersdef main():
4358296aa0fSIan Rogers    parser = optparse.OptionParser(usage=USAGE)
4368296aa0fSIan Rogers
4378296aa0fSIan Rogers    parser.add_option("-t", "--test",
4388296aa0fSIan Rogers                      action="store", type="string", dest="test")
4398296aa0fSIan Rogers    parser.add_option("-d", "--test-dir",
4408296aa0fSIan Rogers                      action="store", type="string", dest="test_dir")
4418296aa0fSIan Rogers    parser.add_option("-p", "--perf",
4428296aa0fSIan Rogers                      action="store", type="string", dest="perf")
4438296aa0fSIan Rogers    parser.add_option("-v", "--verbose",
4448296aa0fSIan Rogers                      default=0, action="count", dest="verbose")
4458296aa0fSIan Rogers
4468296aa0fSIan Rogers    options, args = parser.parse_args()
4478296aa0fSIan Rogers    if args:
4488296aa0fSIan Rogers        parser.error('FAILED wrong arguments %s' %  ' '.join(args))
4498296aa0fSIan Rogers        return -1
4508296aa0fSIan Rogers
4518296aa0fSIan Rogers    setup_log(options.verbose)
4528296aa0fSIan Rogers
4538296aa0fSIan Rogers    if not options.test_dir:
4548296aa0fSIan Rogers        print('FAILED no -d option specified')
4558296aa0fSIan Rogers        sys.exit(-1)
4568296aa0fSIan Rogers
4578296aa0fSIan Rogers    if not options.test:
4588296aa0fSIan Rogers        options.test = 'test*'
4598296aa0fSIan Rogers
4608296aa0fSIan Rogers    try:
4618296aa0fSIan Rogers        run_tests(options)
4628296aa0fSIan Rogers
4638296aa0fSIan Rogers    except Fail as obj:
4648296aa0fSIan Rogers        print("FAILED %s" % obj.getMsg())
4658296aa0fSIan Rogers        sys.exit(-1)
4668296aa0fSIan Rogers
4678296aa0fSIan Rogers    sys.exit(0)
4688296aa0fSIan Rogers
4698296aa0fSIan Rogersif __name__ == '__main__':
4708296aa0fSIan Rogers    main()
471