linux/tools/perf/builtin-test.c
<<
>>
Prefs
   1/*
   2 * builtin-test.c
   3 *
   4 * Builtin regression testing command: ever growing number of sanity tests
   5 */
   6#include "builtin.h"
   7
   8#include "util/cache.h"
   9#include "util/debug.h"
  10#include "util/evlist.h"
  11#include "util/parse-options.h"
  12#include "util/parse-events.h"
  13#include "util/symbol.h"
  14#include "util/thread_map.h"
  15#include "../../include/linux/hw_breakpoint.h"
  16
  17static long page_size;
  18
  19static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym)
  20{
  21        bool *visited = symbol__priv(sym);
  22        *visited = true;
  23        return 0;
  24}
  25
  26static int test__vmlinux_matches_kallsyms(void)
  27{
  28        int err = -1;
  29        struct rb_node *nd;
  30        struct symbol *sym;
  31        struct map *kallsyms_map, *vmlinux_map;
  32        struct machine kallsyms, vmlinux;
  33        enum map_type type = MAP__FUNCTION;
  34        struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
  35
  36        /*
  37         * Step 1:
  38         *
  39         * Init the machines that will hold kernel, modules obtained from
  40         * both vmlinux + .ko files and from /proc/kallsyms split by modules.
  41         */
  42        machine__init(&kallsyms, "", HOST_KERNEL_ID);
  43        machine__init(&vmlinux, "", HOST_KERNEL_ID);
  44
  45        /*
  46         * Step 2:
  47         *
  48         * Create the kernel maps for kallsyms and the DSO where we will then
  49         * load /proc/kallsyms. Also create the modules maps from /proc/modules
  50         * and find the .ko files that match them in /lib/modules/`uname -r`/.
  51         */
  52        if (machine__create_kernel_maps(&kallsyms) < 0) {
  53                pr_debug("machine__create_kernel_maps ");
  54                return -1;
  55        }
  56
  57        /*
  58         * Step 3:
  59         *
  60         * Load and split /proc/kallsyms into multiple maps, one per module.
  61         */
  62        if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) {
  63                pr_debug("dso__load_kallsyms ");
  64                goto out;
  65        }
  66
  67        /*
  68         * Step 4:
  69         *
  70         * kallsyms will be internally on demand sorted by name so that we can
  71         * find the reference relocation * symbol, i.e. the symbol we will use
  72         * to see if the running kernel was relocated by checking if it has the
  73         * same value in the vmlinux file we load.
  74         */
  75        kallsyms_map = machine__kernel_map(&kallsyms, type);
  76
  77        sym = map__find_symbol_by_name(kallsyms_map, ref_reloc_sym.name, NULL);
  78        if (sym == NULL) {
  79                pr_debug("dso__find_symbol_by_name ");
  80                goto out;
  81        }
  82
  83        ref_reloc_sym.addr = sym->start;
  84
  85        /*
  86         * Step 5:
  87         *
  88         * Now repeat step 2, this time for the vmlinux file we'll auto-locate.
  89         */
  90        if (machine__create_kernel_maps(&vmlinux) < 0) {
  91                pr_debug("machine__create_kernel_maps ");
  92                goto out;
  93        }
  94
  95        vmlinux_map = machine__kernel_map(&vmlinux, type);
  96        map__kmap(vmlinux_map)->ref_reloc_sym = &ref_reloc_sym;
  97
  98        /*
  99         * Step 6:
 100         *
 101         * Locate a vmlinux file in the vmlinux path that has a buildid that
 102         * matches the one of the running kernel.
 103         *
 104         * While doing that look if we find the ref reloc symbol, if we find it
 105         * we'll have its ref_reloc_symbol.unrelocated_addr and then
 106         * maps__reloc_vmlinux will notice and set proper ->[un]map_ip routines
 107         * to fixup the symbols.
 108         */
 109        if (machine__load_vmlinux_path(&vmlinux, type,
 110                                       vmlinux_matches_kallsyms_filter) <= 0) {
 111                pr_debug("machine__load_vmlinux_path ");
 112                goto out;
 113        }
 114
 115        err = 0;
 116        /*
 117         * Step 7:
 118         *
 119         * Now look at the symbols in the vmlinux DSO and check if we find all of them
 120         * in the kallsyms dso. For the ones that are in both, check its names and
 121         * end addresses too.
 122         */
 123        for (nd = rb_first(&vmlinux_map->dso->symbols[type]); nd; nd = rb_next(nd)) {
 124                struct symbol *pair, *first_pair;
 125                bool backwards = true;
 126
 127                sym  = rb_entry(nd, struct symbol, rb_node);
 128
 129                if (sym->start == sym->end)
 130                        continue;
 131
 132                first_pair = machine__find_kernel_symbol(&kallsyms, type, sym->start, NULL, NULL);
 133                pair = first_pair;
 134
 135                if (pair && pair->start == sym->start) {
 136next_pair:
 137                        if (strcmp(sym->name, pair->name) == 0) {
 138                                /*
 139                                 * kallsyms don't have the symbol end, so we
 140                                 * set that by using the next symbol start - 1,
 141                                 * in some cases we get this up to a page
 142                                 * wrong, trace_kmalloc when I was developing
 143                                 * this code was one such example, 2106 bytes
 144                                 * off the real size. More than that and we
 145                                 * _really_ have a problem.
 146                                 */
 147                                s64 skew = sym->end - pair->end;
 148                                if (llabs(skew) < page_size)
 149                                        continue;
 150
 151                                pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
 152                                         sym->start, sym->name, sym->end, pair->end);
 153                        } else {
 154                                struct rb_node *nnd;
 155detour:
 156                                nnd = backwards ? rb_prev(&pair->rb_node) :
 157                                                  rb_next(&pair->rb_node);
 158                                if (nnd) {
 159                                        struct symbol *next = rb_entry(nnd, struct symbol, rb_node);
 160
 161                                        if (next->start == sym->start) {
 162                                                pair = next;
 163                                                goto next_pair;
 164                                        }
 165                                }
 166
 167                                if (backwards) {
 168                                        backwards = false;
 169                                        pair = first_pair;
 170                                        goto detour;
 171                                }
 172
 173                                pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n",
 174                                         sym->start, sym->name, pair->name);
 175                        }
 176                } else
 177                        pr_debug("%#" PRIx64 ": %s not on kallsyms\n", sym->start, sym->name);
 178
 179                err = -1;
 180        }
 181
 182        if (!verbose)
 183                goto out;
 184
 185        pr_info("Maps only in vmlinux:\n");
 186
 187        for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
 188                struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
 189                /*
 190                 * If it is the kernel, kallsyms is always "[kernel.kallsyms]", while
 191                 * the kernel will have the path for the vmlinux file being used,
 192                 * so use the short name, less descriptive but the same ("[kernel]" in
 193                 * both cases.
 194                 */
 195                pair = map_groups__find_by_name(&kallsyms.kmaps, type,
 196                                                (pos->dso->kernel ?
 197                                                        pos->dso->short_name :
 198                                                        pos->dso->name));
 199                if (pair)
 200                        pair->priv = 1;
 201                else
 202                        map__fprintf(pos, stderr);
 203        }
 204
 205        pr_info("Maps in vmlinux with a different name in kallsyms:\n");
 206
 207        for (nd = rb_first(&vmlinux.kmaps.maps[type]); nd; nd = rb_next(nd)) {
 208                struct map *pos = rb_entry(nd, struct map, rb_node), *pair;
 209
 210                pair = map_groups__find(&kallsyms.kmaps, type, pos->start);
 211                if (pair == NULL || pair->priv)
 212                        continue;
 213
 214                if (pair->start == pos->start) {
 215                        pair->priv = 1;
 216                        pr_info(" %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s in kallsyms as",
 217                                pos->start, pos->end, pos->pgoff, pos->dso->name);
 218                        if (pos->pgoff != pair->pgoff || pos->end != pair->end)
 219                                pr_info(": \n*%" PRIx64 "-%" PRIx64 " %" PRIx64 "",
 220                                        pair->start, pair->end, pair->pgoff);
 221                        pr_info(" %s\n", pair->dso->name);
 222                        pair->priv = 1;
 223                }
 224        }
 225
 226        pr_info("Maps only in kallsyms:\n");
 227
 228        for (nd = rb_first(&kallsyms.kmaps.maps[type]);
 229             nd; nd = rb_next(nd)) {
 230                struct map *pos = rb_entry(nd, struct map, rb_node);
 231
 232                if (!pos->priv)
 233                        map__fprintf(pos, stderr);
 234        }
 235out:
 236        return err;
 237}
 238
 239#include "util/cpumap.h"
 240#include "util/evsel.h"
 241#include <sys/types.h>
 242
 243static int trace_event__id(const char *evname)
 244{
 245        char *filename;
 246        int err = -1, fd;
 247
 248        if (asprintf(&filename,
 249                     "%s/syscalls/%s/id",
 250                     debugfs_path, evname) < 0)
 251                return -1;
 252
 253        fd = open(filename, O_RDONLY);
 254        if (fd >= 0) {
 255                char id[16];
 256                if (read(fd, id, sizeof(id)) > 0)
 257                        err = atoi(id);
 258                close(fd);
 259        }
 260
 261        free(filename);
 262        return err;
 263}
 264
 265static int test__open_syscall_event(void)
 266{
 267        int err = -1, fd;
 268        struct thread_map *threads;
 269        struct perf_evsel *evsel;
 270        struct perf_event_attr attr;
 271        unsigned int nr_open_calls = 111, i;
 272        int id = trace_event__id("sys_enter_open");
 273
 274        if (id < 0) {
 275                pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
 276                return -1;
 277        }
 278
 279        threads = thread_map__new(-1, getpid());
 280        if (threads == NULL) {
 281                pr_debug("thread_map__new\n");
 282                return -1;
 283        }
 284
 285        memset(&attr, 0, sizeof(attr));
 286        attr.type = PERF_TYPE_TRACEPOINT;
 287        attr.config = id;
 288        evsel = perf_evsel__new(&attr, 0);
 289        if (evsel == NULL) {
 290                pr_debug("perf_evsel__new\n");
 291                goto out_thread_map_delete;
 292        }
 293
 294        if (perf_evsel__open_per_thread(evsel, threads, false, NULL) < 0) {
 295                pr_debug("failed to open counter: %s, "
 296                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 297                         strerror(errno));
 298                goto out_evsel_delete;
 299        }
 300
 301        for (i = 0; i < nr_open_calls; ++i) {
 302                fd = open("/etc/passwd", O_RDONLY);
 303                close(fd);
 304        }
 305
 306        if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) {
 307                pr_debug("perf_evsel__read_on_cpu\n");
 308                goto out_close_fd;
 309        }
 310
 311        if (evsel->counts->cpu[0].val != nr_open_calls) {
 312                pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
 313                         nr_open_calls, evsel->counts->cpu[0].val);
 314                goto out_close_fd;
 315        }
 316        
 317        err = 0;
 318out_close_fd:
 319        perf_evsel__close_fd(evsel, 1, threads->nr);
 320out_evsel_delete:
 321        perf_evsel__delete(evsel);
 322out_thread_map_delete:
 323        thread_map__delete(threads);
 324        return err;
 325}
 326
 327#include <sched.h>
 328
 329static int test__open_syscall_event_on_all_cpus(void)
 330{
 331        int err = -1, fd, cpu;
 332        struct thread_map *threads;
 333        struct cpu_map *cpus;
 334        struct perf_evsel *evsel;
 335        struct perf_event_attr attr;
 336        unsigned int nr_open_calls = 111, i;
 337        cpu_set_t cpu_set;
 338        int id = trace_event__id("sys_enter_open");
 339
 340        if (id < 0) {
 341                pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
 342                return -1;
 343        }
 344
 345        threads = thread_map__new(-1, getpid());
 346        if (threads == NULL) {
 347                pr_debug("thread_map__new\n");
 348                return -1;
 349        }
 350
 351        cpus = cpu_map__new(NULL);
 352        if (cpus == NULL) {
 353                pr_debug("cpu_map__new\n");
 354                goto out_thread_map_delete;
 355        }
 356
 357
 358        CPU_ZERO(&cpu_set);
 359
 360        memset(&attr, 0, sizeof(attr));
 361        attr.type = PERF_TYPE_TRACEPOINT;
 362        attr.config = id;
 363        evsel = perf_evsel__new(&attr, 0);
 364        if (evsel == NULL) {
 365                pr_debug("perf_evsel__new\n");
 366                goto out_thread_map_delete;
 367        }
 368
 369        if (perf_evsel__open(evsel, cpus, threads, false, NULL) < 0) {
 370                pr_debug("failed to open counter: %s, "
 371                         "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 372                         strerror(errno));
 373                goto out_evsel_delete;
 374        }
 375
 376        for (cpu = 0; cpu < cpus->nr; ++cpu) {
 377                unsigned int ncalls = nr_open_calls + cpu;
 378                /*
 379                 * XXX eventually lift this restriction in a way that
 380                 * keeps perf building on older glibc installations
 381                 * without CPU_ALLOC. 1024 cpus in 2010 still seems
 382                 * a reasonable upper limit tho :-)
 383                 */
 384                if (cpus->map[cpu] >= CPU_SETSIZE) {
 385                        pr_debug("Ignoring CPU %d\n", cpus->map[cpu]);
 386                        continue;
 387                }
 388
 389                CPU_SET(cpus->map[cpu], &cpu_set);
 390                if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
 391                        pr_debug("sched_setaffinity() failed on CPU %d: %s ",
 392                                 cpus->map[cpu],
 393                                 strerror(errno));
 394                        goto out_close_fd;
 395                }
 396                for (i = 0; i < ncalls; ++i) {
 397                        fd = open("/etc/passwd", O_RDONLY);
 398                        close(fd);
 399                }
 400                CPU_CLR(cpus->map[cpu], &cpu_set);
 401        }
 402
 403        /*
 404         * Here we need to explicitely preallocate the counts, as if
 405         * we use the auto allocation it will allocate just for 1 cpu,
 406         * as we start by cpu 0.
 407         */
 408        if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
 409                pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
 410                goto out_close_fd;
 411        }
 412
 413        err = 0;
 414
 415        for (cpu = 0; cpu < cpus->nr; ++cpu) {
 416                unsigned int expected;
 417
 418                if (cpus->map[cpu] >= CPU_SETSIZE)
 419                        continue;
 420
 421                if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) {
 422                        pr_debug("perf_evsel__read_on_cpu\n");
 423                        err = -1;
 424                        break;
 425                }
 426
 427                expected = nr_open_calls + cpu;
 428                if (evsel->counts->cpu[cpu].val != expected) {
 429                        pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
 430                                 expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
 431                        err = -1;
 432                }
 433        }
 434
 435out_close_fd:
 436        perf_evsel__close_fd(evsel, 1, threads->nr);
 437out_evsel_delete:
 438        perf_evsel__delete(evsel);
 439out_thread_map_delete:
 440        thread_map__delete(threads);
 441        return err;
 442}
 443
 444/*
 445 * This test will generate random numbers of calls to some getpid syscalls,
 446 * then establish an mmap for a group of events that are created to monitor
 447 * the syscalls.
 448 *
 449 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
 450 * sample.id field to map back to its respective perf_evsel instance.
 451 *
 452 * Then it checks if the number of syscalls reported as perf events by
 453 * the kernel corresponds to the number of syscalls made.
 454 */
 455static int test__basic_mmap(void)
 456{
 457        int err = -1;
 458        union perf_event *event;
 459        struct thread_map *threads;
 460        struct cpu_map *cpus;
 461        struct perf_evlist *evlist;
 462        struct perf_event_attr attr = {
 463                .type           = PERF_TYPE_TRACEPOINT,
 464                .read_format    = PERF_FORMAT_ID,
 465                .sample_type    = PERF_SAMPLE_ID,
 466                .watermark      = 0,
 467        };
 468        cpu_set_t cpu_set;
 469        const char *syscall_names[] = { "getsid", "getppid", "getpgrp",
 470                                        "getpgid", };
 471        pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp,
 472                                      (void*)getpgid };
 473#define nsyscalls ARRAY_SIZE(syscall_names)
 474        int ids[nsyscalls];
 475        unsigned int nr_events[nsyscalls],
 476                     expected_nr_events[nsyscalls], i, j;
 477        struct perf_evsel *evsels[nsyscalls], *evsel;
 478        int sample_size = __perf_evsel__sample_size(attr.sample_type);
 479
 480        for (i = 0; i < nsyscalls; ++i) {
 481                char name[64];
 482
 483                snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
 484                ids[i] = trace_event__id(name);
 485                if (ids[i] < 0) {
 486                        pr_debug("Is debugfs mounted on /sys/kernel/debug?\n");
 487                        return -1;
 488                }
 489                nr_events[i] = 0;
 490                expected_nr_events[i] = random() % 257;
 491        }
 492
 493        threads = thread_map__new(-1, getpid());
 494        if (threads == NULL) {
 495                pr_debug("thread_map__new\n");
 496                return -1;
 497        }
 498
 499        cpus = cpu_map__new(NULL);
 500        if (cpus == NULL) {
 501                pr_debug("cpu_map__new\n");
 502                goto out_free_threads;
 503        }
 504
 505        CPU_ZERO(&cpu_set);
 506        CPU_SET(cpus->map[0], &cpu_set);
 507        sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
 508        if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
 509                pr_debug("sched_setaffinity() failed on CPU %d: %s ",
 510                         cpus->map[0], strerror(errno));
 511                goto out_free_cpus;
 512        }
 513
 514        evlist = perf_evlist__new(cpus, threads);
 515        if (evlist == NULL) {
 516                pr_debug("perf_evlist__new\n");
 517                goto out_free_cpus;
 518        }
 519
 520        /* anonymous union fields, can't be initialized above */
 521        attr.wakeup_events = 1;
 522        attr.sample_period = 1;
 523
 524        for (i = 0; i < nsyscalls; ++i) {
 525                attr.config = ids[i];
 526                evsels[i] = perf_evsel__new(&attr, i);
 527                if (evsels[i] == NULL) {
 528                        pr_debug("perf_evsel__new\n");
 529                        goto out_free_evlist;
 530                }
 531
 532                perf_evlist__add(evlist, evsels[i]);
 533
 534                if (perf_evsel__open(evsels[i], cpus, threads, false, NULL) < 0) {
 535                        pr_debug("failed to open counter: %s, "
 536                                 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
 537                                 strerror(errno));
 538                        goto out_close_fd;
 539                }
 540        }
 541
 542        if (perf_evlist__mmap(evlist, 128, true) < 0) {
 543                pr_debug("failed to mmap events: %d (%s)\n", errno,
 544                         strerror(errno));
 545                goto out_close_fd;
 546        }
 547
 548        for (i = 0; i < nsyscalls; ++i)
 549                for (j = 0; j < expected_nr_events[i]; ++j) {
 550                        int foo = syscalls[i]();
 551                        ++foo;
 552                }
 553
 554        while ((event = perf_evlist__mmap_read(evlist, 0)) != NULL) {
 555                struct perf_sample sample;
 556
 557                if (event->header.type != PERF_RECORD_SAMPLE) {
 558                        pr_debug("unexpected %s event\n",
 559                                 perf_event__name(event->header.type));
 560                        goto out_munmap;
 561                }
 562
 563                err = perf_event__parse_sample(event, attr.sample_type, sample_size,
 564                                               false, &sample, false);
 565                if (err) {
 566                        pr_err("Can't parse sample, err = %d\n", err);
 567                        goto out_munmap;
 568                }
 569
 570                evsel = perf_evlist__id2evsel(evlist, sample.id);
 571                if (evsel == NULL) {
 572                        pr_debug("event with id %" PRIu64
 573                                 " doesn't map to an evsel\n", sample.id);
 574                        goto out_munmap;
 575                }
 576                nr_events[evsel->idx]++;
 577        }
 578
 579        list_for_each_entry(evsel, &evlist->entries, node) {
 580                if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
 581                        pr_debug("expected %d %s events, got %d\n",
 582                                 expected_nr_events[evsel->idx],
 583                                 event_name(evsel), nr_events[evsel->idx]);
 584                        goto out_munmap;
 585                }
 586        }
 587
 588        err = 0;
 589out_munmap:
 590        perf_evlist__munmap(evlist);
 591out_close_fd:
 592        for (i = 0; i < nsyscalls; ++i)
 593                perf_evsel__close_fd(evsels[i], 1, threads->nr);
 594out_free_evlist:
 595        perf_evlist__delete(evlist);
 596out_free_cpus:
 597        cpu_map__delete(cpus);
 598out_free_threads:
 599        thread_map__delete(threads);
 600        return err;
 601#undef nsyscalls
 602}
 603
 604#define TEST_ASSERT_VAL(text, cond) \
 605do { \
 606        if (!cond) { \
 607                pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
 608                return -1; \
 609        } \
 610} while (0)
 611
 612static int test__checkevent_tracepoint(struct perf_evlist *evlist)
 613{
 614        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 615                                              struct perf_evsel, node);
 616
 617        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 618        TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
 619        TEST_ASSERT_VAL("wrong sample_type",
 620                (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
 621                evsel->attr.sample_type);
 622        TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
 623        return 0;
 624}
 625
 626static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
 627{
 628        struct perf_evsel *evsel;
 629
 630        TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
 631
 632        list_for_each_entry(evsel, &evlist->entries, node) {
 633                TEST_ASSERT_VAL("wrong type",
 634                        PERF_TYPE_TRACEPOINT == evsel->attr.type);
 635                TEST_ASSERT_VAL("wrong sample_type",
 636                        (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
 637                        == evsel->attr.sample_type);
 638                TEST_ASSERT_VAL("wrong sample_period",
 639                        1 == evsel->attr.sample_period);
 640        }
 641        return 0;
 642}
 643
 644static int test__checkevent_raw(struct perf_evlist *evlist)
 645{
 646        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 647                                              struct perf_evsel, node);
 648
 649        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 650        TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
 651        TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
 652        return 0;
 653}
 654
 655static int test__checkevent_numeric(struct perf_evlist *evlist)
 656{
 657        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 658                                              struct perf_evsel, node);
 659
 660        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 661        TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
 662        TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
 663        return 0;
 664}
 665
 666static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
 667{
 668        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 669                                              struct perf_evsel, node);
 670
 671        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 672        TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
 673        TEST_ASSERT_VAL("wrong config",
 674                        PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
 675        return 0;
 676}
 677
 678static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
 679{
 680        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 681                                              struct perf_evsel, node);
 682
 683        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 684        TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
 685        TEST_ASSERT_VAL("wrong config",
 686                        PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
 687        return 0;
 688}
 689
 690static int test__checkevent_genhw(struct perf_evlist *evlist)
 691{
 692        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 693                                              struct perf_evsel, node);
 694
 695        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 696        TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
 697        TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
 698        return 0;
 699}
 700
 701static int test__checkevent_breakpoint(struct perf_evlist *evlist)
 702{
 703        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 704                                              struct perf_evsel, node);
 705
 706        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 707        TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
 708        TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
 709        TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
 710                                         evsel->attr.bp_type);
 711        TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
 712                                        evsel->attr.bp_len);
 713        return 0;
 714}
 715
 716static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
 717{
 718        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 719                                              struct perf_evsel, node);
 720
 721        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 722        TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
 723        TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
 724        TEST_ASSERT_VAL("wrong bp_type",
 725                        HW_BREAKPOINT_X == evsel->attr.bp_type);
 726        TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
 727        return 0;
 728}
 729
 730static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
 731{
 732        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 733                                              struct perf_evsel, node);
 734
 735        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 736        TEST_ASSERT_VAL("wrong type",
 737                        PERF_TYPE_BREAKPOINT == evsel->attr.type);
 738        TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
 739        TEST_ASSERT_VAL("wrong bp_type",
 740                        HW_BREAKPOINT_R == evsel->attr.bp_type);
 741        TEST_ASSERT_VAL("wrong bp_len",
 742                        HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
 743        return 0;
 744}
 745
 746static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
 747{
 748        struct perf_evsel *evsel = list_entry(evlist->entries.next,
 749                                              struct perf_evsel, node);
 750
 751        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
 752        TEST_ASSERT_VAL("wrong type",
 753                        PERF_TYPE_BREAKPOINT == evsel->attr.type);
 754        TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
 755        TEST_ASSERT_VAL("wrong bp_type",
 756                        HW_BREAKPOINT_W == evsel->attr.bp_type);
 757        TEST_ASSERT_VAL("wrong bp_len",
 758                        HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
 759        return 0;
 760}
 761
 762static struct test__event_st {
 763        const char *name;
 764        __u32 type;
 765        int (*check)(struct perf_evlist *evlist);
 766} test__events[] = {
 767        {
 768                .name  = "syscalls:sys_enter_open",
 769                .check = test__checkevent_tracepoint,
 770        },
 771        {
 772                .name  = "syscalls:*",
 773                .check = test__checkevent_tracepoint_multi,
 774        },
 775        {
 776                .name  = "r1",
 777                .check = test__checkevent_raw,
 778        },
 779        {
 780                .name  = "1:1",
 781                .check = test__checkevent_numeric,
 782        },
 783        {
 784                .name  = "instructions",
 785                .check = test__checkevent_symbolic_name,
 786        },
 787        {
 788                .name  = "faults",
 789                .check = test__checkevent_symbolic_alias,
 790        },
 791        {
 792                .name  = "L1-dcache-load-miss",
 793                .check = test__checkevent_genhw,
 794        },
 795        {
 796                .name  = "mem:0",
 797                .check = test__checkevent_breakpoint,
 798        },
 799        {
 800                .name  = "mem:0:x",
 801                .check = test__checkevent_breakpoint_x,
 802        },
 803        {
 804                .name  = "mem:0:r",
 805                .check = test__checkevent_breakpoint_r,
 806        },
 807        {
 808                .name  = "mem:0:w",
 809                .check = test__checkevent_breakpoint_w,
 810        },
 811};
 812
 813#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
 814
 815static int test__parse_events(void)
 816{
 817        struct perf_evlist *evlist;
 818        u_int i;
 819        int ret = 0;
 820
 821        for (i = 0; i < TEST__EVENTS_CNT; i++) {
 822                struct test__event_st *e = &test__events[i];
 823
 824                evlist = perf_evlist__new(NULL, NULL);
 825                if (evlist == NULL)
 826                        break;
 827
 828                ret = parse_events(evlist, e->name, 0);
 829                if (ret) {
 830                        pr_debug("failed to parse event '%s', err %d\n",
 831                                 e->name, ret);
 832                        break;
 833                }
 834
 835                ret = e->check(evlist);
 836                if (ret)
 837                        break;
 838
 839                perf_evlist__delete(evlist);
 840        }
 841
 842        return ret;
 843}
 844static struct test {
 845        const char *desc;
 846        int (*func)(void);
 847} tests[] = {
 848        {
 849                .desc = "vmlinux symtab matches kallsyms",
 850                .func = test__vmlinux_matches_kallsyms,
 851        },
 852        {
 853                .desc = "detect open syscall event",
 854                .func = test__open_syscall_event,
 855        },
 856        {
 857                .desc = "detect open syscall event on all cpus",
 858                .func = test__open_syscall_event_on_all_cpus,
 859        },
 860        {
 861                .desc = "read samples using the mmap interface",
 862                .func = test__basic_mmap,
 863        },
 864        {
 865                .desc = "parse events tests",
 866                .func = test__parse_events,
 867        },
 868        {
 869                .func = NULL,
 870        },
 871};
 872
 873static int __cmd_test(void)
 874{
 875        int i = 0;
 876
 877        page_size = sysconf(_SC_PAGE_SIZE);
 878
 879        while (tests[i].func) {
 880                int err;
 881                pr_info("%2d: %s:", i + 1, tests[i].desc);
 882                pr_debug("\n--- start ---\n");
 883                err = tests[i].func();
 884                pr_debug("---- end ----\n%s:", tests[i].desc);
 885                pr_info(" %s\n", err ? "FAILED!\n" : "Ok");
 886                ++i;
 887        }
 888
 889        return 0;
 890}
 891
 892static const char * const test_usage[] = {
 893        "perf test [<options>]",
 894        NULL,
 895};
 896
 897static const struct option test_options[] = {
 898        OPT_INTEGER('v', "verbose", &verbose,
 899                    "be more verbose (show symbol address, etc)"),
 900        OPT_END()
 901};
 902
 903int cmd_test(int argc, const char **argv, const char *prefix __used)
 904{
 905        argc = parse_options(argc, argv, test_options, test_usage, 0);
 906        if (argc)
 907                usage_with_options(test_usage, test_options);
 908
 909        symbol_conf.priv_size = sizeof(int);
 910        symbol_conf.sort_by_name = true;
 911        symbol_conf.try_vmlinux_path = true;
 912
 913        if (symbol__init() < 0)
 914                return -1;
 915
 916        setup_pager();
 917
 918        return __cmd_test();
 919}
 920
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.