xref: /openbmc/linux/tools/perf/tests/builtin-test.c (revision cfffae2ef7029d38e71d337fbc2a9c6cf1fa5aaf)
1945aea22SJiri Olsa /*
2945aea22SJiri Olsa  * builtin-test.c
3945aea22SJiri Olsa  *
4945aea22SJiri Olsa  * Builtin regression testing command: ever growing number of sanity tests
5945aea22SJiri Olsa  */
6945aea22SJiri Olsa #include "builtin.h"
7945aea22SJiri Olsa 
8945aea22SJiri Olsa #include "util/cache.h"
9945aea22SJiri Olsa #include "util/color.h"
10945aea22SJiri Olsa #include "util/debug.h"
11945aea22SJiri Olsa #include "util/debugfs.h"
12945aea22SJiri Olsa #include "util/evlist.h"
1369d2591aSArnaldo Carvalho de Melo #include "util/machine.h"
14945aea22SJiri Olsa #include "util/parse-options.h"
15945aea22SJiri Olsa #include "util/parse-events.h"
16945aea22SJiri Olsa #include "util/symbol.h"
17945aea22SJiri Olsa #include "util/thread_map.h"
18945aea22SJiri Olsa #include "util/pmu.h"
19945aea22SJiri Olsa #include "event-parse.h"
20945aea22SJiri Olsa #include "../../include/linux/hw_breakpoint.h"
21945aea22SJiri Olsa 
22945aea22SJiri Olsa #include <sys/mman.h>
23945aea22SJiri Olsa 
24945aea22SJiri Olsa #include "util/cpumap.h"
25945aea22SJiri Olsa #include "util/evsel.h"
26945aea22SJiri Olsa #include <sys/types.h>
27945aea22SJiri Olsa 
280a4e1ae6SJiri Olsa #include "tests.h"
290a4e1ae6SJiri Olsa 
30945aea22SJiri Olsa #include <sched.h>
31945aea22SJiri Olsa 
32945aea22SJiri Olsa 
33945aea22SJiri Olsa static int test__perf_pmu(void)
34945aea22SJiri Olsa {
35945aea22SJiri Olsa 	return perf_pmu__test();
36945aea22SJiri Olsa }
37945aea22SJiri Olsa 
38945aea22SJiri Olsa static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
39945aea22SJiri Olsa 				  int size, bool should_be_signed)
40945aea22SJiri Olsa {
41945aea22SJiri Olsa 	struct format_field *field = perf_evsel__field(evsel, name);
42945aea22SJiri Olsa 	int is_signed;
43945aea22SJiri Olsa 	int ret = 0;
44945aea22SJiri Olsa 
45945aea22SJiri Olsa 	if (field == NULL) {
46945aea22SJiri Olsa 		pr_debug("%s: \"%s\" field not found!\n", evsel->name, name);
47945aea22SJiri Olsa 		return -1;
48945aea22SJiri Olsa 	}
49945aea22SJiri Olsa 
50945aea22SJiri Olsa 	is_signed = !!(field->flags | FIELD_IS_SIGNED);
51945aea22SJiri Olsa 	if (should_be_signed && !is_signed) {
52945aea22SJiri Olsa 		pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n",
53945aea22SJiri Olsa 			 evsel->name, name, is_signed, should_be_signed);
54945aea22SJiri Olsa 		ret = -1;
55945aea22SJiri Olsa 	}
56945aea22SJiri Olsa 
57945aea22SJiri Olsa 	if (field->size != size) {
58945aea22SJiri Olsa 		pr_debug("%s: \"%s\" size (%d) should be %d!\n",
59945aea22SJiri Olsa 			 evsel->name, name, field->size, size);
60945aea22SJiri Olsa 		ret = -1;
61945aea22SJiri Olsa 	}
62945aea22SJiri Olsa 
63945aea22SJiri Olsa 	return ret;
64945aea22SJiri Olsa }
65945aea22SJiri Olsa 
66945aea22SJiri Olsa static int perf_evsel__tp_sched_test(void)
67945aea22SJiri Olsa {
68945aea22SJiri Olsa 	struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0);
69945aea22SJiri Olsa 	int ret = 0;
70945aea22SJiri Olsa 
71945aea22SJiri Olsa 	if (evsel == NULL) {
72945aea22SJiri Olsa 		pr_debug("perf_evsel__new\n");
73945aea22SJiri Olsa 		return -1;
74945aea22SJiri Olsa 	}
75945aea22SJiri Olsa 
76945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "prev_comm", 16, true))
77945aea22SJiri Olsa 		ret = -1;
78945aea22SJiri Olsa 
79945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "prev_pid", 4, true))
80945aea22SJiri Olsa 		ret = -1;
81945aea22SJiri Olsa 
82945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
83945aea22SJiri Olsa 		ret = -1;
84945aea22SJiri Olsa 
85945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "prev_state", 8, true))
86945aea22SJiri Olsa 		ret = -1;
87945aea22SJiri Olsa 
88945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "next_comm", 16, true))
89945aea22SJiri Olsa 		ret = -1;
90945aea22SJiri Olsa 
91945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "next_pid", 4, true))
92945aea22SJiri Olsa 		ret = -1;
93945aea22SJiri Olsa 
94945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "next_prio", 4, true))
95945aea22SJiri Olsa 		ret = -1;
96945aea22SJiri Olsa 
97945aea22SJiri Olsa 	perf_evsel__delete(evsel);
98945aea22SJiri Olsa 
99945aea22SJiri Olsa 	evsel = perf_evsel__newtp("sched", "sched_wakeup", 0);
100945aea22SJiri Olsa 
101945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "comm", 16, true))
102945aea22SJiri Olsa 		ret = -1;
103945aea22SJiri Olsa 
104945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "pid", 4, true))
105945aea22SJiri Olsa 		ret = -1;
106945aea22SJiri Olsa 
107945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "prio", 4, true))
108945aea22SJiri Olsa 		ret = -1;
109945aea22SJiri Olsa 
110945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "success", 4, true))
111945aea22SJiri Olsa 		ret = -1;
112945aea22SJiri Olsa 
113945aea22SJiri Olsa 	if (perf_evsel__test_field(evsel, "target_cpu", 4, true))
114945aea22SJiri Olsa 		ret = -1;
115945aea22SJiri Olsa 
116945aea22SJiri Olsa 	return ret;
117945aea22SJiri Olsa }
118945aea22SJiri Olsa 
119945aea22SJiri Olsa static int test__syscall_open_tp_fields(void)
120945aea22SJiri Olsa {
121945aea22SJiri Olsa 	struct perf_record_opts opts = {
122945aea22SJiri Olsa 		.target = {
123945aea22SJiri Olsa 			.uid = UINT_MAX,
124945aea22SJiri Olsa 			.uses_mmap = true,
125945aea22SJiri Olsa 		},
126945aea22SJiri Olsa 		.no_delay   = true,
127945aea22SJiri Olsa 		.freq	    = 1,
128945aea22SJiri Olsa 		.mmap_pages = 256,
129945aea22SJiri Olsa 		.raw_samples = true,
130945aea22SJiri Olsa 	};
131945aea22SJiri Olsa 	const char *filename = "/etc/passwd";
132945aea22SJiri Olsa 	int flags = O_RDONLY | O_DIRECTORY;
133945aea22SJiri Olsa 	struct perf_evlist *evlist = perf_evlist__new(NULL, NULL);
134945aea22SJiri Olsa 	struct perf_evsel *evsel;
135945aea22SJiri Olsa 	int err = -1, i, nr_events = 0, nr_polls = 0;
136945aea22SJiri Olsa 
137945aea22SJiri Olsa 	if (evlist == NULL) {
138945aea22SJiri Olsa 		pr_debug("%s: perf_evlist__new\n", __func__);
139945aea22SJiri Olsa 		goto out;
140945aea22SJiri Olsa 	}
141945aea22SJiri Olsa 
142945aea22SJiri Olsa 	evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0);
143945aea22SJiri Olsa 	if (evsel == NULL) {
144945aea22SJiri Olsa 		pr_debug("%s: perf_evsel__newtp\n", __func__);
145945aea22SJiri Olsa 		goto out_delete_evlist;
146945aea22SJiri Olsa 	}
147945aea22SJiri Olsa 
148945aea22SJiri Olsa 	perf_evlist__add(evlist, evsel);
149945aea22SJiri Olsa 
150945aea22SJiri Olsa 	err = perf_evlist__create_maps(evlist, &opts.target);
151945aea22SJiri Olsa 	if (err < 0) {
152945aea22SJiri Olsa 		pr_debug("%s: perf_evlist__create_maps\n", __func__);
153945aea22SJiri Olsa 		goto out_delete_evlist;
154945aea22SJiri Olsa 	}
155945aea22SJiri Olsa 
156945aea22SJiri Olsa 	perf_evsel__config(evsel, &opts, evsel);
157945aea22SJiri Olsa 
158945aea22SJiri Olsa 	evlist->threads->map[0] = getpid();
159945aea22SJiri Olsa 
160945aea22SJiri Olsa 	err = perf_evlist__open(evlist);
161945aea22SJiri Olsa 	if (err < 0) {
162945aea22SJiri Olsa 		pr_debug("perf_evlist__open: %s\n", strerror(errno));
163945aea22SJiri Olsa 		goto out_delete_evlist;
164945aea22SJiri Olsa 	}
165945aea22SJiri Olsa 
166945aea22SJiri Olsa 	err = perf_evlist__mmap(evlist, UINT_MAX, false);
167945aea22SJiri Olsa 	if (err < 0) {
168945aea22SJiri Olsa 		pr_debug("perf_evlist__mmap: %s\n", strerror(errno));
169945aea22SJiri Olsa 		goto out_delete_evlist;
170945aea22SJiri Olsa 	}
171945aea22SJiri Olsa 
172945aea22SJiri Olsa 	perf_evlist__enable(evlist);
173945aea22SJiri Olsa 
174945aea22SJiri Olsa 	/*
175945aea22SJiri Olsa 	 * Generate the event:
176945aea22SJiri Olsa 	 */
177945aea22SJiri Olsa 	open(filename, flags);
178945aea22SJiri Olsa 
179945aea22SJiri Olsa 	while (1) {
180945aea22SJiri Olsa 		int before = nr_events;
181945aea22SJiri Olsa 
182945aea22SJiri Olsa 		for (i = 0; i < evlist->nr_mmaps; i++) {
183945aea22SJiri Olsa 			union perf_event *event;
184945aea22SJiri Olsa 
185945aea22SJiri Olsa 			while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
186945aea22SJiri Olsa 				const u32 type = event->header.type;
187945aea22SJiri Olsa 				int tp_flags;
188945aea22SJiri Olsa 				struct perf_sample sample;
189945aea22SJiri Olsa 
190945aea22SJiri Olsa 				++nr_events;
191945aea22SJiri Olsa 
192945aea22SJiri Olsa 				if (type != PERF_RECORD_SAMPLE)
193945aea22SJiri Olsa 					continue;
194945aea22SJiri Olsa 
195945aea22SJiri Olsa 				err = perf_evsel__parse_sample(evsel, event, &sample);
196945aea22SJiri Olsa 				if (err) {
197945aea22SJiri Olsa 					pr_err("Can't parse sample, err = %d\n", err);
198945aea22SJiri Olsa 					goto out_munmap;
199945aea22SJiri Olsa 				}
200945aea22SJiri Olsa 
201945aea22SJiri Olsa 				tp_flags = perf_evsel__intval(evsel, &sample, "flags");
202945aea22SJiri Olsa 
203945aea22SJiri Olsa 				if (flags != tp_flags) {
204945aea22SJiri Olsa 					pr_debug("%s: Expected flags=%#x, got %#x\n",
205945aea22SJiri Olsa 						 __func__, flags, tp_flags);
206945aea22SJiri Olsa 					goto out_munmap;
207945aea22SJiri Olsa 				}
208945aea22SJiri Olsa 
209945aea22SJiri Olsa 				goto out_ok;
210945aea22SJiri Olsa 			}
211945aea22SJiri Olsa 		}
212945aea22SJiri Olsa 
213945aea22SJiri Olsa 		if (nr_events == before)
214945aea22SJiri Olsa 			poll(evlist->pollfd, evlist->nr_fds, 10);
215945aea22SJiri Olsa 
216945aea22SJiri Olsa 		if (++nr_polls > 5) {
217945aea22SJiri Olsa 			pr_debug("%s: no events!\n", __func__);
218945aea22SJiri Olsa 			goto out_munmap;
219945aea22SJiri Olsa 		}
220945aea22SJiri Olsa 	}
221945aea22SJiri Olsa out_ok:
222945aea22SJiri Olsa 	err = 0;
223945aea22SJiri Olsa out_munmap:
224945aea22SJiri Olsa 	perf_evlist__munmap(evlist);
225945aea22SJiri Olsa out_delete_evlist:
226945aea22SJiri Olsa 	perf_evlist__delete(evlist);
227945aea22SJiri Olsa out:
228945aea22SJiri Olsa 	return err;
229945aea22SJiri Olsa }
230945aea22SJiri Olsa 
231945aea22SJiri Olsa static struct test {
232945aea22SJiri Olsa 	const char *desc;
233945aea22SJiri Olsa 	int (*func)(void);
234945aea22SJiri Olsa } tests[] = {
235945aea22SJiri Olsa 	{
236945aea22SJiri Olsa 		.desc = "vmlinux symtab matches kallsyms",
237945aea22SJiri Olsa 		.func = test__vmlinux_matches_kallsyms,
238945aea22SJiri Olsa 	},
239945aea22SJiri Olsa 	{
240945aea22SJiri Olsa 		.desc = "detect open syscall event",
241945aea22SJiri Olsa 		.func = test__open_syscall_event,
242945aea22SJiri Olsa 	},
243945aea22SJiri Olsa 	{
244945aea22SJiri Olsa 		.desc = "detect open syscall event on all cpus",
245945aea22SJiri Olsa 		.func = test__open_syscall_event_on_all_cpus,
246945aea22SJiri Olsa 	},
247945aea22SJiri Olsa 	{
248945aea22SJiri Olsa 		.desc = "read samples using the mmap interface",
249945aea22SJiri Olsa 		.func = test__basic_mmap,
250945aea22SJiri Olsa 	},
251945aea22SJiri Olsa 	{
252945aea22SJiri Olsa 		.desc = "parse events tests",
253945aea22SJiri Olsa 		.func = parse_events__test,
254945aea22SJiri Olsa 	},
255945aea22SJiri Olsa #if defined(__x86_64__) || defined(__i386__)
256945aea22SJiri Olsa 	{
257945aea22SJiri Olsa 		.desc = "x86 rdpmc test",
258945aea22SJiri Olsa 		.func = test__rdpmc,
259945aea22SJiri Olsa 	},
260945aea22SJiri Olsa #endif
261945aea22SJiri Olsa 	{
262945aea22SJiri Olsa 		.desc = "Validate PERF_RECORD_* events & perf_sample fields",
263945aea22SJiri Olsa 		.func = test__PERF_RECORD,
264945aea22SJiri Olsa 	},
265945aea22SJiri Olsa 	{
266945aea22SJiri Olsa 		.desc = "Test perf pmu format parsing",
267945aea22SJiri Olsa 		.func = test__perf_pmu,
268945aea22SJiri Olsa 	},
269945aea22SJiri Olsa 	{
270945aea22SJiri Olsa 		.desc = "Test dso data interface",
271945aea22SJiri Olsa 		.func = dso__test_data,
272945aea22SJiri Olsa 	},
273945aea22SJiri Olsa 	{
274945aea22SJiri Olsa 		.desc = "roundtrip evsel->name check",
275*cfffae2eSJiri Olsa 		.func = test__perf_evsel__roundtrip_name_test,
276945aea22SJiri Olsa 	},
277945aea22SJiri Olsa 	{
278945aea22SJiri Olsa 		.desc = "Check parsing of sched tracepoints fields",
279945aea22SJiri Olsa 		.func = perf_evsel__tp_sched_test,
280945aea22SJiri Olsa 	},
281945aea22SJiri Olsa 	{
282945aea22SJiri Olsa 		.desc = "Generate and check syscalls:sys_enter_open event fields",
283945aea22SJiri Olsa 		.func = test__syscall_open_tp_fields,
284945aea22SJiri Olsa 	},
285945aea22SJiri Olsa 	{
286d898b241SJiri Olsa 		.desc = "struct perf_event_attr setup",
287d898b241SJiri Olsa 		.func = test_attr__run,
288d898b241SJiri Olsa 	},
289d898b241SJiri Olsa 	{
290945aea22SJiri Olsa 		.func = NULL,
291945aea22SJiri Olsa 	},
292945aea22SJiri Olsa };
293945aea22SJiri Olsa 
294945aea22SJiri Olsa static bool perf_test__matches(int curr, int argc, const char *argv[])
295945aea22SJiri Olsa {
296945aea22SJiri Olsa 	int i;
297945aea22SJiri Olsa 
298945aea22SJiri Olsa 	if (argc == 0)
299945aea22SJiri Olsa 		return true;
300945aea22SJiri Olsa 
301945aea22SJiri Olsa 	for (i = 0; i < argc; ++i) {
302945aea22SJiri Olsa 		char *end;
303945aea22SJiri Olsa 		long nr = strtoul(argv[i], &end, 10);
304945aea22SJiri Olsa 
305945aea22SJiri Olsa 		if (*end == '\0') {
306945aea22SJiri Olsa 			if (nr == curr + 1)
307945aea22SJiri Olsa 				return true;
308945aea22SJiri Olsa 			continue;
309945aea22SJiri Olsa 		}
310945aea22SJiri Olsa 
311945aea22SJiri Olsa 		if (strstr(tests[curr].desc, argv[i]))
312945aea22SJiri Olsa 			return true;
313945aea22SJiri Olsa 	}
314945aea22SJiri Olsa 
315945aea22SJiri Olsa 	return false;
316945aea22SJiri Olsa }
317945aea22SJiri Olsa 
318945aea22SJiri Olsa static int __cmd_test(int argc, const char *argv[])
319945aea22SJiri Olsa {
320945aea22SJiri Olsa 	int i = 0;
321945aea22SJiri Olsa 	int width = 0;
322945aea22SJiri Olsa 
323945aea22SJiri Olsa 	while (tests[i].func) {
324945aea22SJiri Olsa 		int len = strlen(tests[i].desc);
325945aea22SJiri Olsa 
326945aea22SJiri Olsa 		if (width < len)
327945aea22SJiri Olsa 			width = len;
328945aea22SJiri Olsa 		++i;
329945aea22SJiri Olsa 	}
330945aea22SJiri Olsa 
331945aea22SJiri Olsa 	i = 0;
332945aea22SJiri Olsa 	while (tests[i].func) {
333945aea22SJiri Olsa 		int curr = i++, err;
334945aea22SJiri Olsa 
335945aea22SJiri Olsa 		if (!perf_test__matches(curr, argc, argv))
336945aea22SJiri Olsa 			continue;
337945aea22SJiri Olsa 
338945aea22SJiri Olsa 		pr_info("%2d: %-*s:", i, width, tests[curr].desc);
339945aea22SJiri Olsa 		pr_debug("\n--- start ---\n");
340945aea22SJiri Olsa 		err = tests[curr].func();
341945aea22SJiri Olsa 		pr_debug("---- end ----\n%s:", tests[curr].desc);
342945aea22SJiri Olsa 		if (err)
343945aea22SJiri Olsa 			color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
344945aea22SJiri Olsa 		else
345945aea22SJiri Olsa 			pr_info(" Ok\n");
346945aea22SJiri Olsa 	}
347945aea22SJiri Olsa 
348945aea22SJiri Olsa 	return 0;
349945aea22SJiri Olsa }
350945aea22SJiri Olsa 
351945aea22SJiri Olsa static int perf_test__list(int argc, const char **argv)
352945aea22SJiri Olsa {
353945aea22SJiri Olsa 	int i = 0;
354945aea22SJiri Olsa 
355945aea22SJiri Olsa 	while (tests[i].func) {
356945aea22SJiri Olsa 		int curr = i++;
357945aea22SJiri Olsa 
358945aea22SJiri Olsa 		if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
359945aea22SJiri Olsa 			continue;
360945aea22SJiri Olsa 
361945aea22SJiri Olsa 		pr_info("%2d: %s\n", i, tests[curr].desc);
362945aea22SJiri Olsa 	}
363945aea22SJiri Olsa 
364945aea22SJiri Olsa 	return 0;
365945aea22SJiri Olsa }
366945aea22SJiri Olsa 
367945aea22SJiri Olsa int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
368945aea22SJiri Olsa {
369945aea22SJiri Olsa 	const char * const test_usage[] = {
370945aea22SJiri Olsa 	"perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]",
371945aea22SJiri Olsa 	NULL,
372945aea22SJiri Olsa 	};
373945aea22SJiri Olsa 	const struct option test_options[] = {
374945aea22SJiri Olsa 	OPT_INCR('v', "verbose", &verbose,
375945aea22SJiri Olsa 		    "be more verbose (show symbol address, etc)"),
376945aea22SJiri Olsa 	OPT_END()
377945aea22SJiri Olsa 	};
378945aea22SJiri Olsa 
379945aea22SJiri Olsa 	argc = parse_options(argc, argv, test_options, test_usage, 0);
380945aea22SJiri Olsa 	if (argc >= 1 && !strcmp(argv[0], "list"))
381945aea22SJiri Olsa 		return perf_test__list(argc, argv);
382945aea22SJiri Olsa 
383945aea22SJiri Olsa 	symbol_conf.priv_size = sizeof(int);
384945aea22SJiri Olsa 	symbol_conf.sort_by_name = true;
385945aea22SJiri Olsa 	symbol_conf.try_vmlinux_path = true;
386945aea22SJiri Olsa 
387945aea22SJiri Olsa 	if (symbol__init() < 0)
388945aea22SJiri Olsa 		return -1;
389945aea22SJiri Olsa 
390945aea22SJiri Olsa 	return __cmd_test(argc, argv);
391945aea22SJiri Olsa }
392