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