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