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 28*0a4e1ae6SJiri Olsa #include "tests.h" 29*0a4e1ae6SJiri Olsa 30945aea22SJiri Olsa static int trace_event__id(const char *evname) 31945aea22SJiri Olsa { 32945aea22SJiri Olsa char *filename; 33945aea22SJiri Olsa int err = -1, fd; 34945aea22SJiri Olsa 35945aea22SJiri Olsa if (asprintf(&filename, 36945aea22SJiri Olsa "%s/syscalls/%s/id", 37945aea22SJiri Olsa tracing_events_path, evname) < 0) 38945aea22SJiri Olsa return -1; 39945aea22SJiri Olsa 40945aea22SJiri Olsa fd = open(filename, O_RDONLY); 41945aea22SJiri Olsa if (fd >= 0) { 42945aea22SJiri Olsa char id[16]; 43945aea22SJiri Olsa if (read(fd, id, sizeof(id)) > 0) 44945aea22SJiri Olsa err = atoi(id); 45945aea22SJiri Olsa close(fd); 46945aea22SJiri Olsa } 47945aea22SJiri Olsa 48945aea22SJiri Olsa free(filename); 49945aea22SJiri Olsa return err; 50945aea22SJiri Olsa } 51945aea22SJiri Olsa 52945aea22SJiri Olsa static int test__open_syscall_event(void) 53945aea22SJiri Olsa { 54945aea22SJiri Olsa int err = -1, fd; 55945aea22SJiri Olsa struct thread_map *threads; 56945aea22SJiri Olsa struct perf_evsel *evsel; 57945aea22SJiri Olsa struct perf_event_attr attr; 58945aea22SJiri Olsa unsigned int nr_open_calls = 111, i; 59945aea22SJiri Olsa int id = trace_event__id("sys_enter_open"); 60945aea22SJiri Olsa 61945aea22SJiri Olsa if (id < 0) { 62945aea22SJiri Olsa pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); 63945aea22SJiri Olsa return -1; 64945aea22SJiri Olsa } 65945aea22SJiri Olsa 66945aea22SJiri Olsa threads = thread_map__new(-1, getpid(), UINT_MAX); 67945aea22SJiri Olsa if (threads == NULL) { 68945aea22SJiri Olsa pr_debug("thread_map__new\n"); 69945aea22SJiri Olsa return -1; 70945aea22SJiri Olsa } 71945aea22SJiri Olsa 72945aea22SJiri Olsa memset(&attr, 0, sizeof(attr)); 73945aea22SJiri Olsa attr.type = PERF_TYPE_TRACEPOINT; 74945aea22SJiri Olsa attr.config = id; 75945aea22SJiri Olsa evsel = perf_evsel__new(&attr, 0); 76945aea22SJiri Olsa if (evsel == NULL) { 77945aea22SJiri Olsa pr_debug("perf_evsel__new\n"); 78945aea22SJiri Olsa goto out_thread_map_delete; 79945aea22SJiri Olsa } 80945aea22SJiri Olsa 81945aea22SJiri Olsa if (perf_evsel__open_per_thread(evsel, threads) < 0) { 82945aea22SJiri Olsa pr_debug("failed to open counter: %s, " 83945aea22SJiri Olsa "tweak /proc/sys/kernel/perf_event_paranoid?\n", 84945aea22SJiri Olsa strerror(errno)); 85945aea22SJiri Olsa goto out_evsel_delete; 86945aea22SJiri Olsa } 87945aea22SJiri Olsa 88945aea22SJiri Olsa for (i = 0; i < nr_open_calls; ++i) { 89945aea22SJiri Olsa fd = open("/etc/passwd", O_RDONLY); 90945aea22SJiri Olsa close(fd); 91945aea22SJiri Olsa } 92945aea22SJiri Olsa 93945aea22SJiri Olsa if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) { 94945aea22SJiri Olsa pr_debug("perf_evsel__read_on_cpu\n"); 95945aea22SJiri Olsa goto out_close_fd; 96945aea22SJiri Olsa } 97945aea22SJiri Olsa 98945aea22SJiri Olsa if (evsel->counts->cpu[0].val != nr_open_calls) { 99945aea22SJiri Olsa pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n", 100945aea22SJiri Olsa nr_open_calls, evsel->counts->cpu[0].val); 101945aea22SJiri Olsa goto out_close_fd; 102945aea22SJiri Olsa } 103945aea22SJiri Olsa 104945aea22SJiri Olsa err = 0; 105945aea22SJiri Olsa out_close_fd: 106945aea22SJiri Olsa perf_evsel__close_fd(evsel, 1, threads->nr); 107945aea22SJiri Olsa out_evsel_delete: 108945aea22SJiri Olsa perf_evsel__delete(evsel); 109945aea22SJiri Olsa out_thread_map_delete: 110945aea22SJiri Olsa thread_map__delete(threads); 111945aea22SJiri Olsa return err; 112945aea22SJiri Olsa } 113945aea22SJiri Olsa 114945aea22SJiri Olsa #include <sched.h> 115945aea22SJiri Olsa 116945aea22SJiri Olsa static int test__open_syscall_event_on_all_cpus(void) 117945aea22SJiri Olsa { 118945aea22SJiri Olsa int err = -1, fd, cpu; 119945aea22SJiri Olsa struct thread_map *threads; 120945aea22SJiri Olsa struct cpu_map *cpus; 121945aea22SJiri Olsa struct perf_evsel *evsel; 122945aea22SJiri Olsa struct perf_event_attr attr; 123945aea22SJiri Olsa unsigned int nr_open_calls = 111, i; 124945aea22SJiri Olsa cpu_set_t cpu_set; 125945aea22SJiri Olsa int id = trace_event__id("sys_enter_open"); 126945aea22SJiri Olsa 127945aea22SJiri Olsa if (id < 0) { 128945aea22SJiri Olsa pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); 129945aea22SJiri Olsa return -1; 130945aea22SJiri Olsa } 131945aea22SJiri Olsa 132945aea22SJiri Olsa threads = thread_map__new(-1, getpid(), UINT_MAX); 133945aea22SJiri Olsa if (threads == NULL) { 134945aea22SJiri Olsa pr_debug("thread_map__new\n"); 135945aea22SJiri Olsa return -1; 136945aea22SJiri Olsa } 137945aea22SJiri Olsa 138945aea22SJiri Olsa cpus = cpu_map__new(NULL); 139945aea22SJiri Olsa if (cpus == NULL) { 140945aea22SJiri Olsa pr_debug("cpu_map__new\n"); 141945aea22SJiri Olsa goto out_thread_map_delete; 142945aea22SJiri Olsa } 143945aea22SJiri Olsa 144945aea22SJiri Olsa 145945aea22SJiri Olsa CPU_ZERO(&cpu_set); 146945aea22SJiri Olsa 147945aea22SJiri Olsa memset(&attr, 0, sizeof(attr)); 148945aea22SJiri Olsa attr.type = PERF_TYPE_TRACEPOINT; 149945aea22SJiri Olsa attr.config = id; 150945aea22SJiri Olsa evsel = perf_evsel__new(&attr, 0); 151945aea22SJiri Olsa if (evsel == NULL) { 152945aea22SJiri Olsa pr_debug("perf_evsel__new\n"); 153945aea22SJiri Olsa goto out_thread_map_delete; 154945aea22SJiri Olsa } 155945aea22SJiri Olsa 156945aea22SJiri Olsa if (perf_evsel__open(evsel, cpus, threads) < 0) { 157945aea22SJiri Olsa pr_debug("failed to open counter: %s, " 158945aea22SJiri Olsa "tweak /proc/sys/kernel/perf_event_paranoid?\n", 159945aea22SJiri Olsa strerror(errno)); 160945aea22SJiri Olsa goto out_evsel_delete; 161945aea22SJiri Olsa } 162945aea22SJiri Olsa 163945aea22SJiri Olsa for (cpu = 0; cpu < cpus->nr; ++cpu) { 164945aea22SJiri Olsa unsigned int ncalls = nr_open_calls + cpu; 165945aea22SJiri Olsa /* 166945aea22SJiri Olsa * XXX eventually lift this restriction in a way that 167945aea22SJiri Olsa * keeps perf building on older glibc installations 168945aea22SJiri Olsa * without CPU_ALLOC. 1024 cpus in 2010 still seems 169945aea22SJiri Olsa * a reasonable upper limit tho :-) 170945aea22SJiri Olsa */ 171945aea22SJiri Olsa if (cpus->map[cpu] >= CPU_SETSIZE) { 172945aea22SJiri Olsa pr_debug("Ignoring CPU %d\n", cpus->map[cpu]); 173945aea22SJiri Olsa continue; 174945aea22SJiri Olsa } 175945aea22SJiri Olsa 176945aea22SJiri Olsa CPU_SET(cpus->map[cpu], &cpu_set); 177945aea22SJiri Olsa if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { 178945aea22SJiri Olsa pr_debug("sched_setaffinity() failed on CPU %d: %s ", 179945aea22SJiri Olsa cpus->map[cpu], 180945aea22SJiri Olsa strerror(errno)); 181945aea22SJiri Olsa goto out_close_fd; 182945aea22SJiri Olsa } 183945aea22SJiri Olsa for (i = 0; i < ncalls; ++i) { 184945aea22SJiri Olsa fd = open("/etc/passwd", O_RDONLY); 185945aea22SJiri Olsa close(fd); 186945aea22SJiri Olsa } 187945aea22SJiri Olsa CPU_CLR(cpus->map[cpu], &cpu_set); 188945aea22SJiri Olsa } 189945aea22SJiri Olsa 190945aea22SJiri Olsa /* 191945aea22SJiri Olsa * Here we need to explicitely preallocate the counts, as if 192945aea22SJiri Olsa * we use the auto allocation it will allocate just for 1 cpu, 193945aea22SJiri Olsa * as we start by cpu 0. 194945aea22SJiri Olsa */ 195945aea22SJiri Olsa if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) { 196945aea22SJiri Olsa pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr); 197945aea22SJiri Olsa goto out_close_fd; 198945aea22SJiri Olsa } 199945aea22SJiri Olsa 200945aea22SJiri Olsa err = 0; 201945aea22SJiri Olsa 202945aea22SJiri Olsa for (cpu = 0; cpu < cpus->nr; ++cpu) { 203945aea22SJiri Olsa unsigned int expected; 204945aea22SJiri Olsa 205945aea22SJiri Olsa if (cpus->map[cpu] >= CPU_SETSIZE) 206945aea22SJiri Olsa continue; 207945aea22SJiri Olsa 208945aea22SJiri Olsa if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { 209945aea22SJiri Olsa pr_debug("perf_evsel__read_on_cpu\n"); 210945aea22SJiri Olsa err = -1; 211945aea22SJiri Olsa break; 212945aea22SJiri Olsa } 213945aea22SJiri Olsa 214945aea22SJiri Olsa expected = nr_open_calls + cpu; 215945aea22SJiri Olsa if (evsel->counts->cpu[cpu].val != expected) { 216945aea22SJiri Olsa pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n", 217945aea22SJiri Olsa expected, cpus->map[cpu], evsel->counts->cpu[cpu].val); 218945aea22SJiri Olsa err = -1; 219945aea22SJiri Olsa } 220945aea22SJiri Olsa } 221945aea22SJiri Olsa 222945aea22SJiri Olsa out_close_fd: 223945aea22SJiri Olsa perf_evsel__close_fd(evsel, 1, threads->nr); 224945aea22SJiri Olsa out_evsel_delete: 225945aea22SJiri Olsa perf_evsel__delete(evsel); 226945aea22SJiri Olsa out_thread_map_delete: 227945aea22SJiri Olsa thread_map__delete(threads); 228945aea22SJiri Olsa return err; 229945aea22SJiri Olsa } 230945aea22SJiri Olsa 231945aea22SJiri Olsa /* 232945aea22SJiri Olsa * This test will generate random numbers of calls to some getpid syscalls, 233945aea22SJiri Olsa * then establish an mmap for a group of events that are created to monitor 234945aea22SJiri Olsa * the syscalls. 235945aea22SJiri Olsa * 236945aea22SJiri Olsa * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated 237945aea22SJiri Olsa * sample.id field to map back to its respective perf_evsel instance. 238945aea22SJiri Olsa * 239945aea22SJiri Olsa * Then it checks if the number of syscalls reported as perf events by 240945aea22SJiri Olsa * the kernel corresponds to the number of syscalls made. 241945aea22SJiri Olsa */ 242945aea22SJiri Olsa static int test__basic_mmap(void) 243945aea22SJiri Olsa { 244945aea22SJiri Olsa int err = -1; 245945aea22SJiri Olsa union perf_event *event; 246945aea22SJiri Olsa struct thread_map *threads; 247945aea22SJiri Olsa struct cpu_map *cpus; 248945aea22SJiri Olsa struct perf_evlist *evlist; 249945aea22SJiri Olsa struct perf_event_attr attr = { 250945aea22SJiri Olsa .type = PERF_TYPE_TRACEPOINT, 251945aea22SJiri Olsa .read_format = PERF_FORMAT_ID, 252945aea22SJiri Olsa .sample_type = PERF_SAMPLE_ID, 253945aea22SJiri Olsa .watermark = 0, 254945aea22SJiri Olsa }; 255945aea22SJiri Olsa cpu_set_t cpu_set; 256945aea22SJiri Olsa const char *syscall_names[] = { "getsid", "getppid", "getpgrp", 257945aea22SJiri Olsa "getpgid", }; 258945aea22SJiri Olsa pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, 259945aea22SJiri Olsa (void*)getpgid }; 260945aea22SJiri Olsa #define nsyscalls ARRAY_SIZE(syscall_names) 261945aea22SJiri Olsa int ids[nsyscalls]; 262945aea22SJiri Olsa unsigned int nr_events[nsyscalls], 263945aea22SJiri Olsa expected_nr_events[nsyscalls], i, j; 264945aea22SJiri Olsa struct perf_evsel *evsels[nsyscalls], *evsel; 265945aea22SJiri Olsa 266945aea22SJiri Olsa for (i = 0; i < nsyscalls; ++i) { 267945aea22SJiri Olsa char name[64]; 268945aea22SJiri Olsa 269945aea22SJiri Olsa snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); 270945aea22SJiri Olsa ids[i] = trace_event__id(name); 271945aea22SJiri Olsa if (ids[i] < 0) { 272945aea22SJiri Olsa pr_debug("Is debugfs mounted on /sys/kernel/debug?\n"); 273945aea22SJiri Olsa return -1; 274945aea22SJiri Olsa } 275945aea22SJiri Olsa nr_events[i] = 0; 276945aea22SJiri Olsa expected_nr_events[i] = random() % 257; 277945aea22SJiri Olsa } 278945aea22SJiri Olsa 279945aea22SJiri Olsa threads = thread_map__new(-1, getpid(), UINT_MAX); 280945aea22SJiri Olsa if (threads == NULL) { 281945aea22SJiri Olsa pr_debug("thread_map__new\n"); 282945aea22SJiri Olsa return -1; 283945aea22SJiri Olsa } 284945aea22SJiri Olsa 285945aea22SJiri Olsa cpus = cpu_map__new(NULL); 286945aea22SJiri Olsa if (cpus == NULL) { 287945aea22SJiri Olsa pr_debug("cpu_map__new\n"); 288945aea22SJiri Olsa goto out_free_threads; 289945aea22SJiri Olsa } 290945aea22SJiri Olsa 291945aea22SJiri Olsa CPU_ZERO(&cpu_set); 292945aea22SJiri Olsa CPU_SET(cpus->map[0], &cpu_set); 293945aea22SJiri Olsa sched_setaffinity(0, sizeof(cpu_set), &cpu_set); 294945aea22SJiri Olsa if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { 295945aea22SJiri Olsa pr_debug("sched_setaffinity() failed on CPU %d: %s ", 296945aea22SJiri Olsa cpus->map[0], strerror(errno)); 297945aea22SJiri Olsa goto out_free_cpus; 298945aea22SJiri Olsa } 299945aea22SJiri Olsa 300945aea22SJiri Olsa evlist = perf_evlist__new(cpus, threads); 301945aea22SJiri Olsa if (evlist == NULL) { 302945aea22SJiri Olsa pr_debug("perf_evlist__new\n"); 303945aea22SJiri Olsa goto out_free_cpus; 304945aea22SJiri Olsa } 305945aea22SJiri Olsa 306945aea22SJiri Olsa /* anonymous union fields, can't be initialized above */ 307945aea22SJiri Olsa attr.wakeup_events = 1; 308945aea22SJiri Olsa attr.sample_period = 1; 309945aea22SJiri Olsa 310945aea22SJiri Olsa for (i = 0; i < nsyscalls; ++i) { 311945aea22SJiri Olsa attr.config = ids[i]; 312945aea22SJiri Olsa evsels[i] = perf_evsel__new(&attr, i); 313945aea22SJiri Olsa if (evsels[i] == NULL) { 314945aea22SJiri Olsa pr_debug("perf_evsel__new\n"); 315945aea22SJiri Olsa goto out_free_evlist; 316945aea22SJiri Olsa } 317945aea22SJiri Olsa 318945aea22SJiri Olsa perf_evlist__add(evlist, evsels[i]); 319945aea22SJiri Olsa 320945aea22SJiri Olsa if (perf_evsel__open(evsels[i], cpus, threads) < 0) { 321945aea22SJiri Olsa pr_debug("failed to open counter: %s, " 322945aea22SJiri Olsa "tweak /proc/sys/kernel/perf_event_paranoid?\n", 323945aea22SJiri Olsa strerror(errno)); 324945aea22SJiri Olsa goto out_close_fd; 325945aea22SJiri Olsa } 326945aea22SJiri Olsa } 327945aea22SJiri Olsa 328945aea22SJiri Olsa if (perf_evlist__mmap(evlist, 128, true) < 0) { 329945aea22SJiri Olsa pr_debug("failed to mmap events: %d (%s)\n", errno, 330945aea22SJiri Olsa strerror(errno)); 331945aea22SJiri Olsa goto out_close_fd; 332945aea22SJiri Olsa } 333945aea22SJiri Olsa 334945aea22SJiri Olsa for (i = 0; i < nsyscalls; ++i) 335945aea22SJiri Olsa for (j = 0; j < expected_nr_events[i]; ++j) { 336945aea22SJiri Olsa int foo = syscalls[i](); 337945aea22SJiri Olsa ++foo; 338945aea22SJiri Olsa } 339945aea22SJiri Olsa 340945aea22SJiri Olsa while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) { 341945aea22SJiri Olsa struct perf_sample sample; 342945aea22SJiri Olsa 343945aea22SJiri Olsa if (event->header.type != PERF_RECORD_SAMPLE) { 344945aea22SJiri Olsa pr_debug("unexpected %s event\n", 345945aea22SJiri Olsa perf_event__name(event->header.type)); 346945aea22SJiri Olsa goto out_munmap; 347945aea22SJiri Olsa } 348945aea22SJiri Olsa 349945aea22SJiri Olsa err = perf_evlist__parse_sample(evlist, event, &sample); 350945aea22SJiri Olsa if (err) { 351945aea22SJiri Olsa pr_err("Can't parse sample, err = %d\n", err); 352945aea22SJiri Olsa goto out_munmap; 353945aea22SJiri Olsa } 354945aea22SJiri Olsa 355945aea22SJiri Olsa evsel = perf_evlist__id2evsel(evlist, sample.id); 356945aea22SJiri Olsa if (evsel == NULL) { 357945aea22SJiri Olsa pr_debug("event with id %" PRIu64 358945aea22SJiri Olsa " doesn't map to an evsel\n", sample.id); 359945aea22SJiri Olsa goto out_munmap; 360945aea22SJiri Olsa } 361945aea22SJiri Olsa nr_events[evsel->idx]++; 362945aea22SJiri Olsa } 363945aea22SJiri Olsa 364945aea22SJiri Olsa list_for_each_entry(evsel, &evlist->entries, node) { 365945aea22SJiri Olsa if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { 366945aea22SJiri Olsa pr_debug("expected %d %s events, got %d\n", 367945aea22SJiri Olsa expected_nr_events[evsel->idx], 368945aea22SJiri Olsa perf_evsel__name(evsel), nr_events[evsel->idx]); 369945aea22SJiri Olsa goto out_munmap; 370945aea22SJiri Olsa } 371945aea22SJiri Olsa } 372945aea22SJiri Olsa 373945aea22SJiri Olsa err = 0; 374945aea22SJiri Olsa out_munmap: 375945aea22SJiri Olsa perf_evlist__munmap(evlist); 376945aea22SJiri Olsa out_close_fd: 377945aea22SJiri Olsa for (i = 0; i < nsyscalls; ++i) 378945aea22SJiri Olsa perf_evsel__close_fd(evsels[i], 1, threads->nr); 379945aea22SJiri Olsa out_free_evlist: 380945aea22SJiri Olsa perf_evlist__delete(evlist); 381945aea22SJiri Olsa out_free_cpus: 382945aea22SJiri Olsa cpu_map__delete(cpus); 383945aea22SJiri Olsa out_free_threads: 384945aea22SJiri Olsa thread_map__delete(threads); 385945aea22SJiri Olsa return err; 386945aea22SJiri Olsa #undef nsyscalls 387945aea22SJiri Olsa } 388945aea22SJiri Olsa 38912f8f74bSZheng Liu static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp) 390945aea22SJiri Olsa { 391945aea22SJiri Olsa int i, cpu = -1, nrcpus = 1024; 392945aea22SJiri Olsa realloc: 39312f8f74bSZheng Liu CPU_ZERO(maskp); 394945aea22SJiri Olsa 39512f8f74bSZheng Liu if (sched_getaffinity(pid, sizeof(*maskp), maskp) == -1) { 396945aea22SJiri Olsa if (errno == EINVAL && nrcpus < (1024 << 8)) { 397945aea22SJiri Olsa nrcpus = nrcpus << 2; 398945aea22SJiri Olsa goto realloc; 399945aea22SJiri Olsa } 400945aea22SJiri Olsa perror("sched_getaffinity"); 401945aea22SJiri Olsa return -1; 402945aea22SJiri Olsa } 403945aea22SJiri Olsa 404945aea22SJiri Olsa for (i = 0; i < nrcpus; i++) { 40512f8f74bSZheng Liu if (CPU_ISSET(i, maskp)) { 406945aea22SJiri Olsa if (cpu == -1) 40712f8f74bSZheng Liu cpu = i; 40812f8f74bSZheng Liu else 40912f8f74bSZheng Liu CPU_CLR(i, maskp); 41012f8f74bSZheng Liu } 41112f8f74bSZheng Liu } 412945aea22SJiri Olsa 413945aea22SJiri Olsa return cpu; 414945aea22SJiri Olsa } 415945aea22SJiri Olsa 416945aea22SJiri Olsa static int test__PERF_RECORD(void) 417945aea22SJiri Olsa { 418945aea22SJiri Olsa struct perf_record_opts opts = { 419945aea22SJiri Olsa .target = { 420945aea22SJiri Olsa .uid = UINT_MAX, 421945aea22SJiri Olsa .uses_mmap = true, 422945aea22SJiri Olsa }, 423945aea22SJiri Olsa .no_delay = true, 424945aea22SJiri Olsa .freq = 10, 425945aea22SJiri Olsa .mmap_pages = 256, 426945aea22SJiri Olsa }; 42712f8f74bSZheng Liu cpu_set_t cpu_mask; 42812f8f74bSZheng Liu size_t cpu_mask_size = sizeof(cpu_mask); 429945aea22SJiri Olsa struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 430945aea22SJiri Olsa struct perf_evsel *evsel; 431945aea22SJiri Olsa struct perf_sample sample; 432945aea22SJiri Olsa const char *cmd = "sleep"; 433945aea22SJiri Olsa const char *argv[] = { cmd, "1", NULL, }; 434945aea22SJiri Olsa char *bname; 435945aea22SJiri Olsa u64 prev_time = 0; 436945aea22SJiri Olsa bool found_cmd_mmap = false, 437945aea22SJiri Olsa found_libc_mmap = false, 438945aea22SJiri Olsa found_vdso_mmap = false, 439945aea22SJiri Olsa found_ld_mmap = false; 440945aea22SJiri Olsa int err = -1, errs = 0, i, wakeups = 0; 441945aea22SJiri Olsa u32 cpu; 442945aea22SJiri Olsa int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; 443945aea22SJiri Olsa 444945aea22SJiri Olsa if (evlist == NULL || argv == NULL) { 445945aea22SJiri Olsa pr_debug("Not enough memory to create evlist\n"); 446945aea22SJiri Olsa goto out; 447945aea22SJiri Olsa } 448945aea22SJiri Olsa 449945aea22SJiri Olsa /* 450945aea22SJiri Olsa * We need at least one evsel in the evlist, use the default 451945aea22SJiri Olsa * one: "cycles". 452945aea22SJiri Olsa */ 453945aea22SJiri Olsa err = perf_evlist__add_default(evlist); 454945aea22SJiri Olsa if (err < 0) { 455945aea22SJiri Olsa pr_debug("Not enough memory to create evsel\n"); 456945aea22SJiri Olsa goto out_delete_evlist; 457945aea22SJiri Olsa } 458945aea22SJiri Olsa 459945aea22SJiri Olsa /* 460945aea22SJiri Olsa * Create maps of threads and cpus to monitor. In this case 461945aea22SJiri Olsa * we start with all threads and cpus (-1, -1) but then in 462945aea22SJiri Olsa * perf_evlist__prepare_workload we'll fill in the only thread 463945aea22SJiri Olsa * we're monitoring, the one forked there. 464945aea22SJiri Olsa */ 465945aea22SJiri Olsa err = perf_evlist__create_maps(evlist, &opts.target); 466945aea22SJiri Olsa if (err < 0) { 467945aea22SJiri Olsa pr_debug("Not enough memory to create thread/cpu maps\n"); 468945aea22SJiri Olsa goto out_delete_evlist; 469945aea22SJiri Olsa } 470945aea22SJiri Olsa 471945aea22SJiri Olsa /* 472945aea22SJiri Olsa * Prepare the workload in argv[] to run, it'll fork it, and then wait 473945aea22SJiri Olsa * for perf_evlist__start_workload() to exec it. This is done this way 474945aea22SJiri Olsa * so that we have time to open the evlist (calling sys_perf_event_open 475945aea22SJiri Olsa * on all the fds) and then mmap them. 476945aea22SJiri Olsa */ 477945aea22SJiri Olsa err = perf_evlist__prepare_workload(evlist, &opts, argv); 478945aea22SJiri Olsa if (err < 0) { 479945aea22SJiri Olsa pr_debug("Couldn't run the workload!\n"); 480945aea22SJiri Olsa goto out_delete_evlist; 481945aea22SJiri Olsa } 482945aea22SJiri Olsa 483945aea22SJiri Olsa /* 484945aea22SJiri Olsa * Config the evsels, setting attr->comm on the first one, etc. 485945aea22SJiri Olsa */ 486945aea22SJiri Olsa evsel = perf_evlist__first(evlist); 487945aea22SJiri Olsa evsel->attr.sample_type |= PERF_SAMPLE_CPU; 488945aea22SJiri Olsa evsel->attr.sample_type |= PERF_SAMPLE_TID; 489945aea22SJiri Olsa evsel->attr.sample_type |= PERF_SAMPLE_TIME; 490945aea22SJiri Olsa perf_evlist__config_attrs(evlist, &opts); 491945aea22SJiri Olsa 49212f8f74bSZheng Liu err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); 493945aea22SJiri Olsa if (err < 0) { 494945aea22SJiri Olsa pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); 495945aea22SJiri Olsa goto out_delete_evlist; 496945aea22SJiri Olsa } 497945aea22SJiri Olsa 498945aea22SJiri Olsa cpu = err; 499945aea22SJiri Olsa 500945aea22SJiri Olsa /* 501945aea22SJiri Olsa * So that we can check perf_sample.cpu on all the samples. 502945aea22SJiri Olsa */ 50312f8f74bSZheng Liu if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) { 504945aea22SJiri Olsa pr_debug("sched_setaffinity: %s\n", strerror(errno)); 50512f8f74bSZheng Liu goto out_delete_evlist; 506945aea22SJiri Olsa } 507945aea22SJiri Olsa 508945aea22SJiri Olsa /* 509945aea22SJiri Olsa * Call sys_perf_event_open on all the fds on all the evsels, 510945aea22SJiri Olsa * grouping them if asked to. 511945aea22SJiri Olsa */ 512945aea22SJiri Olsa err = perf_evlist__open(evlist); 513945aea22SJiri Olsa if (err < 0) { 514945aea22SJiri Olsa pr_debug("perf_evlist__open: %s\n", strerror(errno)); 515945aea22SJiri Olsa goto out_delete_evlist; 516945aea22SJiri Olsa } 517945aea22SJiri Olsa 518945aea22SJiri Olsa /* 519945aea22SJiri Olsa * mmap the first fd on a given CPU and ask for events for the other 520945aea22SJiri Olsa * fds in the same CPU to be injected in the same mmap ring buffer 521945aea22SJiri Olsa * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)). 522945aea22SJiri Olsa */ 523945aea22SJiri Olsa err = perf_evlist__mmap(evlist, opts.mmap_pages, false); 524945aea22SJiri Olsa if (err < 0) { 525945aea22SJiri Olsa pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 526945aea22SJiri Olsa goto out_delete_evlist; 527945aea22SJiri Olsa } 528945aea22SJiri Olsa 529945aea22SJiri Olsa /* 530945aea22SJiri Olsa * Now that all is properly set up, enable the events, they will 531945aea22SJiri Olsa * count just on workload.pid, which will start... 532945aea22SJiri Olsa */ 533945aea22SJiri Olsa perf_evlist__enable(evlist); 534945aea22SJiri Olsa 535945aea22SJiri Olsa /* 536945aea22SJiri Olsa * Now! 537945aea22SJiri Olsa */ 538945aea22SJiri Olsa perf_evlist__start_workload(evlist); 539945aea22SJiri Olsa 540945aea22SJiri Olsa while (1) { 541945aea22SJiri Olsa int before = total_events; 542945aea22SJiri Olsa 543945aea22SJiri Olsa for (i = 0; i < evlist->nr_mmaps; i++) { 544945aea22SJiri Olsa union perf_event *event; 545945aea22SJiri Olsa 546945aea22SJiri Olsa while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { 547945aea22SJiri Olsa const u32 type = event->header.type; 548945aea22SJiri Olsa const char *name = perf_event__name(type); 549945aea22SJiri Olsa 550945aea22SJiri Olsa ++total_events; 551945aea22SJiri Olsa if (type < PERF_RECORD_MAX) 552945aea22SJiri Olsa nr_events[type]++; 553945aea22SJiri Olsa 554945aea22SJiri Olsa err = perf_evlist__parse_sample(evlist, event, &sample); 555945aea22SJiri Olsa if (err < 0) { 556945aea22SJiri Olsa if (verbose) 557945aea22SJiri Olsa perf_event__fprintf(event, stderr); 558945aea22SJiri Olsa pr_debug("Couldn't parse sample\n"); 559945aea22SJiri Olsa goto out_err; 560945aea22SJiri Olsa } 561945aea22SJiri Olsa 562945aea22SJiri Olsa if (verbose) { 563945aea22SJiri Olsa pr_info("%" PRIu64" %d ", sample.time, sample.cpu); 564945aea22SJiri Olsa perf_event__fprintf(event, stderr); 565945aea22SJiri Olsa } 566945aea22SJiri Olsa 567945aea22SJiri Olsa if (prev_time > sample.time) { 568945aea22SJiri Olsa pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n", 569945aea22SJiri Olsa name, prev_time, sample.time); 570945aea22SJiri Olsa ++errs; 571945aea22SJiri Olsa } 572945aea22SJiri Olsa 573945aea22SJiri Olsa prev_time = sample.time; 574945aea22SJiri Olsa 575945aea22SJiri Olsa if (sample.cpu != cpu) { 576945aea22SJiri Olsa pr_debug("%s with unexpected cpu, expected %d, got %d\n", 577945aea22SJiri Olsa name, cpu, sample.cpu); 578945aea22SJiri Olsa ++errs; 579945aea22SJiri Olsa } 580945aea22SJiri Olsa 581945aea22SJiri Olsa if ((pid_t)sample.pid != evlist->workload.pid) { 582945aea22SJiri Olsa pr_debug("%s with unexpected pid, expected %d, got %d\n", 583945aea22SJiri Olsa name, evlist->workload.pid, sample.pid); 584945aea22SJiri Olsa ++errs; 585945aea22SJiri Olsa } 586945aea22SJiri Olsa 587945aea22SJiri Olsa if ((pid_t)sample.tid != evlist->workload.pid) { 588945aea22SJiri Olsa pr_debug("%s with unexpected tid, expected %d, got %d\n", 589945aea22SJiri Olsa name, evlist->workload.pid, sample.tid); 590945aea22SJiri Olsa ++errs; 591945aea22SJiri Olsa } 592945aea22SJiri Olsa 593945aea22SJiri Olsa if ((type == PERF_RECORD_COMM || 594945aea22SJiri Olsa type == PERF_RECORD_MMAP || 595945aea22SJiri Olsa type == PERF_RECORD_FORK || 596945aea22SJiri Olsa type == PERF_RECORD_EXIT) && 597945aea22SJiri Olsa (pid_t)event->comm.pid != evlist->workload.pid) { 598945aea22SJiri Olsa pr_debug("%s with unexpected pid/tid\n", name); 599945aea22SJiri Olsa ++errs; 600945aea22SJiri Olsa } 601945aea22SJiri Olsa 602945aea22SJiri Olsa if ((type == PERF_RECORD_COMM || 603945aea22SJiri Olsa type == PERF_RECORD_MMAP) && 604945aea22SJiri Olsa event->comm.pid != event->comm.tid) { 605945aea22SJiri Olsa pr_debug("%s with different pid/tid!\n", name); 606945aea22SJiri Olsa ++errs; 607945aea22SJiri Olsa } 608945aea22SJiri Olsa 609945aea22SJiri Olsa switch (type) { 610945aea22SJiri Olsa case PERF_RECORD_COMM: 611945aea22SJiri Olsa if (strcmp(event->comm.comm, cmd)) { 612945aea22SJiri Olsa pr_debug("%s with unexpected comm!\n", name); 613945aea22SJiri Olsa ++errs; 614945aea22SJiri Olsa } 615945aea22SJiri Olsa break; 616945aea22SJiri Olsa case PERF_RECORD_EXIT: 617945aea22SJiri Olsa goto found_exit; 618945aea22SJiri Olsa case PERF_RECORD_MMAP: 619945aea22SJiri Olsa bname = strrchr(event->mmap.filename, '/'); 620945aea22SJiri Olsa if (bname != NULL) { 621945aea22SJiri Olsa if (!found_cmd_mmap) 622945aea22SJiri Olsa found_cmd_mmap = !strcmp(bname + 1, cmd); 623945aea22SJiri Olsa if (!found_libc_mmap) 624945aea22SJiri Olsa found_libc_mmap = !strncmp(bname + 1, "libc", 4); 625945aea22SJiri Olsa if (!found_ld_mmap) 626945aea22SJiri Olsa found_ld_mmap = !strncmp(bname + 1, "ld", 2); 627945aea22SJiri Olsa } else if (!found_vdso_mmap) 628945aea22SJiri Olsa found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]"); 629945aea22SJiri Olsa break; 630945aea22SJiri Olsa 631945aea22SJiri Olsa case PERF_RECORD_SAMPLE: 632945aea22SJiri Olsa /* Just ignore samples for now */ 633945aea22SJiri Olsa break; 634945aea22SJiri Olsa default: 635945aea22SJiri Olsa pr_debug("Unexpected perf_event->header.type %d!\n", 636945aea22SJiri Olsa type); 637945aea22SJiri Olsa ++errs; 638945aea22SJiri Olsa } 639945aea22SJiri Olsa } 640945aea22SJiri Olsa } 641945aea22SJiri Olsa 642945aea22SJiri Olsa /* 643945aea22SJiri Olsa * We don't use poll here because at least at 3.1 times the 644945aea22SJiri Olsa * PERF_RECORD_{!SAMPLE} events don't honour 645945aea22SJiri Olsa * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does. 646945aea22SJiri Olsa */ 647945aea22SJiri Olsa if (total_events == before && false) 648945aea22SJiri Olsa poll(evlist->pollfd, evlist->nr_fds, -1); 649945aea22SJiri Olsa 650945aea22SJiri Olsa sleep(1); 651945aea22SJiri Olsa if (++wakeups > 5) { 652945aea22SJiri Olsa pr_debug("No PERF_RECORD_EXIT event!\n"); 653945aea22SJiri Olsa break; 654945aea22SJiri Olsa } 655945aea22SJiri Olsa } 656945aea22SJiri Olsa 657945aea22SJiri Olsa found_exit: 658945aea22SJiri Olsa if (nr_events[PERF_RECORD_COMM] > 1) { 659945aea22SJiri Olsa pr_debug("Excessive number of PERF_RECORD_COMM events!\n"); 660945aea22SJiri Olsa ++errs; 661945aea22SJiri Olsa } 662945aea22SJiri Olsa 663945aea22SJiri Olsa if (nr_events[PERF_RECORD_COMM] == 0) { 664945aea22SJiri Olsa pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd); 665945aea22SJiri Olsa ++errs; 666945aea22SJiri Olsa } 667945aea22SJiri Olsa 668945aea22SJiri Olsa if (!found_cmd_mmap) { 669945aea22SJiri Olsa pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd); 670945aea22SJiri Olsa ++errs; 671945aea22SJiri Olsa } 672945aea22SJiri Olsa 673945aea22SJiri Olsa if (!found_libc_mmap) { 674945aea22SJiri Olsa pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc"); 675945aea22SJiri Olsa ++errs; 676945aea22SJiri Olsa } 677945aea22SJiri Olsa 678945aea22SJiri Olsa if (!found_ld_mmap) { 679945aea22SJiri Olsa pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld"); 680945aea22SJiri Olsa ++errs; 681945aea22SJiri Olsa } 682945aea22SJiri Olsa 683945aea22SJiri Olsa if (!found_vdso_mmap) { 684945aea22SJiri Olsa pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); 685945aea22SJiri Olsa ++errs; 686945aea22SJiri Olsa } 687945aea22SJiri Olsa out_err: 688945aea22SJiri Olsa perf_evlist__munmap(evlist); 689945aea22SJiri Olsa out_delete_evlist: 690945aea22SJiri Olsa perf_evlist__delete(evlist); 691945aea22SJiri Olsa out: 692945aea22SJiri Olsa return (err < 0 || errs > 0) ? -1 : 0; 693945aea22SJiri Olsa } 694945aea22SJiri Olsa 695945aea22SJiri Olsa 696945aea22SJiri Olsa #if defined(__x86_64__) || defined(__i386__) 697945aea22SJiri Olsa 698945aea22SJiri Olsa #define barrier() asm volatile("" ::: "memory") 699945aea22SJiri Olsa 700945aea22SJiri Olsa static u64 rdpmc(unsigned int counter) 701945aea22SJiri Olsa { 702945aea22SJiri Olsa unsigned int low, high; 703945aea22SJiri Olsa 704945aea22SJiri Olsa asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter)); 705945aea22SJiri Olsa 706945aea22SJiri Olsa return low | ((u64)high) << 32; 707945aea22SJiri Olsa } 708945aea22SJiri Olsa 709945aea22SJiri Olsa static u64 rdtsc(void) 710945aea22SJiri Olsa { 711945aea22SJiri Olsa unsigned int low, high; 712945aea22SJiri Olsa 713945aea22SJiri Olsa asm volatile("rdtsc" : "=a" (low), "=d" (high)); 714945aea22SJiri Olsa 715945aea22SJiri Olsa return low | ((u64)high) << 32; 716945aea22SJiri Olsa } 717945aea22SJiri Olsa 718945aea22SJiri Olsa static u64 mmap_read_self(void *addr) 719945aea22SJiri Olsa { 720945aea22SJiri Olsa struct perf_event_mmap_page *pc = addr; 721945aea22SJiri Olsa u32 seq, idx, time_mult = 0, time_shift = 0; 722945aea22SJiri Olsa u64 count, cyc = 0, time_offset = 0, enabled, running, delta; 723945aea22SJiri Olsa 724945aea22SJiri Olsa do { 725945aea22SJiri Olsa seq = pc->lock; 726945aea22SJiri Olsa barrier(); 727945aea22SJiri Olsa 728945aea22SJiri Olsa enabled = pc->time_enabled; 729945aea22SJiri Olsa running = pc->time_running; 730945aea22SJiri Olsa 731945aea22SJiri Olsa if (enabled != running) { 732945aea22SJiri Olsa cyc = rdtsc(); 733945aea22SJiri Olsa time_mult = pc->time_mult; 734945aea22SJiri Olsa time_shift = pc->time_shift; 735945aea22SJiri Olsa time_offset = pc->time_offset; 736945aea22SJiri Olsa } 737945aea22SJiri Olsa 738945aea22SJiri Olsa idx = pc->index; 739945aea22SJiri Olsa count = pc->offset; 740945aea22SJiri Olsa if (idx) 741945aea22SJiri Olsa count += rdpmc(idx - 1); 742945aea22SJiri Olsa 743945aea22SJiri Olsa barrier(); 744945aea22SJiri Olsa } while (pc->lock != seq); 745945aea22SJiri Olsa 746945aea22SJiri Olsa if (enabled != running) { 747945aea22SJiri Olsa u64 quot, rem; 748945aea22SJiri Olsa 749945aea22SJiri Olsa quot = (cyc >> time_shift); 750945aea22SJiri Olsa rem = cyc & ((1 << time_shift) - 1); 751945aea22SJiri Olsa delta = time_offset + quot * time_mult + 752945aea22SJiri Olsa ((rem * time_mult) >> time_shift); 753945aea22SJiri Olsa 754945aea22SJiri Olsa enabled += delta; 755945aea22SJiri Olsa if (idx) 756945aea22SJiri Olsa running += delta; 757945aea22SJiri Olsa 758945aea22SJiri Olsa quot = count / running; 759945aea22SJiri Olsa rem = count % running; 760945aea22SJiri Olsa count = quot * enabled + (rem * enabled) / running; 761945aea22SJiri Olsa } 762945aea22SJiri Olsa 763945aea22SJiri Olsa return count; 764945aea22SJiri Olsa } 765945aea22SJiri Olsa 766945aea22SJiri Olsa /* 767945aea22SJiri Olsa * If the RDPMC instruction faults then signal this back to the test parent task: 768945aea22SJiri Olsa */ 769945aea22SJiri Olsa static void segfault_handler(int sig __maybe_unused, 770945aea22SJiri Olsa siginfo_t *info __maybe_unused, 771945aea22SJiri Olsa void *uc __maybe_unused) 772945aea22SJiri Olsa { 773945aea22SJiri Olsa exit(-1); 774945aea22SJiri Olsa } 775945aea22SJiri Olsa 776945aea22SJiri Olsa static int __test__rdpmc(void) 777945aea22SJiri Olsa { 778945aea22SJiri Olsa volatile int tmp = 0; 779945aea22SJiri Olsa u64 i, loops = 1000; 780945aea22SJiri Olsa int n; 781945aea22SJiri Olsa int fd; 782945aea22SJiri Olsa void *addr; 783945aea22SJiri Olsa struct perf_event_attr attr = { 784945aea22SJiri Olsa .type = PERF_TYPE_HARDWARE, 785945aea22SJiri Olsa .config = PERF_COUNT_HW_INSTRUCTIONS, 786945aea22SJiri Olsa .exclude_kernel = 1, 787945aea22SJiri Olsa }; 788945aea22SJiri Olsa u64 delta_sum = 0; 789945aea22SJiri Olsa struct sigaction sa; 790945aea22SJiri Olsa 791945aea22SJiri Olsa sigfillset(&sa.sa_mask); 792945aea22SJiri Olsa sa.sa_sigaction = segfault_handler; 793945aea22SJiri Olsa sigaction(SIGSEGV, &sa, NULL); 794945aea22SJiri Olsa 795945aea22SJiri Olsa fd = sys_perf_event_open(&attr, 0, -1, -1, 0); 796945aea22SJiri Olsa if (fd < 0) { 797945aea22SJiri Olsa pr_err("Error: sys_perf_event_open() syscall returned " 798945aea22SJiri Olsa "with %d (%s)\n", fd, strerror(errno)); 799945aea22SJiri Olsa return -1; 800945aea22SJiri Olsa } 801945aea22SJiri Olsa 802945aea22SJiri Olsa addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); 803945aea22SJiri Olsa if (addr == (void *)(-1)) { 804945aea22SJiri Olsa pr_err("Error: mmap() syscall returned with (%s)\n", 805945aea22SJiri Olsa strerror(errno)); 806945aea22SJiri Olsa goto out_close; 807945aea22SJiri Olsa } 808945aea22SJiri Olsa 809945aea22SJiri Olsa for (n = 0; n < 6; n++) { 810945aea22SJiri Olsa u64 stamp, now, delta; 811945aea22SJiri Olsa 812945aea22SJiri Olsa stamp = mmap_read_self(addr); 813945aea22SJiri Olsa 814945aea22SJiri Olsa for (i = 0; i < loops; i++) 815945aea22SJiri Olsa tmp++; 816945aea22SJiri Olsa 817945aea22SJiri Olsa now = mmap_read_self(addr); 818945aea22SJiri Olsa loops *= 10; 819945aea22SJiri Olsa 820945aea22SJiri Olsa delta = now - stamp; 821945aea22SJiri Olsa pr_debug("%14d: %14Lu\n", n, (long long)delta); 822945aea22SJiri Olsa 823945aea22SJiri Olsa delta_sum += delta; 824945aea22SJiri Olsa } 825945aea22SJiri Olsa 826945aea22SJiri Olsa munmap(addr, page_size); 827945aea22SJiri Olsa pr_debug(" "); 828945aea22SJiri Olsa out_close: 829945aea22SJiri Olsa close(fd); 830945aea22SJiri Olsa 831945aea22SJiri Olsa if (!delta_sum) 832945aea22SJiri Olsa return -1; 833945aea22SJiri Olsa 834945aea22SJiri Olsa return 0; 835945aea22SJiri Olsa } 836945aea22SJiri Olsa 837945aea22SJiri Olsa static int test__rdpmc(void) 838945aea22SJiri Olsa { 839945aea22SJiri Olsa int status = 0; 840945aea22SJiri Olsa int wret = 0; 841945aea22SJiri Olsa int ret; 842945aea22SJiri Olsa int pid; 843945aea22SJiri Olsa 844945aea22SJiri Olsa pid = fork(); 845945aea22SJiri Olsa if (pid < 0) 846945aea22SJiri Olsa return -1; 847945aea22SJiri Olsa 848945aea22SJiri Olsa if (!pid) { 849945aea22SJiri Olsa ret = __test__rdpmc(); 850945aea22SJiri Olsa 851945aea22SJiri Olsa exit(ret); 852945aea22SJiri Olsa } 853945aea22SJiri Olsa 854945aea22SJiri Olsa wret = waitpid(pid, &status, 0); 855945aea22SJiri Olsa if (wret < 0 || status) 856945aea22SJiri Olsa return -1; 857945aea22SJiri Olsa 858945aea22SJiri Olsa return 0; 859945aea22SJiri Olsa } 860945aea22SJiri Olsa 861945aea22SJiri Olsa #endif 862945aea22SJiri Olsa 863945aea22SJiri Olsa static int test__perf_pmu(void) 864945aea22SJiri Olsa { 865945aea22SJiri Olsa return perf_pmu__test(); 866945aea22SJiri Olsa } 867945aea22SJiri Olsa 868945aea22SJiri Olsa static int perf_evsel__roundtrip_cache_name_test(void) 869945aea22SJiri Olsa { 870945aea22SJiri Olsa char name[128]; 871945aea22SJiri Olsa int type, op, err = 0, ret = 0, i, idx; 872945aea22SJiri Olsa struct perf_evsel *evsel; 873945aea22SJiri Olsa struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 874945aea22SJiri Olsa 875945aea22SJiri Olsa if (evlist == NULL) 876945aea22SJiri Olsa return -ENOMEM; 877945aea22SJiri Olsa 878945aea22SJiri Olsa for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 879945aea22SJiri Olsa for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 880945aea22SJiri Olsa /* skip invalid cache type */ 881945aea22SJiri Olsa if (!perf_evsel__is_cache_op_valid(type, op)) 882945aea22SJiri Olsa continue; 883945aea22SJiri Olsa 884945aea22SJiri Olsa for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 885945aea22SJiri Olsa __perf_evsel__hw_cache_type_op_res_name(type, op, i, 886945aea22SJiri Olsa name, sizeof(name)); 887945aea22SJiri Olsa err = parse_events(evlist, name, 0); 888945aea22SJiri Olsa if (err) 889945aea22SJiri Olsa ret = err; 890945aea22SJiri Olsa } 891945aea22SJiri Olsa } 892945aea22SJiri Olsa } 893945aea22SJiri Olsa 894945aea22SJiri Olsa idx = 0; 895945aea22SJiri Olsa evsel = perf_evlist__first(evlist); 896945aea22SJiri Olsa 897945aea22SJiri Olsa for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { 898945aea22SJiri Olsa for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { 899945aea22SJiri Olsa /* skip invalid cache type */ 900945aea22SJiri Olsa if (!perf_evsel__is_cache_op_valid(type, op)) 901945aea22SJiri Olsa continue; 902945aea22SJiri Olsa 903945aea22SJiri Olsa for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { 904945aea22SJiri Olsa __perf_evsel__hw_cache_type_op_res_name(type, op, i, 905945aea22SJiri Olsa name, sizeof(name)); 906945aea22SJiri Olsa if (evsel->idx != idx) 907945aea22SJiri Olsa continue; 908945aea22SJiri Olsa 909945aea22SJiri Olsa ++idx; 910945aea22SJiri Olsa 911945aea22SJiri Olsa if (strcmp(perf_evsel__name(evsel), name)) { 912945aea22SJiri Olsa pr_debug("%s != %s\n", perf_evsel__name(evsel), name); 913945aea22SJiri Olsa ret = -1; 914945aea22SJiri Olsa } 915945aea22SJiri Olsa 916945aea22SJiri Olsa evsel = perf_evsel__next(evsel); 917945aea22SJiri Olsa } 918945aea22SJiri Olsa } 919945aea22SJiri Olsa } 920945aea22SJiri Olsa 921945aea22SJiri Olsa perf_evlist__delete(evlist); 922945aea22SJiri Olsa return ret; 923945aea22SJiri Olsa } 924945aea22SJiri Olsa 925945aea22SJiri Olsa static int __perf_evsel__name_array_test(const char *names[], int nr_names) 926945aea22SJiri Olsa { 927945aea22SJiri Olsa int i, err; 928945aea22SJiri Olsa struct perf_evsel *evsel; 929945aea22SJiri Olsa struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 930945aea22SJiri Olsa 931945aea22SJiri Olsa if (evlist == NULL) 932945aea22SJiri Olsa return -ENOMEM; 933945aea22SJiri Olsa 934945aea22SJiri Olsa for (i = 0; i < nr_names; ++i) { 935945aea22SJiri Olsa err = parse_events(evlist, names[i], 0); 936945aea22SJiri Olsa if (err) { 937945aea22SJiri Olsa pr_debug("failed to parse event '%s', err %d\n", 938945aea22SJiri Olsa names[i], err); 939945aea22SJiri Olsa goto out_delete_evlist; 940945aea22SJiri Olsa } 941945aea22SJiri Olsa } 942945aea22SJiri Olsa 943945aea22SJiri Olsa err = 0; 944945aea22SJiri Olsa list_for_each_entry(evsel, &evlist->entries, node) { 945945aea22SJiri Olsa if (strcmp(perf_evsel__name(evsel), names[evsel->idx])) { 946945aea22SJiri Olsa --err; 947945aea22SJiri Olsa pr_debug("%s != %s\n", perf_evsel__name(evsel), names[evsel->idx]); 948945aea22SJiri Olsa } 949945aea22SJiri Olsa } 950945aea22SJiri Olsa 951945aea22SJiri Olsa out_delete_evlist: 952945aea22SJiri Olsa perf_evlist__delete(evlist); 953945aea22SJiri Olsa return err; 954945aea22SJiri Olsa } 955945aea22SJiri Olsa 956945aea22SJiri Olsa #define perf_evsel__name_array_test(names) \ 957945aea22SJiri Olsa __perf_evsel__name_array_test(names, ARRAY_SIZE(names)) 958945aea22SJiri Olsa 959945aea22SJiri Olsa static int perf_evsel__roundtrip_name_test(void) 960945aea22SJiri Olsa { 961945aea22SJiri Olsa int err = 0, ret = 0; 962945aea22SJiri Olsa 963945aea22SJiri Olsa err = perf_evsel__name_array_test(perf_evsel__hw_names); 964945aea22SJiri Olsa if (err) 965945aea22SJiri Olsa ret = err; 966945aea22SJiri Olsa 967945aea22SJiri Olsa err = perf_evsel__name_array_test(perf_evsel__sw_names); 968945aea22SJiri Olsa if (err) 969945aea22SJiri Olsa ret = err; 970945aea22SJiri Olsa 971945aea22SJiri Olsa err = perf_evsel__roundtrip_cache_name_test(); 972945aea22SJiri Olsa if (err) 973945aea22SJiri Olsa ret = err; 974945aea22SJiri Olsa 975945aea22SJiri Olsa return ret; 976945aea22SJiri Olsa } 977945aea22SJiri Olsa 978945aea22SJiri Olsa static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, 979945aea22SJiri Olsa int size, bool should_be_signed) 980945aea22SJiri Olsa { 981945aea22SJiri Olsa struct format_field *field = perf_evsel__field(evsel, name); 982945aea22SJiri Olsa int is_signed; 983945aea22SJiri Olsa int ret = 0; 984945aea22SJiri Olsa 985945aea22SJiri Olsa if (field == NULL) { 986945aea22SJiri Olsa pr_debug("%s: \"%s\" field not found!\n", evsel->name, name); 987945aea22SJiri Olsa return -1; 988945aea22SJiri Olsa } 989945aea22SJiri Olsa 990945aea22SJiri Olsa is_signed = !!(field->flags | FIELD_IS_SIGNED); 991945aea22SJiri Olsa if (should_be_signed && !is_signed) { 992945aea22SJiri Olsa pr_debug("%s: \"%s\" signedness(%d) is wrong, should be %d\n", 993945aea22SJiri Olsa evsel->name, name, is_signed, should_be_signed); 994945aea22SJiri Olsa ret = -1; 995945aea22SJiri Olsa } 996945aea22SJiri Olsa 997945aea22SJiri Olsa if (field->size != size) { 998945aea22SJiri Olsa pr_debug("%s: \"%s\" size (%d) should be %d!\n", 999945aea22SJiri Olsa evsel->name, name, field->size, size); 1000945aea22SJiri Olsa ret = -1; 1001945aea22SJiri Olsa } 1002945aea22SJiri Olsa 1003945aea22SJiri Olsa return ret; 1004945aea22SJiri Olsa } 1005945aea22SJiri Olsa 1006945aea22SJiri Olsa static int perf_evsel__tp_sched_test(void) 1007945aea22SJiri Olsa { 1008945aea22SJiri Olsa struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch", 0); 1009945aea22SJiri Olsa int ret = 0; 1010945aea22SJiri Olsa 1011945aea22SJiri Olsa if (evsel == NULL) { 1012945aea22SJiri Olsa pr_debug("perf_evsel__new\n"); 1013945aea22SJiri Olsa return -1; 1014945aea22SJiri Olsa } 1015945aea22SJiri Olsa 1016945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "prev_comm", 16, true)) 1017945aea22SJiri Olsa ret = -1; 1018945aea22SJiri Olsa 1019945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "prev_pid", 4, true)) 1020945aea22SJiri Olsa ret = -1; 1021945aea22SJiri Olsa 1022945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "prev_prio", 4, true)) 1023945aea22SJiri Olsa ret = -1; 1024945aea22SJiri Olsa 1025945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "prev_state", 8, true)) 1026945aea22SJiri Olsa ret = -1; 1027945aea22SJiri Olsa 1028945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "next_comm", 16, true)) 1029945aea22SJiri Olsa ret = -1; 1030945aea22SJiri Olsa 1031945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "next_pid", 4, true)) 1032945aea22SJiri Olsa ret = -1; 1033945aea22SJiri Olsa 1034945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "next_prio", 4, true)) 1035945aea22SJiri Olsa ret = -1; 1036945aea22SJiri Olsa 1037945aea22SJiri Olsa perf_evsel__delete(evsel); 1038945aea22SJiri Olsa 1039945aea22SJiri Olsa evsel = perf_evsel__newtp("sched", "sched_wakeup", 0); 1040945aea22SJiri Olsa 1041945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "comm", 16, true)) 1042945aea22SJiri Olsa ret = -1; 1043945aea22SJiri Olsa 1044945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "pid", 4, true)) 1045945aea22SJiri Olsa ret = -1; 1046945aea22SJiri Olsa 1047945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "prio", 4, true)) 1048945aea22SJiri Olsa ret = -1; 1049945aea22SJiri Olsa 1050945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "success", 4, true)) 1051945aea22SJiri Olsa ret = -1; 1052945aea22SJiri Olsa 1053945aea22SJiri Olsa if (perf_evsel__test_field(evsel, "target_cpu", 4, true)) 1054945aea22SJiri Olsa ret = -1; 1055945aea22SJiri Olsa 1056945aea22SJiri Olsa return ret; 1057945aea22SJiri Olsa } 1058945aea22SJiri Olsa 1059945aea22SJiri Olsa static int test__syscall_open_tp_fields(void) 1060945aea22SJiri Olsa { 1061945aea22SJiri Olsa struct perf_record_opts opts = { 1062945aea22SJiri Olsa .target = { 1063945aea22SJiri Olsa .uid = UINT_MAX, 1064945aea22SJiri Olsa .uses_mmap = true, 1065945aea22SJiri Olsa }, 1066945aea22SJiri Olsa .no_delay = true, 1067945aea22SJiri Olsa .freq = 1, 1068945aea22SJiri Olsa .mmap_pages = 256, 1069945aea22SJiri Olsa .raw_samples = true, 1070945aea22SJiri Olsa }; 1071945aea22SJiri Olsa const char *filename = "/etc/passwd"; 1072945aea22SJiri Olsa int flags = O_RDONLY | O_DIRECTORY; 1073945aea22SJiri Olsa struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); 1074945aea22SJiri Olsa struct perf_evsel *evsel; 1075945aea22SJiri Olsa int err = -1, i, nr_events = 0, nr_polls = 0; 1076945aea22SJiri Olsa 1077945aea22SJiri Olsa if (evlist == NULL) { 1078945aea22SJiri Olsa pr_debug("%s: perf_evlist__new\n", __func__); 1079945aea22SJiri Olsa goto out; 1080945aea22SJiri Olsa } 1081945aea22SJiri Olsa 1082945aea22SJiri Olsa evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); 1083945aea22SJiri Olsa if (evsel == NULL) { 1084945aea22SJiri Olsa pr_debug("%s: perf_evsel__newtp\n", __func__); 1085945aea22SJiri Olsa goto out_delete_evlist; 1086945aea22SJiri Olsa } 1087945aea22SJiri Olsa 1088945aea22SJiri Olsa perf_evlist__add(evlist, evsel); 1089945aea22SJiri Olsa 1090945aea22SJiri Olsa err = perf_evlist__create_maps(evlist, &opts.target); 1091945aea22SJiri Olsa if (err < 0) { 1092945aea22SJiri Olsa pr_debug("%s: perf_evlist__create_maps\n", __func__); 1093945aea22SJiri Olsa goto out_delete_evlist; 1094945aea22SJiri Olsa } 1095945aea22SJiri Olsa 1096945aea22SJiri Olsa perf_evsel__config(evsel, &opts, evsel); 1097945aea22SJiri Olsa 1098945aea22SJiri Olsa evlist->threads->map[0] = getpid(); 1099945aea22SJiri Olsa 1100945aea22SJiri Olsa err = perf_evlist__open(evlist); 1101945aea22SJiri Olsa if (err < 0) { 1102945aea22SJiri Olsa pr_debug("perf_evlist__open: %s\n", strerror(errno)); 1103945aea22SJiri Olsa goto out_delete_evlist; 1104945aea22SJiri Olsa } 1105945aea22SJiri Olsa 1106945aea22SJiri Olsa err = perf_evlist__mmap(evlist, UINT_MAX, false); 1107945aea22SJiri Olsa if (err < 0) { 1108945aea22SJiri Olsa pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); 1109945aea22SJiri Olsa goto out_delete_evlist; 1110945aea22SJiri Olsa } 1111945aea22SJiri Olsa 1112945aea22SJiri Olsa perf_evlist__enable(evlist); 1113945aea22SJiri Olsa 1114945aea22SJiri Olsa /* 1115945aea22SJiri Olsa * Generate the event: 1116945aea22SJiri Olsa */ 1117945aea22SJiri Olsa open(filename, flags); 1118945aea22SJiri Olsa 1119945aea22SJiri Olsa while (1) { 1120945aea22SJiri Olsa int before = nr_events; 1121945aea22SJiri Olsa 1122945aea22SJiri Olsa for (i = 0; i < evlist->nr_mmaps; i++) { 1123945aea22SJiri Olsa union perf_event *event; 1124945aea22SJiri Olsa 1125945aea22SJiri Olsa while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { 1126945aea22SJiri Olsa const u32 type = event->header.type; 1127945aea22SJiri Olsa int tp_flags; 1128945aea22SJiri Olsa struct perf_sample sample; 1129945aea22SJiri Olsa 1130945aea22SJiri Olsa ++nr_events; 1131945aea22SJiri Olsa 1132945aea22SJiri Olsa if (type != PERF_RECORD_SAMPLE) 1133945aea22SJiri Olsa continue; 1134945aea22SJiri Olsa 1135945aea22SJiri Olsa err = perf_evsel__parse_sample(evsel, event, &sample); 1136945aea22SJiri Olsa if (err) { 1137945aea22SJiri Olsa pr_err("Can't parse sample, err = %d\n", err); 1138945aea22SJiri Olsa goto out_munmap; 1139945aea22SJiri Olsa } 1140945aea22SJiri Olsa 1141945aea22SJiri Olsa tp_flags = perf_evsel__intval(evsel, &sample, "flags"); 1142945aea22SJiri Olsa 1143945aea22SJiri Olsa if (flags != tp_flags) { 1144945aea22SJiri Olsa pr_debug("%s: Expected flags=%#x, got %#x\n", 1145945aea22SJiri Olsa __func__, flags, tp_flags); 1146945aea22SJiri Olsa goto out_munmap; 1147945aea22SJiri Olsa } 1148945aea22SJiri Olsa 1149945aea22SJiri Olsa goto out_ok; 1150945aea22SJiri Olsa } 1151945aea22SJiri Olsa } 1152945aea22SJiri Olsa 1153945aea22SJiri Olsa if (nr_events == before) 1154945aea22SJiri Olsa poll(evlist->pollfd, evlist->nr_fds, 10); 1155945aea22SJiri Olsa 1156945aea22SJiri Olsa if (++nr_polls > 5) { 1157945aea22SJiri Olsa pr_debug("%s: no events!\n", __func__); 1158945aea22SJiri Olsa goto out_munmap; 1159945aea22SJiri Olsa } 1160945aea22SJiri Olsa } 1161945aea22SJiri Olsa out_ok: 1162945aea22SJiri Olsa err = 0; 1163945aea22SJiri Olsa out_munmap: 1164945aea22SJiri Olsa perf_evlist__munmap(evlist); 1165945aea22SJiri Olsa out_delete_evlist: 1166945aea22SJiri Olsa perf_evlist__delete(evlist); 1167945aea22SJiri Olsa out: 1168945aea22SJiri Olsa return err; 1169945aea22SJiri Olsa } 1170945aea22SJiri Olsa 1171945aea22SJiri Olsa static struct test { 1172945aea22SJiri Olsa const char *desc; 1173945aea22SJiri Olsa int (*func)(void); 1174945aea22SJiri Olsa } tests[] = { 1175945aea22SJiri Olsa { 1176945aea22SJiri Olsa .desc = "vmlinux symtab matches kallsyms", 1177945aea22SJiri Olsa .func = test__vmlinux_matches_kallsyms, 1178945aea22SJiri Olsa }, 1179945aea22SJiri Olsa { 1180945aea22SJiri Olsa .desc = "detect open syscall event", 1181945aea22SJiri Olsa .func = test__open_syscall_event, 1182945aea22SJiri Olsa }, 1183945aea22SJiri Olsa { 1184945aea22SJiri Olsa .desc = "detect open syscall event on all cpus", 1185945aea22SJiri Olsa .func = test__open_syscall_event_on_all_cpus, 1186945aea22SJiri Olsa }, 1187945aea22SJiri Olsa { 1188945aea22SJiri Olsa .desc = "read samples using the mmap interface", 1189945aea22SJiri Olsa .func = test__basic_mmap, 1190945aea22SJiri Olsa }, 1191945aea22SJiri Olsa { 1192945aea22SJiri Olsa .desc = "parse events tests", 1193945aea22SJiri Olsa .func = parse_events__test, 1194945aea22SJiri Olsa }, 1195945aea22SJiri Olsa #if defined(__x86_64__) || defined(__i386__) 1196945aea22SJiri Olsa { 1197945aea22SJiri Olsa .desc = "x86 rdpmc test", 1198945aea22SJiri Olsa .func = test__rdpmc, 1199945aea22SJiri Olsa }, 1200945aea22SJiri Olsa #endif 1201945aea22SJiri Olsa { 1202945aea22SJiri Olsa .desc = "Validate PERF_RECORD_* events & perf_sample fields", 1203945aea22SJiri Olsa .func = test__PERF_RECORD, 1204945aea22SJiri Olsa }, 1205945aea22SJiri Olsa { 1206945aea22SJiri Olsa .desc = "Test perf pmu format parsing", 1207945aea22SJiri Olsa .func = test__perf_pmu, 1208945aea22SJiri Olsa }, 1209945aea22SJiri Olsa { 1210945aea22SJiri Olsa .desc = "Test dso data interface", 1211945aea22SJiri Olsa .func = dso__test_data, 1212945aea22SJiri Olsa }, 1213945aea22SJiri Olsa { 1214945aea22SJiri Olsa .desc = "roundtrip evsel->name check", 1215945aea22SJiri Olsa .func = perf_evsel__roundtrip_name_test, 1216945aea22SJiri Olsa }, 1217945aea22SJiri Olsa { 1218945aea22SJiri Olsa .desc = "Check parsing of sched tracepoints fields", 1219945aea22SJiri Olsa .func = perf_evsel__tp_sched_test, 1220945aea22SJiri Olsa }, 1221945aea22SJiri Olsa { 1222945aea22SJiri Olsa .desc = "Generate and check syscalls:sys_enter_open event fields", 1223945aea22SJiri Olsa .func = test__syscall_open_tp_fields, 1224945aea22SJiri Olsa }, 1225945aea22SJiri Olsa { 1226d898b241SJiri Olsa .desc = "struct perf_event_attr setup", 1227d898b241SJiri Olsa .func = test_attr__run, 1228d898b241SJiri Olsa }, 1229d898b241SJiri Olsa { 1230945aea22SJiri Olsa .func = NULL, 1231945aea22SJiri Olsa }, 1232945aea22SJiri Olsa }; 1233945aea22SJiri Olsa 1234945aea22SJiri Olsa static bool perf_test__matches(int curr, int argc, const char *argv[]) 1235945aea22SJiri Olsa { 1236945aea22SJiri Olsa int i; 1237945aea22SJiri Olsa 1238945aea22SJiri Olsa if (argc == 0) 1239945aea22SJiri Olsa return true; 1240945aea22SJiri Olsa 1241945aea22SJiri Olsa for (i = 0; i < argc; ++i) { 1242945aea22SJiri Olsa char *end; 1243945aea22SJiri Olsa long nr = strtoul(argv[i], &end, 10); 1244945aea22SJiri Olsa 1245945aea22SJiri Olsa if (*end == '\0') { 1246945aea22SJiri Olsa if (nr == curr + 1) 1247945aea22SJiri Olsa return true; 1248945aea22SJiri Olsa continue; 1249945aea22SJiri Olsa } 1250945aea22SJiri Olsa 1251945aea22SJiri Olsa if (strstr(tests[curr].desc, argv[i])) 1252945aea22SJiri Olsa return true; 1253945aea22SJiri Olsa } 1254945aea22SJiri Olsa 1255945aea22SJiri Olsa return false; 1256945aea22SJiri Olsa } 1257945aea22SJiri Olsa 1258945aea22SJiri Olsa static int __cmd_test(int argc, const char *argv[]) 1259945aea22SJiri Olsa { 1260945aea22SJiri Olsa int i = 0; 1261945aea22SJiri Olsa int width = 0; 1262945aea22SJiri Olsa 1263945aea22SJiri Olsa while (tests[i].func) { 1264945aea22SJiri Olsa int len = strlen(tests[i].desc); 1265945aea22SJiri Olsa 1266945aea22SJiri Olsa if (width < len) 1267945aea22SJiri Olsa width = len; 1268945aea22SJiri Olsa ++i; 1269945aea22SJiri Olsa } 1270945aea22SJiri Olsa 1271945aea22SJiri Olsa i = 0; 1272945aea22SJiri Olsa while (tests[i].func) { 1273945aea22SJiri Olsa int curr = i++, err; 1274945aea22SJiri Olsa 1275945aea22SJiri Olsa if (!perf_test__matches(curr, argc, argv)) 1276945aea22SJiri Olsa continue; 1277945aea22SJiri Olsa 1278945aea22SJiri Olsa pr_info("%2d: %-*s:", i, width, tests[curr].desc); 1279945aea22SJiri Olsa pr_debug("\n--- start ---\n"); 1280945aea22SJiri Olsa err = tests[curr].func(); 1281945aea22SJiri Olsa pr_debug("---- end ----\n%s:", tests[curr].desc); 1282945aea22SJiri Olsa if (err) 1283945aea22SJiri Olsa color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n"); 1284945aea22SJiri Olsa else 1285945aea22SJiri Olsa pr_info(" Ok\n"); 1286945aea22SJiri Olsa } 1287945aea22SJiri Olsa 1288945aea22SJiri Olsa return 0; 1289945aea22SJiri Olsa } 1290945aea22SJiri Olsa 1291945aea22SJiri Olsa static int perf_test__list(int argc, const char **argv) 1292945aea22SJiri Olsa { 1293945aea22SJiri Olsa int i = 0; 1294945aea22SJiri Olsa 1295945aea22SJiri Olsa while (tests[i].func) { 1296945aea22SJiri Olsa int curr = i++; 1297945aea22SJiri Olsa 1298945aea22SJiri Olsa if (argc > 1 && !strstr(tests[curr].desc, argv[1])) 1299945aea22SJiri Olsa continue; 1300945aea22SJiri Olsa 1301945aea22SJiri Olsa pr_info("%2d: %s\n", i, tests[curr].desc); 1302945aea22SJiri Olsa } 1303945aea22SJiri Olsa 1304945aea22SJiri Olsa return 0; 1305945aea22SJiri Olsa } 1306945aea22SJiri Olsa 1307945aea22SJiri Olsa int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused) 1308945aea22SJiri Olsa { 1309945aea22SJiri Olsa const char * const test_usage[] = { 1310945aea22SJiri Olsa "perf test [<options>] [{list <test-name-fragment>|[<test-name-fragments>|<test-numbers>]}]", 1311945aea22SJiri Olsa NULL, 1312945aea22SJiri Olsa }; 1313945aea22SJiri Olsa const struct option test_options[] = { 1314945aea22SJiri Olsa OPT_INCR('v', "verbose", &verbose, 1315945aea22SJiri Olsa "be more verbose (show symbol address, etc)"), 1316945aea22SJiri Olsa OPT_END() 1317945aea22SJiri Olsa }; 1318945aea22SJiri Olsa 1319945aea22SJiri Olsa argc = parse_options(argc, argv, test_options, test_usage, 0); 1320945aea22SJiri Olsa if (argc >= 1 && !strcmp(argv[0], "list")) 1321945aea22SJiri Olsa return perf_test__list(argc, argv); 1322945aea22SJiri Olsa 1323945aea22SJiri Olsa symbol_conf.priv_size = sizeof(int); 1324945aea22SJiri Olsa symbol_conf.sort_by_name = true; 1325945aea22SJiri Olsa symbol_conf.try_vmlinux_path = true; 1326945aea22SJiri Olsa 1327945aea22SJiri Olsa if (symbol__init() < 0) 1328945aea22SJiri Olsa return -1; 1329945aea22SJiri Olsa 1330945aea22SJiri Olsa return __cmd_test(argc, argv); 1331945aea22SJiri Olsa } 1332