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