diff options
Diffstat (limited to 'tools/perf/tests/attr.py')
-rw-r--r-- | tools/perf/tests/attr.py | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/tools/perf/tests/attr.py b/tools/perf/tests/attr.py new file mode 100644 index 000000000000..e702b82dcb86 --- /dev/null +++ b/tools/perf/tests/attr.py | |||
@@ -0,0 +1,322 @@ | |||
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() | ||