linux/tools/perf/tests/attr.py
<<
>>
Prefs
   1#! /usr/bin/python
   2
   3import os
   4import sys
   5import glob
   6import optparse
   7import tempfile
   8import logging
   9import shutil
  10import ConfigParser
  11
  12class Fail(Exception):
  13    def __init__(self, test, msg):
  14        self.msg = msg
  15        self.test = test
  16    def getMsg(self):
  17        return '\'%s\' - %s' % (self.test.path, self.msg)
  18
  19class Unsup(Exception):
  20    def __init__(self, test):
  21        self.test = test
  22    def getMsg(self):
  23        return '\'%s\'' % self.test.path
  24
  25class Event(dict):
  26    terms = [
  27        'cpu',
  28        'flags',
  29        'type',
  30        'size',
  31        'config',
  32        'sample_period',
  33        'sample_type',
  34        'read_format',
  35        'disabled',
  36        'inherit',
  37        'pinned',
  38        'exclusive',
  39        'exclude_user',
  40        'exclude_kernel',
  41        'exclude_hv',
  42        'exclude_idle',
  43        'mmap',
  44        'comm',
  45        'freq',
  46        'inherit_stat',
  47        'enable_on_exec',
  48        'task',
  49        'watermark',
  50        'precise_ip',
  51        'mmap_data',
  52        'sample_id_all',
  53        'exclude_host',
  54        'exclude_guest',
  55        'exclude_callchain_kernel',
  56        'exclude_callchain_user',
  57        'wakeup_events',
  58        'bp_type',
  59        'config1',
  60        'config2',
  61        'branch_sample_type',
  62        'sample_regs_user',
  63        'sample_stack_user',
  64    ]
  65
  66    def add(self, data):
  67        for key, val in data:
  68            log.debug("      %s = %s" % (key, val))
  69            self[key] = val
  70
  71    def __init__(self, name, data, base):
  72        log.debug("    Event %s" % name);
  73        self.name  = name;
  74        self.group = ''
  75        self.add(base)
  76        self.add(data)
  77
  78    def compare_data(self, a, b):
  79        # Allow multiple values in assignment separated by '|'
  80        a_list = a.split('|')
  81        b_list = b.split('|')
  82
  83        for a_item in a_list:
  84            for b_item in b_list:
  85                if (a_item == b_item):
  86                    return True
  87                elif (a_item == '*') or (b_item == '*'):
  88                    return True
  89
  90        return False
  91
  92    def equal(self, other):
  93        for t in Event.terms:
  94            log.debug("      [%s] %s %s" % (t, self[t], other[t]));
  95            if not self.has_key(t) or not other.has_key(t):
  96                return False
  97            if not self.compare_data(self[t], other[t]):
  98                return False
  99        return True
 100
 101    def diff(self, other):
 102        for t in Event.terms:
 103            if not self.has_key(t) or not other.has_key(t):
 104                continue
 105            if not self.compare_data(self[t], other[t]):
 106                log.warning("expected %s=%s, got %s" % (t, self[t], other[t]))
 107
 108# Test file description needs to have following sections:
 109# [config]
 110#   - just single instance in file
 111#   - needs to specify:
 112#     'command' - perf command name
 113#     'args'    - special command arguments
 114#     'ret'     - expected command return value (0 by default)
 115#
 116# [eventX:base]
 117#   - one or multiple instances in file
 118#   - expected values assignments
 119class Test(object):
 120    def __init__(self, path, options):
 121        parser = ConfigParser.SafeConfigParser()
 122        parser.read(path)
 123
 124        log.warning("running '%s'" % path)
 125
 126        self.path     = path
 127        self.test_dir = options.test_dir
 128        self.perf     = options.perf
 129        self.command  = parser.get('config', 'command')
 130        self.args     = parser.get('config', 'args')
 131
 132        try:
 133            self.ret  = parser.get('config', 'ret')
 134        except:
 135            self.ret  = 0
 136
 137        self.expect   = {}
 138        self.result   = {}
 139        log.debug("  loading expected events");
 140        self.load_events(path, self.expect)
 141
 142    def is_event(self, name):
 143        if name.find("event") == -1:
 144            return False
 145        else:
 146            return True
 147
 148    def load_events(self, path, events):
 149        parser_event = ConfigParser.SafeConfigParser()
 150        parser_event.read(path)
 151
 152        # The event record section header contains 'event' word,
 153        # optionaly followed by ':' allowing to load 'parent
 154        # event' first as a base
 155        for section in filter(self.is_event, parser_event.sections()):
 156
 157            parser_items = parser_event.items(section);
 158            base_items   = {}
 159
 160            # Read parent event if there's any
 161            if (':' in section):
 162                base = section[section.index(':') + 1:]
 163                parser_base = ConfigParser.SafeConfigParser()
 164                parser_base.read(self.test_dir + '/' + base)
 165                base_items = parser_base.items('event')
 166
 167            e = Event(section, parser_items, base_items)
 168            events[section] = e
 169
 170    def run_cmd(self, tempdir):
 171        cmd = "PERF_TEST_ATTR=%s %s %s -o %s/perf.data %s" % (tempdir,
 172              self.perf, self.command, tempdir, self.args)
 173        ret = os.WEXITSTATUS(os.system(cmd))
 174
 175        log.info("  '%s' ret %d " % (cmd, ret))
 176
 177        if ret != int(self.ret):
 178            raise Unsup(self)
 179
 180    def compare(self, expect, result):
 181        match = {}
 182
 183        log.debug("  compare");
 184
 185        # For each expected event find all matching
 186        # events in result. Fail if there's not any.
 187        for exp_name, exp_event in expect.items():
 188            exp_list = []
 189            log.debug("    matching [%s]" % exp_name)
 190            for res_name, res_event in result.items():
 191                log.debug("      to [%s]" % res_name)
 192                if (exp_event.equal(res_event)):
 193                    exp_list.append(res_name)
 194                    log.debug("    ->OK")
 195                else:
 196                    log.debug("    ->FAIL");
 197
 198            log.debug("    match: [%s] matches %s" % (exp_name, str(exp_list)))
 199
 200            # we did not any matching event - fail
 201            if (not exp_list):
 202                exp_event.diff(res_event)
 203                raise Fail(self, 'match failure');
 204
 205            match[exp_name] = exp_list
 206
 207        # For each defined group in the expected events
 208        # check we match the same group in the result.
 209        for exp_name, exp_event in expect.items():
 210            group = exp_event.group
 211
 212            if (group == ''):
 213                continue
 214
 215            for res_name in match[exp_name]:
 216                res_group = result[res_name].group
 217                if res_group not in match[group]:
 218                    raise Fail(self, 'group failure')
 219
 220                log.debug("    group: [%s] matches group leader %s" %
 221                         (exp_name, str(match[group])))
 222
 223        log.debug("  matched")
 224
 225    def resolve_groups(self, events):
 226        for name, event in events.items():
 227            group_fd = event['group_fd'];
 228            if group_fd == '-1':
 229                continue;
 230
 231            for iname, ievent in events.items():
 232                if (ievent['fd'] == group_fd):
 233                    event.group = iname
 234                    log.debug('[%s] has group leader [%s]' % (name, iname))
 235                    break;
 236
 237    def run(self):
 238        tempdir = tempfile.mkdtemp();
 239
 240        try:
 241            # run the test script
 242            self.run_cmd(tempdir);
 243
 244            # load events expectation for the test
 245            log.debug("  loading result events");
 246            for f in glob.glob(tempdir + '/event*'):
 247                self.load_events(f, self.result);
 248
 249            # resolve group_fd to event names
 250            self.resolve_groups(self.expect);
 251            self.resolve_groups(self.result);
 252
 253            # do the expectation - results matching - both ways
 254            self.compare(self.expect, self.result)
 255            self.compare(self.result, self.expect)
 256
 257        finally:
 258            # cleanup
 259            shutil.rmtree(tempdir)
 260
 261
 262def run_tests(options):
 263    for f in glob.glob(options.test_dir + '/' + options.test):
 264        try:
 265            Test(f, options).run()
 266        except Unsup, obj:
 267            log.warning("unsupp  %s" % obj.getMsg())
 268
 269def setup_log(verbose):
 270    global log
 271    level = logging.CRITICAL
 272
 273    if verbose == 1:
 274        level = logging.WARNING
 275    if verbose == 2:
 276        level = logging.INFO
 277    if verbose >= 3:
 278        level = logging.DEBUG
 279
 280    log = logging.getLogger('test')
 281    log.setLevel(level)
 282    ch  = logging.StreamHandler()
 283    ch.setLevel(level)
 284    formatter = logging.Formatter('%(message)s')
 285    ch.setFormatter(formatter)
 286    log.addHandler(ch)
 287
 288USAGE = '''%s [OPTIONS]
 289  -d dir  # tests dir
 290  -p path # perf binary
 291  -t test # single test
 292  -v      # verbose level
 293''' % sys.argv[0]
 294
 295def main():
 296    parser = optparse.OptionParser(usage=USAGE)
 297
 298    parser.add_option("-t", "--test",
 299                      action="store", type="string", dest="test")
 300    parser.add_option("-d", "--test-dir",
 301                      action="store", type="string", dest="test_dir")
 302    parser.add_option("-p", "--perf",
 303                      action="store", type="string", dest="perf")
 304    parser.add_option("-v", "--verbose",
 305                      action="count", dest="verbose")
 306
 307    options, args = parser.parse_args()
 308    if args:
 309        parser.error('FAILED wrong arguments %s' %  ' '.join(args))
 310        return -1
 311
 312    setup_log(options.verbose)
 313
 314    if not options.test_dir:
 315        print 'FAILED no -d option specified'
 316        sys.exit(-1)
 317
 318    if not options.test:
 319        options.test = 'test*'
 320
 321    try:
 322        run_tests(options)
 323
 324    except Fail, obj:
 325        print "FAILED %s" % obj.getMsg();
 326        sys.exit(-1)
 327
 328    sys.exit(0)
 329
 330if __name__ == '__main__':
 331    main()
 332