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