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 test__syscall_open_tp_fields(void) 39945aea22SJiri Olsa { 40945aea22SJiri Olsa struct perf_record_opts opts = { 41945aea22SJiri Olsa .target = { 42945aea22SJiri Olsa .uid = UINT_MAX, 43945aea22SJiri Olsa .uses_mmap = true, 44945aea22SJiri Olsa }, 45945aea22SJiri Olsa .no_delay = true, 46945aea22SJiri Olsa .freq = 1, 47945aea22SJiri Olsa .mmap_pages = 256, 48945aea22SJiri Olsa .raw_samples = true, 49945aea22SJiri Olsa }; 50945aea22SJiri Olsa const char *filename = "/etc/passwd"; 51945aea22SJiri Olsa int flags = O_RDONLY | O_DIRECTORY; 52945aea22SJiri Olsa struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 53945aea22SJiri Olsa struct perf_evsel *evsel; 54945aea22SJiri Olsa int err = -1, i, nr_events = 0, nr_polls = 0; 55945aea22SJiri Olsa 56945aea22SJiri Olsa if (evlist == NULL) { 57945aea22SJiri Olsa pr_debug("%s: perf_evlist__new\n", __func__); 58945aea22SJiri Olsa goto out; 59945aea22SJiri Olsa } 60945aea22SJiri Olsa 61945aea22SJiri Olsa evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); 62945aea22SJiri Olsa if (evsel == NULL) { 63945aea22SJiri Olsa pr_debug("%s: perf_evsel__newtp\n", __func__); 64945aea22SJiri Olsa goto out_delete_evlist; 65945aea22SJiri Olsa } 66945aea22SJiri Olsa 67945aea22SJiri Olsa perf_evlist__add(evlist, evsel); 68945aea22SJiri Olsa 69945aea22SJiri Olsa err = perf_evlist__create_maps(evlist, &opts.target); 70945aea22SJiri Olsa if (err < 0) { 71945aea22SJiri Olsa pr_debug("%s: perf_evlist__create_maps\n", __func__); 72945aea22SJiri Olsa goto out_delete_evlist; 73945aea22SJiri Olsa } 74945aea22SJiri Olsa 75945aea22SJiri Olsa perf_evsel__config(evsel, &opts, evsel); 76945aea22SJiri Olsa 77945aea22SJiri Olsa evlist->threads->map[0] = getpid(); 78945aea22SJiri Olsa 79945aea22SJiri Olsa err = perf_evlist__open(evlist); 80945aea22SJiri Olsa if (err < 0) { 81945aea22SJiri Olsa pr_debug("perf_evlist__open: %s\n", strerror(errno)); 82945aea22SJiri Olsa goto out_delete_evlist; 83945aea22SJiri Olsa } 84945aea22SJiri Olsa 85945aea22SJiri Olsa err = perf_evlist__mmap(evlist, UINT_MAX, false); 86945aea22SJiri Olsa if (err < 0) { 87945aea22SJiri Olsa pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 88945aea22SJiri Olsa goto out_delete_evlist; 89945aea22SJiri Olsa } 90945aea22SJiri Olsa 91945aea22SJiri Olsa perf_evlist__enable(evlist); 92945aea22SJiri Olsa 93945aea22SJiri Olsa /* 94945aea22SJiri Olsa * Generate the event: 95945aea22SJiri Olsa */ 96945aea22SJiri Olsa open(filename, flags); 97945aea22SJiri Olsa 98945aea22SJiri Olsa while (1) { 99945aea22SJiri Olsa int before = nr_events; 100945aea22SJiri Olsa 101945aea22SJiri Olsa for (i = 0; i < evlist->nr_mmaps; i++) { 102945aea22SJiri Olsa union perf_event *event; 103945aea22SJiri Olsa 104945aea22SJiri Olsa while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { 105945aea22SJiri Olsa const u32 type = event->header.type; 106945aea22SJiri Olsa int tp_flags; 107945aea22SJiri Olsa struct perf_sample sample; 108945aea22SJiri Olsa 109945aea22SJiri Olsa ++nr_events; 110945aea22SJiri Olsa 111945aea22SJiri Olsa if (type != PERF_RECORD_SAMPLE) 112945aea22SJiri Olsa continue; 113945aea22SJiri Olsa 114945aea22SJiri Olsa err = perf_evsel__parse_sample(evsel, event, &sample); 115945aea22SJiri Olsa if (err) { 116945aea22SJiri Olsa pr_err("Can't parse sample, err = %d\n", err); 117945aea22SJiri Olsa goto out_munmap; 118945aea22SJiri Olsa } 119945aea22SJiri Olsa 120945aea22SJiri Olsa tp_flags = perf_evsel__intval(evsel, &sample, "flags"); 121945aea22SJiri Olsa 122945aea22SJiri Olsa if (flags != tp_flags) { 123945aea22SJiri Olsa pr_debug("%s: Expected flags=%#x, got %#x\n", 124945aea22SJiri Olsa __func__, flags, tp_flags); 125945aea22SJiri Olsa goto out_munmap; 126945aea22SJiri Olsa } 127945aea22SJiri Olsa 128945aea22SJiri Olsa goto out_ok; 129945aea22SJiri Olsa } 130945aea22SJiri Olsa } 131945aea22SJiri Olsa 132945aea22SJiri Olsa if (nr_events == before) 133945aea22SJiri Olsa poll(evlist->pollfd, evlist->nr_fds, 10); 134945aea22SJiri Olsa 135945aea22SJiri Olsa if (++nr_polls > 5) { 136945aea22SJiri Olsa pr_debug("%s: no events!\n", __func__); 137945aea22SJiri Olsa goto out_munmap; 138945aea22SJiri Olsa } 139945aea22SJiri Olsa } 140945aea22SJiri Olsa out_ok: 141945aea22SJiri Olsa err = 0; 142945aea22SJiri Olsa out_munmap: 143945aea22SJiri Olsa perf_evlist__munmap(evlist); 144945aea22SJiri Olsa out_delete_evlist: 145945aea22SJiri Olsa perf_evlist__delete(evlist); 146945aea22SJiri Olsa out: 147945aea22SJiri Olsa return err; 148945aea22SJiri Olsa } 149945aea22SJiri Olsa 150945aea22SJiri Olsa static struct test { 151945aea22SJiri Olsa const char *desc; 152945aea22SJiri Olsa int (*func)(void); 153945aea22SJiri Olsa } tests[] = { 154945aea22SJiri Olsa { 155945aea22SJiri Olsa .desc = "vmlinux symtab matches kallsyms", 156945aea22SJiri Olsa .func = test__vmlinux_matches_kallsyms, 157945aea22SJiri Olsa }, 158945aea22SJiri Olsa { 159945aea22SJiri Olsa .desc = "detect open syscall event", 160945aea22SJiri Olsa .func = test__open_syscall_event, 161945aea22SJiri Olsa }, 162945aea22SJiri Olsa { 163945aea22SJiri Olsa .desc = "detect open syscall event on all cpus", 164945aea22SJiri Olsa .func = test__open_syscall_event_on_all_cpus, 165945aea22SJiri Olsa }, 166945aea22SJiri Olsa { 167945aea22SJiri Olsa .desc = "read samples using the mmap interface", 168945aea22SJiri Olsa .func = test__basic_mmap, 169945aea22SJiri Olsa }, 170945aea22SJiri Olsa { 171945aea22SJiri Olsa .desc = "parse events tests", 172945aea22SJiri Olsa .func = parse_events__test, 173945aea22SJiri Olsa }, 174945aea22SJiri Olsa #if defined(__x86_64__) || defined(__i386__) 175945aea22SJiri Olsa { 176945aea22SJiri Olsa .desc = "x86 rdpmc test", 177945aea22SJiri Olsa .func = test__rdpmc, 178945aea22SJiri Olsa }, 179945aea22SJiri Olsa #endif 180945aea22SJiri Olsa { 181945aea22SJiri Olsa .desc = "Validate PERF_RECORD_* events & perf_sample fields", 182945aea22SJiri Olsa .func = test__PERF_RECORD, 183945aea22SJiri Olsa }, 184945aea22SJiri Olsa { 185945aea22SJiri Olsa .desc = "Test perf pmu format parsing", 186945aea22SJiri Olsa .func = test__perf_pmu, 187945aea22SJiri Olsa }, 188945aea22SJiri Olsa { 189945aea22SJiri Olsa .desc = "Test dso data interface", 190945aea22SJiri Olsa .func = dso__test_data, 191945aea22SJiri Olsa }, 192945aea22SJiri Olsa { 193945aea22SJiri Olsa .desc = "roundtrip evsel->name check", 194cfffae2eSJiri Olsa .func = test__perf_evsel__roundtrip_name_test, 195945aea22SJiri Olsa }, 196945aea22SJiri Olsa { 197945aea22SJiri Olsa .desc = "Check parsing of sched tracepoints fields", 198*5e24a090SJiri Olsa .func = test__perf_evsel__tp_sched_test, 199945aea22SJiri Olsa }, 200945aea22SJiri Olsa { 201945aea22SJiri Olsa .desc = "Generate and check syscalls:sys_enter_open event fields", 202945aea22SJiri Olsa .func = test__syscall_open_tp_fields, 203945aea22SJiri Olsa }, 204945aea22SJiri Olsa { 205d898b241SJiri Olsa .desc = "struct perf_event_attr setup", 206d898b241SJiri Olsa .func = test_attr__run, 207d898b241SJiri Olsa }, 208d898b241SJiri Olsa { 209945aea22SJiri Olsa .func = NULL, 210945aea22SJiri Olsa }, 211945aea22SJiri Olsa }; 212945aea22SJiri Olsa 213945aea22SJiri Olsa static bool perf_test__matches(int curr, int argc, const char *argv[]) 214945aea22SJiri Olsa { 215945aea22SJiri Olsa int i; 216945aea22SJiri Olsa 217945aea22SJiri Olsa if (argc == 0) 218945aea22SJiri Olsa return true; 219945aea22SJiri Olsa 220945aea22SJiri Olsa for (i = 0; i < argc; ++i) { 221945aea22SJiri Olsa char *end; 222945aea22SJiri Olsa long nr = strtoul(argv[i], &end, 10); 223945aea22SJiri Olsa 224945aea22SJiri Olsa if (*end == '\0') { 225945aea22SJiri Olsa if (nr == curr + 1) 226945aea22SJiri Olsa return true; 227945aea22SJiri Olsa continue; 228945aea22SJiri Olsa } 229945aea22SJiri Olsa 230945aea22SJiri Olsa if (strstr(tests[curr].desc, argv[i])) 231945aea22SJiri Olsa return true; 232945aea22SJiri Olsa } 233945aea22SJiri Olsa 234945aea22SJiri Olsa return false; 235945aea22SJiri Olsa } 236945aea22SJiri Olsa 237945aea22SJiri Olsa static int __cmd_test(int argc, const char *argv[]) 238945aea22SJiri Olsa { 239945aea22SJiri Olsa int i = 0; 240945aea22SJiri Olsa int width = 0; 241945aea22SJiri Olsa 242945aea22SJiri Olsa while (tests[i].func) { 243945aea22SJiri Olsa int len = strlen(tests[i].desc); 244945aea22SJiri Olsa 245945aea22SJiri Olsa if (width < len) 246945aea22SJiri Olsa width = len; 247945aea22SJiri Olsa ++i; 248945aea22SJiri Olsa } 249945aea22SJiri Olsa 250945aea22SJiri Olsa i = 0; 251945aea22SJiri Olsa while (tests[i].func) { 252945aea22SJiri Olsa int curr = i++, err; 253945aea22SJiri Olsa 254945aea22SJiri Olsa if (!perf_test__matches(curr, argc, argv)) 255945aea22SJiri Olsa continue; 256945aea22SJiri Olsa 257945aea22SJiri Olsa pr_info("%2d: %-*s:", i, width, tests[curr].desc); 258945aea22SJiri Olsa pr_debug("\n--- start ---\n"); 259945aea22SJiri Olsa err = tests[curr].func(); 260945aea22SJiri Olsa pr_debug("---- end ----\n%s:", tests[curr].desc); 261945aea22SJiri Olsa if (err) 262945aea22SJiri Olsa color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); 263945aea22SJiri Olsa else 264945aea22SJiri Olsa pr_info(" Ok\n"); 265945aea22SJiri Olsa } 266945aea22SJiri Olsa 267945aea22SJiri Olsa return 0; 268945aea22SJiri Olsa } 269945aea22SJiri Olsa 270945aea22SJiri Olsa static int perf_test__list(int argc, const char **argv) 271945aea22SJiri Olsa { 272945aea22SJiri Olsa int i = 0; 273945aea22SJiri Olsa 274945aea22SJiri Olsa while (tests[i].func) { 275945aea22SJiri Olsa int curr = i++; 276945aea22SJiri Olsa 277945aea22SJiri Olsa if (argc > 1 && !strstr(tests[curr].desc, argv[1])) 278945aea22SJiri Olsa continue; 279945aea22SJiri Olsa 280945aea22SJiri Olsa pr_info("%2d: %s\n", i, tests[curr].desc); 281945aea22SJiri Olsa } 282945aea22SJiri Olsa 283945aea22SJiri Olsa return 0; 284945aea22SJiri Olsa } 285945aea22SJiri Olsa 286945aea22SJiri Olsa int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) 287945aea22SJiri Olsa { 288945aea22SJiri Olsa const char * const test_usage[] = { 289945aea22SJiri Olsa "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", 290945aea22SJiri Olsa NULL, 291945aea22SJiri Olsa }; 292945aea22SJiri Olsa const struct option test_options[] = { 293945aea22SJiri Olsa OPT_INCR('v', "verbose", &verbose, 294945aea22SJiri Olsa "be more verbose (show symbol address, etc)"), 295945aea22SJiri Olsa OPT_END() 296945aea22SJiri Olsa }; 297945aea22SJiri Olsa 298945aea22SJiri Olsa argc = parse_options(argc, argv, test_options, test_usage, 0); 299945aea22SJiri Olsa if (argc >= 1 && !strcmp(argv[0], "list")) 300945aea22SJiri Olsa return perf_test__list(argc, argv); 301945aea22SJiri Olsa 302945aea22SJiri Olsa symbol_conf.priv_size = sizeof(int); 303945aea22SJiri Olsa symbol_conf.sort_by_name = true; 304945aea22SJiri Olsa symbol_conf.try_vmlinux_path = true; 305945aea22SJiri Olsa 306945aea22SJiri Olsa if (symbol__init() < 0) 307945aea22SJiri Olsa return -1; 308945aea22SJiri Olsa 309945aea22SJiri Olsa return __cmd_test(argc, argv); 310945aea22SJiri Olsa } 311