Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: * Improve listing of accessible enum perf probe variables, from Hyeoncheol Lee. * Don't stop the build if the audit libraries are not installed, fix from Namhyung Kim.
Unified · Split
| @@ -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] | |
| @@ -559,6 +559,19 @@ else · 558 unmodified lines | ||
| 559 | 559 | LIB_OBJS += $(OUTPUT)util/unwind.o |
| 560 | 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 | 575 | ifdef NO_NEWT |
| 563 | 576 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT |
| 564 | 577 | else |
| @@ -320,7 +320,7 @@ try_again: · 319 unmodified lines | ||
| 320 | 320 | } |
| 321 | 321 | } |
| 322 | 322 | |
| 323 | − if (perf_evlist__set_filters(evlist)) { | |
| 323 | + if (perf_evlist__apply_filters(evlist)) { | |
| 324 | 324 | error("failed to set filter with %d (%s)\n", errno, |
| 325 | 325 | strerror(errno)); |
| 326 | 326 | rc = -1; |
| @@ -478,7 +478,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) · 477 unmodified lines | ||
| 478 | 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 | 482 | error("failed to set filter with %d (%s)\n", errno, |
| 483 | 483 | strerror(errno)); |
| 484 | 484 | return -1; |
| @@ -564,7 +564,7 @@ static int test__basic_mmap(void) · 563 unmodified lines | ||
| 564 | 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 | 568 | if (err) { |
| 569 | 569 | pr_err("Can't parse sample, err = %d\n", err); |
| 570 | 570 | goto out_munmap; |
| @@ -781,7 +781,7 @@ static int test__PERF_RECORD(void) · 210 unmodified lines | ||
| 781 | 781 | if (type < PERF_RECORD_MAX) |
| 782 | 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 | 785 | if (err < 0) { |
| 786 | 786 | if (verbose) |
| 787 | 787 | perf_event__fprintf(event, stderr); |
| @@ -1289,6 +1289,118 @@ static int perf_evsel__tp_sched_test(void) · 501 unmodified lines | ||
| 1289 | 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 | 1404 | static struct test { |
| 1293 | 1405 | const char *desc; |
| 1294 | 1406 | int (*func)(void); |
| @@ -1339,6 +1451,10 @@ static struct test { · 44 unmodified lines | ||
| 1339 | 1451 | .desc = "Check parsing of sched tracepoints fields", |
| 1340 | 1452 | .func = perf_evsel__tp_sched_test, |
| 1341 | 1453 | }, |
| 1454 | + { | |
| 1455 | + .desc = "Generate and check syscalls:sys_enter_open event fields", | |
| 1456 | + .func = test__syscall_open_tp_fields, | |
| 1457 | + }, | |
| 1342 | 1458 | { |
| 1343 | 1459 | .func = NULL, |
| 1344 | 1460 | }, |
| @@ -823,7 +823,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx) · 822 unmodified lines | ||
| 823 | 823 | int ret; |
| 824 | 824 | |
| 825 | 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 | 827 | if (ret) { |
| 828 | 828 | pr_err("Can't parse sample, err = %d\n", ret); |
| 829 | 829 | continue; |
| @@ -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 | +} | |
| @@ -34,6 +34,7 @@ extern int cmd_kmem(int argc, const char **argv, const char *prefix); · 33 unmodified lines | ||
| 34 | 34 | extern int cmd_lock(int argc, const char **argv, const char *prefix); |
| 35 | 35 | extern int cmd_kvm(int argc, const char **argv, const char *prefix); |
| 36 | 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 | 38 | extern int cmd_inject(int argc, const char **argv, const char *prefix); |
| 38 | 39 | |
| 39 | 40 | extern int find_scripts(char **scripts_array, char **scripts_path_array); |
| @@ -17,6 +17,7 @@ perf-report mainporcelain common · 16 unmodified lines | ||
| 17 | 17 | perf-stat mainporcelain common |
| 18 | 18 | perf-timechart mainporcelain common |
| 19 | 19 | perf-top mainporcelain common |
| 20 | +perf-trace mainporcelain common | |
| 20 | 21 | perf-script mainporcelain common |
| 21 | 22 | perf-probe mainporcelain full |
| 22 | 23 | perf-kmem mainporcelain common |
| @@ -193,3 +193,14 @@ int main(void) · 192 unmodified lines | ||
| 193 | 193 | } |
| 194 | 194 | endef |
| 195 | 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 | |
| @@ -55,6 +55,9 @@ static struct cmd_struct commands[] = { · 54 unmodified lines | ||
| 55 | 55 | { "lock", cmd_lock, 0 }, |
| 56 | 56 | { "kvm", cmd_kvm, 0 }, |
| 57 | 57 | { "test", cmd_test, 0 }, |
| 58 | +#ifndef NO_LIBAUDIT_SUPPORT | |
| 59 | + { "trace", cmd_trace, 0 }, | |
| 60 | +#endif | |
| 58 | 61 | { "inject", cmd_inject, 0 }, |
| 59 | 62 | }; |
| 60 | 63 | |
| @@ -2,6 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | #define __PERF_CPUMAP_H |
| 3 | 3 | |
| 4 | 4 | #include <stdio.h> |
| 5 | +#include <stdbool.h> | |
| 5 | 6 | |
| 6 | 7 | struct cpu_map { |
| 7 | 8 | int nr; |
| @@ -14,4 +15,14 @@ void cpu_map__delete(struct cpu_map *map); · 6 unmodified lines | ||
| 14 | 15 | struct cpu_map *cpu_map__read(FILE *file); |
| 15 | 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 | 28 | #endif /* __PERF_CPUMAP_H */ |
| @@ -804,6 +804,8 @@ int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) · 803 unmodified lines | ||
| 804 | 804 | tmp = "union "; |
| 805 | 805 | else if (tag == DW_TAG_structure_type) |
| 806 | 806 | tmp = "struct "; |
| 807 | + else if (tag == DW_TAG_enumeration_type) | |
| 808 | + tmp = "enum "; | |
| 807 | 809 | /* Write a base name */ |
| 808 | 810 | ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); |
| 809 | 811 | return (ret >= len) ? -E2BIG : ret; |
| @@ -304,7 +304,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) · 303 unmodified lines | ||
| 304 | 304 | int cpu, thread; |
| 305 | 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 | 308 | list_for_each_entry(pos, &evlist->entries, node) { |
| 309 | 309 | for (thread = 0; thread < evlist->threads->nr; thread++) |
| 310 | 310 | ioctl(FD(pos, cpu, thread), |
| @@ -315,7 +315,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) · 4 unmodified lines | ||
| 315 | 315 | |
| 316 | 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 | 319 | evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); |
| 320 | 320 | return evlist->pollfd != NULL ? 0 : -ENOMEM; |
| 321 | 321 | } |
| @@ -475,8 +475,8 @@ void perf_evlist__munmap(struct perf_evlist *evlist) · 153 unmodified lines | ||
| 475 | 475 | |
| 476 | 476 | static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) |
| 477 | 477 | { |
| 478 | − evlist->nr_mmaps = evlist->cpus->nr; | |
| 479 | − if (evlist->cpus->map[0] == -1) | |
| 478 | + evlist->nr_mmaps = cpu_map__nr(evlist->cpus); | |
| 479 | + if (cpu_map__all(evlist->cpus)) | |
| 480 | 480 | evlist->nr_mmaps = evlist->threads->nr; |
| 481 | 481 | evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); |
| 482 | 482 | return evlist->mmap != NULL ? 0 : -ENOMEM; |
| @@ -622,11 +622,11 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, · 139 unmodified lines | ||
| 622 | 622 | list_for_each_entry(evsel, &evlist->entries, node) { |
| 623 | 623 | if ((evsel->attr.read_format & PERF_FORMAT_ID) && |
| 624 | 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 | 626 | return -ENOMEM; |
| 627 | 627 | } |
| 628 | 628 | |
| 629 | − if (evlist->cpus->map[0] == -1) | |
| 629 | + if (cpu_map__all(cpus)) | |
| 630 | 630 | return perf_evlist__mmap_per_thread(evlist, prot, mask); |
| 631 | 631 | |
| 632 | 632 | return perf_evlist__mmap_per_cpu(evlist, prot, mask); |
| @@ -666,32 +666,39 @@ void perf_evlist__delete_maps(struct perf_evlist *evlist) · 33 unmodified lines | ||
| 666 | 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 | 671 | struct perf_evsel *evsel; |
| 674 | − char *filter; | |
| 675 | − int thread; | |
| 676 | − int cpu; | |
| 677 | − int err; | |
| 678 | − int fd; | |
| 672 | + int err = 0; | |
| 673 | + const int ncpus = cpu_map__nr(evlist->cpus), | |
| 674 | + nthreads = evlist->threads->nr; | |
| 679 | 675 | |
| 680 | 676 | list_for_each_entry(evsel, &evlist->entries, node) { |
| 681 | − filter = evsel->filter; | |
| 682 | − if (!filter) | |
| 677 | + if (evsel->filter == NULL) | |
| 683 | 678 | continue; |
| 684 | − for (cpu = 0; cpu < cpus->nr; cpu++) { | |
| 685 | − for (thread = 0; thread < threads->nr; thread++) { | |
| 686 | − fd = FD(evsel, cpu, thread); | |
| 687 | − err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter); | |
| 688 | − if (err) | |
| 689 | − return err; | |
| 690 | − } | |
| 691 | − } | |
| 679 | + | |
| 680 | + err = perf_evsel__set_filter(evsel, ncpus, nthreads, evsel->filter); | |
| 681 | + if (err) | |
| 682 | + break; | |
| 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 | 704 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) |
| @@ -884,10 +891,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist) · 186 unmodified lines | ||
| 884 | 891 | } |
| 885 | 892 | |
| 886 | 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 | 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 | 900 | size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) |
| @@ -72,6 +72,8 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, · 71 unmodified lines | ||
| 72 | 72 | #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ |
| 73 | 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 | 77 | struct perf_evsel * |
| 76 | 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, · 37 unmodified lines | ||
| 115 | 117 | int perf_evlist__create_maps(struct perf_evlist *evlist, |
| 116 | 118 | struct perf_target *target); |
| 117 | 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 | 122 | void __perf_evlist__set_leader(struct list_head *list); |
| 121 | 123 | void perf_evlist__set_leader(struct perf_evlist *evlist); |
| @@ -125,7 +127,7 @@ bool perf_evlist__sample_id_all(struct perf_evlist *evlist); · 3 unmodified lines | ||
| 125 | 127 | u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); |
| 126 | 128 | |
| 127 | 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 | 132 | bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); |
| 131 | 133 | bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); |
| @@ -70,7 +70,7 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) · 69 unmodified lines | ||
| 70 | 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 | 75 | int fd, n; |
| 76 | 76 | char *filename; |
| @@ -117,21 +117,28 @@ struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx) · 40 unmodified lines | ||
| 117 | 117 | |
| 118 | 118 | if (evsel != NULL) { |
| 119 | 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 | 128 | evsel->tp_format = event_format__new(sys, name); |
| 124 | 129 | if (evsel->tp_format == NULL) |
| 125 | 130 | goto out_free; |
| 126 | 131 | |
| 132 | + event_attr_init(&attr); | |
| 127 | 133 | attr.config = evsel->tp_format->id; |
| 134 | + attr.sample_period = 1; | |
| 128 | 135 | perf_evsel__init(evsel, &attr, idx); |
| 129 | − evsel->name = evsel->tp_format->name; | |
| 130 | 136 | } |
| 131 | 137 | |
| 132 | 138 | return evsel; |
| 133 | 139 | |
| 134 | 140 | out_free: |
| 141 | + free(evsel->name); | |
| 135 | 142 | free(evsel); |
| 136 | 143 | return NULL; |
| 137 | 144 | } |
| @@ -501,6 +508,24 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) · 363 unmodified lines | ||
| 501 | 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 | 529 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) |
| 505 | 530 | { |
| 506 | 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) · 55 unmodified lines | ||
| 562 | 587 | perf_evsel__exit(evsel); |
| 563 | 588 | close_cgroup(evsel->cgrp); |
| 564 | 589 | free(evsel->group_name); |
| 565 | − if (evsel->tp_format && evsel->name == evsel->tp_format->name) { | |
| 566 | − evsel->name = NULL; | |
| 590 | + if (evsel->tp_format) | |
| 567 | 591 | pevent_free_format(evsel->tp_format); |
| 568 | − } | |
| 569 | 592 | free(evsel->name); |
| 570 | 593 | free(evsel); |
| 571 | 594 | } |
| @@ -763,11 +786,13 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel, · 191 unmodified lines | ||
| 763 | 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, | |
| 767 | − struct perf_sample *sample, | |
| 768 | − bool swapped) | |
| 789 | +static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, | |
| 790 | + const union perf_event *event, | |
| 791 | + struct perf_sample *sample) | |
| 769 | 792 | { |
| 793 | + u64 type = evsel->attr.sample_type; | |
| 770 | 794 | const u64 *array = event->sample.array; |
| 795 | + bool swapped = evsel->needs_swap; | |
| 771 | 796 | union u64_swap u; |
| 772 | 797 | |
| 773 | 798 | array += ((event->header.size - |
| @@ -828,10 +853,11 @@ static bool sample_overlap(const union perf_event *event, · 54 unmodified lines | ||
| 828 | 853 | } |
| 829 | 854 | |
| 830 | 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 | 858 | u64 type = evsel->attr.sample_type; |
| 834 | 859 | u64 regs_user = evsel->attr.sample_regs_user; |
| 860 | + bool swapped = evsel->needs_swap; | |
| 835 | 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, · 10 unmodified lines | ||
| 848 | 874 | if (event->header.type != PERF_RECORD_SAMPLE) { |
| 849 | 875 | if (!evsel->attr.sample_id_all) |
| 850 | 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 | 880 | array = event->sample.array; |
| @@ -1078,7 +1104,7 @@ struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *nam · 223 unmodified lines | ||
| 1078 | 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 | 1108 | const char *name) |
| 1083 | 1109 | { |
| 1084 | 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, · 16 unmodified lines | ||
| 1101 | 1127 | const char *name) |
| 1102 | 1128 | { |
| 1103 | 1129 | struct format_field *field = perf_evsel__field(evsel, name); |
| 1104 | − u64 val; | |
| 1130 | + void *ptr; | |
| 1131 | + u64 value; | |
| 1105 | 1132 | |
| 1106 | 1133 | if (!field) |
| 1107 | 1134 | return 0; |
| 1108 | 1135 | |
| 1109 | − val = pevent_read_number(evsel->tp_format->pevent, | |
| 1110 | − sample->raw_data + field->offset, field->size); | |
| 1111 | − return val; | |
| 1136 | + ptr = sample->raw_data + field->offset; | |
| 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 | } |
| @@ -69,6 +69,7 @@ struct perf_evsel { · 68 unmodified lines | ||
| 69 | 69 | struct cpu_map *cpus; |
| 70 | 70 | unsigned int sample_size; |
| 71 | 71 | bool supported; |
| 72 | + bool needs_swap; | |
| 72 | 73 | /* parse modifier helper */ |
| 73 | 74 | int exclude_GH; |
| 74 | 75 | struct perf_evsel *leader; |
| @@ -82,6 +83,9 @@ struct perf_record_opts; · 7 unmodified lines | ||
| 82 | 83 | |
| 83 | 84 | struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); |
| 84 | 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 | 89 | void perf_evsel__init(struct perf_evsel *evsel, |
| 86 | 90 | struct perf_event_attr *attr, int idx); |
| 87 | 91 | void perf_evsel__exit(struct perf_evsel *evsel); |
| @@ -114,6 +118,9 @@ void perf_evsel__free_fd(struct perf_evsel *evsel); · 26 unmodified lines | ||
| 114 | 118 | void perf_evsel__free_id(struct perf_evsel *evsel); |
| 115 | 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 | 124 | int perf_evsel__open_per_cpu(struct perf_evsel *evsel, |
| 118 | 125 | struct cpu_map *cpus); |
| 119 | 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); · 4 unmodified lines | ||
| 124 | 131 | |
| 125 | 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 | 135 | const char *name); |
| 129 | 136 | u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, |
| 130 | 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 | 146 | struct format_field; |
| 133 | 147 | |
| 134 | 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, · 70 unmodified lines | ||
| 205 | 219 | void hists__init(struct hists *hists); |
| 206 | 220 | |
| 207 | 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 | 224 | static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) |
| 211 | 225 | { |
| @@ -1256,8 +1256,10 @@ read_event_desc(struct perf_header *ph, int fd) · 1255 unmodified lines | ||
| 1256 | 1256 | if (ret != (ssize_t)sizeof(nr)) |
| 1257 | 1257 | goto error; |
| 1258 | 1258 | |
| 1259 | − if (ph->needs_swap) | |
| 1259 | + if (ph->needs_swap) { | |
| 1260 | 1260 | nr = bswap_32(nr); |
| 1261 | + evsel->needs_swap = true; | |
| 1262 | + } | |
| 1261 | 1263 | |
| 1262 | 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) · 1362 unmodified lines | ||
| 2626 | 2628 | |
| 2627 | 2629 | if (evsel == NULL) |
| 2628 | 2630 | goto out_delete_evlist; |
| 2631 | + | |
| 2632 | + evsel->needs_swap = header->needs_swap; | |
| 2629 | 2633 | /* |
| 2630 | 2634 | * Do it before so that if perf_evsel__alloc_id fails, this |
| 2631 | 2635 | * entry gets purged too at perf_evlist__delete(). |
| @@ -410,8 +410,13 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused, · 409 unmodified lines | ||
| 410 | 410 | cmp = hist_entry__collapse(iter, he); |
| 411 | 411 | |
| 412 | 412 | if (!cmp) { |
| 413 | − iter->period += he->period; | |
| 414 | − iter->nr_events += he->nr_events; | |
| 413 | + iter->period += he->period; | |
| 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 | 420 | if (symbol_conf.use_callchain) { |
| 416 | 421 | callchain_cursor_reset(&callchain_cursor); |
| 417 | 422 | callchain_merge(&callchain_cursor, |
| @@ -356,42 +356,28 @@ int parse_events_add_cache(struct list_head **list, int *idx, · 355 unmodified lines | ||
| 356 | 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 | 360 | char *sys_name, char *evt_name) |
| 361 | 361 | { |
| 362 | − struct perf_event_attr attr; | |
| 363 | − char name[MAX_NAME_LEN]; | |
| 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; | |
| 362 | + struct perf_evsel *evsel; | |
| 363 | + struct list_head *list = *listp; | |
| 375 | 364 | |
| 376 | − if (read(fd, id_buf, sizeof(id_buf)) < 0) { | |
| 377 | − close(fd); | |
| 378 | − return -1; | |
| 365 | + if (!list) { | |
| 366 | + list = malloc(sizeof(*list)); | |
| 367 | + if (!list) | |
| 368 | + return -ENOMEM; | |
| 369 | + INIT_LIST_HEAD(list); | |
| 379 | 370 | } |
| 380 | 371 | |
| 381 | − close(fd); | |
| 382 | − id = atoll(id_buf); | |
| 383 | − | |
| 384 | − memset(&attr, 0, sizeof(attr)); | |
| 385 | − attr.config = id; | |
| 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; | |
| 372 | + evsel = perf_evsel__newtp(sys_name, evt_name, (*idx)++); | |
| 373 | + if (!evsel) { | |
| 374 | + free(list); | |
| 375 | + return -ENOMEM; | |
| 376 | + } | |
| 392 | 377 | |
| 393 | − snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); | |
| 394 | − return add_event(list, idx, &attr, name); | |
| 378 | + list_add_tail(&evsel->node, list); | |
| 379 | + *listp = list; | |
| 380 | + return 0; | |
| 395 | 381 | } |
| 396 | 382 | |
| 397 | 383 | static int add_tracepoint_multi(struct list_head **list, int *idx, |
| @@ -805,7 +805,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, · 804 unmodified lines | ||
| 805 | 805 | if (pyevent == NULL) |
| 806 | 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 | 809 | if (err) |
| 810 | 810 | return PyErr_Format(PyExc_OSError, |
| 811 | 811 | "perf: can't parse sample, err=%d", err); |
| @@ -722,8 +722,7 @@ static int flush_sample_queue(struct perf_session *s, · 721 unmodified lines | ||
| 722 | 722 | if (iter->timestamp > limit) |
| 723 | 723 | break; |
| 724 | 724 | |
| 725 | − ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample, | |
| 726 | − s->header.needs_swap); | |
| 725 | + ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample); | |
| 727 | 726 | if (ret) |
| 728 | 727 | pr_err("Can't parse sample, err = %d\n", ret); |
| 729 | 728 | else { |
| @@ -1174,8 +1173,7 @@ static int perf_session__process_event(struct perf_session *session, · 444 unmodified lines | ||
| 1174 | 1173 | /* |
| 1175 | 1174 | * For all kernel events we get the sample data |
| 1176 | 1175 | */ |
| 1177 | − ret = perf_evlist__parse_sample(session->evlist, event, &sample, | |
| 1178 | − session->header.needs_swap); | |
| 1176 | + ret = perf_evlist__parse_sample(session->evlist, event, &sample); | |
| 1179 | 1177 | if (ret) |
| 1180 | 1178 | return ret; |
| 1181 | 1179 | |