diff options
| -rw-r--r-- | tools/perf/Documentation/perf-trace.txt | 53 | ||||
| -rw-r--r-- | tools/perf/Makefile | 13 | ||||
| -rw-r--r-- | tools/perf/builtin-record.c | 2 | ||||
| -rw-r--r-- | tools/perf/builtin-stat.c | 2 | ||||
| -rw-r--r-- | tools/perf/builtin-test.c | 120 | ||||
| -rw-r--r-- | tools/perf/builtin-top.c | 2 | ||||
| -rw-r--r-- | tools/perf/builtin-trace.c | 310 | ||||
| -rw-r--r-- | tools/perf/builtin.h | 1 | ||||
| -rw-r--r-- | tools/perf/command-list.txt | 1 | ||||
| -rw-r--r-- | tools/perf/config/feature-tests.mak | 11 | ||||
| -rw-r--r-- | tools/perf/perf.c | 3 | ||||
| -rw-r--r-- | tools/perf/util/cpumap.h | 11 | ||||
| -rw-r--r-- | tools/perf/util/dwarf-aux.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/evlist.c | 61 | ||||
| -rw-r--r-- | tools/perf/util/evlist.h | 6 | ||||
| -rw-r--r-- | tools/perf/util/evsel.c | 88 | ||||
| -rw-r--r-- | tools/perf/util/evsel.h | 18 | ||||
| -rw-r--r-- | tools/perf/util/header.c | 6 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 9 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.c | 46 | ||||
| -rw-r--r-- | tools/perf/util/python.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 6 |
22 files changed, 683 insertions, 90 deletions
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt new file mode 100644 index 000000000000..3a2ae37310a9 --- /dev/null +++ b/tools/perf/Documentation/perf-trace.txt | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | perf-trace(1) | ||
| 2 | ============= | ||
| 3 | |||
| 4 | NAME | ||
| 5 | ---- | ||
| 6 | perf-trace - strace inspired tool | ||
| 7 | |||
| 8 | SYNOPSIS | ||
| 9 | -------- | ||
| 10 | [verse] | ||
| 11 | 'perf trace' | ||
| 12 | |||
| 13 | DESCRIPTION | ||
| 14 | ----------- | ||
| 15 | This command will show the events associated with the target, initially | ||
| 16 | syscalls, but other system events like pagefaults, task lifetime events, | ||
| 17 | scheduling events, etc. | ||
| 18 | |||
| 19 | Initially this is a live mode only tool, but eventually will work with | ||
| 20 | perf.data files like the other tools, allowing a detached 'record' from | ||
| 21 | analysis phases. | ||
| 22 | |||
| 23 | OPTIONS | ||
| 24 | ------- | ||
| 25 | |||
| 26 | --all-cpus:: | ||
| 27 | System-wide collection from all CPUs. | ||
| 28 | |||
| 29 | -p:: | ||
| 30 | --pid=:: | ||
| 31 | Record events on existing process ID (comma separated list). | ||
| 32 | |||
| 33 | --tid=:: | ||
| 34 | Record events on existing thread ID (comma separated list). | ||
| 35 | |||
| 36 | --uid=:: | ||
| 37 | Record events in threads owned by uid. Name or number. | ||
| 38 | |||
| 39 | --no-inherit:: | ||
| 40 | Child tasks do not inherit counters. | ||
| 41 | |||
| 42 | --mmap-pages=:: | ||
| 43 | Number of mmap data pages. Must be a power of two. | ||
| 44 | |||
| 45 | --cpu:: | ||
| 46 | Collect samples only on the list of CPUs provided. Multiple CPUs can be provided as a | ||
| 47 | comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. | ||
| 48 | In per-thread mode with inheritance mode on (default), Events are captured only when | ||
| 49 | the thread executes on the designated CPUs. Default is to monitor all CPUs. | ||
| 50 | |||
| 51 | SEE ALSO | ||
| 52 | -------- | ||
| 53 | linkperf:perf-record[1], linkperf:perf-script[1] | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 251dcd7fb5ac..e5e71e7d95a0 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -559,6 +559,19 @@ else | |||
| 559 | LIB_OBJS += $(OUTPUT)util/unwind.o | 559 | LIB_OBJS += $(OUTPUT)util/unwind.o |
| 560 | endif | 560 | endif |
| 561 | 561 | ||
| 562 | ifdef NO_LIBAUDIT | ||
| 563 | BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT | ||
| 564 | else | ||
| 565 | FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit | ||
| 566 | ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT)),y) | ||
| 567 | msg := $(warning No libaudit.h found, disables 'trace' tool, please install audit-libs-devel or libaudit-dev); | ||
| 568 | BASIC_CFLAGS += -DNO_LIBAUDIT_SUPPORT | ||
| 569 | else | ||
| 570 | BUILTIN_OBJS += $(OUTPUT)builtin-trace.o | ||
| 571 | EXTLIBS += -laudit | ||
| 572 | endif | ||
| 573 | endif | ||
| 574 | |||
| 562 | ifdef NO_NEWT | 575 | ifdef NO_NEWT |
| 563 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT | 576 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT |
| 564 | else | 577 | else |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 2cb74343de3e..f14cb5fdb91f 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
| @@ -320,7 +320,7 @@ try_again: | |||
| 320 | } | 320 | } |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | if (perf_evlist__set_filters(evlist)) { | 323 | if (perf_evlist__apply_filters(evlist)) { |
| 324 | error("failed to set filter with %d (%s)\n", errno, | 324 | error("failed to set filter with %d (%s)\n", errno, |
| 325 | strerror(errno)); | 325 | strerror(errno)); |
| 326 | rc = -1; | 326 | rc = -1; |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e0f65fe65944..e8cd4d81b06e 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -478,7 +478,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) | |||
| 478 | counter->supported = true; | 478 | counter->supported = true; |
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | if (perf_evlist__set_filters(evsel_list)) { | 481 | if (perf_evlist__apply_filters(evsel_list)) { |
| 482 | error("failed to set filter with %d (%s)\n", errno, | 482 | error("failed to set filter with %d (%s)\n", errno, |
| 483 | strerror(errno)); | 483 | strerror(errno)); |
| 484 | return -1; | 484 | return -1; |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 78b47a75a7c9..484f26cc0c00 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
| @@ -564,7 +564,7 @@ static int test__basic_mmap(void) | |||
| 564 | goto out_munmap; | 564 | goto out_munmap; |
| 565 | } | 565 | } |
| 566 | 566 | ||
| 567 | err = perf_evlist__parse_sample(evlist, event, &sample, false); | 567 | err = perf_evlist__parse_sample(evlist, event, &sample); |
| 568 | if (err) { | 568 | if (err) { |
| 569 | pr_err("Can't parse sample, err = %d\n", err); | 569 | pr_err("Can't parse sample, err = %d\n", err); |
| 570 | goto out_munmap; | 570 | goto out_munmap; |
| @@ -781,7 +781,7 @@ static int test__PERF_RECORD(void) | |||
| 781 | if (type < PERF_RECORD_MAX) | 781 | if (type < PERF_RECORD_MAX) |
| 782 | nr_events[type]++; | 782 | nr_events[type]++; |
| 783 | 783 | ||
| 784 | err = perf_evlist__parse_sample(evlist, event, &sample, false); | 784 | err = perf_evlist__parse_sample(evlist, event, &sample); |
| 785 | if (err < 0) { | 785 | if (err < 0) { |
| 786 | if (verbose) | 786 | if (verbose) |
| 787 | perf_event__fprintf(event, stderr); | 787 | perf_event__fprintf(event, stderr); |
| @@ -1289,6 +1289,118 @@ static int perf_evsel__tp_sched_test(void) | |||
| 1289 | return ret; | 1289 | return ret; |
| 1290 | } | 1290 | } |
| 1291 | 1291 | ||
| 1292 | static int test__syscall_open_tp_fields(void) | ||
| 1293 | { | ||
| 1294 | struct perf_record_opts opts = { | ||
| 1295 | .target = { | ||
| 1296 | .uid = UINT_MAX, | ||
| 1297 | .uses_mmap = true, | ||
| 1298 | }, | ||
| 1299 | .no_delay = true, | ||
| 1300 | .freq = 1, | ||
| 1301 | .mmap_pages = 256, | ||
| 1302 | .raw_samples = true, | ||
| 1303 | }; | ||
| 1304 | const char *filename = "/etc/passwd"; | ||
| 1305 | int flags = O_RDONLY | O_DIRECTORY; | ||
| 1306 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | ||
| 1307 | struct perf_evsel *evsel; | ||
| 1308 | int err = -1, i, nr_events = 0, nr_polls = 0; | ||
| 1309 | |||
| 1310 | if (evlist == NULL) { | ||
| 1311 | pr_debug("%s: perf_evlist__new\n", __func__); | ||
| 1312 | goto out; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | evsel = perf_evsel__newtp("syscalls", "sys_enter_open", 0); | ||
| 1316 | if (evsel == NULL) { | ||
| 1317 | pr_debug("%s: perf_evsel__newtp\n", __func__); | ||
| 1318 | goto out_delete_evlist; | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | perf_evlist__add(evlist, evsel); | ||
| 1322 | |||
| 1323 | err = perf_evlist__create_maps(evlist, &opts.target); | ||
| 1324 | if (err < 0) { | ||
| 1325 | pr_debug("%s: perf_evlist__create_maps\n", __func__); | ||
| 1326 | goto out_delete_evlist; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | perf_evsel__config(evsel, &opts, evsel); | ||
| 1330 | |||
| 1331 | evlist->threads->map[0] = getpid(); | ||
| 1332 | |||
| 1333 | err = perf_evlist__open(evlist); | ||
| 1334 | if (err < 0) { | ||
| 1335 | pr_debug("perf_evlist__open: %s\n", strerror(errno)); | ||
| 1336 | goto out_delete_evlist; | ||
| 1337 | } | ||
| 1338 | |||
| 1339 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | ||
| 1340 | if (err < 0) { | ||
| 1341 | pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); | ||
| 1342 | goto out_delete_evlist; | ||
| 1343 | } | ||
| 1344 | |||
| 1345 | perf_evlist__enable(evlist); | ||
| 1346 | |||
| 1347 | /* | ||
| 1348 | * Generate the event: | ||
| 1349 | */ | ||
| 1350 | open(filename, flags); | ||
| 1351 | |||
| 1352 | while (1) { | ||
| 1353 | int before = nr_events; | ||
| 1354 | |||
| 1355 | for (i = 0; i < evlist->nr_mmaps; i++) { | ||
| 1356 | union perf_event *event; | ||
| 1357 | |||
| 1358 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | ||
| 1359 | const u32 type = event->header.type; | ||
| 1360 | int tp_flags; | ||
| 1361 | struct perf_sample sample; | ||
| 1362 | |||
| 1363 | ++nr_events; | ||
| 1364 | |||
| 1365 | if (type != PERF_RECORD_SAMPLE) | ||
| 1366 | continue; | ||
| 1367 | |||
| 1368 | err = perf_evsel__parse_sample(evsel, event, &sample); | ||
| 1369 | if (err) { | ||
| 1370 | pr_err("Can't parse sample, err = %d\n", err); | ||
| 1371 | goto out_munmap; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | tp_flags = perf_evsel__intval(evsel, &sample, "flags"); | ||
| 1375 | |||
| 1376 | if (flags != tp_flags) { | ||
| 1377 | pr_debug("%s: Expected flags=%#x, got %#x\n", | ||
| 1378 | __func__, flags, tp_flags); | ||
| 1379 | goto out_munmap; | ||
| 1380 | } | ||
| 1381 | |||
| 1382 | goto out_ok; | ||
| 1383 | } | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | if (nr_events == before) | ||
| 1387 | poll(evlist->pollfd, evlist->nr_fds, 10); | ||
| 1388 | |||
| 1389 | if (++nr_polls > 5) { | ||
| 1390 | pr_debug("%s: no events!\n", __func__); | ||
| 1391 | goto out_munmap; | ||
| 1392 | } | ||
| 1393 | } | ||
| 1394 | out_ok: | ||
| 1395 | err = 0; | ||
| 1396 | out_munmap: | ||
| 1397 | perf_evlist__munmap(evlist); | ||
| 1398 | out_delete_evlist: | ||
| 1399 | perf_evlist__delete(evlist); | ||
| 1400 | out: | ||
| 1401 | return err; | ||
| 1402 | } | ||
| 1403 | |||
| 1292 | static struct test { | 1404 | static struct test { |
| 1293 | const char *desc; | 1405 | const char *desc; |
| 1294 | int (*func)(void); | 1406 | int (*func)(void); |
| @@ -1340,6 +1452,10 @@ static struct test { | |||
| 1340 | .func = perf_evsel__tp_sched_test, | 1452 | .func = perf_evsel__tp_sched_test, |
| 1341 | }, | 1453 | }, |
| 1342 | { | 1454 | { |
| 1455 | .desc = "Generate and check syscalls:sys_enter_open event fields", | ||
| 1456 | .func = test__syscall_open_tp_fields, | ||
| 1457 | }, | ||
| 1458 | { | ||
| 1343 | .func = NULL, | 1459 | .func = NULL, |
| 1344 | }, | 1460 | }, |
| 1345 | }; | 1461 | }; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 5550754c05f2..e434a16bb5ac 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -823,7 +823,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) | |||
| 823 | int ret; | 823 | int ret; |
| 824 | 824 | ||
| 825 | while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { | 825 | while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { |
| 826 | ret = perf_evlist__parse_sample(top->evlist, event, &sample, false); | 826 | ret = perf_evlist__parse_sample(top->evlist, event, &sample); |
| 827 | if (ret) { | 827 | if (ret) { |
| 828 | pr_err("Can't parse sample, err = %d\n", ret); | 828 | pr_err("Can't parse sample, err = %d\n", ret); |
| 829 | continue; | 829 | continue; |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c new file mode 100644 index 000000000000..8f113dab8bf1 --- /dev/null +++ b/tools/perf/builtin-trace.c | |||
| @@ -0,0 +1,310 @@ | |||
| 1 | #include "builtin.h" | ||
| 2 | #include "util/evlist.h" | ||
| 3 | #include "util/parse-options.h" | ||
| 4 | #include "util/thread_map.h" | ||
| 5 | #include "event-parse.h" | ||
| 6 | |||
| 7 | #include <libaudit.h> | ||
| 8 | #include <stdlib.h> | ||
| 9 | |||
| 10 | static struct syscall_fmt { | ||
| 11 | const char *name; | ||
| 12 | const char *alias; | ||
| 13 | bool errmsg; | ||
| 14 | bool timeout; | ||
| 15 | } syscall_fmts[] = { | ||
| 16 | { .name = "arch_prctl", .errmsg = true, .alias = "prctl", }, | ||
| 17 | { .name = "fstat", .errmsg = true, .alias = "newfstat", }, | ||
| 18 | { .name = "fstatat", .errmsg = true, .alias = "newfstatat", }, | ||
| 19 | { .name = "futex", .errmsg = true, }, | ||
| 20 | { .name = "poll", .errmsg = true, .timeout = true, }, | ||
| 21 | { .name = "ppoll", .errmsg = true, .timeout = true, }, | ||
| 22 | { .name = "read", .errmsg = true, }, | ||
| 23 | { .name = "recvfrom", .errmsg = true, }, | ||
| 24 | { .name = "select", .errmsg = true, .timeout = true, }, | ||
| 25 | { .name = "stat", .errmsg = true, .alias = "newstat", }, | ||
| 26 | }; | ||
| 27 | |||
| 28 | static int syscall_fmt__cmp(const void *name, const void *fmtp) | ||
| 29 | { | ||
| 30 | const struct syscall_fmt *fmt = fmtp; | ||
| 31 | return strcmp(name, fmt->name); | ||
| 32 | } | ||
| 33 | |||
| 34 | static struct syscall_fmt *syscall_fmt__find(const char *name) | ||
| 35 | { | ||
| 36 | const int nmemb = ARRAY_SIZE(syscall_fmts); | ||
| 37 | return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); | ||
| 38 | } | ||
| 39 | |||
| 40 | struct syscall { | ||
| 41 | struct event_format *tp_format; | ||
| 42 | const char *name; | ||
| 43 | struct syscall_fmt *fmt; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct trace { | ||
| 47 | int audit_machine; | ||
| 48 | struct { | ||
| 49 | int max; | ||
| 50 | struct syscall *table; | ||
| 51 | } syscalls; | ||
| 52 | struct perf_record_opts opts; | ||
| 53 | }; | ||
| 54 | |||
| 55 | static int trace__read_syscall_info(struct trace *trace, int id) | ||
| 56 | { | ||
| 57 | char tp_name[128]; | ||
| 58 | struct syscall *sc; | ||
| 59 | |||
| 60 | if (id > trace->syscalls.max) { | ||
| 61 | struct syscall *nsyscalls = realloc(trace->syscalls.table, (id + 1) * sizeof(*sc)); | ||
| 62 | |||
| 63 | if (nsyscalls == NULL) | ||
| 64 | return -1; | ||
| 65 | |||
| 66 | if (trace->syscalls.max != -1) { | ||
| 67 | memset(nsyscalls + trace->syscalls.max + 1, 0, | ||
| 68 | (id - trace->syscalls.max) * sizeof(*sc)); | ||
| 69 | } else { | ||
| 70 | memset(nsyscalls, 0, (id + 1) * sizeof(*sc)); | ||
| 71 | } | ||
| 72 | |||
| 73 | trace->syscalls.table = nsyscalls; | ||
| 74 | trace->syscalls.max = id; | ||
| 75 | } | ||
| 76 | |||
| 77 | sc = trace->syscalls.table + id; | ||
| 78 | sc->name = audit_syscall_to_name(id, trace->audit_machine); | ||
| 79 | if (sc->name == NULL) | ||
| 80 | return -1; | ||
| 81 | |||
| 82 | sc->fmt = syscall_fmt__find(sc->name); | ||
| 83 | |||
| 84 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->name); | ||
| 85 | sc->tp_format = event_format__new("syscalls", tp_name); | ||
| 86 | |||
| 87 | if (sc->tp_format == NULL && sc->fmt && sc->fmt->alias) { | ||
| 88 | snprintf(tp_name, sizeof(tp_name), "sys_enter_%s", sc->fmt->alias); | ||
| 89 | sc->tp_format = event_format__new("syscalls", tp_name); | ||
| 90 | } | ||
| 91 | |||
| 92 | return sc->tp_format != NULL ? 0 : -1; | ||
| 93 | } | ||
| 94 | |||
| 95 | static size_t syscall__fprintf_args(struct syscall *sc, unsigned long *args, FILE *fp) | ||
| 96 | { | ||
| 97 | int i = 0; | ||
| 98 | size_t printed = 0; | ||
| 99 | |||
| 100 | if (sc->tp_format != NULL) { | ||
| 101 | struct format_field *field; | ||
| 102 | |||
| 103 | for (field = sc->tp_format->format.fields->next; field; field = field->next) { | ||
| 104 | printed += fprintf(fp, "%s%s: %ld", printed ? ", " : "", | ||
| 105 | field->name, args[i++]); | ||
| 106 | } | ||
| 107 | } else { | ||
| 108 | while (i < 6) { | ||
| 109 | printed += fprintf(fp, "%sarg%d: %ld", printed ? ", " : "", i, args[i]); | ||
| 110 | ++i; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | return printed; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int trace__run(struct trace *trace) | ||
| 118 | { | ||
| 119 | struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); | ||
| 120 | struct perf_evsel *evsel, *evsel_enter, *evsel_exit; | ||
| 121 | int err = -1, i, nr_events = 0, before; | ||
| 122 | |||
| 123 | if (evlist == NULL) { | ||
| 124 | printf("Not enough memory to run!\n"); | ||
| 125 | goto out; | ||
| 126 | } | ||
| 127 | |||
| 128 | evsel_enter = perf_evsel__newtp("raw_syscalls", "sys_enter", 0); | ||
| 129 | if (evsel_enter == NULL) { | ||
| 130 | printf("Couldn't read the raw_syscalls:sys_enter tracepoint information!\n"); | ||
| 131 | goto out_delete_evlist; | ||
| 132 | } | ||
| 133 | |||
| 134 | perf_evlist__add(evlist, evsel_enter); | ||
| 135 | |||
| 136 | evsel_exit = perf_evsel__newtp("raw_syscalls", "sys_exit", 1); | ||
| 137 | if (evsel_exit == NULL) { | ||
| 138 | printf("Couldn't read the raw_syscalls:sys_exit tracepoint information!\n"); | ||
| 139 | goto out_delete_evlist; | ||
| 140 | } | ||
| 141 | |||
| 142 | perf_evlist__add(evlist, evsel_exit); | ||
| 143 | |||
| 144 | err = perf_evlist__create_maps(evlist, &trace->opts.target); | ||
| 145 | if (err < 0) { | ||
| 146 | printf("Problems parsing the target to trace, check your options!\n"); | ||
| 147 | goto out_delete_evlist; | ||
| 148 | } | ||
| 149 | |||
| 150 | perf_evlist__config_attrs(evlist, &trace->opts); | ||
| 151 | |||
| 152 | err = perf_evlist__open(evlist); | ||
| 153 | if (err < 0) { | ||
| 154 | printf("Couldn't create the events: %s\n", strerror(errno)); | ||
| 155 | goto out_delete_evlist; | ||
| 156 | } | ||
| 157 | |||
| 158 | err = perf_evlist__mmap(evlist, UINT_MAX, false); | ||
| 159 | if (err < 0) { | ||
| 160 | printf("Couldn't mmap the events: %s\n", strerror(errno)); | ||
| 161 | goto out_delete_evlist; | ||
| 162 | } | ||
| 163 | |||
| 164 | perf_evlist__enable(evlist); | ||
| 165 | again: | ||
| 166 | before = nr_events; | ||
| 167 | |||
| 168 | for (i = 0; i < evlist->nr_mmaps; i++) { | ||
| 169 | union perf_event *event; | ||
| 170 | |||
| 171 | while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { | ||
| 172 | const u32 type = event->header.type; | ||
| 173 | struct syscall *sc; | ||
| 174 | struct perf_sample sample; | ||
| 175 | int id; | ||
| 176 | |||
| 177 | ++nr_events; | ||
| 178 | |||
| 179 | switch (type) { | ||
| 180 | case PERF_RECORD_SAMPLE: | ||
| 181 | break; | ||
| 182 | case PERF_RECORD_LOST: | ||
| 183 | printf("LOST %" PRIu64 " events!\n", event->lost.lost); | ||
| 184 | continue; | ||
| 185 | default: | ||
| 186 | printf("Unexpected %s event, skipping...\n", | ||
| 187 | perf_event__name(type)); | ||
| 188 | continue; | ||
| 189 | } | ||
| 190 | |||
| 191 | err = perf_evlist__parse_sample(evlist, event, &sample); | ||
| 192 | if (err) { | ||
| 193 | printf("Can't parse sample, err = %d, skipping...\n", err); | ||
| 194 | continue; | ||
| 195 | } | ||
| 196 | |||
| 197 | evsel = perf_evlist__id2evsel(evlist, sample.id); | ||
| 198 | if (evsel == NULL) { | ||
| 199 | printf("Unknown tp ID %" PRIu64 ", skipping...\n", sample.id); | ||
| 200 | continue; | ||
| 201 | } | ||
| 202 | |||
| 203 | id = perf_evsel__intval(evsel, &sample, "id"); | ||
| 204 | if (id < 0) { | ||
| 205 | printf("Invalid syscall %d id, skipping...\n", id); | ||
| 206 | continue; | ||
| 207 | } | ||
| 208 | |||
| 209 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL) && | ||
| 210 | trace__read_syscall_info(trace, id)) | ||
| 211 | continue; | ||
| 212 | |||
| 213 | if ((id > trace->syscalls.max || trace->syscalls.table[id].name == NULL)) | ||
| 214 | continue; | ||
| 215 | |||
| 216 | sc = &trace->syscalls.table[id]; | ||
| 217 | |||
| 218 | if (evlist->threads->map[0] == -1 || evlist->threads->nr > 1) | ||
| 219 | printf("%d ", sample.tid); | ||
| 220 | |||
| 221 | if (evsel == evsel_enter) { | ||
| 222 | void *args = perf_evsel__rawptr(evsel, &sample, "args"); | ||
| 223 | |||
| 224 | printf("%s(", sc->name); | ||
| 225 | syscall__fprintf_args(sc, args, stdout); | ||
| 226 | } else if (evsel == evsel_exit) { | ||
| 227 | int ret = perf_evsel__intval(evsel, &sample, "ret"); | ||
| 228 | |||
| 229 | if (ret < 0 && sc->fmt && sc->fmt->errmsg) { | ||
| 230 | char bf[256]; | ||
| 231 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | ||
| 232 | *e = audit_errno_to_name(-ret); | ||
| 233 | |||
| 234 | printf(") = -1 %s %s", e, emsg); | ||
| 235 | } else if (ret == 0 && sc->fmt && sc->fmt->timeout) | ||
| 236 | printf(") = 0 Timeout"); | ||
| 237 | else | ||
| 238 | printf(") = %d", ret); | ||
| 239 | |||
| 240 | putchar('\n'); | ||
| 241 | } | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | if (nr_events == before) | ||
| 246 | poll(evlist->pollfd, evlist->nr_fds, -1); | ||
| 247 | |||
| 248 | goto again; | ||
| 249 | |||
| 250 | out_delete_evlist: | ||
| 251 | perf_evlist__delete(evlist); | ||
| 252 | out: | ||
| 253 | return err; | ||
| 254 | } | ||
| 255 | |||
| 256 | int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | ||
| 257 | { | ||
| 258 | const char * const trace_usage[] = { | ||
| 259 | "perf trace [<options>]", | ||
| 260 | NULL | ||
| 261 | }; | ||
| 262 | struct trace trace = { | ||
| 263 | .audit_machine = audit_detect_machine(), | ||
| 264 | .syscalls = { | ||
| 265 | . max = -1, | ||
| 266 | }, | ||
| 267 | .opts = { | ||
| 268 | .target = { | ||
| 269 | .uid = UINT_MAX, | ||
| 270 | .uses_mmap = true, | ||
| 271 | }, | ||
| 272 | .user_freq = UINT_MAX, | ||
| 273 | .user_interval = ULLONG_MAX, | ||
| 274 | .no_delay = true, | ||
| 275 | .mmap_pages = 1024, | ||
| 276 | }, | ||
| 277 | }; | ||
| 278 | const struct option trace_options[] = { | ||
| 279 | OPT_STRING('p', "pid", &trace.opts.target.pid, "pid", | ||
| 280 | "trace events on existing process id"), | ||
| 281 | OPT_STRING(0, "tid", &trace.opts.target.tid, "tid", | ||
| 282 | "trace events on existing thread id"), | ||
| 283 | OPT_BOOLEAN(0, "all-cpus", &trace.opts.target.system_wide, | ||
| 284 | "system-wide collection from all CPUs"), | ||
| 285 | OPT_STRING(0, "cpu", &trace.opts.target.cpu_list, "cpu", | ||
| 286 | "list of cpus to monitor"), | ||
| 287 | OPT_BOOLEAN(0, "no-inherit", &trace.opts.no_inherit, | ||
| 288 | "child tasks do not inherit counters"), | ||
| 289 | OPT_UINTEGER(0, "mmap-pages", &trace.opts.mmap_pages, | ||
| 290 | "number of mmap data pages"), | ||
| 291 | OPT_STRING(0, "uid", &trace.opts.target.uid_str, "user", | ||
| 292 | "user to profile"), | ||
| 293 | OPT_END() | ||
| 294 | }; | ||
| 295 | int err; | ||
| 296 | |||
| 297 | argc = parse_options(argc, argv, trace_options, trace_usage, 0); | ||
| 298 | if (argc) | ||
| 299 | usage_with_options(trace_usage, trace_options); | ||
| 300 | |||
| 301 | err = perf_target__parse_uid(&trace.opts.target); | ||
| 302 | if (err) { | ||
| 303 | char bf[BUFSIZ]; | ||
| 304 | perf_target__strerror(&trace.opts.target, err, bf, sizeof(bf)); | ||
| 305 | printf("%s", bf); | ||
| 306 | return err; | ||
| 307 | } | ||
| 308 | |||
| 309 | return trace__run(&trace); | ||
| 310 | } | ||
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index 3ea74ed1b26b..08143bd854c7 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h | |||
| @@ -34,6 +34,7 @@ extern int cmd_kmem(int argc, const char **argv, const char *prefix); | |||
| 34 | extern int cmd_lock(int argc, const char **argv, const char *prefix); | 34 | extern int cmd_lock(int argc, const char **argv, const char *prefix); |
| 35 | extern int cmd_kvm(int argc, const char **argv, const char *prefix); | 35 | extern int cmd_kvm(int argc, const char **argv, const char *prefix); |
| 36 | extern int cmd_test(int argc, const char **argv, const char *prefix); | 36 | extern int cmd_test(int argc, const char **argv, const char *prefix); |
| 37 | extern int cmd_trace(int argc, const char **argv, const char *prefix); | ||
| 37 | extern int cmd_inject(int argc, const char **argv, const char *prefix); | 38 | extern int cmd_inject(int argc, const char **argv, const char *prefix); |
| 38 | 39 | ||
| 39 | extern int find_scripts(char **scripts_array, char **scripts_path_array); | 40 | extern int find_scripts(char **scripts_array, char **scripts_path_array); |
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt index 0303ec692274..3e86bbd8c2d5 100644 --- a/tools/perf/command-list.txt +++ b/tools/perf/command-list.txt | |||
| @@ -17,6 +17,7 @@ perf-report mainporcelain common | |||
| 17 | perf-stat mainporcelain common | 17 | perf-stat mainporcelain common |
| 18 | perf-timechart mainporcelain common | 18 | perf-timechart mainporcelain common |
| 19 | perf-top mainporcelain common | 19 | perf-top mainporcelain common |
| 20 | perf-trace mainporcelain common | ||
| 20 | perf-script mainporcelain common | 21 | perf-script mainporcelain common |
| 21 | perf-probe mainporcelain full | 22 | perf-probe mainporcelain full |
| 22 | perf-kmem mainporcelain common | 23 | perf-kmem mainporcelain common |
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak index 116690a669d2..4add41bb0c7e 100644 --- a/tools/perf/config/feature-tests.mak +++ b/tools/perf/config/feature-tests.mak | |||
| @@ -193,3 +193,14 @@ int main(void) | |||
| 193 | } | 193 | } |
| 194 | endef | 194 | endef |
| 195 | endif | 195 | endif |
| 196 | |||
| 197 | ifndef NO_LIBAUDIT | ||
| 198 | define SOURCE_LIBAUDIT | ||
| 199 | #include <libaudit.h> | ||
| 200 | |||
| 201 | int main(void) | ||
| 202 | { | ||
| 203 | return audit_open(); | ||
| 204 | } | ||
| 205 | endef | ||
| 206 | endif \ No newline at end of file | ||
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index fb8578cfa03c..fc2f770e3027 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
| @@ -55,6 +55,9 @@ static struct cmd_struct commands[] = { | |||
| 55 | { "lock", cmd_lock, 0 }, | 55 | { "lock", cmd_lock, 0 }, |
| 56 | { "kvm", cmd_kvm, 0 }, | 56 | { "kvm", cmd_kvm, 0 }, |
| 57 | { "test", cmd_test, 0 }, | 57 | { "test", cmd_test, 0 }, |
| 58 | #ifndef NO_LIBAUDIT_SUPPORT | ||
| 59 | { "trace", cmd_trace, 0 }, | ||
| 60 | #endif | ||
| 58 | { "inject", cmd_inject, 0 }, | 61 | { "inject", cmd_inject, 0 }, |
| 59 | }; | 62 | }; |
| 60 | 63 | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 17b5264f6436..2f68a3b8c285 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #define __PERF_CPUMAP_H | 2 | #define __PERF_CPUMAP_H |
| 3 | 3 | ||
| 4 | #include <stdio.h> | 4 | #include <stdio.h> |
| 5 | #include <stdbool.h> | ||
| 5 | 6 | ||
| 6 | struct cpu_map { | 7 | struct cpu_map { |
| 7 | int nr; | 8 | int nr; |
| @@ -14,4 +15,14 @@ void cpu_map__delete(struct cpu_map *map); | |||
| 14 | struct cpu_map *cpu_map__read(FILE *file); | 15 | struct cpu_map *cpu_map__read(FILE *file); |
| 15 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); | 16 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); |
| 16 | 17 | ||
| 18 | static inline int cpu_map__nr(const struct cpu_map *map) | ||
| 19 | { | ||
| 20 | return map ? map->nr : 1; | ||
| 21 | } | ||
| 22 | |||
| 23 | static inline bool cpu_map__all(const struct cpu_map *map) | ||
| 24 | { | ||
| 25 | return map ? map->map[0] == -1 : true; | ||
| 26 | } | ||
| 27 | |||
| 17 | #endif /* __PERF_CPUMAP_H */ | 28 | #endif /* __PERF_CPUMAP_H */ |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index ee51e9b4dc09..3e5f5430a28a 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
| @@ -804,6 +804,8 @@ int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) | |||
| 804 | tmp = "union "; | 804 | tmp = "union "; |
| 805 | else if (tag == DW_TAG_structure_type) | 805 | else if (tag == DW_TAG_structure_type) |
| 806 | tmp = "struct "; | 806 | tmp = "struct "; |
| 807 | else if (tag == DW_TAG_enumeration_type) | ||
| 808 | tmp = "enum "; | ||
| 807 | /* Write a base name */ | 809 | /* Write a base name */ |
| 808 | ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); | 810 | ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); |
| 809 | return (ret >= len) ? -E2BIG : ret; | 811 | return (ret >= len) ? -E2BIG : ret; |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 892353729c7a..ae89686102f4 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -304,7 +304,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
| 304 | int cpu, thread; | 304 | int cpu, thread; |
| 305 | struct perf_evsel *pos; | 305 | struct perf_evsel *pos; |
| 306 | 306 | ||
| 307 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | 307 | for (cpu = 0; cpu < cpu_map__nr(evlist->cpus); cpu++) { |
| 308 | list_for_each_entry(pos, &evlist->entries, node) { | 308 | list_for_each_entry(pos, &evlist->entries, node) { |
| 309 | for (thread = 0; thread < evlist->threads->nr; thread++) | 309 | for (thread = 0; thread < evlist->threads->nr; thread++) |
| 310 | ioctl(FD(pos, cpu, thread), | 310 | ioctl(FD(pos, cpu, thread), |
| @@ -315,7 +315,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) | |||
| 315 | 315 | ||
| 316 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 316 | static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
| 317 | { | 317 | { |
| 318 | int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; | 318 | int nfds = cpu_map__nr(evlist->cpus) * evlist->threads->nr * evlist->nr_entries; |
| 319 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); | 319 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); |
| 320 | return evlist->pollfd != NULL ? 0 : -ENOMEM; | 320 | return evlist->pollfd != NULL ? 0 : -ENOMEM; |
| 321 | } | 321 | } |
| @@ -475,8 +475,8 @@ void perf_evlist__munmap(struct perf_evlist *evlist) | |||
| 475 | 475 | ||
| 476 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) | 476 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) |
| 477 | { | 477 | { |
| 478 | evlist->nr_mmaps = evlist->cpus->nr; | 478 | evlist->nr_mmaps = cpu_map__nr(evlist->cpus); |
| 479 | if (evlist->cpus->map[0] == -1) | 479 | if (cpu_map__all(evlist->cpus)) |
| 480 | evlist->nr_mmaps = evlist->threads->nr; | 480 | evlist->nr_mmaps = evlist->threads->nr; |
| 481 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); | 481 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); |
| 482 | return evlist->mmap != NULL ? 0 : -ENOMEM; | 482 | return evlist->mmap != NULL ? 0 : -ENOMEM; |
| @@ -622,11 +622,11 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, | |||
| 622 | list_for_each_entry(evsel, &evlist->entries, node) { | 622 | list_for_each_entry(evsel, &evlist->entries, node) { |
| 623 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && | 623 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
| 624 | evsel->sample_id == NULL && | 624 | evsel->sample_id == NULL && |
| 625 | perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0) | 625 | perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) |
| 626 | return -ENOMEM; | 626 | return -ENOMEM; |
| 627 | } | 627 | } |
| 628 | 628 | ||
| 629 | if (evlist->cpus->map[0] == -1) | 629 | if (cpu_map__all(cpus)) |
| 630 | return perf_evlist__mmap_per_thread(evlist, prot, mask); | 630 | return perf_evlist__mmap_per_thread(evlist, prot, mask); |
| 631 | 631 | ||
| 632 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); | 632 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); |
| @@ -666,32 +666,39 @@ void perf_evlist__delete_maps(struct perf_evlist *evlist) | |||
| 666 | evlist->threads = NULL; | 666 | evlist->threads = NULL; |
| 667 | } | 667 | } |
| 668 | 668 | ||
| 669 | int perf_evlist__set_filters(struct perf_evlist *evlist) | 669 | int perf_evlist__apply_filters(struct perf_evlist *evlist) |
| 670 | { | 670 | { |
| 671 | const struct thread_map *threads = evlist->threads; | ||
| 672 | const struct cpu_map *cpus = evlist->cpus; | ||
| 673 | struct perf_evsel *evsel; | 671 | struct perf_evsel *evsel; |
| 674 | char *filter; | 672 | int err = 0; |
| 675 | int thread; | 673 | const int ncpus = cpu_map__nr(evlist->cpus), |
| 676 | int cpu; | 674 | nthreads = evlist->threads->nr; |
| 677 | int err; | ||
| 678 | int fd; | ||
| 679 | 675 | ||
| 680 | list_for_each_entry(evsel, &evlist->entries, node) { | 676 | list_for_each_entry(evsel, &evlist->entries, node) { |
| 681 | filter = evsel->filter; | 677 | if (evsel->filter == NULL) |
| 682 | if (!filter) | ||
| 683 | continue; | 678 | continue; |
| 684 | for (cpu = 0; cpu < cpus->nr; cpu++) { | 679 | |
| 685 | for (thread = 0; thread < threads->nr; thread++) { | 680 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, evsel->filter); |
| 686 | fd = FD(evsel, cpu, thread); | 681 | if (err) |
| 687 | err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter); | 682 | break; |
| 688 | if (err) | ||
| 689 | return err; | ||
| 690 | } | ||
| 691 | } | ||
| 692 | } | 683 | } |
| 693 | 684 | ||
| 694 | return 0; | 685 | return err; |
| 686 | } | ||
| 687 | |||
| 688 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) | ||
| 689 | { | ||
| 690 | struct perf_evsel *evsel; | ||
| 691 | int err = 0; | ||
| 692 | const int ncpus = cpu_map__nr(evlist->cpus), | ||
| 693 | nthreads = evlist->threads->nr; | ||
| 694 | |||
| 695 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
| 696 | err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); | ||
| 697 | if (err) | ||
| 698 | break; | ||
| 699 | } | ||
| 700 | |||
| 701 | return err; | ||
| 695 | } | 702 | } |
| 696 | 703 | ||
| 697 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) | 704 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) |
| @@ -884,10 +891,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist) | |||
| 884 | } | 891 | } |
| 885 | 892 | ||
| 886 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, | 893 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, |
| 887 | struct perf_sample *sample, bool swapped) | 894 | struct perf_sample *sample) |
| 888 | { | 895 | { |
| 889 | struct perf_evsel *evsel = perf_evlist__first(evlist); | 896 | struct perf_evsel *evsel = perf_evlist__first(evlist); |
| 890 | return perf_evsel__parse_sample(evsel, event, sample, swapped); | 897 | return perf_evsel__parse_sample(evsel, event, sample); |
| 891 | } | 898 | } |
| 892 | 899 | ||
| 893 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) | 900 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 3f2e1e4ccdd5..3f1fb66be022 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
| @@ -72,6 +72,8 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, | |||
| 72 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ | 72 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ |
| 73 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) | 73 | perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) |
| 74 | 74 | ||
| 75 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); | ||
| 76 | |||
| 75 | struct perf_evsel * | 77 | struct perf_evsel * |
| 76 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); | 78 | perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); |
| 77 | 79 | ||
| @@ -115,7 +117,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | |||
| 115 | int perf_evlist__create_maps(struct perf_evlist *evlist, | 117 | int perf_evlist__create_maps(struct perf_evlist *evlist, |
| 116 | struct perf_target *target); | 118 | struct perf_target *target); |
| 117 | void perf_evlist__delete_maps(struct perf_evlist *evlist); | 119 | void perf_evlist__delete_maps(struct perf_evlist *evlist); |
| 118 | int perf_evlist__set_filters(struct perf_evlist *evlist); | 120 | int perf_evlist__apply_filters(struct perf_evlist *evlist); |
| 119 | 121 | ||
| 120 | void __perf_evlist__set_leader(struct list_head *list); | 122 | void __perf_evlist__set_leader(struct list_head *list); |
| 121 | void perf_evlist__set_leader(struct perf_evlist *evlist); | 123 | void perf_evlist__set_leader(struct perf_evlist *evlist); |
| @@ -125,7 +127,7 @@ bool perf_evlist__sample_id_all(struct perf_evlist *evlist); | |||
| 125 | u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); | 127 | u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); |
| 126 | 128 | ||
| 127 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, | 129 | int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, |
| 128 | struct perf_sample *sample, bool swapped); | 130 | struct perf_sample *sample); |
| 129 | 131 | ||
| 130 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); | 132 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); |
| 131 | bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); | 133 | bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 00936ad29ff2..ffdd94e9c9c3 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -70,7 +70,7 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) | |||
| 70 | return evsel; | 70 | return evsel; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static struct event_format *event_format__new(const char *sys, const char *name) | 73 | struct event_format *event_format__new(const char *sys, const char *name) |
| 74 | { | 74 | { |
| 75 | int fd, n; | 75 | int fd, n; |
| 76 | char *filename; | 76 | char *filename; |
| @@ -117,21 +117,28 @@ struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx) | |||
| 117 | 117 | ||
| 118 | if (evsel != NULL) { | 118 | if (evsel != NULL) { |
| 119 | struct perf_event_attr attr = { | 119 | struct perf_event_attr attr = { |
| 120 | .type = PERF_TYPE_TRACEPOINT, | 120 | .type = PERF_TYPE_TRACEPOINT, |
| 121 | .sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | | ||
| 122 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD), | ||
| 121 | }; | 123 | }; |
| 122 | 124 | ||
| 125 | if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) | ||
| 126 | goto out_free; | ||
| 127 | |||
| 123 | evsel->tp_format = event_format__new(sys, name); | 128 | evsel->tp_format = event_format__new(sys, name); |
| 124 | if (evsel->tp_format == NULL) | 129 | if (evsel->tp_format == NULL) |
| 125 | goto out_free; | 130 | goto out_free; |
| 126 | 131 | ||
| 132 | event_attr_init(&attr); | ||
| 127 | attr.config = evsel->tp_format->id; | 133 | attr.config = evsel->tp_format->id; |
| 134 | attr.sample_period = 1; | ||
| 128 | perf_evsel__init(evsel, &attr, idx); | 135 | perf_evsel__init(evsel, &attr, idx); |
| 129 | evsel->name = evsel->tp_format->name; | ||
| 130 | } | 136 | } |
| 131 | 137 | ||
| 132 | return evsel; | 138 | return evsel; |
| 133 | 139 | ||
| 134 | out_free: | 140 | out_free: |
| 141 | free(evsel->name); | ||
| 135 | free(evsel); | 142 | free(evsel); |
| 136 | return NULL; | 143 | return NULL; |
| 137 | } | 144 | } |
| @@ -501,6 +508,24 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) | |||
| 501 | return evsel->fd != NULL ? 0 : -ENOMEM; | 508 | return evsel->fd != NULL ? 0 : -ENOMEM; |
| 502 | } | 509 | } |
| 503 | 510 | ||
| 511 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, | ||
| 512 | const char *filter) | ||
| 513 | { | ||
| 514 | int cpu, thread; | ||
| 515 | |||
| 516 | for (cpu = 0; cpu < ncpus; cpu++) { | ||
| 517 | for (thread = 0; thread < nthreads; thread++) { | ||
| 518 | int fd = FD(evsel, cpu, thread), | ||
| 519 | err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter); | ||
| 520 | |||
| 521 | if (err) | ||
| 522 | return err; | ||
| 523 | } | ||
| 524 | } | ||
| 525 | |||
| 526 | return 0; | ||
| 527 | } | ||
| 528 | |||
| 504 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) | 529 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) |
| 505 | { | 530 | { |
| 506 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); | 531 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); |
| @@ -562,10 +587,8 @@ void perf_evsel__delete(struct perf_evsel *evsel) | |||
| 562 | perf_evsel__exit(evsel); | 587 | perf_evsel__exit(evsel); |
| 563 | close_cgroup(evsel->cgrp); | 588 | close_cgroup(evsel->cgrp); |
| 564 | free(evsel->group_name); | 589 | free(evsel->group_name); |
| 565 | if (evsel->tp_format && evsel->name == evsel->tp_format->name) { | 590 | if (evsel->tp_format) |
| 566 | evsel->name = NULL; | ||
| 567 | pevent_free_format(evsel->tp_format); | 591 | pevent_free_format(evsel->tp_format); |
| 568 | } | ||
| 569 | free(evsel->name); | 592 | free(evsel->name); |
| 570 | free(evsel); | 593 | free(evsel); |
| 571 | } | 594 | } |
| @@ -763,11 +786,13 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel, | |||
| 763 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); | 786 | return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); |
| 764 | } | 787 | } |
| 765 | 788 | ||
| 766 | static int perf_event__parse_id_sample(const union perf_event *event, u64 type, | 789 | static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, |
| 767 | struct perf_sample *sample, | 790 | const union perf_event *event, |
| 768 | bool swapped) | 791 | struct perf_sample *sample) |
| 769 | { | 792 | { |
| 793 | u64 type = evsel->attr.sample_type; | ||
| 770 | const u64 *array = event->sample.array; | 794 | const u64 *array = event->sample.array; |
| 795 | bool swapped = evsel->needs_swap; | ||
| 771 | union u64_swap u; | 796 | union u64_swap u; |
| 772 | 797 | ||
| 773 | array += ((event->header.size - | 798 | array += ((event->header.size - |
| @@ -828,10 +853,11 @@ static bool sample_overlap(const union perf_event *event, | |||
| 828 | } | 853 | } |
| 829 | 854 | ||
| 830 | int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | 855 | int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, |
| 831 | struct perf_sample *data, bool swapped) | 856 | struct perf_sample *data) |
| 832 | { | 857 | { |
| 833 | u64 type = evsel->attr.sample_type; | 858 | u64 type = evsel->attr.sample_type; |
| 834 | u64 regs_user = evsel->attr.sample_regs_user; | 859 | u64 regs_user = evsel->attr.sample_regs_user; |
| 860 | bool swapped = evsel->needs_swap; | ||
| 835 | const u64 *array; | 861 | const u64 *array; |
| 836 | 862 | ||
| 837 | /* | 863 | /* |
| @@ -848,7 +874,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | |||
| 848 | if (event->header.type != PERF_RECORD_SAMPLE) { | 874 | if (event->header.type != PERF_RECORD_SAMPLE) { |
| 849 | if (!evsel->attr.sample_id_all) | 875 | if (!evsel->attr.sample_id_all) |
| 850 | return 0; | 876 | return 0; |
| 851 | return perf_event__parse_id_sample(event, type, data, swapped); | 877 | return perf_evsel__parse_id_sample(evsel, event, data); |
| 852 | } | 878 | } |
| 853 | 879 | ||
| 854 | array = event->sample.array; | 880 | array = event->sample.array; |
| @@ -1078,7 +1104,7 @@ struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *nam | |||
| 1078 | return pevent_find_field(evsel->tp_format, name); | 1104 | return pevent_find_field(evsel->tp_format, name); |
| 1079 | } | 1105 | } |
| 1080 | 1106 | ||
| 1081 | char *perf_evsel__strval(struct perf_evsel *evsel, struct perf_sample *sample, | 1107 | void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, |
| 1082 | const char *name) | 1108 | const char *name) |
| 1083 | { | 1109 | { |
| 1084 | struct format_field *field = perf_evsel__field(evsel, name); | 1110 | struct format_field *field = perf_evsel__field(evsel, name); |
| @@ -1101,13 +1127,43 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, | |||
| 1101 | const char *name) | 1127 | const char *name) |
| 1102 | { | 1128 | { |
| 1103 | struct format_field *field = perf_evsel__field(evsel, name); | 1129 | struct format_field *field = perf_evsel__field(evsel, name); |
| 1104 | u64 val; | 1130 | void *ptr; |
| 1131 | u64 value; | ||
| 1105 | 1132 | ||
| 1106 | if (!field) | 1133 | if (!field) |
| 1107 | return 0; | 1134 | return 0; |
| 1108 | 1135 | ||
| 1109 | val = pevent_read_number(evsel->tp_format->pevent, | 1136 | ptr = sample->raw_data + field->offset; |
| 1110 | sample->raw_data + field->offset, field->size); | ||
| 1111 | return val; | ||
| 1112 | 1137 | ||
| 1138 | switch (field->size) { | ||
| 1139 | case 1: | ||
| 1140 | return *(u8 *)ptr; | ||
| 1141 | case 2: | ||
| 1142 | value = *(u16 *)ptr; | ||
| 1143 | break; | ||
| 1144 | case 4: | ||
| 1145 | value = *(u32 *)ptr; | ||
| 1146 | break; | ||
| 1147 | case 8: | ||
| 1148 | value = *(u64 *)ptr; | ||
| 1149 | break; | ||
| 1150 | default: | ||
| 1151 | return 0; | ||
| 1152 | } | ||
| 1153 | |||
| 1154 | if (!evsel->needs_swap) | ||
| 1155 | return value; | ||
| 1156 | |||
| 1157 | switch (field->size) { | ||
| 1158 | case 2: | ||
| 1159 | return bswap_16(value); | ||
| 1160 | case 4: | ||
| 1161 | return bswap_32(value); | ||
| 1162 | case 8: | ||
| 1163 | return bswap_64(value); | ||
| 1164 | default: | ||
| 1165 | return 0; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | return 0; | ||
| 1113 | } | 1169 | } |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index bb445d1cbc7b..3ead0d59c03d 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -69,6 +69,7 @@ struct perf_evsel { | |||
| 69 | struct cpu_map *cpus; | 69 | struct cpu_map *cpus; |
| 70 | unsigned int sample_size; | 70 | unsigned int sample_size; |
| 71 | bool supported; | 71 | bool supported; |
| 72 | bool needs_swap; | ||
| 72 | /* parse modifier helper */ | 73 | /* parse modifier helper */ |
| 73 | int exclude_GH; | 74 | int exclude_GH; |
| 74 | struct perf_evsel *leader; | 75 | struct perf_evsel *leader; |
| @@ -82,6 +83,9 @@ struct perf_record_opts; | |||
| 82 | 83 | ||
| 83 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); | 84 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); |
| 84 | struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx); | 85 | struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx); |
| 86 | |||
| 87 | struct event_format *event_format__new(const char *sys, const char *name); | ||
| 88 | |||
| 85 | void perf_evsel__init(struct perf_evsel *evsel, | 89 | void perf_evsel__init(struct perf_evsel *evsel, |
| 86 | struct perf_event_attr *attr, int idx); | 90 | struct perf_event_attr *attr, int idx); |
| 87 | void perf_evsel__exit(struct perf_evsel *evsel); | 91 | void perf_evsel__exit(struct perf_evsel *evsel); |
| @@ -114,6 +118,9 @@ void perf_evsel__free_fd(struct perf_evsel *evsel); | |||
| 114 | void perf_evsel__free_id(struct perf_evsel *evsel); | 118 | void perf_evsel__free_id(struct perf_evsel *evsel); |
| 115 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); | 119 | void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); |
| 116 | 120 | ||
| 121 | int perf_evsel__set_filter(struct perf_evsel *evsel, int ncpus, int nthreads, | ||
| 122 | const char *filter); | ||
| 123 | |||
| 117 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, | 124 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
| 118 | struct cpu_map *cpus); | 125 | struct cpu_map *cpus); |
| 119 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, | 126 | int perf_evsel__open_per_thread(struct perf_evsel *evsel, |
| @@ -124,11 +131,18 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads); | |||
| 124 | 131 | ||
| 125 | struct perf_sample; | 132 | struct perf_sample; |
| 126 | 133 | ||
| 127 | char *perf_evsel__strval(struct perf_evsel *evsel, struct perf_sample *sample, | 134 | void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, |
| 128 | const char *name); | 135 | const char *name); |
| 129 | u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, | 136 | u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, |
| 130 | const char *name); | 137 | const char *name); |
| 131 | 138 | ||
| 139 | static inline char *perf_evsel__strval(struct perf_evsel *evsel, | ||
| 140 | struct perf_sample *sample, | ||
| 141 | const char *name) | ||
| 142 | { | ||
| 143 | return perf_evsel__rawptr(evsel, sample, name); | ||
| 144 | } | ||
| 145 | |||
| 132 | struct format_field; | 146 | struct format_field; |
| 133 | 147 | ||
| 134 | struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name); | 148 | struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name); |
| @@ -205,7 +219,7 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel, | |||
| 205 | void hists__init(struct hists *hists); | 219 | void hists__init(struct hists *hists); |
| 206 | 220 | ||
| 207 | int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | 221 | int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, |
| 208 | struct perf_sample *sample, bool swapped); | 222 | struct perf_sample *sample); |
| 209 | 223 | ||
| 210 | static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) | 224 | static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) |
| 211 | { | 225 | { |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 6aae3290358e..7daad237dea5 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -1256,8 +1256,10 @@ read_event_desc(struct perf_header *ph, int fd) | |||
| 1256 | if (ret != (ssize_t)sizeof(nr)) | 1256 | if (ret != (ssize_t)sizeof(nr)) |
| 1257 | goto error; | 1257 | goto error; |
| 1258 | 1258 | ||
| 1259 | if (ph->needs_swap) | 1259 | if (ph->needs_swap) { |
| 1260 | nr = bswap_32(nr); | 1260 | nr = bswap_32(nr); |
| 1261 | evsel->needs_swap = true; | ||
| 1262 | } | ||
| 1261 | 1263 | ||
| 1262 | evsel->name = do_read_string(fd, ph); | 1264 | evsel->name = do_read_string(fd, ph); |
| 1263 | 1265 | ||
| @@ -2626,6 +2628,8 @@ int perf_session__read_header(struct perf_session *session, int fd) | |||
| 2626 | 2628 | ||
| 2627 | if (evsel == NULL) | 2629 | if (evsel == NULL) |
| 2628 | goto out_delete_evlist; | 2630 | goto out_delete_evlist; |
| 2631 | |||
| 2632 | evsel->needs_swap = header->needs_swap; | ||
| 2629 | /* | 2633 | /* |
| 2630 | * Do it before so that if perf_evsel__alloc_id fails, this | 2634 | * Do it before so that if perf_evsel__alloc_id fails, this |
| 2631 | * entry gets purged too at perf_evlist__delete(). | 2635 | * entry gets purged too at perf_evlist__delete(). |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6ec5398de89d..236bc9d98ff2 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -410,8 +410,13 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, | |||
| 410 | cmp = hist_entry__collapse(iter, he); | 410 | cmp = hist_entry__collapse(iter, he); |
| 411 | 411 | ||
| 412 | if (!cmp) { | 412 | if (!cmp) { |
| 413 | iter->period += he->period; | 413 | iter->period += he->period; |
| 414 | iter->nr_events += he->nr_events; | 414 | iter->period_sys += he->period_sys; |
| 415 | iter->period_us += he->period_us; | ||
| 416 | iter->period_guest_sys += he->period_guest_sys; | ||
| 417 | iter->period_guest_us += he->period_guest_us; | ||
| 418 | iter->nr_events += he->nr_events; | ||
| 419 | |||
| 415 | if (symbol_conf.use_callchain) { | 420 | if (symbol_conf.use_callchain) { |
| 416 | callchain_cursor_reset(&callchain_cursor); | 421 | callchain_cursor_reset(&callchain_cursor); |
| 417 | callchain_merge(&callchain_cursor, | 422 | callchain_merge(&callchain_cursor, |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index bf5d033ee1b4..aed38e4b9dfa 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -356,42 +356,28 @@ int parse_events_add_cache(struct list_head **list, int *idx, | |||
| 356 | return add_event(list, idx, &attr, name); | 356 | return add_event(list, idx, &attr, name); |
| 357 | } | 357 | } |
| 358 | 358 | ||
| 359 | static int add_tracepoint(struct list_head **list, int *idx, | 359 | static int add_tracepoint(struct list_head **listp, int *idx, |
| 360 | char *sys_name, char *evt_name) | 360 | char *sys_name, char *evt_name) |
| 361 | { | 361 | { |
| 362 | struct perf_event_attr attr; | 362 | struct perf_evsel *evsel; |
| 363 | char name[MAX_NAME_LEN]; | 363 | struct list_head *list = *listp; |
| 364 | char evt_path[MAXPATHLEN]; | ||
| 365 | char id_buf[4]; | ||
| 366 | u64 id; | ||
| 367 | int fd; | ||
| 368 | |||
| 369 | snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, | ||
| 370 | sys_name, evt_name); | ||
| 371 | |||
| 372 | fd = open(evt_path, O_RDONLY); | ||
| 373 | if (fd < 0) | ||
| 374 | return -1; | ||
| 375 | 364 | ||
| 376 | if (read(fd, id_buf, sizeof(id_buf)) < 0) { | 365 | if (!list) { |
| 377 | close(fd); | 366 | list = malloc(sizeof(*list)); |
| 378 | return -1; | 367 | if (!list) |
| 368 | return -ENOMEM; | ||
| 369 | INIT_LIST_HEAD(list); | ||
| 379 | } | 370 | } |
| 380 | 371 | ||
| 381 | close(fd); | 372 | evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); |
| 382 | id = atoll(id_buf); | 373 | if (!evsel) { |
| 383 | 374 | free(list); | |
| 384 | memset(&attr, 0, sizeof(attr)); | 375 | return -ENOMEM; |
| 385 | attr.config = id; | 376 | } |
| 386 | attr.type = PERF_TYPE_TRACEPOINT; | ||
| 387 | attr.sample_type |= PERF_SAMPLE_RAW; | ||
| 388 | attr.sample_type |= PERF_SAMPLE_TIME; | ||
| 389 | attr.sample_type |= PERF_SAMPLE_CPU; | ||
| 390 | attr.sample_type |= PERF_SAMPLE_PERIOD; | ||
| 391 | attr.sample_period = 1; | ||
| 392 | 377 | ||
| 393 | snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); | 378 | list_add_tail(&evsel->node, list); |
| 394 | return add_event(list, idx, &attr, name); | 379 | *listp = list; |
| 380 | return 0; | ||
| 395 | } | 381 | } |
| 396 | 382 | ||
| 397 | static int add_tracepoint_multi(struct list_head **list, int *idx, | 383 | static int add_tracepoint_multi(struct list_head **list, int *idx, |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index ca85444bcfbf..9181bf212fb9 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
| @@ -805,7 +805,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | |||
| 805 | if (pyevent == NULL) | 805 | if (pyevent == NULL) |
| 806 | return PyErr_NoMemory(); | 806 | return PyErr_NoMemory(); |
| 807 | 807 | ||
| 808 | err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false); | 808 | err = perf_evlist__parse_sample(evlist, event, &pevent->sample); |
| 809 | if (err) | 809 | if (err) |
| 810 | return PyErr_Format(PyExc_OSError, | 810 | return PyErr_Format(PyExc_OSError, |
| 811 | "perf: can't parse sample, err=%d", err); | 811 | "perf: can't parse sample, err=%d", err); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 3049b0ae7003..8cdd23239c90 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -722,8 +722,7 @@ static int flush_sample_queue(struct perf_session *s, | |||
| 722 | if (iter->timestamp > limit) | 722 | if (iter->timestamp > limit) |
| 723 | break; | 723 | break; |
| 724 | 724 | ||
| 725 | ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample, | 725 | ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); |
| 726 | s->header.needs_swap); | ||
| 727 | if (ret) | 726 | if (ret) |
| 728 | pr_err("Can't parse sample, err = %d\n", ret); | 727 | pr_err("Can't parse sample, err = %d\n", ret); |
| 729 | else { | 728 | else { |
| @@ -1174,8 +1173,7 @@ static int perf_session__process_event(struct perf_session *session, | |||
| 1174 | /* | 1173 | /* |
| 1175 | * For all kernel events we get the sample data | 1174 | * For all kernel events we get the sample data |
| 1176 | */ | 1175 | */ |
| 1177 | ret = perf_evlist__parse_sample(session->evlist, event, &sample, | 1176 | ret = perf_evlist__parse_sample(session->evlist, event, &sample); |
| 1178 | session->header.needs_swap); | ||
| 1179 | if (ret) | 1177 | if (ret) |
| 1180 | return ret; | 1178 | return ret; |
| 1181 | 1179 | ||
