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 | ||